Обмен технологиями

После того как ffmpeg найдет кодек и контекст кодека, как он инициализирует конкретный кодек? Процесс инициализации aac примерно следующий:

2024-07-12

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

1. При использовании avcodec_find_encoder_by_name для поиска кодировщика
const AVCodec * aacencoder = avcodec_find_encoder_by_name("libx264");

Значения энкодера:
идентификатор AV_CODEC_ID_H264 (27)
длинное_имя libx264 H.264 / AVC / MPEG-4 AVC / MPEG-4 часть 10
имя libx264
pix_fmts AV_PIX_FMT_YUV420P (0)

тип AVMEDIA_TYPE_VIDEO (0)


2. После вызова AVCodecContext *aacencodercontext = avcodec_alloc_context3(aacencoder);.
Кодировщик тот же, что и выше, без изменений


Содержимое в контексте кодировщика:
Codec_id и codec_type в контексте кодировщика имеют значения, а остальным присваиваются значения по умолчанию.
кодек_идентификатор AV_CODEC_ID_H264 (27)
codec_type AVMEDIA_TYPE_VIDEO (0)
Значения по умолчанию следующие:

s->time_base = (AVRational){0,1};
s->частота кадров = (AVRational){ 0, 1 };
s->pkt_timebase = (AVRational){ 0, 1 };


3. При вызове метода avcodec_open2(encoderAVCodecContext, encoderAVCodec, NULL) будет установлено множество параметров.

Мы можем представить, что если кодировщиком является AAC, какие параметры будут установлены?
Первый — это количество образцов кадров в avframe.

3.1 Начните с avcodec_find_encoder или avcodec_find_decoder в начале.
Этот метод находится в файле D:Ctoolyinshipinffmpeg-6.0sourcelibavcodecallcodecs.c.


const AVCodec *avcodec_find_encoder(enum AVCodecID id)
{
вернуть find_codec(id, av_codec_is_encoder);
}

const AVCodec *avcodec_find_decoder(enum AVCodecID id)
{
вернуть find_codec(id, av_codec_is_decoder);
}


3.2 Ядром метода find_codec является метод av_codec_iterate.

статический константный AVCodec *find_codec(enum AVCodecID id, int (*x)(const AVCodec *))
{
const AVCodec *p, *экспериментальный = NULL;
пустота *i = 0;

id = remap_deprecated_codec_id(id);

в то время как ((p = av_codec_iterate(&i))) {
если (!x(p))
продолжать;
если (p->id == id) {
если (p->возможности & AV_CODEC_CAP_EXPERIMENTAL && !экспериментальный) {
экспериментальный = p;
} еще
вернуть р;
        }
    }

возвращение экспериментального;
}

3.3. Метод av_codec_iterate фактически находит соответствующий кодек из codec_list. Этот список очень длинный и включает имена всех кодеров и декодеров в ffmepg.
const AVCodec *av_codec_iterate(void **opaque)
{
uintptr_t i = (uintptr_t)*непрозрачный;
const FFCodec *c = codec_list[i];

ff_thread_once(&av_codec_static_init, av_codec_init_static);

если (с) {
*непрозрачный = (пустой*)(i + 1);
возврат &c->p;
    }
вернуть NULL;
}


Мы видим, что существует несколько aacs, соответствующих codec_list, и для иллюстрации мы используем ff_aac_encoder.
После поиска кода я обнаружил, что определение ff_aac_encoder находится в файле aacenc.c, который содержит


Следующую информацию можно увидеть в D:Ctoolyinshipinffmpeg-6.0sourcelibavcodecaacenc.c,
Field.init = aac_encode_init должен быть функцией,
Как вы можете видеть из функции aac_encode_init, размер кадра равен 1024.
avctx->размер_кадра = 1024;


константа FFCodec ff_aac_encoder = {
.p.имя = "aac",
CODEC_LONG_NAME("AAC (Расширенное аудиокодирование)"),
.p.type = AVMEDIA_TYPE_AUDIO,
.p.id = AV_CODEC_ID_AAC,
.p.возможности = 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,
};

На этом этапе все еще остается вопрос: когда была инициализирована ff_aac_encoder?
Фактически, ret = avcodec_open2(avcodecContext,nullptr,nullptr);
Основной код находится в

если (codec2->init) {
        
На самом деле он будет называться:
статический av_cold int aac_encode_init(AVCodecContext *avctx)