ffmpeg编解码过程中AVCodecContex的作用分析

发布时间:2026/10/31 10:41:28
ffmpeg编解码过程中AVCodecContex的作用分析

主要内容

本章主要内容就是讲解ffmpeg中实现硬件加速的代码的AVCodecContext的讲解内容,主要是基于ffmpeg 4.0代码进行分析。以下流程以h264硬件编解码为例。

硬件解码过程中AVCodecContext的变化

用户设置AVCodecContext项目

成员函数类型说明(description)
hw_device_ctx用户设置AVHWDeviceContext的AVBufferRef指针

AVCodecContext在不同的API中的作用和内部变量都会发生变化。

avcodec_alloc_context3

avcodec_alloc_context3(libavcodec\options.c)会根据AVCodec的值来分配和初始化AVCodecContext结构体。

avcodec_alloc_context3

AVCodecContext使用malloc分配内存

init_context_defaults

av_opt_set_defaults2

成员函数类型说明(description)
av_classinit_context_defaultsAVClassav_codec_context_class
codec_typeinit_context_defaultsAVMediaTypeAVMEDIA_TYPE_VIDOE,AVMEDIA_TYPE_AUDIO等
codecinit_context_defaultsAVCode指针decoder的指针
codec_idinit_context_defaultsAVCodecIDAV_CODEC_ID_H264,AV_CODEC_ID_HEVC等
time_baseinit_context_defaultsAVRational设置为1
framerateinit_context_defaultsAVRational设置为1
pkt_timebaseinit_context_defaultsAVRational设置为1
get_buffer2init_context_defaults函数指针avcodec_default_get_buffer2
get_formatinit_context_defaults函数指针avcodec_default_get_format
executeinit_context_defaults函数指针avcodec_default_execute
execute2init_context_defaults函数指针avcodec_default_execute2
sample_aspect_ratioinit_context_defaultsAVRational设置为1
pix_fmtinit_context_defaults函数指针AV_PIX_FMT_NONE
sw_pix_fmtinit_context_defaults函数指针AV_PIX_FMT_NONE
sample_fmtinit_context_defaults函数指针AV_SAMPLE_FMT_NONE
reordered_opaqueinit_context_defaults函数指针AV_NOPTS_VALUE
priv_datainit_context_defaults普通指针使用malloc根据AVCodec的priv_data_size分配,对h264而言就是H264Context结构体,并将AVCodec->priv_class赋值给priv_data

avcodec_parameters_to_context

avcodec_parameters_to_context完全是拷贝赋值操作,将AVStream中的AVCodecParameters赋值给AVCodecContext,没有调用其他函数。

成员函数类型说明(description)
codec_typeavcodec_parameters_to_contextAVMediaTypeAVMEDIA_TYPE_VIDOE,AVMEDIA_TYPE_AUDIO等
codec_idavcodec_parameters_to_contextAVCodecIDAV_CODEC_ID_H264,AV_CODEC_ID_HEVC等
codec_tagavcodec_parameters_to_contextint
bit_rateavcodec_parameters_to_contextint
bits_per_coded_sampleavcodec_parameters_to_contextint
bits_per_raw_sampleavcodec_parameters_to_contextintint
profileavcodec_parameters_to_contextint
levelavcodec_parameters_to_contextint
pix_fmtavcodec_parameters_to_contextAVPixelFormat属于视频参数,如AV_PIX_FMT_RGB24,AV_PIX_FMT_VAAPI等
widthavcodec_parameters_to_contextint属于视频和subtile参数
heiightavcodec_parameters_to_contextint属于视频和subtile参数
field_orderavcodec_parameters_to_contextint属于视频参数
color_rangeavcodec_parameters_to_contextAVColorRange属于视频参数
color_primariesavcodec_parameters_to_contextAVColorPrimaries属于视频参数
color_trcavcodec_parameters_to_contextAVColorTransferCharacteristic属于视频参数
colorspaceavcodec_parameters_to_contextAVColorSpace属于视频参数
chroma_sample_locationavcodec_parameters_to_contextAVChromaLocation属于视频参数
sample_aspect_ratioavcodec_parameters_to_contextAVRational属于视频参数
has_b_framesavcodec_parameters_to_contextint属于视频参数
sample_fmtavcodec_parameters_to_contextAVSampleFormat属于音频参数
channel_layoutavcodec_parameters_to_contextuint64_t属于音频参数
channelsavcodec_parameters_to_contextint属于音频参数
sample_rateavcodec_parameters_to_contextint属于音频参数
block_alignavcodec_parameters_to_contextint属于音频参数
frame_sizeavcodec_parameters_to_contextint属于音频参数
delayavcodec_parameters_to_contextint属于音频参数
initial_paddingavcodec_parameters_to_contextint属于音频参数
trailing_paddingavcodec_parameters_to_contextint属于音频参数
seek_prerollavcodec_parameters_to_contextint属于音频参数
initial_paddingavcodec_parameters_to_contextint属于音频参数
initial_paddingavcodec_parameters_to_contextint属于音频参数
extradataavcodec_parameters_to_context普通指针使用av_mallocz分配AVCodecParameters->extradata_size + AV_INPUT_BUFFER_PADDING_SIZE(64)大小空间,并将AVCodecParameters->extradata其数据拷贝到extradata中
extradata_sizeavcodec_parameters_to_contextintAVCodecParameters->extradata_size赋值给extradata_size

