ffmpeg源码分析——av_register_all

1 av_register_all()函数骨架

void av_register_all(void)
{
    static int initialized;
    if (initialized)
        return;   // 如果没有初始化过就直接返回
    initialized = 1;
    avcodec_register_all();
    // 注册复用和解复用器,这里其他格式注册的过程是一样的,省略
    REGISTER_MUXDEMUX(MP3,              mp3);
    // 注册协议,这里其他协议注册的过程是一样的,省略
    REGISTER_PROTOCOL(RTP,              rtp);
}

原理:在ffmepg中主要通过链表来保存注册的所有的复用和解复用器,使用全局静态变量来保存这些链表的头指针,所以通过向链表中插入指定的节点来完成注册。

av_register_all()函数就是用这种方式完成了endoder和decoder,parser,muxer和demuxer以及protocol的注册。

2 代码细节分析

2.1 avcodec_register_all()函数骨架

void avcodec_register_all(void)
{
    static int initialized;

    if (initialized)
        return; // 如果已经注册过了,直接返回
    initialized = 1;

    /* hardware accelerators */
    REGISTER_HWACCEL(H263_VAAPI,        h263_vaapi);
    /*注册编解码器*/
    REGISTER_DECODER(H264,              h264);
    REGISTER_DECODER(LIBSTAGEFRIGHT_H264, libstagefright_h264); 
    /*注册解析器*/
    REGISTER_PARSER(H264,               h264);
}

2.1.1 REGISTER_DECODER宏定义

#define REGISTER_DECODER(X, x)                                          \
    {                                                                   \
        extern AVCodec ff_##x##_decoder;                                \
        if (CONFIG_##X##_DECODER)                                       \
            avcodec_register(&ff_##x##_decoder);                        \
    }
相当于就是:
extern AVCodec ff_h264_decoder;
if(CONFIG_H264_DECODER)
    avcodec_register(&ff_h264_decoder);
2.1.1.1 avcodec_register()函数

刚开始分析不要陷入代码细节中,无法自拔!一句话,把当前的AVCodec加到链表的尾部。

void avcodec_register(AVCodec *codec)
{
    AVCodec **p;
    avcodec_init();
    p = last_avcodec;
    codec->next = NULL;

    while(*p || avpriv_atomic_ptr_cas((void * volatile *)p, NULL, codec))
        p = &(*p)->next;
    last_avcodec = &codec->next;

    if (codec->init_static_data)
        codec->init_static_data(codec);
}

2.1.2 REGISTER_PARSER宏定义

#define REGISTER_PARSER(X, x)                                           \
    {                                                                   \
        extern AVCodecParser ff_##x##_parser;                           \
        if (CONFIG_##X##_PARSER)                                        \
            av_register_codec_parser(&ff_##x##_parser);                 \
    }
extern AVCodecParser ff_h264_parser;
if(CONFIG_H264_PARSER)
     av_register_codec_parser(&ff_h264_parser);


2.2 REGISTER_MUXDEMUX宏定义

#define REGISTER_MUXDEMUX(X, x) REGISTER_MUXER(X, x); REGISTER_DEMUXER(X, x)

这个宏定义显然是用了两个宏定义。

2.2.1  REGISTER_MUXER和REGISTER_DEMUXER

#define REGISTER_MUXER(X, x)                                            \
    {                                                                   \
        extern AVOutputFormat ff_##x##_muxer;                           \
        if (CONFIG_##X##_MUXER)                                         \
            av_register_output_format(&ff_##x##_muxer);                 \
    }
#define REGISTER_DEMUXER(X, x)                                          \
    {                                                                   \
        extern AVInputFormat ff_##x##_demuxer;                          \
        if (CONFIG_##X##_DEMUXER)                                       \
            av_register_input_format(&ff_##x##_demuxer);                \
    }
这段代码宏定义展开之后是:
extern AVOutputFormat ff_mp3_muxer;
if(CONFIG_MP3_MUXER)
    av_register_output_format(&ff_mp3_muxer);
extern AVInputFormat ff_mp3_demuxer;                          
if (CONFIG_MP3_DEMUXER)                                       
    av_register_input_format(&ff_mp3_demuxer);

    

2.2.1.1 av_register_output_format()函数和av_register_input_format()函数

输入格式和输出格式都是用的链表来管理的,而这两个链表的头尾指针则用静态全局变量(文件内)来保存,如下:

/** head of registered input format linked list */
static AVInputFormat *first_iformat = NULL;
/** head of registered output format linked list */
static AVOutputFormat *first_oformat = NULL;

static AVInputFormat **last_iformat = &first_iformat;
static AVOutputFormat **last_oformat = &first_oformat;

遍历链表把当前的AVInputFormat和AVOutputFormat加到链表的尾部。

void av_register_input_format(AVInputFormat *format)
{
    AVInputFormat **p = last_iformat;

    format->next = NULL;
    while(*p || avpriv_atomic_ptr_cas((void * volatile *)p, NULL, format))
        p = &(*p)->next;
    last_iformat = &format->next;
}
void av_register_output_format(AVOutputFormat *format)
{
    AVOutputFormat **p = last_oformat;

    format->next = NULL;
    while(*p || avpriv_atomic_ptr_cas((void * volatile *)p, NULL, format))
        p = &(*p)->next;
    last_oformat = &format->next;
}


2.3 REGISTER_PROTOCOL宏定义

#define REGISTER_PROTOCOL(X, x)                                         \
    {                                                                   \
        extern URLProtocol ff_##x##_protocol;                           \
        if (CONFIG_##X##_PROTOCOL)                                      \
            ffurl_register_protocol(&ff_##x##_protocol);                \
    }
这段代码就相当于:
extern URLProtocol ff_rtp_protocol;                           \
        if (CONFIG_RTP_PROTOCOL)                                      \
            ffurl_register_protocol(&ff_rtp_protocol);

2.3.1 ffurl_register_protocol()函数

同样的协议也是用的链表来保存的,由全局静态变量first_protocol指针。

static URLProtocol *first_protocol = NULL;

这样ffurl_register_protocol()函数就是把参数中的这个指针给插入到链表中去(完成注册)。

int ffurl_register_protocol(URLProtocol *protocol)
{
    URLProtocol **p;
    p = &first_protocol;
    while (*p)
        p = &(*p)->next;
    *p             = protocol;
    protocol->next = NULL;
    return 0;
}

3 代码中的链表深入分析

参考资料:

1 http://blog.csdn.net/leixiaohua1020/article/details/12677129

2 http://blog.csdn.net/leixiaohua1020/article/details/12677265

你可能感兴趣的:(ffmpeg源码分析——av_register_all)