Technologieaustausch

Wie initialisiert ffmpeg den spezifischen Codec, nachdem es den Codec und den Codec-Kontext gefunden hat? Der AAC-Initialisierungsprozess ist ungefähr wie folgt

2024-07-12

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

1. Wenn Sie avcodec_find_encoder_by_name verwenden, um den Encoder zu finden,
const AVCodec * aacencoder = avcodec_find_encoder_by_name("libx264");

Die Encoderwerte sind:
ID AV_CODEC_ID_H264 (27)
Langname libx264 H.264 / AVC / MPEG-4 AVC / MPEG-4 Teil 10
Name libx264
pix_fmts AV_PIX_FMT_YUV420P (0)

Typ AVMEDIA_TYPE_VIDEO (0)


2. Nach dem Aufruf von AVCodecContext *aacencodercontext = avcodec_alloc_context3(aacencoder);.
Der Encoder ist derselbe wie oben, keine Änderungen


Der Inhalt im Encoder-Kontext ist:
Die codec_id und codec_type im Encoderkontext haben Werte und die anderen werden ihren Standardwerten neu zugewiesen.
Codec-ID AV_CODEC_ID_H264 (27)
Codec-Typ AVMEDIA_TYPE_VIDEO (0)
Die Standardwerte sind wie folgt:

s->Zeitbasis = (AVRational){0,1};
s->Bildrate = (AVRational){ 0, 1 };
s->pkt_timebase = (AVRational){ 0, 1 };


3. Wenn die Methode avcodec_open2 (encoderAVCodecContext, EncoderAVCodec, NULL) aufgerufen wird, werden viele Parameter festgelegt.

Wir können uns vorstellen, dass unter der Annahme, dass der Encoder AAC ist, welche Parameter eingestellt werden?
Die erste Frage ist, wie viele Beispielbilder ein Avframe hat.

3.1 Beginnen Sie mit avcodec_find_encoder oder avcodec_find_decoder am Anfang.
Die Methode befindet sich in der Datei D:Ctoolyinshipinffmpeg-6.0sourcelibavcodecallcodecs.c.


const AVCodec *avcodec_find_encoder(enum AVCodecID id)
{
gibt find_codec(id, av_codec_is_encoder) zurück;
}

const AVCodec *avcodec_find_decoder(enum AVCodecID id)
{
gibt find_codec(id, av_codec_is_decoder) zurück;
}


3.2 Der Kern der find_codec-Methode ist die av_codec_iterate-Methode

statisch const AVCodec *find_codec(enum AVCodecID id, int (*x)(const AVCodec *))
{
const AVCodec *p, *experimentell = NULL;
ungültig *i = 0;

id = remap_deprecated_codec_id(id);

während ((p = av_codec_iterate(&i))) {
wenn (!x(p))
weitermachen;
wenn (p->id == id) {
wenn (p->Fähigkeiten & AV_CODEC_CAP_EXPERIMENTAL && !experimentell) {
experimentell = p;
} anders
Rückgabe p;
        }
    }

Rückkehr experimentell;
}

3.3 Die Methode av_codec_iterate findet tatsächlich den entsprechenden Codec aus der codec_list. Diese Liste ist sehr lang, einschließlich der Namen aller Encoder und Decoder in ffmepg.
const AVCodec *av_codec_iterate(void **undurchsichtig)
{
uintptr_t i = (uintptr_t)*undurchsichtig;
const FFCodec *c = Codecliste[i];

ff_thread_once(&av_codec_static_init, av_codec_init_static);

wenn (c) {
*undurchsichtig = (undurchsichtig*)(i + 1);
zurück &c->p;
    }
gibt NULL zurück;
}


Wir können sehen, dass der codec_list mehrere AACs entsprechen, und wir verwenden zur Veranschaulichung ff_aac_encoder.
Nachdem ich den Code durchsucht hatte, stellte ich fest, dass die Definition von ff_aac_encoder in aacenc.c enthalten ist


Die folgenden Informationen sind aus D:Ctoolyinshipinffmpeg-6.0sourcelibavcodecaacenc.c ersichtlich.
Field.init = aac_encode_init, sollte eine Funktion sein,
Wie Sie der Funktion aac_encode_init entnehmen können, beträgt Frame_size 1024
avctx->Rahmengröße = 1024;


const FFCodec ff_aac_encoder = {
.p.name = "aac",
CODEC_LONG_NAME("AAC (Erweiterte Audiocodierung)"),
.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 = Größe von (AACEncContext),
.init = aac_encode_init,
FF_CODEC_ENCODE_CB(aac_encode_frame),
.schließen = 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,
};

An diesem Punkt stellt sich noch die Frage: Wann wurde ff_aac_encoder initialisiert?
Tatsächlich führt ret = avcodec_open2(avcodecContext,nullptr,nullptr); dies intern aus.
Der Kerncode ist in

wenn (codec2->init) {
        
Tatsächlich wird es heißen:
statisches av_cold int aac_encode_init(AVCodecContext *avctx)