avcodec_register_all()的函数定义位于libavcodec/allcodecs.c。
它是用来注册编解码器的函数,只有调用了该函数,才能使用编解码器、解析器、硬件加速器等。
编码器和解码器调用的是同一个注册函数 avcodec_register();
代码解析:
这段代码使用了链表结构,并为链表设置了两个全局指针,
指向链表头的 first_avcodec,
指向链表尾的 last_avcodec,
调用函数avpriv_atomic_ptr_cas((void * volatile *)p, NULL, codec),将新的codec添加到链表的尾部。
如果last_avcodec没有指向链表的尾,则要先遍历链表,将其指向链表的尾部。
这样做的好处是省去了每次添加一个新codec时,必须对链表的从头到尾遍历以找到链表的尾部。
如果使用遍历的方法,则代码要用如下写:
//注册所有的AVCodec
void avcodec_register(AVCodec *codec)
{
AVCodec **p;
/* 初始化 */
avcodec_init();
/* 从第一个开始, 遍历到链表的尾部 */
p = &first_avcodec;
while (*p != NULL)
p = &(*p)->next;
/* 将新的codec添加到链表的尾部 */
*p = codec;
codec->next = NULL;
if (codec->init_static_data)
codec->init_static_data(codec);
}
这段代码和编解码器的用法一样。
代码解析:
解析器的注册方法和编解码器的注册方法不一样,
它是用av_first_parser指向链表的头,
然后再将新的parser添加到原链表的头之前,再将av_first_parser指向这个新链表头。
参考文档:
http://blog.csdn.net/leixiaohua1020/article/details/12677265
它是用来注册编解码器的函数,只有调用了该函数,才能使用编解码器、解析器、硬件加速器等。
1. 函数主体如下:
- void avcodec_register_all(void)
- {
- static int initialized;
- if (initialized)
- return;
- initialized = 1;
- /* hardware accelerators */
- REGISTER_HWACCEL();
- /* video codecs */
- REGISTER_ENCODER();
- REGISTER_DECODER();
- /* audio codecs */
- REGISTER_ENCODER();
- REGISTER_DECODER();
- /* PCM codecs */
- REGISTER_ENCODER();
- REGISTER_DECODER();
- /* subtitles */
- /* external libraries */
- /* parsers */
- REGISTER_PARSER();
- }
2. 注册函数的宏定义如下:
- #define REGISTER_HWACCEL(X, x) \
- { \
- extern AVHWAccel ff_##x##_hwaccel; \
- if (CONFIG_##X##_HWACCEL) \
- av_register_hwaccel(&ff_##x##_hwaccel); \
- }
- #define REGISTER_ENCODER(X, x) \
- { \
- extern AVCodec ff_##x##_encoder; \
- if (CONFIG_##X##_ENCODER) \
- avcodec_register(&ff_##x##_encoder); \
- }
- #define REGISTER_DECODER(X, x) \
- { \
- extern AVCodec ff_##x##_decoder; \
- if (CONFIG_##X##_DECODER) \
- avcodec_register(&ff_##x##_decoder); \
- }
- #define REGISTER_ENCDEC(X, x) REGISTER_ENCODER(X, x); REGISTER_DECODER(X, x)
- #define REGISTER_PARSER(X, x) \
- { \
- extern AVCodecParser ff_##x##_parser; \
- if (CONFIG_##X##_PARSER) \
- av_register_codec_parser(&ff_##x##_parser); \
- }
编码器和解码器调用的是同一个注册函数 avcodec_register();
3. 编解码器
- REGISTER_DECODER(H264, h264);
- #define REGISTER_DECODER(X, x) \
- { \
- extern AVCodec ff_##x##_decoder; \
- if (CONFIG_##X##_DECODER) \
- avcodec_register(&ff_##x##_decoder); \
- }
- 的宏展开后:
- {
- /* extern表明全局唯一 */
- extern AVCodec ff_h264_decoder;
- if (CONFIG_H264_DECODER)
- avcodec_register(&ff_h264_decoder);
- }
- avcodec_register的函数定义: libavcodec/utils.c
- /* encoder management */
- static AVCodec *first_avcodec = NULL;
- static AVCodec **last_avcodec = &first_avcodec;
- av_cold void avcodec_register(AVCodec *codec)
- {
- AVCodec **p;
- avcodec_init();
- p = last_avcodec;
- codec->next = NULL;
- /* 将新的codec 添加到链接的尾部*/
- 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);
- }
- void *avpriv_atomic_ptr_cas(void * volatile *ptr, void *oldval, void *newval)
- {
- if (*ptr == oldval) {
- *ptr = newval;
- return oldval;
- }
- return *ptr;
- }
这段代码使用了链表结构,并为链表设置了两个全局指针,
指向链表头的 first_avcodec,
指向链表尾的 last_avcodec,
调用函数avpriv_atomic_ptr_cas((void * volatile *)p, NULL, codec),将新的codec添加到链表的尾部。
如果last_avcodec没有指向链表的尾,则要先遍历链表,将其指向链表的尾部。
这样做的好处是省去了每次添加一个新codec时,必须对链表的从头到尾遍历以找到链表的尾部。
如果使用遍历的方法,则代码要用如下写:
//注册所有的AVCodec
void avcodec_register(AVCodec *codec)
{
AVCodec **p;
/* 初始化 */
avcodec_init();
/* 从第一个开始, 遍历到链表的尾部 */
p = &first_avcodec;
while (*p != NULL)
p = &(*p)->next;
/* 将新的codec添加到链表的尾部 */
*p = codec;
codec->next = NULL;
if (codec->init_static_data)
codec->init_static_data(codec);
}
4. 硬件加速器
- REGISTER_HWACCEL(H264_CUVID, h264_cuvid);
- 的宏展开后为:
- {
- extern AVHWAccel ff_h264_cuvid_hwacel;
- if (CONFIG_H264_CUVID_HWACCEL)
- av_register_hwaccel(&ff_h264_cuvid_hwacel);
- }
- av_register_hwaccel()的定义位于libavcodec/utils.c
- static AVHWAccel *first_hwaccel = NULL;
- static AVHWAccel **last_hwaccel = &first_hwaccel;
- void av_register_hwaccel(AVHWAccel *hwaccel)
- {
- AVHWAccel **p = last_hwaccel;
- hwaccel->next = NULL;
- while(*p || avpriv_atomic_ptr_cas((void * volatile *)p, NULL, hwaccel))
- p = &(*p)->next;
- last_hwaccel = &hwaccel->next;
- }
5. 解析器
- REGISTER_PARSER(AAC, aac);
- #define REGISTER_PARSER(X, x) \
- { \
- extern AVCodecParser ff_##x##_parser; \
- if (CONFIG_##X##_PARSER) \
- av_register_codec_parser(&ff_##x##_parser); \
- }
- 宏展开后:
- {
- extern AVCodecParser ff_aac_parser;
- if (CONFIG_AAC_PARSER)
- av_register_codec_parser(&ff_aac_parser);
- }
- av_register_codec_parser的函数定义,libavcodec/parser.c
- static AVCodecParser *av_first_parser = NULL;
- void av_register_codec_parser(AVCodecParser *parser)
- {
- do {
- parser->next = av_first_parser;
- } while (parser->next != avpriv_atomic_ptr_cas((void * volatile *)&av_first_parser, parser->next, parser));
- }
- void *avpriv_atomic_ptr_cas(void * volatile *ptr, void *oldval, void *newval)
- {
- if (*ptr == oldval) {
- *ptr = newval;
- return oldval;
- }
- return *ptr;
- }
解析器的注册方法和编解码器的注册方法不一样,
它是用av_first_parser指向链表的头,
然后再将新的parser添加到原链表的头之前,再将av_first_parser指向这个新链表头。
参考文档:
http://blog.csdn.net/leixiaohua1020/article/details/12677265