[ffmpeg] avcodec_alloc_context3 解析

背景

ffmpeg 通过 avcodec_alloc_context3 解析编码器,本文主要来解析一下,这个函数主要做了什么。

具体代码分析

主要是创建了 AVCodecContext ,并给结构体参数赋予初值。

初值设置主要分成两块,1. 所有编码器都相同的部分;2.每个编码器独有的参数设置。

接下来主要分析后者是如何设置的。

c 复制代码
AVCodecContext *avcodec_alloc_context3(const AVCodec *codec)
{
    AVCodecContext *avctx= av_malloc(sizeof(AVCodecContext));

    if (!avctx)
        return NULL;

    if (init_context_defaults(avctx, codec) < 0) {
        av_free(avctx);
        return NULL;
    }

    return avctx;
}

static int init_context_defaults(AVCodecContext *s, const AVCodec *codec)
{
    const FFCodec *const codec2 = ffcodec(codec);
    int flags=0;
    memset(s, 0, sizeof(AVCodecContext));

    s->av_class = &av_codec_context_class;

    s->codec_type = codec ? codec->type : AVMEDIA_TYPE_UNKNOWN;
    if (codec) {
        s->codec = codec;
        s->codec_id = codec->id;
    }

    if(s->codec_type == AVMEDIA_TYPE_AUDIO)
        flags= AV_OPT_FLAG_AUDIO_PARAM;
    else if(s->codec_type == AVMEDIA_TYPE_VIDEO)
        flags= AV_OPT_FLAG_VIDEO_PARAM;
    else if(s->codec_type == AVMEDIA_TYPE_SUBTITLE)
        flags= AV_OPT_FLAG_SUBTITLE_PARAM;
    av_opt_set_defaults2(s, flags, flags);

    av_channel_layout_uninit(&s->ch_layout);

    s->time_base           = (AVRational){0,1};
    s->framerate           = (AVRational){ 0, 1 };
    s->pkt_timebase        = (AVRational){ 0, 1 };
    s->get_buffer2         = avcodec_default_get_buffer2;
    s->get_format          = avcodec_default_get_format;
    s->get_encode_buffer   = avcodec_default_get_encode_buffer;
    s->execute             = avcodec_default_execute;
    s->execute2            = avcodec_default_execute2;
    s->sample_aspect_ratio = (AVRational){0,1};
    s->ch_layout.order     = AV_CHANNEL_ORDER_UNSPEC;
    s->pix_fmt             = AV_PIX_FMT_NONE;
    s->sw_pix_fmt          = AV_PIX_FMT_NONE;
    s->sample_fmt          = AV_SAMPLE_FMT_NONE;

    s->reordered_opaque    = AV_NOPTS_VALUE;
    if(codec && codec2->priv_data_size){
        s->priv_data = av_mallocz(codec2->priv_data_size);
        if (!s->priv_data)
            return AVERROR(ENOMEM);
        if(codec->priv_class){
            *(const AVClass**)s->priv_data = codec->priv_class;
            av_opt_set_defaults(s->priv_data);
        }
    }
    if (codec && codec2->defaults) {
        int ret;
        const FFCodecDefault *d = codec2->defaults;
        while (d->key) {
            ret = av_opt_set(s, d->key, d->value, 0);
            av_assert0(ret >= 0);
            d++;
        }
    }
    return 0;
}

每个编码器独有参数设置

avcodec_alloc_context3 时,会将 codec2->priv_data_size 创建大小的内存赋值给 priv_data,并将 codec 的priv_class 赋值给 priv_data。

av_opt_set_defaults 会把 options 中的默认值,设置到 priv_data 中,相当于给编码器的参数结构体设置了默认值。

c 复制代码
if(codec && codec2->priv_data_size){
        s->priv_data = av_mallocz(codec2->priv_data_size);
        if (!s->priv_data)
            return AVERROR(ENOMEM);
        if(codec->priv_class){
            *(const AVClass**)s->priv_data = codec->priv_class;
            av_opt_set_defaults(s->priv_data);
        }
    }

