Chinaunix首页 | 论坛 | 博客
  • 博客访问: 7773774
  • 博文数量: 701
  • 博客积分: 2150
  • 博客等级: 上尉
  • 技术积分: 13233
  • 用 户 组: 普通用户
  • 注册时间: 2011-06-29 16:28
个人简介

天行健,君子以自强不息!

文章分类

全部博文(701)

文章存档

2019年(2)

2018年(12)

2017年(76)

2016年(120)

2015年(178)

2014年(129)

2013年(123)

2012年(61)

分类: 云计算

2017-09-11 23:21:00

avcodec_register_all()的函数定义位于libavcodec/allcodecs.c。
它是用来注册编解码器的函数,只有调用了该函数,才能使用编解码器、解析器、硬件加速器等。

1. 函数主体如下:

  1. void avcodec_register_all(void)
  2. {

  3.     static int initialized;


  4.     if (initialized)

  5.         return;

  6.     initialized = 1;
  7.     /* hardware accelerators */
  8.     REGISTER_HWACCEL();

  9.     /* video codecs */
  10.     REGISTER_ENCODER();
  11.     REGISTER_DECODER();

  12.     /* audio codecs */
  13.     REGISTER_ENCODER();
  14.     REGISTER_DECODER();

  15.     /* PCM codecs */
  16.     REGISTER_ENCODER();
  17.     REGISTER_DECODER();

  18.     /* subtitles */

  19.     /* external libraries */

  20.     /* parsers */
  21.     REGISTER_PARSER();


  22. }

2. 注册函数的宏定义如下:


  1. #define REGISTER_HWACCEL(X, x) \
  2.     { \
  3.         extern AVHWAccel ff_##x##_hwaccel; \
  4.         if (CONFIG_##X##_HWACCEL) \
  5.             av_register_hwaccel(&ff_##x##_hwaccel); \
  6.     }

  7. #define REGISTER_ENCODER(X, x) \
  8.     { \
  9.         extern AVCodec ff_##x##_encoder; \
  10.         if (CONFIG_##X##_ENCODER) \
  11.             avcodec_register(&ff_##x##_encoder); \
  12.     }

  13. #define REGISTER_DECODER(X, x) \
  14.     { \
  15.         extern AVCodec ff_##x##_decoder; \
  16.         if (CONFIG_##X##_DECODER) \
  17.             avcodec_register(&ff_##x##_decoder); \
  18.     }

  19. #define REGISTER_ENCDEC(X, x) REGISTER_ENCODER(X, x); REGISTER_DECODER(X, x)
  20. #define REGISTER_PARSER(X, x) \
  21.     { \
  22.         extern AVCodecParser ff_##x##_parser; \
  23.         if (CONFIG_##X##_PARSER) \
  24.             av_register_codec_parser(&ff_##x##_parser); \
  25.     }

编码器和解码器调用的是同一个注册函数 avcodec_register();


3. 编解码器


  1. REGISTER_DECODER(H264, h264);

  2. #define REGISTER_DECODER(X, x) \
  3.     { \
  4.         extern AVCodec ff_##x##_decoder; \
  5.         if (CONFIG_##X##_DECODER) \
  6.             avcodec_register(&ff_##x##_decoder); \
  7.     }

  8. 的宏展开后:
  9. {
  10.   /* extern表明全局唯一 */
  11.   extern AVCodec ff_h264_decoder;
  12.   if (CONFIG_H264_DECODER)
  13.     avcodec_register(&ff_h264_decoder);
  14. }

  15. avcodec_register的函数定义: libavcodec/utils.c
  16. /* encoder management */
  17. static AVCodec *first_avcodec = NULL;
  18. static AVCodec **last_avcodec = &first_avcodec;
  19. av_cold void avcodec_register(AVCodec *codec)
  20. {
  21.     AVCodec **p;
  22.     avcodec_init();
  23.     p = last_avcodec;
  24.     codec->next = NULL;

  25.     /* 将新的codec 添加到链接的尾部*/
  26.     while(*p || avpriv_atomic_ptr_cas((void * volatile *)p, NULL, codec))
  27.         p = &(*p)->next;

  28.     last_avcodec = &codec->next;
  29.     if (codec->init_static_data)
  30.         codec->init_static_data(codec);
  31. }

  32. void *avpriv_atomic_ptr_cas(void * volatile *ptr, void *oldval, void *newval)
  33. {
  34.     if (*ptr == oldval) {
  35.         *ptr = newval;
  36.         return oldval;
  37.     }
  38.     return *ptr;
  39. }
代码解析:
这段代码使用了链表结构,并为链表设置了两个全局指针,
指向链表头的 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. 硬件加速器


  1. REGISTER_HWACCEL(H264_CUVID, h264_cuvid);
  2. 的宏展开后为:
  3. {
  4.     extern AVHWAccel ff_h264_cuvid_hwacel;
  5.     if (CONFIG_H264_CUVID_HWACCEL)
  6.         av_register_hwaccel(&ff_h264_cuvid_hwacel);
  7. }

  8. av_register_hwaccel()的定义位于libavcodec/utils.c
  9. static AVHWAccel *first_hwaccel = NULL;

  10. static AVHWAccel **last_hwaccel = &first_hwaccel;

  11. void av_register_hwaccel(AVHWAccel *hwaccel)
  12. {
  13.     AVHWAccel **p = last_hwaccel;
  14.     hwaccel->next = NULL;

  15.     while(*p || avpriv_atomic_ptr_cas((void * volatile *)p, NULL, hwaccel))
  16.         p = &(*p)->next;
  17.     last_hwaccel = &hwaccel->next;
  18. }
这段代码和编解码器的用法一样。

5. 解析器


  1. REGISTER_PARSER(AAC, aac);
  2. #define REGISTER_PARSER(X, x) \
  3.     { \
  4.         extern AVCodecParser ff_##x##_parser; \
  5.         if (CONFIG_##X##_PARSER) \
  6.             av_register_codec_parser(&ff_##x##_parser); \
  7.     }

  8. 宏展开后:
  9. {
  10.   extern AVCodecParser ff_aac_parser;
  11.   if (CONFIG_AAC_PARSER)
  12.     av_register_codec_parser(&ff_aac_parser);
  13. }

  14. av_register_codec_parser的函数定义,libavcodec/parser.c

  15. static AVCodecParser *av_first_parser = NULL;
  16. void av_register_codec_parser(AVCodecParser *parser)
  17. {
  18.     do {
  19.         parser->next = av_first_parser;
  20.     } while (parser->next != avpriv_atomic_ptr_cas((void * volatile *)&av_first_parser, parser->next, parser));
  21. }

  22. void *avpriv_atomic_ptr_cas(void * volatile *ptr, void *oldval, void *newval)
  23. {
  24.     if (*ptr == oldval) {
  25.         *ptr = newval;
  26.         return oldval;
  27.     }
  28.     return *ptr;
  29. }
代码解析:
解析器的注册方法和编解码器的注册方法不一样,
它是用av_first_parser指向链表的头,
然后再将新的parser添加到原链表的头之前,再将av_first_parser指向这个新链表头。


参考文档:
http://blog.csdn.net/leixiaohua1020/article/details/12677265


阅读(1683) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~