ffmpeg的编译选项浅析

熟悉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的参与.

猜你喜欢

转载自blog.csdn.net/jyt0551/article/details/77074662