FFmpeg的AVFrame全部数据操作函数详解

目录

核心看点

[一、AVFrame 本质一句话定义](#一、AVFrame 本质一句话定义)

[二、AVFrame 数据操作函数总览表(核心 8 个)](#二、AVFrame 数据操作函数总览表(核心 8 个))

三、逐函数深度拆解(高分博客级)

[1️. av_frame_alloc()------ 只造壳](#1️. av_frame_alloc()—— 只造壳)

[2️. av_frame_get_buffer()------ 真正分配数据](#2️. av_frame_get_buffer()—— 真正分配数据)

[3️. av_frame_ref()------ 引用拷贝(最容易误解)](#3️. av_frame_ref()—— 引用拷贝(最容易误解))

[4️. av_frame_make_writable()------ FFmpeg 的"深拷哲学](#4️. av_frame_make_writable()—— FFmpeg 的“深拷哲学)

[5️. av_frame_clone()------ 一行式深拷](#5️. av_frame_clone()—— 一行式深拷)

[6️. av_frame_copy()------ 只拷数据(不碰壳)](#6️. av_frame_copy()—— 只拷数据(不碰壳))

[7️. av_buffersrc_add_frame*()对 frame 的影响](#7️. av_buffersrc_add_frame*()对 frame 的影响)

[8️. av_frame_unref()vs av_frame_free()](#8️. av_frame_unref()vs av_frame_free())

av_frame_unref()

av_frame_free()

[四、AVFrame 音频数据访问速查](#四、AVFrame 音频数据访问速查)

[五、FFmpeg 音频帧"生命周期铁三角"](#五、FFmpeg 音频帧“生命周期铁三角”)

[铁律 3 条](#铁律 3 条)

六、高频踩雷速诊表

七、一句话总结

八、推荐记忆口诀


觉得有用,就请您帮忙点赞转发收藏吧,您的鼓励是我创作的动力,多谢看官。

由于能力水平有限,文中的错误或不严谨的地方在所难免,还请批评指正。

本文不是 API 翻译,而是FFmpeg 音频开发者踩坑 3 年后的生命周期总结

围绕 AVFrame解码 → swr 重采样 → filter 滤镜 → 播放/编码 ​ 链路中的真实行为,逐条拆解 av_frame_get_buffer / av_frame_ref / av_frame_make_writable / av_buffersrc_add_frame等高频函数的底层语义,直击 planar / packed 杂音、swr_convert 闪退、double free、破音等"玄学 Bug"的根因。

全文给出 唯一正确用法 + 生命周期铁三角模型,适合做播放器 / 转码 / 实时音频的工程师收藏级参考。

核心看点

为什么 av_frame_ref()不是深拷贝,却最容易写崩

av_buffersrc_add_frame()后 frame 到底变没变(官方文档没说清)

swr_convert 闪退的 90% 真因:frame ownership 污染

planar(FLTP)和 packed(S16)在 AVFrame 里的真实内存布局

FFmpeg 官方都不爱说的:**filter 输入帧能不能复用?**​

一、AVFrame 本质一句话定义

**AVFrame = 媒体数据的"引用型描述符"**​

不是 malloc 出来的裸 buffer

AVBufferRef + 元数据壳


二、AVFrame 数据操作函数总览表(核心 8 个)

函数 行为本质 是否深拷 使用场景
av_frame_alloc() 分配壳 初始化
av_frame_get_buffer() 分配 PCM buffer swr / filter 输出
av_frame_ref() 引用拷贝 传帧 / 浅拷贝
av_frame_clone() ref + writable 存档帧
av_frame_make_writable() COW 深拷 写前安全
av_frame_copy() 拷 PCM 纯数据复制
av_frame_unref() 减引用 归还
av_frame_free() unref + free 析构

三、逐函数深度拆解(高分博客级)


1️. av_frame_alloc()------ 只造壳

复制代码
AVFrame *f = av_frame_alloc();

做了什么:

  • 分配 AVFrame结构体

  • data / buf 全 NULL

没干:

  • 没 alloc PCM

  • 没填格式

用途:声明"我准备要一帧"


2️. av_frame_get_buffer()------ 真正分配数据

复制代码
f->format = AV_SAMPLE_FMT_FLTP;
f->nb_samples = 1024;
av_channel_layout_copy(&f->ch_layout, &stereo);
av_frame_get_buffer(f, 0);

内部:

  • 按 planar / packed 算 stride

  • av_malloc_aligned()

  • buf[] / data[] / extended_data

规则:

  • nb_samples必须先设

  • planar 自动多 plane

swr_convert / filter 输出唯一正确初始化方式


3️. av_frame_ref()------ 引用拷贝(最容易误解)

复制代码
av_frame_ref(dst, src);

行为:

  • dst->data = src->data

  • AVBufferRef refcount++

不拷贝 PCM

buffersrc / 队列 / 多线程传帧用

别拿 ref 后的 dst 当 swr 输出


4️. av_frame_make_writable()------ FFmpeg 的"深拷哲学

复制代码
av_frame_make_writable(f);

内部逻辑:

复制代码
refcount == 1 → 啥也不干
refcount > 1 → 新 malloc + memcpy

经典用法:

复制代码
av_frame_ref(cp, src);
av_frame_make_writable(cp); // ✅ 安全可写

filter 前想"保留原帧又想写"的唯一正解


5️. av_frame_clone()------ 一行式深拷

复制代码
AVFrame *cp = av_frame_clone(src);

等价伪码:

复制代码
alloc → ref → make_writable

适合:

  • 解码帧缓存

  • 音频回调队列

比手写慢一丢丢(可忽略)


6️. av_frame_copy()------ 只拷数据(不碰壳)

复制代码
av_frame_copy(dst, src);

前提:

  • dst / src 格式一致

  • dst 已 get_buffer

用途:

  • 自己管理 buffer 时纯拷数据

7️. av_buffersrc_add_frame*()对 frame 的影响

复制代码
av_buffersrc_add_frame(src_ctx, f);

frame 本身:

  • 不改 data / pts

  • 不改 buffer 内容

但:

  • filtergraph 内部 av_frame_ref()

  • 共享 buffer

正确姿势:

复制代码
av_buffersrc_add_frame_flags(ctx, f, AV_BUFFERSRC_FLAG_KEEP_REF);
av_frame_unref(f); // 你负责

8️. av_frame_unref()vs av_frame_free()

av_frame_unref()

  • buf ref--

  • data / linesize 清 0

  • frame 可复用

av_frame_free()

  • unref + av_free(frame)

规则:

场景 API
循环复用 unref
析构 free
unique_ptr deleter free

四、AVFrame 音频数据访问速查

复制代码
// planar
float *L = (float *)f->extended_data[0];
float *R = (float *)f->extended_data[1];

// packed
int16_t *pcm = (int16_t *)f->data[0];

// 字节数(正确)
int bytes = f->nb_samples *
            av_get_bytes_per_sample(f->format) *
            (av_sample_fmt_is_planar(f->format) ? 1 : f->ch_layout.nb_channels);

五、FFmpeg 音频帧"生命周期铁三角"

复制代码
┌────────────┐  解码  ┌────────────┐  swr  ┌────────────┐
│ dec_frame  │──────▶│ swr_frame  │──────▶│ filt_frame │
│ (ref only) │        │ make_writable│      │ sink get   │
└────────────┘        └────────────┘       └────┬───────┘
                                                 ↓
                                            av_frame_unref

铁律 3 条

  1. 一个 AVFrame 只干一件事

  2. swr 输出 / filter 输入 / 解码帧 绝不混用

  3. 谁 alloc buffer 谁 unref


六、高频踩雷速诊表

现象 原因
SIGSEGV swr_convert frame buffer 被 filter ref 过
杂音 planar → packed 解释错
double free free(data0)
破音 volume 超 ±1 + float
偶发炸 outSamples > nb_samples
闪退 buffersrc frame 没 get_buffer

七、一句话总结

**AVFrame 不是 struct { uint8_tdata }*

是 shared_ptr<PCM> + 描述符

get_buffer= malloc

ref= share

make_writable= COW

unref= 还权


八、推荐记忆口诀

alloc 壳,get_buffer 肉

ref 借帧,writable 动手

filter 不抢,swr 不共用

unref 归位,free 收工

相关推荐
glumes2 小时前
从《牛来》到 DCP:一部电影是怎么走进电影院的?
ffmpeg·音视频开发
tech讯息5 小时前
商业化内容生产适用企业级视频生成模型云平台推荐|从模型生成至审核分发全链路 AWS 选型方案
人工智能·音视频·aws
杀生丸学AI21 小时前
【稀疏重建】StructSplat:基于非校准稀疏视图的可泛化3DGS
深度学习·3d·音视频·transformer·三维重建·空间智能
小柯南敲键盘21 小时前
跨境电商图片翻译工具推荐:批量AI翻译+视频字幕+智能抠图
人工智能·python·音视频
DogDaoDao1 天前
【H266/VVC提案解读】ITU-T H.274 (V4) 规范深度解读 — 视频编码 SEI 消息的全面演进
音视频·实时音视频·视频编解码·流媒体·h266·vvc·视频编解码标准
程序员老陆1 天前
FFmpeg RTSP 解复用器(rtsp demuxer)完全解析:从「能播」到「稳播」的参数圣经
ffmpeg·音视频·拉流·rtsp
hhzz1 天前
Tiger AI 平台「手势识别」功能全解析:从数字手势 0–9,到中国手语字母,再到本地视频批量识别——一条链路,三种输入,双模型可同开;双手比划,机器秒懂
人工智能·python·深度学习·aigc·音视频
martindelophy1 天前
DeepSeek Harness 插件开发实战:用自然语言检查、修改并渲染 Timeline Studio 视频工程
音视频
平原20181 天前
LTX-2.5 22B 本地部署:ModelScope 下载、8 步推理与图生视频命令
音视频