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

日期:2016.10.18
作者:isshe
github:github.com/isshe
邮箱:[email protected]

前言

接下来打算学习一下编解码,不过好像很难的样子, 希望能看懂。

1. av_register_all()

  • 所在文件:allformats.c
  • 主要代码:(每个宏只列举一个)
void av_register_all(void)
{
    static int initialized;

    if (initialized)
        return;

    //注册编解码器
    avcodec_register_all();

    /* (de)muxers */
    //注册复用器
    REGISTER_MUXER   (A64,              a64);
    //注册解复用器
    REGISTER_DEMUXER (AA,               aa);
    //两个同时注册
    REGISTER_MUXDEMUX(AC3,              ac3);

1.1 REGISTER_MUXER宏

  • 代码:
#define REGISTER_MUXER(X, x)                                            \
    {                                                                   \
        extern AVOutputFormat ff_##x##_muxer;                           \
        if (CONFIG_##X##_MUXER)                                         \
            av_register_output_format(&ff_##x##_muxer);                 \
    }
  • “##”号起连接作用,例如:a##b = ab.
  • ff_##x##_muxer, 一个与x对应的AVOutputFormat.
  • 其实这些外部变量,一般定义的时候就赋了初值。(限于篇幅,具体的示例在下面编解码相关的地方)

1.1.1 av_register_output_format()

  • 注册一个与该格式相应的AVFormat结构
  • 相关代码:
//head of registered output format linked list 
static AVOutputFormat *first_oformat = NULL;
static AVOutputFormat **last_oformat = &first_oformat;

void av_register_output_format(AVOutputFormat *format)
{
    AVOutputFormat **p = last_oformat;

    // Note, format could be added after the first 2 checks but that implies that *p is no longer NULL
    //检查链表中有无指定的format,没有就加入。
    //在前面两个条件成立后才把format连接到p链表中。
    while(p != &format->next && !format->next && avpriv_atomic_ptr_cas((void * volatile *)p, NULL, format))
        p = &(*p)->next;

    if (!format->next)
        last_oformat = &format->next;
}
  • last_oformat是一个二次指针。
  • avpriv_atomic_ptr_cas把format放到p链表中。
  • 遍历链表,把指定format加到链表后面。

1.2 REGISTER_DEMUXER 宏

  • 和REGISTER_MUXER()类似。

1.3 REGISTER_MUXDEMUX 宏

  • #define REGISTER_MUXDEMUX(X, x) REGISTER_MUXER(X, x); REGISTER_DEMUXER(X, x)

2. avcodec_register_all()

  • 所在文件:allcodecs.c
  • 主要代码:(每种情况列举一个)
void avcodec_register_all(void)
{
    static int initialized;

    if (initialized)
        return;
    initialized = 1;

    //硬件加速器
    /* hardware accelerators */
    REGISTER_HWACCEL(H263_CUVID,        h263_cuvid);

    //注意以下函数适用于视频和音频
    //注册编码器
    REGISTER_ENCODER(A64MULTI,          a64multi);
    //注册解码器
    REGISTER_DECODER(AASC,              aasc);
    //两个同时注册
    REGISTER_ENCDEC (ALIAS_PIX,         alias_pix);
    //注册分析器???不懂
    REGISTER_PARSER(AAC,                aac);

2.1 REGISTER_HWACCEL 宏

  • 注册硬件加速器宏
  • 代码:
#define REGISTER_HWACCEL(X, x)                                          \
    {                                                                   \
        extern AVHWAccel ff_##x##_hwaccel;                              \
        if (CONFIG_##X##_HWACCEL)                                       \
            av_register_hwaccel(&ff_##x##_hwaccel);                     \
    }
  • extern的那个变量在源码中没找着…

2.1.1 av_register_hwaccel()

  • 注册硬件加速器的函数
  • 代码:和前面的muter类似。
void av_register_hwaccel(AVHWAccel *hwaccel)
{
    AVHWAccel **p = last_hwaccel;
    hwaccel->next = NULL;
    while(*p || avpriv_atomic_ptr_cas((void * volatile *)p, NULL, hwaccel))
        p = &(*p)->next;
    last_hwaccel = &hwaccel->next;
}

2.2 REGISTER_ENCODER宏

  • 注册编码器的宏
  • 代码:
#define REGISTER_ENCODER(X, x)                                          \
    {                                                                   \
        extern AVCodec ff_##x##_encoder;                                \
        if (CONFIG_##X##_ENCODER)                                       \
            avcodec_register(&ff_##x##_encoder);                        \
    }

2.2.1 ff_##x##_encoder变量

  • 用aac示例:ff_aac_encoder变量
AVCodec ff_aac_encoder = {
    .name           = "aac",
    .long_name      = NULL_IF_CONFIG_SMALL("AAC (Advanced Audio Coding)"),
    .type           = AVMEDIA_TYPE_AUDIO,
    .id             = AV_CODEC_ID_AAC,
    .priv_data_size = sizeof(AACEncContext),
    .init           = aac_encode_init,   //初始化
    .encode2        = aac_encode_frame,  //编码函数
    .close          = aac_encode_end,    //
    .defaults       = aac_encode_defaults,
    .supported_samplerates = mpeg4audio_sample_rates,
    .caps_internal  = FF_CODEC_CAP_INIT_THREADSAFE,
    .capabilities   = AV_CODEC_CAP_SMALL_LAST_FRAME | AV_CODEC_CAP_DELAY,
    .sample_fmts    = (const enum AVSampleFormat[]){ AV_SAMPLE_FMT_FLTP,
                                                     AV_SAMPLE_FMT_NONE },
    .priv_class     = &aacenc_class,
};
  • 可见,这些外部变量都是已经赋值好的,解码的【或其他】也类似。
  • 下面调用的注册函数就是把这么一个结构放到链表中。

2.2.2 avcodec_register

  • 注册编码器的函数
  • 代码:
av_cold void avcodec_register(AVCodec *codec)
{
    AVCodec **p;
    avcodec_init();      //!!!
    p = last_avcodec;  
    codec->next = NULL;

    while(*p || avpriv_atomic_ptr_cas((void * volatile *)p, NULL, codec))
        p = &(*p)->next;
    last_avcodec = &codec->next;

    if (codec->init_static_data)
        codec->init_static_data(codec);
}

2.3 REGISTER_DECODER 宏

  • 和编码类似

2.4 REGISTER_ENCDEC 宏

  • 同时注册解码和编码器

2.5 REGISTER_PARSER 宏

  • 代码:
#define REGISTER_PARSER(X, x)                                           \
    {                                                                   \
        extern AVCodecParser ff_##x##_parser;                           \
        if (CONFIG_##X##_PARSER)                                        \
            av_register_codec_parser(&ff_##x##_parser);                 \
    }

av_register_codec_parser()

  • 代码:
void av_register_codec_parser(AVCodecParser *parser)
{
    do {
        parser->next = av_first_parser;
    } while (parser->next != avpriv_atomic_ptr_cas((void * volatile *)&av_first_parser, parser->next, parser));
}

参考资料

  • 雷神博文:av_register_all()
  • 雷神博文:avcodec_register_all()
  • ffmpeg-3.1.3源码

代码下载

  • ffmpeg-3.1.3源码:http://download.csdn.net/detail/i_scream_/9657369

你可能感兴趣的:(「初探」ffmpeg)