FFmpeg源码剖析-通用:avcodec_register_all()

FFMpeg 源码分析(1)av_register_all() FFMpeg 源码分析(1)av_register_all()一般我们使用FFMpeg做编解码都会先调用`av_register_all()`这个函数开头,完成基本的初始化工作。而至于它具体初始化了哪些东西呢,我们直接从代码里面来看吧。 void av_register_all(void) { static int initialized; //标志位指示是否已经初始化 阅读详情
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.youkuaiyun.com/leixiaohua1020/article/details/12677265


从学龄前开始解读FFMPEG代码 之 avcodec_register_all函数 提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录前言一、pandas是什么?二、使用步骤1.引入库2.读入数据总结 前言 提示:这里可以添加本文要记录的大概内容: 例如:随着人工智能的不断发展,机器学习这门技术也越来越重要,很多人都开启了学习机器学习,本文就介绍了机器学习的基础内容。 提示:以下是本篇文章正文内容,下面案例可供参考 一、pandas是什么? 示例:pandas 是基于NumPy 的一种工具,该工具是为了解决数据分析任务而创建的。 二、使用步骤 1.引入库 代码 阅读详情

相关推荐

ffmpeg源码简析(二)av_register_all(),avcodec_register_all()

av_register_all()该函数在所有基于ffmpeg的应用程序中几乎都是第一个被调用的。只有调用了该函数,才能使用复用器,编码器等。av_register_all()调用了avcodec_register_all()。avcodec_register_all()注册了和编解码器有关的组件:硬件加速器,解码器,编码器,Parser,Bitstream Filter。av_register_a

WangShuo的专栏 5204

FFmpeg源码分析:avcodec_register_all()注册编解码器

FFmpeg的avcodec_register_all()用于注册编解码器,FFmpeg4.0版本以前是调用该方法,运行期把所有编译的编解码器添加到链表。但是FFmpeg4.0版本以后,改为编译期自动生成编解码数组,还有解析器数组。

徐福记456 3万+

ffmpeg源码分析之av_register_all()

1.muxer/demuxer使用的结构是AVOutp

BIGBurning 5722

FFMPEG源码分析一 av_register_all()

我们在使用FFMPEG库时,第一个调用的就是av_register_all(),这个函数到底做了什么,有什么用,这里做个简单分析。本文基于雷霄骅博客学习而来。详情请移步。

yunxiaobaobei的博客 968

ffmpeg源码分析五:ffmpeg调用x264编码器的过程分析

所有编码器和解码器都是在

Austin的博客 2893

雷神FFMpeg源码学习笔记

雷神FFMpeg源码学习笔记 文章目录雷神FFMpeg源码学习笔记读取编码并依据编码初始化内容结构每一帧的视频解码处理 读取编码并依据编码初始化内容结构 在开始编解码视频的时候首先第一步需要注册一个编解码器 :av_register_all(); avformat_open_input来打开这个文件并给AVformartcontext赋值 ,在其中会去查找当前缓存文件的格式 avformat_o...

Abe_liu的博客 1269

ffmpeg 源代码简单分析 : avcodec_register_all()

本文分析一下ffmpeg注册编解码器等的函数avcodec_register_all()(注意不是av_register_all(),那是注册所有东西的)。该函数在所有基于ffmpeg的应用程序中几乎都是第一个被调用的。只有调用了该函数,才能使用编解码器等。 之前已经写过一篇文章了: ffmpeg 源代码简单分析 : av_register_all() 其实注册编解码器和注册复用器解复用

雷霄骅(leixiaohua1020)的专栏 4万+

ffmpeg源码剖析.pdf

首先我们来暴增- ~下研习信心。

FFMpeg (一) av_register_all()

FFMpeg (一) av_register_all()

qq_37705525的博客 4846

FFMPEG源码深入解析.pdf

FFMPEG源码深入解析, 墙裂推荐, 深入理解不容错过. FFMPEG源码深入解析, 墙裂推荐, 深入理解不容错过.

FFMPEGplay源代码分析:整体流程图

FFplay源代码分析:整体流程图,主要用于学习FFMPEG的play功能

ffmpeg源码分析:av_register_all()和avcodec_register_all()

一、av_register_all() 二、avcodec_register_all() 一、av_register_all() av_register_all()注册所有的demuxer,muxer,outdev,indev设备。其定义在文件libavformat\allformats.c中,如下所示: void av_register_all(void) { ff_thread_once(&av_format_next_init, av_format_init_ne...

yangguoyu8023的博客 3720

Vivado安装教程:多版本共存的配置技巧

详解Vivado安装教程中的多版本共存配置技巧,帮助用户在同一系统中管理不同版本的Vivado开发环境,提升开发效率与兼容性,适用于需要切换版本的FPGA开发者。

weixin_35257663的博客 1775

[9]【ffmpeg源码分析 1】av_register_all()和avcodec_register_all()

日期:2016.10.18 作者:isshe github:github.com/isshe 邮箱:i.sshe@outlook.com 前言接下来打算学习一下编解码,不过好像很难的样子, 希望能看懂。1. av_register_all() 所在文件:allformats.c 主要代码:(每个宏只列举一个) void av_register_all(void) {

i.sshe的博客 3194

告别编译噩梦:Vcpkg+Cmake一站式集成Tesseract-OCR C++开发环境(Windows)

本文详细介绍了如何在Windows系统上使用Vcpkg和CMake快速集成Tesseract-OCR C++开发环境,解决传统编译过程中的依赖问题。通过一键安装和自动化配置,开发者可以高效搭建OCR识别系统,支持中英文识别,并提供了常见问题的解决方案和进阶技巧。

weixin_29009339的博客 231

人工智能发展史(从起步到磅礴)以及浪潮阶段

随机森林是将多个有差异的弱学习器(决策树)Bagging并行组合,通过建立多个的拟合较好且有差异模型去组合决策,以优化泛化性能的一种集成学习方法。从论文里可以了解到,GPT-1具有1.17个参数,采用了12层的Transformer 解码器结构,使用5GB的无标注文本数据,在8个GPU上训练了一个月,然后再进行人工监督的微调。训练相结合的理念(该方法在当时计算力上还是有很多挑战,基本上都是和链式求导的梯度算法相关的),这也解决了单层感知器不能做非线性分类的问题,开启了神经网络新一轮的高潮。

xiao77224li的博客 7505

FFmpeg源代码简单分析:avio_open2()

FFmpeg源代码结构图 - 解码 FFmpeg源代码结构图 - 编码 【通用】 FFmpeg 源代码简单分析:av_register_all() FFmpeg 源代码简单分析:avcodec_register_all() FFmpeg 源代码简单分析:内存的分配和释放(av_malloc()、av_free()等) FFmpeg 源代码简单分析:常见结构体的初始化和销毁(AVForm...

m0_37346206的博客 849

YOLOv11改进 | 模型知识蒸馏篇 | 利用模型蒸馏改进YOLOv11进行无损涨点 | 在线蒸馏 (附代码 + 完整文件 + 解析教程)

这篇文章给大家带来的最新改进是模型的蒸馏,利用教师模型指导学生模型从而进行模型的涨点,本文的内容不仅可以用于论文中,在目前的绝大多数的工作中模型蒸馏是一项非常重要的技术,所以大家可以仔细学习一下本文的内容,本文从YOLOv11的项目文件为例,进行详细的修改教程,文章内包括完整的修改教程,针对小白我出了视频修改教程,如果你还不会我提供了修改后的文件大家直接运行即可,所以说不用担心不会适用!模型蒸馏真正的无损涨点,蒸馏你只看这一篇文章就足够了,本文内容为在线蒸馏教程,之前的文章为离线蒸馏!

Snu77的博客 2667

ffmpeg源码阅读:avcodec

libavcodec用来处理各种编码、解码,例如h263、h264等。

j99999999955555的博客 479

极验验证码: 一点即过验证(鼠标轨迹分析)

2、第一个验证接口分析(第一个w值还原) 3、第二个验证接口(第二个w值还原)这里定位w生成跟上篇文章一样,就不展开了;主要分析tt值(鼠标轨迹)的生成逻辑

qq_49268524的博客 1009

一周一个Unity小游戏2D反弹球游戏 - 球反弹的方向

本文将实现当球在球板上反弹时,会根据球板移动的方向来给球施加反弹的力,例如当球板往左移动时反弹球,则球应向左上方反弹,若球板往右移动时反弹球,则球应向右上方反弹。

Giver的博客 752
上一篇: H.265与H.264的差异详解
下一篇: FFmpeg源码剖析-通用:av_register_all()
北雨南萍
北雨南萍 领域专家: 操作系统技术领域 领域专家: 操作系统技术领域
博客等级 码龄20年 2665粉丝 453原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

北雨南萍

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值