FFmpeg 常用结构体与函数详解(2.8 ~ 5.0 版本演进研究)
本章系统整理 FFmpeg 开发中最常打交道的结构体、枚举与函数,并以 FFmpeg 2.8(2015)→ FFmpeg 5.0(2022) 为研究范围,说明各接口在版本演进中的变化。相关结构体内容的详细讲解可以参考:AVPacket、AVPacketSideData、AVBufferRef 与 AVBuffer 详解
0. 版本坐标系与命名勘误
0.1 各版本对应的库版本号(major)
FFmpeg 的接口变化以各子库的 major 版本号为界,跨版本移植代码时首先应核对此表:
| FFmpeg 版本 | 发布时间 | libavutil | libavcodec | libavformat | libavdevice |
|---|---|---|---|---|---|
| 2.8 | 2015-09 | 54 | 56 | 56 | 56 |
| 3.0 ~ 3.4 | 2016-02 ~ 2017-12 | 55 | 57 | 57 | 57 |
| 4.0 ~ 4.4 | 2018-04 ~ 2021 | 56 | 58 | 58 | 58 |
| 5.0 | 2022-01 | 57 | 59 | 59 | 59 |
运行时可用 avutil_version()、avcodec_version() 等函数读取上述版本号,配合 LIBAVCODEC_VERSION_INT 等宏做条件编译,是兼容多版本的常规做法。
0.2 本章涉及的名称勘误
原始表格中部分函数/结构体名称与 FFmpeg 实际 API 有出入,本文按官方名称书写并在此列明对应关系:
| 原文写法 | 官方正确名称 | 说明 |
|---|---|---|
| av_sample_get_buffer_size | av_samples_get_buffer_size |
复数 samples |
| av_send_packet | avcodec_send_packet |
3.1 起的新解码 API |
| avformat_find_best_info | avformat_find_stream_info |
流信息探测 |
| av_find_best_frame | av_find_best_stream |
查找最佳流(另有 av_find_best_stream 之外的帧级函数不存在) |
| avformat_write_tailer | av_write_trailer |
写文件尾 |
| av_frame_get_size_data | av_frame_get_buffer |
为 AVFrame 分配存储 |
| AVContentLightMetaData | AVContentLightMetadata |
Metadata 非 MetaData |
| AVMasteringDisplayMetaData | AVMasteringDisplayMetadata |
同上 |
| AVHWFrameContext | AVHWFramesContext |
复数 Frames |
1. 结构体变量
1.1 AVCodecContext(libavcodec/avcodec.h)
编解码的核心上下文,编码和解码都必须使用 。通过 avcodec_alloc_context3() 分配、avcodec_open2() 打开、avcodec_free_context() 释放。
关键字段:
- 编解码器标识 :
codec(指向 AVCodec)、codec_id、codec_type; - 视频参数 :
width、height、pix_fmt、gop_size、profile、level、bit_rate; - 音频参数 :
sample_fmt、sample_rate、channels/channel_layout; - 时间参数 :
time_base、pkt_timebase; - 码流参数 :
extradata/extradata_size、priv_data; - 硬解相关 :2.8 时代为
hwaccel_context(指向struct vaapi_context等);3.x 起改为hw_device_ctx、hw_frames_ctx(AVBufferRef 形式); - 回调 :
get_buffer2、opaque、draw_horiz_band等。
2.8 → 5.0 的主要变化:
- 与 AVStream 解耦 (3.0 起):2.8 直接用
AVStream->codec拿到 AVCodecContext;3.x 引入AVStream->codecpar(AVCodecParameters),需用avcodec_parameters_to_context()/avcodec_parameters_from_context()搬运参数;AVStream->codec在 3.1 标记废弃、4.0 彻底删除。 - const 化 (5.0):
avcodec_find_decoder()等返回const AVCodec *,avcodec_alloc_context3()入参同样 const 化。 - 收发式 API 成为唯一入口 (5.0):旧的
avcodec_decode_video2()等被删除,必须使用avcodec_send_packet()/avcodec_receive_frame()。 - 声道布局 :2.8 ~ 5.0 一直使用
channels+channel_layout;5.1 起被AVChannelLayout ch_layout取代(超出本章范围,移植 5.0 之后代码时注意)。
1.2 AVRational(libavutil/rational.h)
c
typedef struct AVRational { int num, den; } AVRational;
时间基 (time base),表示一秒钟被切成多少个刻度,即 num/den 秒。典型值:
AV_TIME_BASE = 1000000(微秒基,全局统一时间单位);- 视频流常见
1/framerate或1/90000(mpegts); - 音频常见
1/sample_rate。
时间基之间换算依靠 av_rescale_q()、av_rescale_rnd()、av_compare_ts()。注意 AVPacket.pts/dts 与 AVFrame.pts 的单位分别跟随 AVStream->time_base 与 AVCodecContext->time_base,混用是时间戳错乱的头号原因。该结构体 2.8 ~ 5.0 完全稳定,无变化。
1.3 AVFrame(libavutil/frame.h)
数据帧信息,解码输出/编码输入的载体。
- 软解 :
data[0..3]保存最多四个分量的数据(如 YUV420P 的 Y/U/V),linesize[]为每行字节数;音频则在extended_data中保存各声道/平面数据,nb_samples为每声道采样数。 - 硬解(老 VAAPI 路径) :只有
data[3]保存 VASurfaceID,其余指针无意义;硬解(hwcontext 路径) :帧挂在hw_frames_ctx描述的帧池上,format为AV_PIX_FMT_VAAPI等硬件格式,需av_hwframe_transfer_data()下载到内存才能软访问。
常用字段:width/height/format、pts、pkt_dts、key_frame、pict_type、sample_rate、channel_layout/channels、buf[]/extended_buf(引用计数)、side_data[](HDR 元数据、运动向量等挂在侧数据上)。
2.8 → 5.0 的主要变化:
- 引用计数帧(
av_frame_ref/av_frame_unref/av_buffer)成为标准语义,解码器内部可零拷贝复用缓冲区,使用者必须在用完后av_frame_unref(); - 3.x 起硬解帧增加
hw_frames_ctx、hw_device_ctx字段,取代老的 surface 约定; - 颜色/HDR 相关字段(
color_primaries、color_trc、colorspace、color_range)3.x 起完善,HDR10 元数据通过 side data 挂载。
1.4 AVPacket(libavcodec/packet.h)
数据包信息,是压缩后的数据。
data/size:压缩数据指针与长度(H.264 为 Annex-B 或 AVC 格式,AAC 含 ADTS 头与否取决于封装);pts/dts/duration:时间戳,单位为所属流的time_base;stream_index:所属流下标;flags:AV_PKT_FLAG_KEY表示关键帧;side_data:附加信息(如编码参数、HDR 元数据);buf(AVBufferRef):引用计数存储,av_packet_unref()只减引用、可复用结构体。
2.8 → 5.0 的主要变化 :2.8 必须手动 av_init_packet() 初始化再填充;5.0 中 av_init_packet() 已废弃(且 sizeof(AVPacket) 未来将退出 ABI),改为 av_packet_alloc() / av_packet_free() / av_packet_unref() 的引用计数模型;av_packet_rescale_ts() 全程可用,用于跨时间基换算 pts/dts/duration。
1.5 AVStream(libavformat/avformat.h)
多媒体文件中单条流的信息(一条视频流、一条音频流......)。
常用字段:index、id、codecpar(编码参数)、time_base、avg_frame_rate/r_frame_rate、duration、nb_frames、start_time、metadata(AVDictionary)、disposition、side_data(如旋转矩阵、HDR 元数据)。视频分辨率、编码种类、时长、图像格式等信息均由此获得(2.8 直接读 st->codec->width/height,3.x 起读 st->codecpar->width/height)。
2.8 → 5.0 的主要变化 :codec 字段 3.1 废弃、4.0 移除;codecpar(AVCodecParameters,lavf 57 引入)成为唯一参数载体;5.0 起 AVStream 内部字段逐步私有化,侧数据推荐用 av_stream_get_side_data() 访问。
1.6 struct vaapi_context(libavcodec/vaapi.h)
老版本硬解结构体 (2.8 时代的典型用法)。字段包括 display(VADisplay)、config_id、context_id、render(老式渲染回调)。
- 使用方式:
avctx->hwaccel_context = &vaapi_ctx;,即把外部创建的 VA-API display/context 交给解码器; - 如果需要外部创建 surface (例如解码帧直接送 DRM/KMS 合成、避免拷贝),则必须使用该结构体自行管理 surface;如果由 FFmpeg 内部创建 surface ,则不需要使用它(内部走
AV_PIX_FMT_VAAPI+ 内部帧池)。
版本变化 :FFmpeg 3.x 引入 hwcontext 框架后,该结构体被 AVVAAPIDeviceContext/AVHWFramesContext 组合取代;2017 年初(libavcodec 57.74)官方正式废弃 struct vaapi_context 与安装 vaapi.h 头文件 ,推荐迁移 hwcontext。5.0 中该结构体仍以废弃状态存在(此后更晚的版本才被删除)。研究 2.8 → 5.0 硬解迁移路径,本质就是从 vaapi_context 迁移到 AVHWDeviceContext + AVHWFramesContext。
1.7 AVContentLightMetadata(libavutil/content_light_metadata.h)
图像亮度级别(内容光亮度)元数据,即 HDR10 的 MaxCLL/MaxFALL:
MaxCLL:最大内容亮度(nits);MaxFALL:最大帧平均亮度。
FFmpeg 3.x 系列引入(2.8 中不存在)。传输方式为 side data (AV_PKT_DATA_CONTENT_LIGHT_LEVEL / AV_FRAME_DATA_CONTENT_LIGHT_LEVEL),主要用于 HDMI 的 HDR 输出 :播放器将 MaxCLL/MaxFALL 写入 AVIInfoFrame/DRM HDR metadata,使电视进入 HDR 模式。配套函数 av_content_light_metadata_alloc() / av_content_light_metadata_create()。
1.8 AVMasteringDisplayMetadata(libavutil/mastering_display_metadata.h)
图像显示设备元数据,即 HDR10 的静态母版信息:
display_primaries[3]:RGB 三基色色度坐标;white_point:白点坐标;min_luminance/max_luminance:母版监视器最小/最大亮度(nits);has_primaries/has_luminance:各字段有效标志。
同样 3.x 系列引入,以 side data(AV_PKT_DATA_MASTERING_DISPLAY_METADATA / AV_FRAME_DATA_MASTERING_DISPLAY_METADATA)传递,配合 1.7 一起用于 HDMI HDR 输出 。二者常由 av_frame_new_side_data_from_buf() 挂到 AVFrame 上送显示链路。
1.9 AVCodecDescriptor(libavcodec/codec_desc.h)
编解码器的描述信息(与具体实现无关的元数据):
id(AVCodecID)、name、long_name、type(AVMediaType);props:能力标志(AV_CODEC_PROP_LOSSY、AV_CODEC_PROP_LOSSLESS、AV_CODEC_PROP_INTRA_ONLY、AV_CODEC_PROP_REORDER等);mime_types、profiles(各 profile 名称表)。
访问接口:avcodec_descriptor_get()、avcodec_descriptor_get_by_name()、avcodec_descriptor_get_next()。2.8 ~ 5.0 结构稳定,只增不改,可用于 UI 展示编解码器能力或做兼容性判断。
1.10 AVHWFramesContext(libavutil/hwcontext.h,原文误写作 AVHWFrameContext)
硬解的帧池信息(3.x 起引入)。关键字段:
device_ref/device_ctx:所属设备;format:硬件像素格式(如AV_PIX_FMT_VAAPI);sw_format:对应的软件格式(如NV12);width/height、initial_pool_size:通过设置帧的大小和数目,可以控制创建的帧池的大小和数目;pool:实际帧池(AVBufferRef);hwctx:硬件专用扩展(如AVVAAPIFramesContext)。
创建流程:av_hwframe_context_alloc() → 填充字段 → av_hwframe_context_init();解码器用 avctx->hw_frames_ctx 引用它,帧通过 av_hwframe_get_buffer() 从池中取出。需要外部 surface 时,可向 AVHWFramesContext 注入用户帧池(user_opaque + pool 自定义分配),取代老的 vaapi_context 方案。
1.11 AVHWDeviceContext(libavutil/hwcontext.h)
硬解设备结构体(3.x 起引入),描述一块"硬件设备":
type(AVHWDeviceType);hwctx:设备专用上下文(如AVVAAPIDeviceContext);free、user_opaque。
创建方式:av_hwdevice_ctx_alloc() + 填充 + av_hwdevice_ctx_init(),或一步到位的 av_hwdevice_ctx_create()。解码时赋给 avctx->hw_device_ctx,5.0 中配合 avcodec_get_hw_config()(4.0 引入的 AVCodecHWConfig)可枚举编解码器支持的硬件加速方式。
1.12 AVVAAPIDeviceContext(libavutil/hwcontext_vaapi.h)
VAAPI 设备结构体(3.x 起引入),使用 VAAPI 解码时的核心设备上下文:
display:VADisplay,外部创建的 VA 显示连接;driver_quirks:驱动怪癖标志(FFmpeg 自动设置)。
用法:创建 AVHWDeviceContext(type = AV_HWDEVICE_TYPE_VAAPI)后,把外部 VADisplay 填进 AVVAAPIDeviceContext.display,即等价于老 vaapi_context 中 display 字段的职责,但帧管理交由 AVHWFramesContext 完成。
2. 枚举类变量
2.1 AVSampleFormat(libavutil/samplefmt.h)
采样格式,音频使用:
| 值 | 说明 |
|---|---|
AV_SAMPLE_FMT_NONE |
无效 |
AV_SAMPLE_FMT_U8/S16/S32/FLT/DBL |
打包(interleaved)格式,各声道交错存储 |
AV_SAMPLE_FMT_U8P/S16P/S32P/FLTP/DBLP |
平面(planar)格式,各声道独立存储 |
要点:解码输出多为 planar(如 FLTP);av_sample_fmt_is_planar() 判断平面性;av_get_bytes_per_sample() 取单采样字节数;av_samples_get_buffer_size() 计算整帧缓冲大小。2.8 ~ 5.0 枚举值稳定,5.1 起声道布局 API 变化不影响本枚举。
2.2 AVHWDeviceType(libavutil/hwcontext.h)
硬解类型(3.x 引入;2.8 无此枚举,硬解靠各 hwaccel 结构体):
AV_HWDEVICE_TYPE_NONE / VDPAU / CUDA / VAAPI / DXVA2 / QSV / VIDEOTOOLBOX / MEDIACODEC / VULKAN(4.x 增补 D3D11VA 等,更晚版本增补 D3D12VA)。
配套函数:av_hwdevice_find_type_by_name()、av_hwdevice_iterate_types()、av_hwdevice_get_type_name()。5.0 内 CUDA/NVDEC、VAAPI、D3D11VA、QSV、VideoToolbox 是主流硬解路径。
2.3 AVPixelFormat(libavutil/pixfmt.h)
图像像素格式:软格式 AV_PIX_FMT_YUV420P、NV12、YUYV422、YUV420P10LE、RGB24、BGR24、GRAY8 等;硬表面格式 AV_PIX_FMT_VAAPI、AV_PIX_FMT_CUDA、AV_PIX_FMT_VDPAU、AV_PIX_FMT_DXVA2_VLD、AV_PIX_FMT_D3D11、AV_PIX_FMT_QSV 等。
版本注记:2.8 中 VAAPI 表面格式名为 AV_PIX_FMT_VAAPI_VLD,3.x 起更名为 AV_PIX_FMT_VAAPI;各硬表面格式随 hwcontext 框架陆续补充。配套函数:av_get_pix_fmt_name()、av_pix_fmt_desc_get()、sws_scale() 的转换两端均使用该枚举。
2.4 AVCodecID(libavcodec/avcodec.h)
解码器/编码器的 ID 标识:AV_CODEC_ID_NONE、AV_CODEC_ID_H264、AV_CODEC_ID_HEVC、AV_CODEC_ID_MPEG2VIDEO、AV_CODEC_ID_VP8/VP9、AV_CODEC_ID_AV1、AV_CODEC_ID_AAC、AV_CODEC_ID_MP3、AV_CODEC_ID_AC3、AV_CODEC_ID_FLAC、AV_CODEC_ID_OPUS、AV_CODEC_ID_PCM_* 等。
版本注记:随版本只增不减;AV_CODEC_ID_AV1 在 3.4/4.0 期成熟,5.0 已完整支持。avcodec_descriptor_get(id) 可由 ID 拿到 1.9 节的描述结构体;avcodec_find_decoder(id) 由 ID 查找解码器。
3. 函数
3.1 版本与日志
| 函数 | 说明 | 版本注记 |
|---|---|---|
unsigned avutil_version(void) |
返回 libavutil 版本整数(2.8=54.x,5.0=57.x) | 稳定 |
unsigned avcodec_version(void) |
libavcodec 版本(2.8=56.x,5.0=59.x) | 稳定 |
unsigned avformat_version(void) |
libavformat 版本(2.8=56.x,5.0=59.x) | 稳定 |
unsigned avdevice_version(void) |
libavdevice 版本 | 稳定 |
void av_log_set_level(int level) |
设置日志级别(AV_LOG_QUIET/PANIC/FATAL/ERROR/WARNING/INFO/VERBOSE/DEBUG) |
稳定;调试首选 |
跨版本代码建议以这些函数 + LIBAV* 宏做运行时/编译期双保险。
3.2 解封装(libavformat):输入侧
| 函数 | 说明 | 版本注记 |
|---|---|---|
int avformat_open_input(AVFormatContext **ps, const char *url, AVInputFormat *fmt, AVDictionary **options) |
打开输入文件/流,探测容器格式 | 稳定;5.0 起 AVInputFormat const 化趋势 |
int avformat_find_stream_info(AVFormatContext *ic, AVDictionary **options) |
读若干包探测流信息(分辨率、帧率、时长等),填充 codecpar |
稳定;原文误写作 avformat_find_best_info |
int av_read_frame(AVFormatContext *s, AVPacket *pkt) |
读取一个压缩包 | 稳定;pkt 用完须 av_packet_unref() |
int av_seek_frame(AVFormatContext *s, int stream_index, int64_t ts, int flags) |
按时间戳定位(AVSEEK_FLAG_BACKWARD 等) |
稳定;精细定位可用 avformat_seek_file() |
int av_find_best_stream(AVFormatContext *ic, AVMediaType type, int wanted, int related, AVCodec **decoder, int flags) |
查找指定类型的最佳流并可顺带得到解码器 | 稳定;原文误写作 av_find_best_frame |
void avformat_close_input(AVFormatContext **s) |
关闭输入并释放上下文 | 稳定 |
AVStream *avformat_new_stream(AVFormatContext *s, const AVCodec *c) |
新建一路流(输出侧也用) | 3.x 起第二参数 const AVCodec* |
void avformat_free_context(AVFormatContext *s) |
释放格式上下文 | 稳定 |
3.3 解码(libavcodec):新收发式 API
这是 2.8 → 5.0 最重要的接口变化 。新 API 于 2016-04(libavcodec 57.37,随 FFmpeg 3.1 发布) 引入,把"喂数据"与"取结果"解耦,一个包可解出多帧、一帧可来自多包;5.0 起旧的 avcodec_decode_video2()/avcodec_decode_audio4() 被彻底移除。
| 函数 | 说明 |
|---|---|
int avcodec_send_packet(AVCodecContext *avctx, const AVPacket *pkt) |
送入压缩包;传 NULL 表示冲刷(drain);返回 AVERROR(EAGAIN) 表示输出未取走,需先取帧 |
int avcodec_receive_frame(AVCodecContext *avctx, AVFrame *frame) |
取出解码帧;EAGAIN 表示还需更多输入,AVERROR_EOF 表示结束 |
void avcodec_flush_buffers(AVCodecContext *avctx) |
清空解码器内部缓冲(seek 后必调,否则残留帧导致花屏/时间戳错乱) |
int av_find_decoder(enum AVCodecID id) |
按 ID 查找解码器;5.0 起返回 const AVCodec * |
经典解码循环(5.0 写法):
c
avcodec_send_packet(ctx, pkt);
while (avcodec_receive_frame(ctx, frame) == 0) {
/* 使用 frame->data[] ... */
av_frame_unref(frame);
}
2.8 对应写法为 avcodec_decode_video2(ctx, frame, &got, pkt);,一步解一帧且无 drain 概念,5.0 中已不可用。
3.4 编码(libavcodec)
| 函数 | 说明 | 版本注记 |
|---|---|---|
int avcodec_send_frame(AVCodecContext *avctx, const AVFrame *frame) |
送入原始帧;NULL 触发 drain |
3.1 引入,5.0 唯一编码入口(旧 avcodec_encode_video2 已移除) |
int avcodec_receive_packet(AVCodecContext *avctx, AVPacket *pkt) |
取出编码包 | 同上;注意 B 帧下一次可能出多个包 |
AVCodec *avcodec_find_encoder_by_name(const char *name) |
按名称查找编码器(如 "libx264"、"h264_vaapi") |
稳定;5.0 返回 const |
3.5 编解码器生命周期与参数搬运
| 函数 | 说明 | 版本注记 |
|---|---|---|
AVCodecContext *avcodec_alloc_context3(const AVCodec *codec) |
分配上下文 | 5.0 入参 const 化 |
int avcodec_open2(AVCodecContext *avctx, const AVCodec *codec, AVDictionary **options) |
打开编解码器(传 priv 选项如 preset、tune) |
稳定 |
int avcodec_parameters_from_context(AVCodecParameters *par, const AVCodecContext *codec) |
上下文 → 流参数(写封装前调用) | 3.0 引入 ;2.8 无此概念(直接共用 st->codec) |
int avcodec_parameters_to_context(AVCodecContext *codec, const AVCodecParameters *par) |
流参数 → 上下文(解码前调用) | 3.0 引入 |
void avcodec_free_context(AVCodecContext **avctx) |
释放上下文(内含 avcodec_close) | 2.x 起提供,5.0 推荐唯一释放方式 |
3.6 封装输出(libavformat):输出侧
| 函数 | 说明 | 版本注记 |
|---|---|---|
int avformat_alloc_output_context2(AVFormatContext **ctx, AVOutputFormat *oformat, const char *format_name, const char *filename) |
创建输出上下文 | 稳定 |
int avio_open(AVIOContext **s, const char *url, int flags) |
打开输出 IO | 稳定;自定义 IO 用 avio_alloc_context() |
int avformat_write_header(AVFormatContext *s, AVDictionary **options) |
写文件头(此后 time_base 可能被 muxer 改写,需以流上实际值为准) | 稳定 |
int av_interleaved_write_frame(AVFormatContext *s, AVPacket *pkt) |
交错写出一个包(内部排序音视频) | 稳定;pkt 所有权被接管,勿再 unref |
void av_packet_rescale_ts(AVPacket *pkt, AVRational tb_src, AVRational tb_dst) |
包时间戳跨时间基换算(编码 time_base → 流 time_base) | 稳定,输出前必调 |
int av_write_trailer(AVFormatContext *s) |
写文件尾(mp4 的 moov 等) | 稳定;原文误写作 avformat_write_tailer |
3.7 内存与引用计数(libavutil/libavcodec)
| 函数 | 说明 | 版本注记 |
|---|---|---|
void av_frame_unref(AVFrame *frame) |
解除帧对缓冲区的引用,结构体可复用 | 3.x 起为标准用法 |
void av_frame_free(AVFrame **frame) |
释放帧(含 unref) | 稳定 |
void av_packet_unref(AVPacket *pkt) |
解除包的引用 | 同 av_frame_unref |
AVBufferRef *av_buffer_create(uint8_t *data, size_t size, void (*free)(...), void *opaque, int flags) |
用外部内存创建引用计数缓冲 | 稳定;flags 可设 AV_BUFFER_FLAG_READONLY |
int av_frame_get_buffer(AVFrame *frame, int align) |
为帧分配数据缓冲(按 format/宽高/采样数自动算) | 稳定;原文误写作 av_frame_get_size_data |
3.8 音频工具(libavutil/libswresample)
| 函数 | 说明 | 版本注记 |
|---|---|---|
int av_get_bytes_per_sample(enum AVSampleFormat s) |
单采样字节数 | 稳定 |
int av_samples_get_buffer_size(int *linesize, int nb_channels, int nb_samples, enum AVSampleFormat s, int align) |
计算音频缓冲总大小 | 稳定 |
SwrContext *swr_alloc_set_options(SwrContext *s, int64_t out_ch_layout, enum AVSampleFormat out_fmt, int out_rate, int64_t in_ch_layout, enum AVSampleFormat in_fmt, int in_rate, int log_offset, void *log_ctx) |
配置重采样/转格式/混音(声道布局用 channel_layout 位掩码) |
2.8 ~ 5.0 主力接口;5.1 起推荐 swr_alloc_set_opts2()(AVChannelLayout) |
int swr_init(SwrContext *s) |
初始化 | 稳定 |
int swr_convert(SwrContext *s, uint8_t **out, int out_count, const uint8_t **in, int in_count) |
执行转换;返回实际输出采样数,注意内部有延迟缓冲,结束时传 NULL 冲刷 |
稳定 |
3.9 时间与字典工具(libavutil)
| 函数 | 说明 | 版本注记 |
|---|---|---|
int64_t av_rescale_rnd(int64_t a, int64_t b, int64_t c, enum AVRounding rnd) |
a*b/c 定点换算(防溢出),AV_ROUND_NEAR_INF 等舍入模式 |
稳定;av_rescale_q() 为其时间基封装 |
int av_dict_set_int(AVDictionary **pm, int64_t key_int, int64_t value, int flags) |
以整数键值设置字典项(av_dict_set() 的整型便捷版,常用于设置 video_track_timescale 之类的选项) |
3.x 起提供 |
3.10 硬解(hwcontext)
| 函数 | 说明 | 版本注记 |
|---|---|---|
AVBufferRef *av_hwdevice_context_alloc(enum AVHWDeviceType type) |
分配设备上下文 | 3.x 引入(hwcontext 框架) |
int av_hwdevice_context_init(AVBufferRef *ref) |
初始化设备上下文(此前须填好 AVVAAPIDeviceContext.display 等) |
3.x 引入 |
AVBufferRef *av_hwframe_context_alloc(AVBufferRef *device_ref) |
分配帧上下文(此后设置 sw_format/width/height/initial_pool_size) |
3.x 引入;帧大小与数目由此控制 |
int av_hwframe_context_init(AVBufferRef *ref) |
初始化帧上下文/帧池 | 3.x 引入 |
int av_hwframe_get_buffer(AVBufferRef *hwframe_ref, AVFrame *frame, int flags) |
从帧池取一帧(外部编码/滤镜路径常用) | 3.x 引入 |
一行式创建设备的 av_hwdevice_ctx_create() 是上述 alloc+init 的便捷封装,解码场景直接 avctx->hw_device_ctx = av_buffer_ref(dev_ref) 即可启用硬解。
3.11 其他
| 函数 | 说明 | 版本注记 |
|---|---|---|
const AVCodecDescriptor *avcodec_descriptor_get(enum AVCodecID id) |
由 ID 取编解码器描述(1.9 节) | 稳定 |
4. 2.8 → 5.0 解码流程对照(迁移要点)
2.8(旧 API)骨架:
c
av_register_all(); /* 5.0 已移除 */
avformat_open_input(&fmt, url, 0, 0);
avformat_find_stream_info(fmt, 0);
AVCodec *dec = avcodec_find_decoder(fmt->streams[i]->codec->codec_id); /* st->codec, 4.0 已移除 */
avcodec_open2(fmt->streams[i]->codec, dec, 0);
while (av_read_frame(fmt, pkt) >= 0)
avcodec_decode_video2(ctx, frame, &got, pkt); /* 5.0 已移除 */
5.0(现行 API)骨架:
c
avformat_open_input(&fmt, url, NULL, NULL);
avformat_find_stream_info(fmt, NULL);
int vidx = av_find_best_stream(fmt, AVMEDIA_TYPE_VIDEO, -1, -1, NULL, 0);
const AVCodec *dec = avcodec_find_decoder(fmt->streams[vidx]->codecpar->codec_id);
AVCodecContext *ctx = avcodec_alloc_context3(dec);
avcodec_parameters_to_context(ctx, fmt->streams[vidx]->codecpar);
avcodec_open2(ctx, dec, NULL);
AVPacket *pkt = av_packet_alloc();
AVFrame *frame = av_frame_alloc();
while (av_read_frame(fmt, pkt) >= 0) {
if (pkt->stream_index == vidx) {
avcodec_send_packet(ctx, pkt);
while (avcodec_receive_frame(ctx, frame) == 0) {
/* 使用 frame ... */
av_frame_unref(frame);
}
}
av_packet_unref(pkt);
}
avcodec_send_packet(ctx, NULL); /* drain */
硬解迁移要点:2.8 的 avctx->hwaccel_context = &vaapi_ctx(外部 surface)→ 5.0 的 av_hwdevice_ctx_create(..., "vaapi", ...) + avctx->hw_device_ctx;外部 surface 需求由 AVHWFramesContext 自定义帧池承接。
5. 小结
| 主题 | 2.8 状态 | 5.0 状态 |
|---|---|---|
| 解码/编码 API | avcodec_decode_* / avcodec_encode_* |
仅 send/receive(3.1 引入,5.0 移除旧 API) |
| 流参数 | AVStream->codec |
codecpar + avcodec_parameters_*(4.0 移除 codec) |
| 包/帧内存 | av_init_packet() + 手工管理 |
av_packet_alloc/av_frame_alloc + 引用计数 unref |
| 硬解 | struct vaapi_context + hwaccel_context |
AVHWDeviceContext/AVHWFramesContext(vaapi_context 已废弃) |
| HDR 元数据 | 无 | AVMasteringDisplayMetadata/AVContentLightMetadata side data |
| 查找接口 | AVCodec * |
const AVCodec *(const 化) |
| 库版本 | lavu54/lavc56/lavf56 | lavu57/lavc59/lavf59 |
把握三条主线即可贯通 2.8 → 5.0 的全部差异:收发式编解码 API 取代旧循环 、codecpar 取代 st->codec 、hwcontext 取代 vaapi_context。其余结构体(AVRational、AVCodecDescriptor 等)与工具函数(av_rescale_rnd、swr_* 等)在研究范围内保持稳定,可放心复用。