av_hwdevice_ctx_create

av_hwdevice_ctx_create主要是进行device创建和初始化工作。并将创建和初始化完成的AVHWDeviceContext的AVBufferRef指针赋值给AVCodecContext->hw_device_ctx。表格中的属于AVHWDeviceContext *device_ctx的成员。

成员函数类型说明(description)
user_opaqueav_hwdevice_ctx_createVAAPIDevicePrivVAAPIDevicePriv.display保存XOpenDisplay的Display指针
internalav_hwdevice_ctx_createAVHWDeviceInternalav_mallocz分配内存
internal->privav_hwdevice_ctx_createVAAPIDeviceContext根据(HWContextType)hw_type->device_priv_size使用av_mallocz分配内存
internal->hw_typeav_hwdevice_ctx_createHWContextType对于VAAPI而言就是ff_hwcontext_type_vaapi
hwctxav_hwdevice_ctx_createAVVAAPIDeviceContext根据(HWContextType)hw_type->device_hwctx_size使用av_mallocz分配内存
av_classav_hwdevice_ctx_createAVClasshwframe_ctx_class实例
typeav_hwdevice_ctx_createAVHWDeviceType对于VAAPI而言就是AV_HW_DEVICE_TYPE_VAAPI
sw_ formatav_hwdevice_ctx_createAVPixelFormatAV_PIX_FMT_NONE
displayvaapi_device_connectVADisplayav_hwdevice_ctx_create调用函数vaapi_device_connect

avcodec_open2

使用硬件解码过程中需要在avcodec_open2之前对AVCodecContext.hw_device_ctx使用av_hwdevice_ctx_create根据AVHWDeviceType进行创建,并赋值给AVCodecContext.hw_device_ctx。avcodec_open2调用h264_decode_init进行进一步初始化操作

