Compartir tecnología

Después de que ffmpeg encuentra el códec y el contexto del códec, ¿cómo inicializa el códec específico? El proceso de inicialización de aac es aproximadamente el siguiente

2024-07-12

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

1. Cuando utilice avcodec_find_encoder_by_name para buscar el codificador,
const AVCodec * aacencoder = avcodec_find_encoder_by_name("libx264");

Los valores del codificador son:
Identificación del códec AV_ID_H264 (27)
nombre_largo libx264 H.264 / AVC / MPEG-4 AVC / MPEG-4 parte 10
nombre libx264
pix_fmts AV_PIX_FMT_YUV420P (0)

tipo AVMEDIA_TYPE_VIDEO (0)


2. Después de llamar a AVCodecContext *aacencodercontext = avcodec_alloc_context3(aacencoder);.
El codificador es el mismo que el anterior, sin cambios.


El contenido en el contexto del codificador es:
Codec_id y codec_type en el contexto del codificador tienen valores y los demás se reasignan a sus valores predeterminados.
id de códec AV_CODEC_ID_H264 (27)
tipo de códec AVMEDIA_TYPE_VIDEO (0)
Los valores predeterminados son los siguientes:

s->base_de_tiempo = (AVRacional){0,1};
s->velocidad de cuadros = (AVRational){ 0, 1 };
s->pkt_timebase = (AVRacional){ 0, 1 };


3. Cuando se llama al método avcodec_open2 (encoderAVCodecContext, encoderAVCodec, NULL), se establecerán muchos parámetros.

Podemos imaginar que suponiendo que el codificador sea AAC, ¿qué parámetros se establecerán?
El primero es cuántos fotogramas de muestra tiene un avframe.

3.1 Comience con avcodec_find_encoder o avcodec_find_decoder al principio.
El método está en el archivo D:Ctoolyinshipinffmpeg-6.0sourcelibavcodecallcodecs.c.


constante AVCodec *avcodec_find_encoder(enumeración AVCodecID id)
{
devolver find_codec(id, av_codec_is_encoder);
}

constante AVCodec *avcodec_find_decoder(enumeración AVCodecID id)
{
devolver find_codec(id, av_codec_is_decoder);
}


3.2 El núcleo del método find_codec es el método av_codec_iterate

estática constante AVCodec *find_codec(enum AVCodecID id, int (*x)(const AVCodec *))
{
constante AVCodec *p, *experimental = NULL;
vacío *i = 0;

id = remap_obsoleto_codec_id(id);

mientras ((p = av_codec_iterate(&i))) {
si (!x(p))
continuar;
si (p->id == id) {
si (p->capacidades & AV_CODEC_CAP_EXPERIMENTAL && !experimental) {
experimental=p;
} demás
devolver p;
        }
    }

volver experimental;
}

3.3 El método av_codec_iterate en realidad encuentra el códec correspondiente en codec_list. Esta lista es muy larga e incluye los nombres de todos los codificadores y decodificadores dentro de ffmepg.
constante AVCodec *av_codec_iterate(void **opaco)
{
uintptr_t i = (uintptr_t)*opaco;
const FFCodec *c = lista_de_códecs[i];

ff_thread_once(&av_codec_init_static, av_codec_init_static);

si (c) {
*opaco = (vacío*)(i + 1);
volver &c->p;
    }
devuelve NULL;
}


Podemos ver que hay varios aac correspondientes a codec_list y usamos ff_aac_encoder para ilustrar.
Después de buscar el código, encontré que la definición de ff_aac_encoder está en aacenc.c, que contiene


La siguiente información se puede ver en D: Ctoolyinshipinffmpeg-6.0sourcelibavcodecaacenc.c,
Field.init = aac_encode_init, debería ser una función,
Como puede ver en la función aac_encode_init, frame_size es 1024
avctx->tamaño_marco = 1024;


constante FFCodec ff_aac_encoder = {
.p.nombre = "aac",
CODEC_LONG_NAME("AAC (codificación de audio avanzada)"),
.p.tipo = AVMEDIA_TIPO_AUDIO,
.p.id = ID de CODEC AV_AAC,
.p.capacidades = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_DELAY |
CAPÍTULO ÚLTIMO CUADRO PEQUEÑO DEL CODEC AV,
.priv_data_size = tamaño de (AACEncContext),
.init = aac_encode_init,
FF_CODEC_ENCODE_CB(marco de codificación aac),
.cerrar = aac_encode_end,
.valores predeterminados = valores predeterminados de aac_encode,
.p. tasas_de_muestras_compatibles = tasas_de_muestras_de_audio_ff_mpeg4,
.caps_internal = LIMPIEZA_INICIAL_CAP_CODEC_FF,
.p.sample_fmts = (enumeración constante AVSampleFormat[]){ AV_SAMPLE_FMT_FLTP,
AV_MUESTRA_FMT_NINGUNO },
.p.priv_class = &aacenc_class,
};

En este punto, todavía queda una pregunta: ¿cuándo se inicializó ff_aac_encoder?
De hecho, ret = avcodec_open2(avcodecContext,nullptr,nullptr); hace esto internamente.
El código central está en

si (codec2->init) {
        
De hecho se llamará:
av_cold estático int aac_encode_init(AVCodecContext *avctx)