ffmpeg源码分析:avcodec_find_encoder()和avcodec_find_decoder()

      我们以avcodec_find_encoder(AV_CODEC_ID_AAC)和avcodec_find_decoder(AV_CODEC_ID_AAC)来分析avcodec_find_encoder和avcodec_find_decoder两个函数。

一、avcodec_find_encoder()

avcodec_find_encoder(AV_CODEC_ID_AAC);

      查找ID值为AV_CODEC_ID_AAC的AAC编码器。avcodec_find_encoder()的源代码在文件libavcodec\allcodecs.c中,如下所示:

AVCodec *avcodec_find_encoder(enum AVCodecID id)
{
    return find_codec(id, av_codec_is_encoder);
}

      从源代码可以看出avcodec_find_encoder()调用了一个find_encdec(),注意它的第二个参数是一个函数指针,av_codec_is_encoder函数后面会用到。
      下面我们看一下find_codec()函数的源码,如下所示:

libavcodec\allcodecs.c
static AVCodec *find_codec(enum AVCodecID id, int (*x)(const AVCodec *))
{
    const AVCodec *p, *experimental = NULL;
    void *i = 0;

    id = remap_deprecated_codec_id(id);

    while ((p = av_codec_iterate(&i))) {
        if (!x(p))
            continue;
        if (p->id == id) {
            if (p->capabilities & AV_CODEC_CAP_EXPERIMENTAL && !experimental) {
                experimental = p;
            } else
                return (AVCodec*)p;
        }
    }

    return (AVCodec*)experimental;
}

      find_codec()函数既可以用来查找编码器,也可以用来查找解码器。find_codec()中有一个循环,该循环会遍历AVCodec结构的链表,逐一比较输入的ID和每一个编码器或者解码器的ID,直到找到ID取值相等的编码器或者解码器。
在这里有几点需要注意:
(1)av_codec_iterate是一个遍历器,遍历变量codec_list,存储AVCodec的数组。av_codec_iterate的定义见下面。
(2)remap_deprecated_codec_id()用于将一些过时的编码器ID映射到新的编码器ID。
(3)函数的第二个参数x,就是avcodec_find_encoder调用find_codec传递过来的函数av_codec_is_encoder。如果是avcodec_find_decoder调用find_codec传递过来的函数就是av_codec_is_decoder。即find_codec()函数既可以用来查找编码器,也可以用来查找解码器。编码器和解码器都存在变量codec_list中。把满足要求的AVCodec的ID值与传入的ID值进行比较,如果相等,就是我们要找的解码器或者编码器。

const AVCodec *av_codec_iterate(void **opaque)
{
    uintptr_t i = (uintptr_t)*opaque;
    const AVCodec *c = codec_list[i];

    ff_thread_once(&av_codec_static_init, av_codec_init_static);

    if (c)
        *opaque = (void*)(i + 1);

    return c;
}
libavcodec\utils.c
int av_codec_is_encoder(const AVCodec *codec)
{
    return codec && (codec->encode_sub || codec->encode2 ||codec->send_frame);
}

      从源代码可以看出,av_codec_is_encoder()判断了一下AVCodec是否包含了encode2()或者encode_sub()接口函数。当满足这些要求的时候,我们可以认为该编码器是合法的,但是ID值不一定和我们需要的相匹配。

libavcodec\codec_list.c
static const AVCodec * const codec_list[] = {
	.......
    &ff_aac_encoder,
	.....
    &ff_aac_decoder,
	......
	
    NULL };

libavcodec\aacenc.c
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,
};

二、avcodec_find_decoder()

avcodec_find_decoder(AV_CODEC_ID_AAC);

      查找ID值为AV_CODEC_ID_AAC的AAC解码器。该函数与avcodec_find_encoder()逻辑差不多,这里就不多做分析了。

AVCodec *avcodec_find_decoder(enum AVCodecID id)
{
    return find_codec(id, av_codec_is_decoder);
}

static AVCodec *find_codec(enum AVCodecID id, int (*x)(const AVCodec *))
{
    const AVCodec *p, *experimental = NULL;
    void *i = 0;

    id = remap_deprecated_codec_id(id);

    while ((p = av_codec_iterate(&i))) {
        if (!x(p))
            continue;
        if (p->id == id) {
            if (p->capabilities & AV_CODEC_CAP_EXPERIMENTAL && !experimental) {
                experimental = p;
            } else
                return (AVCodec*)p;
        }
    }

    return (AVCodec*)experimental;
}

const AVCodec *av_codec_iterate(void **opaque)
{
    uintptr_t i = (uintptr_t)*opaque;
    const AVCodec *c = codec_list[i];

    ff_thread_once(&av_codec_static_init, av_codec_init_static);

    if (c)
        *opaque = (void*)(i + 1);

    return c;
}

AVCodec ff_aac_decoder = {
    .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(AACContext),
    .init            = aac_decode_init,
    .close           = aac_decode_close,
    .decode          = aac_decode_frame,
    .sample_fmts     = (const enum AVSampleFormat[]) {
        AV_SAMPLE_FMT_FLTP, AV_SAMPLE_FMT_NONE
    },
    .capabilities    = AV_CODEC_CAP_CHANNEL_CONF | AV_CODEC_CAP_DR1,
    .caps_internal   = FF_CODEC_CAP_INIT_THREADSAFE | FF_CODEC_CAP_INIT_CLEANUP,
    .channel_layouts = aac_channel_layout,
    .flush = flush,
    .priv_class      = &aac_decoder_class,
    .profiles        = NULL_IF_CONFIG_SMALL(ff_aac_profiles),
};

int av_codec_is_decoder(const AVCodec *codec)
{
    return codec && (codec->decode || codec->receive_frame);
}

 

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值