懒人李冰

记录我的生活、学习

FFMPEG 源码分析:avcodec_register_all

avcodec_register_all 提供注册codecparsersfilters的功能。

avcodec_register_all 框架

avcodec_register_all
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
void avcodec_register_all(void)
{
    static int initialized;

    if(initialized)
        return;
    initialized = 1;

    /* hardwar accelerators */
    REGISTER_HWACCEL(H264_MMAL,h264_mmal);
    ......

    /* video codecs */
    REGISTER_DECODER(HEVC,hevc);
    ......
    REGISTER_ENCDEC (MPEG4,mpeg4);
    ......
    /* audio codecs */
    REGISTER_ENCDEC (AAC,aac);
    ......
    /* parsers */
    REGISTER_PARSER(HEVC,hevc);
    /* bitstream filters */
    REGISTER_BSF(HEVC_MP4TOANNEXB,hevc_mp4toannexb);
}

调用关系

avcodec_register_all的框架和调用关系图可以看出,该函数主要注册硬件加速器、codec、parsers、比特流过滤器等。

源码分析

注册一次

initialized_once
1
2
3
4
5
static int initialized;

if(initialized)
    return;
initialized = 1;

该段代码可以看出,当调用过该函数一次后,再次调用时,该函数直接返回。
注意,这种方法在 FFMEPG 源码中非常常见。

注册硬件加速器

REGISTER_HWACCEL
1
2
3
4
5
6
#define REGISTER_HWACCEL(X, x)                                          \
    {                                                                   \
        extern AVHWAccel ff_##x##_hwaccel;                              \
        if (CONFIG_##X##_HWACCEL)                                       \
            av_register_hwaccel(&ff_##x##_hwaccel);                     \
    }

H264为例,REGISTER_HWACCEL(H264_MMAL, h264_mmal)展开如下:

1
2
3
extern AVHWAccel ff_h264_mmal_hwaccel;
if(CONFIG_H264_MMAL_HWACCEL)
    av_register_hwaccel(&ff_h264_mmal_hwaccel);

av_register_hwaccel(&ff_h264_mmal_hwaccel) 展开如下:

av_register_hwaccel
1
2
3
4
5
6
7
8
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;
}

注册codec

REGISTER_DECODER
1
2
3
4
5
6
#define REGISTER_DECODER(X, x)                                          \
    {                                                                   \
        extern AVCodec ff_##x##_decoder;                                \
        if (CONFIG_##X##_DECODER)                                       \
            avcodec_register(&ff_##x##_decoder);                        \
    }

HEVC为例,REGISTER_DECODER(HEVC, hevc)展开如下:

1
2
3
extern AVCodec ff_hevc_decoder;
if(CONFIG_HEVC_DECODER)
    avcodec_register(&ff_hevc_decoder);

avcodec_register(&ff_hevc_decoder)展开如下:

avcodec_register
1
2
3
4
5
6
7
8
9
10
11
12
13
14
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);
}

ff_hevc_decoder 定义如下:

ff_hevc_decoder
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
AVCodec ff_hevc_decoder = {
    .name                  = "hevc",
    .long_name             = NULL_IF_CONFIG_SMALL("HEVC (High Efficiency Video Coding)"),
    .type                  = AVMEDIA_TYPE_VIDEO,
    .id                    = AV_CODEC_ID_HEVC,
    .priv_data_size        = sizeof(HEVCContext),
    .priv_class            = &hevc_decoder_class,
    .init                  = hevc_decode_init,
    .close                 = hevc_decode_free,
    .decode                = hevc_decode_frame,
    .flush                 = hevc_decode_flush,
    .update_thread_context = hevc_update_thread_context,
    .init_thread_copy      = hevc_init_thread_copy,
    .capabilities          = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_DELAY |
                             AV_CODEC_CAP_SLICE_THREADS | AV_CODEC_CAP_FRAME_THREADS,
    .profiles              = NULL_IF_CONFIG_SMALL(profiles),
};

注册parser

REGISTER_PARSER
1
2
3
4
5
6
#define REGISTER_PARSER(X, x)                                           \
    {                                                                   \
        extern AVCodecParser ff_##x##_parser;                           \
        if (CONFIG_##X##_PARSER)                                        \
            av_register_codec_parser(&ff_##x##_parser);                 \
    }

HEVC为例,REGISTER_PARSER(HEVC, hevc)展开如下:

1
2
3
extern AVCoderParser ff_hevc_parser;
if(CONFIG_HEVC_PARSER)
    av_register_codec_parser(&ff_hevc_parser);

av_register_codec_parser(&ff_hevc_parser) 展开如下:

av_register_codec_parser
1
2
3
4
5
6
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));
}

ff_hevc_parser 定义如下:

ff_hevc_parser
1
2
3
4
5
6
7
AVCodecParser ff_hevc_parser = {
    .codec_ids      = { AV_CODEC_ID_HEVC },
    .priv_data_size = sizeof(HEVCParserContext),
    .parser_parse   = hevc_parse,
    .parser_close   = hevc_parser_close,
    .split          = hevc_split,
};

注册bitstream filters

REGISTER_BSF
1
2
3
4
5
6
#define REGISTER_BSF(X, x)                                              \
    {                                                                   \
        extern AVBitStreamFilter ff_##x##_bsf;                          \
        if (CONFIG_##X##_BSF)                                           \
            av_register_bitstream_filter(&ff_##x##_bsf);                \
    }

HEVC为例,REGISTER_BSF(HEVC_MP4TOANNEXB, hevc_mp4toannexb) 展开如下:

1
2
3
extern AVBitStreamFilter ff_hevc_mp4toannexb_bsf;
if(CONFIG_HEVC_MP4TOANNEXB_BSF)
    av_register_bitstream_filter(&ff_hevc_mp4toannexb_bsf);

av_register_bitstream_filter(&&ff_hevc_mp4toannexb_bsf) 展开如下:

av_register_bitstream_filter
1
2
3
4
5
6
void av_register_bitstream_filter(AVBitStreamFilter *bsf)
{
    do {
        bsf->next = first_bitstream_filter;
    } while(bsf->next != avpriv_atomic_ptr_cas((void * volatile *)&first_bitstream_filter, bsf->next, bsf));
}

ff_hevc_mp4toannexb_bsf 定义如下:

ff_hevc_mp4toannexb_bsf
1
2
3
4
5
6
AVBitStreamFilter ff_hevc_mp4toannexb_bsf = {
    "hevc_mp4toannexb",
    sizeof(HEVCBSFContext),
    hevc_mp4toannexb_filter,
    hevc_mp4toannexb_close,
};