为啥 codec 的priv_class 可以直接赋值给 priv_data。以 aacenc 为例,codec 的 priv_class 为 &aacenc_class,而 codec 的 priv_data_size 为 sizeof(AACEncContext)。所有相当于 AVCodecContext 创建了 sizeof(AACEncContext) 大小的 priv_data。之所以可以这样,是因为 AACEncContext 第一个参数就是 AVClass*。相当于这也是 ffmpeg 的小技巧,应该所有的编码器变量结构体,第一个参数都是 AVClass* (看了一下 nvenc.h 也是这样的)。

c 复制代码
static const AVClass aacenc_class = {
    .class_name = "AAC encoder",
    .item_name  = av_default_item_name,
    .option     = aacenc_options,
    .version    = LIBAVUTIL_VERSION_INT,
};

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,
};


typedef struct AACEncContext {
    AVClass *av_class;
    AACEncOptions options;                       ///< encoding options
    PutBitContext pb;
    FFTContext mdct1024;                         ///< long (1024 samples) frame transform context
    FFTContext mdct128;                          ///< short (128 samples) frame transform context
    AVFloatDSPContext *fdsp;
    AACPCEInfo pce;                              ///< PCE data, if needed
    float *planar_samples[16];                   ///< saved preprocessed input

    int profile;                                 ///< copied from avctx
    int needs_pce;                               ///< flag for non-standard layout
    LPCContext lpc;                              ///< used by TNS
    int samplerate_index;                        ///< MPEG-4 samplerate index
    int channels;                                ///< channel count
    const uint8_t *reorder_map;                  ///< lavc to aac reorder map
    const uint8_t *chan_map;                     ///< channel configuration map

    ChannelElement *cpe;                         ///< channel elements
    FFPsyContext psy;
    struct FFPsyPreprocessContext* psypp;
    const AACCoefficientsEncoder *coder;
    int cur_channel;                             ///< current channel for coder context
    int random_state;
    float lambda;
    int last_frame_pb_count;                     ///< number of bits for the previous frame
    float lambda_sum;                            ///< sum(lambda), for Qvg reporting
    int lambda_count;                            ///< count(lambda), for Qvg reporting
    enum RawDataBlockType cur_type;              ///< channel group type cur_channel belongs to

    AudioFrameQueue afq;
    DECLARE_ALIGNED(16, int,   qcoefs)[96];      ///< quantized coefficients
    DECLARE_ALIGNED(32, float, scoefs)[1024];    ///< scaled coefficients

    uint16_t quantize_band_cost_cache_generation;
    AACQuantizeBandCostCacheEntry quantize_band_cost_cache[256][128]; ///< memoization area for quantize_band_cost

    void (*abs_pow34)(float *out, const float *in, const int size);
    void (*quant_bands)(int *out, const float *in, const float *scaled,
                        int size, int is_signed, int maxval, const float Q34,
                        const float rounding);

    struct {
        float *samples;
    } buffer;
} AACEncContext;
相关推荐
韩曙亮7 小时前
【FFmpeg】FFmpeg 内存结构 ③ ( AVPacket 函数简介 | av_packet_ref 函数 | av_packet_clone 函数 )
ffmpeg·音视频·avpacket·av_packet_clone·av_packet_ref·ffmpeg内存结构
oushaojun211 小时前
ubuntu中使用ffmpeg和nginx推流rtmp视频
nginx·ubuntu·ffmpeg·rtmp
莫固执,朋友12 小时前
网络抓包工具tcpdump 在海思平台上的编译使用
网络·ffmpeg·音视频·tcpdump
lxkj_202412 小时前
修改ffmpeg实现https-flv内容加密
网络协议·https·ffmpeg
cuijiecheng201812 小时前
音视频入门基础:MPEG2-TS专题(6)——FFmpeg源码中,获取MPEG2-TS传输流每个transport packet长度的实现
ffmpeg·音视频
VisionX Lab17 小时前
数据脱敏工具:基于 FFmpeg 的视频批量裁剪
python·ffmpeg·音视频
柳鲲鹏1 天前
全网首发:Ubuntu编译跨平台嵌入式支持ffmpeg的OpenCV
linux·ubuntu·ffmpeg
冰山一脚20131 天前
ffplay音频SDL播放处理
ffmpeg
cuijiecheng20182 天前
音视频入门基础:MPEG2-TS专题(7)——FFmpeg源码中,读取出一个transport packet数据的实现
ffmpeg·音视频
Maxwellhang2 天前
【java-ffmpeg】java 内存测试和集成
java·ffmpeg·jni