成员函数类型说明(description)
internalavcodec_open2AVCodecInternal使用malloc分配内存
internal->poolavcodec_open2FramePool使用malloc分配内存
internal->to_freeavcodec_open2AVFrame指针使用av_frame_alloc分配内存
internal->compat_decode_frameavcodec_open2AVFrame指针使用av_frame_alloc分配内存
internal->buffer_frameavcodec_open2AVFrame指针使用av_frame_alloc分配内存
internal->buffer_pktavcodec_open2AVPacket指针使用av_packet_alloc分配内存
internal->ds.in_pktavcodec_open2AVPacket指针使用av_packet_alloc分配内存
internal->last_pkt_propsavcodec_open2AVPacket指针使用av_packet_alloc分配内存
internal->skip_samples_multiplieravcodec_open2int设置为1
priv_dataavcodec_open2void指针根据codec->priv_data_size 使用malloc分配内存
codec_ widthff_set_dimensionsint视频编码宽度
codec_heightff_set_dimensionsint视频比编码宽度
widthff_set_dimensionsint视频宽度,与视频宽度有区别,大部分时候相同
heightff_set_dimensionsint视频长度,与视频长度有区别,大部分时候相同
codecavcodec_open2AVCodec指针直接赋值给AVCodecContext.AVCodec指针
frame_numberavcodec_open2AVCodec指针设置0
codec_descriptoravcodec_open2AVCodecDescriptor指针avcodec_descriptor_get根据codec_id获取AVCodecDescriptor
sw_pix_fmtavcodec_open2AVPixelFormat当AVCodecContext.hw_frames_ctx初始化后,将frames_ctx->sw_format直接赋值给AVCodecContext.sw_pix_fmt
pts_correction_num_faulty_pts,pts_correction_num_faulty_dtsavcodec_open2int设置为0
pts_correction_last_pts,pts_correction_last_dtsavcodec_open2int6_t设置为INT64_MIN

av_read_frame

av_read_frame主要是从AVFormatContext中获取AVPacket,不会对AVCodecContext造成影响。

avcodec_send_packet

avcodec_send_packet是将packet发送给ffmpeg进行内部解码,并进行逐级调用,直到ff_get_format调用hwaccel_init。

成员函数类型说明(description)
sw_pix_fmtff_get_formatAVPixelFormatAV_PIX_FMT_NONE
internal->hwaccel_priv_dataff_get_format普通指针根据hwaccel->priv_data_size使用malloc分配内存
hwaccelhwaccel_initAVHWAccel指针根据AVPixelFormat格式将avctx->codec->hw_configs[i]中的AVHWaccel赋值给hwaccel

hwaccel_init

hwaccel_init实质调用ff_vaapi_decode_init进行初始化操作,初始化avctx->internal->hwaccel_priv_data,即VAAPIDecodeContext结构体。表格中为VAAPIDecodeContext *vaapictx的成员

成员函数类型说明(description)
AVCodecContext->internal->hwaccel_priv_datahwaccel_initVAAPIDecodeContext根据(AVHWAccel)hwaccel->hwaccel_priv_size使用av_mallocz分配内存
have_old_contextff_vaapi_decode_initAVPixelFormatAV_PIX_FMT_NONE
old_contextff_vaapi_decode_init普通指针根据hwaccel->priv_data_size使用malloc分配内存
device_refff_vaapi_decode_initAVBufferRef指针have_old_context为1时有效,为旧版本的VAAPI使用方法
deviceff_vaapi_decode_initAVHWDeviceContext指针have_old_context为1时有效,为旧版本的VAAPI使用方法
hwctxff_vaapi_decode_initAVVAAPIDeviceContext指针have_old_context为1时有效,为旧版本的VAAPI使用方法
hwctx->displayff_vaapi_decode_initVADisplayhave_old_context为1时有效,为旧版本的VAAPI使用方法
va_configff_vaapi_decode_initVAConfigIDhave_old_context为1时有效,为旧版本的VAAPI使用方法
va_contextff_vaapi_decode_initVAContextIDhave_old_context为1时有效,为旧版本的VAAPI使用方法
AVCodecContext.hw_frames_ctxff_decode_get_hw_frames_ctxAVBufferRef指针,AVHWFramesContext数据ff_decode_get_hw_frames_ctx–>avcodec_get_hw_frames_parameters–>av_hwframe_ctx_alloc
AVCodecContext->hwaccelhwaccel_initAVHWAccel将ff_h264_vaapi_hwaccel结构体指针赋值给hwaccel

ff_decode_get_hw_frames_ctx

ff_decode_get_hw_frames_ctx进行AVHWFramesContext的初始化操作,初始化avctx->hw_frames_ctx,ff_decode_get_hw_frames_ctx会调用avcodec_get_hw_frames_parameters,然后再avcodec_get_hw_frames_parameters中进行av_hwframe_ctx_alloc,AVHWAccel.frame_params(ff_vaapi_common_frame_params)和av_hwframe_ctx_init操作。

