Technology Sharing

After ffmpeg finds the codec and the codec context, how does it initialize the specific codec? The aac initialization process is roughly as follows

2024-07-12

한어Русский языкEnglishFrançaisIndonesianSanskrit日本語DeutschPortuguêsΕλληνικάespañolItalianoSuomalainenLatina

1. When using avcodec_find_encoder_by_name to find the encoder,
 const AVCodec *   aacencoder = avcodec_find_encoder_by_name("libx264");

The encoder values ​​are:
id                        AV_CODEC_ID_H264 (27)
long_name         libx264 H.264 / AVC / MPEG-4 AVC / MPEG-4 part 10
name        libx264
pix_fmts        AV_PIX_FMT_YUV420P (0)

type        AVMEDIA_TYPE_VIDEO (0)


2. After calling AVCodecContext *aacencodercontext = avcodec_alloc_context3(aacencoder);
The encoder is the same as above, no changes


The encoder context has the following contents:
The codec_id and codec_type in the encoder context have values, and the others are reassigned to default values.
codec_id                AV_CODEC_ID_H264 (27)
codec_type            AVMEDIA_TYPE_VIDEO (0)
The default values ​​are as follows:

    s->time_base           = (AVRational){0,1};
    s->framerate           = (AVRational){ 0, 1 };
    s->pkt_timebase        = (AVRational){ 0, 1 };


3. When the avcodec_open2(encoderAVCodecContext, encoderAVCodec, NULL) method is called, many parameters will be set.

We can imagine, assuming that the encoder is AAC, then which parameters will be set?
The first one is how many sample frames an avframe has.

3.1 Start from the very beginning avcodec_find_encoder or avcodec_find_decoder.
The method is in the D:Ctoolyinshipinffmpeg-6.0sourcelibavcodecallcodecs.c file.


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

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


3.2 The core of find_codec method is av_codec_iterate method

static const 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 p;
        }
    }

    return experimental;
}

3.3 The av_codec_iterate method actually finds the corresponding codec from codec_list. This list is very long and includes the names of all encoders and decoders in ffmepg.
const AVCodec *av_codec_iterate(void **opaque)
{
    uintptr_t i = (uintptr_t)*opaque;
    const FFCodec *c = codec_list[i];

    ff_thread_once(&av_codec_static_init, av_codec_init_static);

    if (c) {
        *opaque = (void*)(i + 1);
        return &c->p;
    }
    return NULL;
}


We can see that there are multiple aacs corresponding to codec_list. We use ff_aac_encoder to illustrate.
After searching the code, I found that the definition of ff_aac_encoder is in aacenc.c, which has


From D:Ctoolyinshipinffmpeg-6.0sourcelibavcodecaacenc.c, you can see the following information:
field.init = aac_encode_init, which should be a function,
From the aac_encode_init function, we can see that frame_size is 1024
    avctx->frame_size = 1024;


const FFCodec ff_aac_encoder = {
    .p.name         = "aac",
    CODEC_LONG_NAME("AAC (Advanced Audio Coding)"),
    .p.type         = AVMEDIA_TYPE_AUDIO,
    .p.id           = AV_CODEC_ID_AAC,
    .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_DELAY |
                      AV_CODEC_CAP_SMALL_LAST_FRAME,
    .priv_data_size = sizeof(AACEncContext),
    .init           = aac_encode_init,
    FF_CODEC_ENCODE_CB(aac_encode_frame),
    .close          = aac_encode_end,
    .defaults       = aac_encode_defaults,
    .p.supported_samplerates = ff_mpeg4audio_sample_rates,
    .caps_internal  = FF_CODEC_CAP_INIT_CLEANUP,
    .p.sample_fmts  = (const enum AVSampleFormat[]){ AV_SAMPLE_FMT_FLTP,
                                                     AV_SAMPLE_FMT_NONE },
    .p.priv_class   = &aacenc_class,
};

At this point, there is still a question: when is ff_aac_encoder initialized?
In fact, ret = avcodec_open2(avcodecContext,nullptr,nullptr); does this internally.
The core code is in

        if (codec2->init) {
        
In fact, it will call:
        static av_cold int aac_encode_init(AVCodecContext *avctx)