熟悉ffmpeg的同学都知道在编译ffmpeg的时候,可以”定制”一些模块,只使能需要的模块,不使能多余的模块。比如如果我们需要一个视频编码库,可能只使能x264就足够了,用这句:–enable-libx264.如果需要解析RTSP协议,那只使能rtsp模块,用这句:–enable-demuxer=RTSP.这样一来可以提高我们的编译速度,二来编译出来的库或者可执行文件也不会很大。
想必每个人初次接触,都会感觉很神奇。在这里我就简单介绍一下其中的奥秘。
ffmpeg提供了一个编译配置脚本,FFmpeg configure script,即configure文件。configure代码看起来有那么点复杂,没必要进去细究一二了。大概就是说,该文件接收一系列输入配置参数,并输出makefile文件、配置文件以及config.h头文件。其中config.h里面,会根据我们的输入参数,生成若干宏定义。比如如果输入参数有–enable-demuxer=RTSP,则会生成一个CONFIG_RTSP_DEMUXER的宏。
打开config.h,可找到如下代码:
#define CONFIG_RTSP_DEMUXER 1
可以猜测一下,Makefile里面自然也包含了RTSP demuxer相关代码了.这样在编译的时候,就会把RTSP demux相关代码编译进去.
在我们调用ffmpeg的时候,首先我们需要调用函数:
av_register_all();
看看这个函数里面的实现,可看到这里面多次调用几个宏函数进行muxer\demuxer的注册:
/* (de)muxers */
REGISTER_MUXER (A64, a64);
REGISTER_DEMUXER (AA, aa);
REGISTER_DEMUXER (AAC, aac);
REGISTER_MUXDEMUX(AC3, ac3);
REGISTER_DEMUXER (ACM, acm);
REGISTER_DEMUXER (ACT, act);
REGISTER_DEMUXER (ADF, adf);
REGISTER_DEMUXER (ADP, adp);
REGISTER_DEMUXER (ADS, ads);
REGISTER_MUXER (ADTS, adts);
REGISTER_MUXDEMUX(ADX, adx);
REGISTER_DEMUXER (AEA, aea);
REGISTER_DEMUXER (AFC, afc);
REGISTER_MUXDEMUX(AIFF, aiff);
REGISTER_DEMUXER (AIX, aix);
...
表面上看,是把各种不同的协议注册了.那到底内部是怎么实现的呢?我们一探究竟.
看看这几个宏函数的定义:
#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); \
}
#define REGISTER_MUXDEMUX(X, x) REGISTER_MUXER(X, x); REGISTER_DEMUXER(X, x)
我们以注册AAC来举例,可看到这三个宏函数都接收AAC和aac两个参数,而第三个宏函数,实际上将前两个宏函数分别执行一次.
前两个宏函数的实现类似.首先,声明ff_aac_muxer\ff_aac_demuxer变量,这两个变量最终会在aac对应的文件里定义(但是否编译这些文件,还是要取决于是否有使能了AAC).其次再根据CONFIG_AAC_MUXER\CONFIG_AAC_DEMUXER的定义,决定是否调用av_register_output_format\av_register_input_format.
如果我们在configure里面使能了AAC,那在config.h里应该可看到CONFIG_AAC_MUXER\CONFIG_AAC_DEMUXER两个宏的值为1,这样av_register_output_format\av_register_input_format最终会得以执行.这两个函数功能很相似,大概功能,就是将ff_aac_muxer\ff_aac_demuxer分别放置到一个format链表中.
两个链表的定义如下:
/**
* @file
* Format register and lookup
*/
/** head of registered input format linked list */
static AVInputFormat *first_iformat = NULL;
/** head of registered output format linked list */
static AVOutputFormat *first_oformat = NULL;
在上一篇博客,我提到了,在ffmpeg probe时,会遍历所有的demuxer,分别进行probe并根据评分来选择.这里说的遍历demuxer,实际上就是遍历AVInputFormat链表.
// 遍历链表
while ((fmt1 = av_iformat_next(fmt1))) {
...
}
而av_iformat_next,顾名思义,就是取当前format的下一个format.
而如果没有在configure里使能AAC,那ff_aac_muxer\ff_aac_demuxer最终并不会被定义,也不会被添加到链表,这样probe的时候,也就不会有AAC的参与.