av_hwframe_ctx_alloc

av_hwframe_ctx_alloc进行AVHWFramesContext内存分配操作,初始化avctx->hw_frames_ctx,即AVHWFramesContext结构体。表格中为AVHWFramesContext*ctx的成员

成员函数类型说明(description)
internalav_hwframe_ctx_allocAVHWFramesInternalav_mallocz分配内存
internal->privav_hwframe_ctx_allocVAAPIFramesContext根据(HWContextType)hw_type->frames_priv_size使用av_mallocz分配内存
hwctxav_hwframe_ctx_allocAVVAAPIFramesContext根据(HWContextType)hw_type->frames_hwctx_size使用av_mallocz分配内存
av_classav_hwframe_ctx_allocAVClasshwframe_ctx_class实例
device_refav_hwframe_ctx_allocAVBufferRef指针avctx->hw_device_ctx数据的AVBufferRef指针
device_ctxav_hwframe_ctx_allocAVHWDeviceContext指针avctx->hw_device_ctx数据
formatav_hwframe_ctx_allocAVPixelFormatAV_PIX_FMT_NONE
sw_ formatav_hwframe_ctx_allocAVPixelFormatAV_PIX_FMT_NONE

ff_vaapi_common_frame_params

ff_vaapi_common_frame_params调用vaapi_decode_make_config初始化 AVHWFramesContext结构体即AVHWFramesContext结构体。表格中为AVHWFramesContext*ctx的初始化成员

成员函数说明(description)
formatff_vaapi_common_frame_params确定解码类型的格式AV_PIX_FMT_VAAPI或者AV_PIX_FMT_VDPAU
widthff_vaapi_common_frame_params解码的宽度,来自于AVCodecContext的coded_width,用来创建surface,并会将其传递给AVFrame的width
heightff_vaapi_common_frame_params解码的高度,来自于AVCodecContext的coded_height,用来创建surface,并会将其传递给AVFrame的height
sw_formatvaapi_decode_find_best_format解码的格式,通过查询驱动确定,vaapi_decode_make_config调用
initial_pool_sizeff_vaapi_common_frame_params用来确定surface分配的个数

av_hwframe_ctx_init

av_hwframe_ctx_init进行AVHWFramesContext判断操作,并不对AVHWFramesContext结构体的数值进行修改

vaapi_decode_make_config

vaapi_decode_make_config对AVVAAPIHWConfig(内部只有VAConfigID成员)进行av_hwdevice_hwconfig_alloc内存分配操作,和使用av_hwdevice_get_hwframe_constraints对AVHWFramesConstraints成员的初始化,这两个结构体不对外部AVCodecContext结构体产生影响,只是作为内部数据参考,只有VAConfigID 赋值给VAAPIDecodeContext ->va_config

成员函数类型说明(description)
AVHWFramesContext.formatvaapi_decode_make_configAVPixelFormatAV_PIX_FMT_VAAPI
AVHWFramesContext.widthvaapi_decode_make_configintavctx->coded_width
AVHWFramesContext.heightvaapi_decode_make_configintavctx->coded_height
AVHWFramesContext.initial_pool_sizevaapi_decode_make_configint原值为1,根据不同的code_id增加,H264(+16),HEVC(+16),VP9(+8),VP8(+3),OTHERS(+2),除此之外所有的还会在增加3,所以对于h264而言surface的最大数目就是20

硬件编码过程中AVCodecContext的变化

编码过程的很多函数和解码过程中的函数是通用的,以下只对差异点进行介绍

用户设置AVCodecContext项目

成员函数类型说明(description)
width用户设置int编码宽度
height用户设置int编码高度
time_base用户设置AVRational可以为{1, 25}
framerate用户设置AVRational可以为{1, 25}
sample_aspect_ratio用户设置AVRational可以为{1, 1}
pix_fmt用户设置AVPixelFormatAV_PIX_FMT_VAAPI
hw_frames_ctx用户设置AVHWFramesContext的AVBufferRef指针用于确定编码surface的size和format

