我们在使用FFMPEG库时,第一个调用的就是av_register_all(),这个函数到底做了什么,有什么用,这里做个简单分析。
本文基于雷霄骅博客学习而来。详情请移步FFmpeg源代码结构图 - 编码_ffmpeg源码结构_雷霄骅的博客-CSDN博客
av_register_all()首先调用了 avcodec_register_all()注册了硬件加速器,编码器/解码器,parser,Bitstream Filter,而后注册所有的解复用器,还有支持的流媒体协议。
av_register_all()调用结构如下:
void av_register_all(void)
{
static int initialized;
//如果注册了,就直接返回,避免重复注册
if (initialized)
return;
initialized = 1;
//注册所有的codec
avcodec_register_all();
//注册所有的MUXER(复用器和解复用器)
/* (de)muxers */
REGISTER_MUXER (A64, a64);
REGISTER_DEMUXER (AAC, aac);
REGISTER_MUXDEMUX (AC3, ac3);
......
}
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_HWACCEL (H264_DXVA2, h264_dxva2);
REGISTER_HWACCEL (H264_VAAPI, h264_vaapi);
REGISTER_HWACCEL (H264_VDA, h264_vda);
REGISTER_HWACCEL (MPEG1_VDPAU, mpeg1_vdpau);
REGISTER_HWACCEL (MPEG2_DXVA2, mpeg2_dxva2);
REGISTER_HWACCEL (MPEG2_VAAPI, mpeg2_vaapi);
REGISTER_HWACCEL (MPEG2_VDPAU, mpeg2_vdpau);
REGISTER_HWACCEL (MPEG4_VAAPI, mpeg4_vaapi);
REGISTER_HWACCEL (VC1_DXVA2, vc1_dxva2);
REGISTER_HWACCEL (VC1_VAAPI, vc1_vaapi);
REGISTER_HWACCEL (WMV3_DXVA2, wmv3_dxva2);
REGISTER_HWACCEL (WMV3_VAAPI, wmv3_vaapi);
/* video codecs */
REGISTER_ENCODER (A64MULTI, a64multi);
REGISTER_ENCODER (A64MULTI5, a64multi5);
REGISTER_DECODER (AASC, aasc);
......
}
我们再看REGISTER_XXXX这个宏的具体结构和作用。
以解复用为例
#define REGISTER_DEMUXER(X,x) { \
extern AVInputFormat ff_##x##_demuxer; \
if(CONFIG_##X##_DEMUXER) av_register_input_format(&ff_##x##_demuxer); }
define里面的##可能不太常见,它的含义就是拼接两个字符串,比如
#define Conn(x,y) x##y
表示
int n = Conn(123,456); 结果就是n=123456;
我们以REGISTER_DEMUXER (AAC, aac)为例,则它等效于
extern AVInputFormat ff_aac_demuxer;
if(CONFIG_AAC_DEMUXER) av_register_input_format(&ff_aac_demuxer);
使用REGISTER_DEMUXER (AAC, aac)就是调用函数av_register_input_format函数
/** head of registered input format linked list */
static AVInputFormat *first_iformat = NULL;
void av_register_input_format(AVInputFormat *format)
{
AVInputFormat **p;
p = &first_iformat;
while (*p != NULL) p = &(*p)->next;
*p = format;
format->next = NULL;
}
我们可以看到first_iformat是链表的头,这个函数就是遍历链表,然后把我们传入的结构添加链表尾,也就是完成了注册,这样后面我们就可以使用注册好了的结构,例如编码器等。所有的注册都是这样的操作。
这样我们就理解了为什么首先需要调用av_register_all(),以及内部的实现原理。
av_register_all()和 avcodec_register_all()是公开的API函数都可以调用,其他函数仅供ffmpeg内部使用。如果你只需要做编码的操作可以直接调用 avcodec_register_all(),而不用调用av_register_all(),不过一般直接调用av_register_all()即可。