对于hw_frames_ctx需要设置以下项目:

成员函数类型说明(description)
format用户设置AVPixelFormat编码的硬件格式标准,如AV_PIX_FMT_VAAPI
sw_format用户设置AVPixelFormat编码的硬件像素格式,如AV_PIX_FMT_NV12
width用户设置int编码surface的宽度
height用户设置int编码surface的高度
initial_pool_size用户设置int编码surface的的使用个数最大值

avcodec_alloc_context3

与解码相同

av_hwdevice_ctx_create

与解码相同

avcodec_open2

使用硬件编码过程中需要在avcodec_open2之前对AVCodecContext.hw_device_ctx使用av_hwdevice_ctx_create根据AVHWDeviceType进行创建,并赋值给AVCodecContext.hw_device_ctx。avcodec_open2对AVCodecContext成员进行初始化与解码过程相同,avcodec_open2会调用vaapi_encode_h264_init对AVCodecContext的成员造成影响,主要是VAAPIEncodeContext结构体,即AVCodecContext.priv_data分配的内存。以下表格中为VAAPIEncodeContext成员

成员函数类型说明(description)
codecvaapi_encode_h264_initVAAPIEncodeType全局变量vaapi_encode_type_h264指针
AVCodecContext.profilevaapi_encode_h264_initint用户设定,如果不存在就使用默认值
AVCodecContext.levelvaapi_encode_h264_initint用户设定,如果不存在就使用默认值
va_profilevaapi_encode_h264_initVAProfile根据AVCodecContext.profile设定
va_entrypointvaapi_encode_h264_initVAEntrypoint根据VA_CHECK_VERSION版本设定,低版本为VAEntrypointEncSliceLP,高版本为VAEntrypointEncSlice
va_rt_formatvaapi_encode_h264_initint设定为VA_RT_FORMAT_YUV420
va_rc_modevaapi_encode_h264_initint设定为VA_RC_CBR,VA_RC_VBR,VA_RC_CQP
va_packed_headersvaapi_encode_h264_initint设定为VA_ENC_PACKED_HEADER_SEQUENCE,VA_ENC_PACKED_HEADER_SLICE,VA_ENC_PACKED_HEADER_MISC
surface_widthvaapi_encode_h264_initint设定为avctx->width的16字节对齐值
surface_heightvaapi_encode_h264_initint设定为设定为avctx->height的16字节对齐值
codec_optionsff_vaapi_encode_initvoid*设定为本身的codec_options
input_frames_refff_vaapi_encode_initAVBufferRef*设定为AVCodecContext.hw_frames_ctx的引用
priv_dataff_vaapi_encode_initvoid*av_mallocz分配VAAPIEncodeTyp.priv_data_size大小的内存
input_framesff_vaapi_encode_initAVHWFramesContext*
device_refff_vaapi_encode_initAVBufferRef*设定为AVCodecContext.hw_frames_ctx的引用
deviceff_vaapi_encode_initAVHWDeviceContext*设定为device_ref的data
hwctxff_vaapi_encode_initAVHWDeviceContext*设定为device的hwctx
va_configff_vaapi_encode_initVAConfigID调用vaCreateConfig
va_contextff_vaapi_encode_initVAContextID调用vaCreateContext
output_buffer_poolff_vaapi_encode_initVAContextID调用av_buffer_pool_init2用来获取VABufferID

av_hwframe_get_buffer

获取一个free的surface,不会对结构体AVCodecContext产生影响。

avcodec_send_frame

avcodec_send_frame主要是调用do_encode进行编码。

成员函数类型说明(description)
internal->buffer_pkt_validdo_encodeint编码的packet是否成功,不成功时avcodec_receive_packet调用do_encode

avcodec_receive_packet

成员函数类型说明(description)
internal->buffer_pkt_validdo_encodeint编码的packet是否成功,不成功时avcodec_receive_packet调用do_encode

ffmpeg硬件解码对于AVCodecContext的影响如上所示,其他不做多余介绍。