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 收工

相关推荐
FFZero110 小时前
[mpv架构] (4) demux 线程到底在“预读“什么?
c++·架构·音视频·多媒体
却道天凉_好个秋10 小时前
音视频学习(一百零五):Access Unit (AU)和RTP分包
学习·音视频·access unit·rtp分包
刘广睿11 小时前
AI 配音怎么做?语音合成 TTS 技术选型与本地部署实战(edge-tts / GPT-SoVITS / CosyVoice / Piper)
人工智能·音视频·效率工具·语音合成·tts
小柯南敲键盘11 小时前
跨马翻译AI工具,批量图片视频翻译与智能抠图一站式解决
人工智能·python·音视频
show43312 小时前
2026小程序端视频处理性能优化:批量+120分钟大文件
性能优化·音视频
阿童木写作21 小时前
跨境图片翻译工具推荐:批量处理视频字幕与智能抠图
python·音视频
Agudamu11611 天前
AI 视频学习笔记工具拆解:4款工具谁能把视频变成复习资料
人工智能·学习·音视频
全速向光1 天前
VLC Media Player:开源全能跨平台播放器详解
开源·音视频
黄一一9112431 天前
跨平台视频图片压缩互转!离线视频压缩工具!Github开源轻松无损压缩视频!Win/Mac/Linux三端通用开源工具
windows·macos·音视频·开源软件
科技拓维者1 天前
短视频配音音效去哪里找比较好?短视频创作者音效指南
人工智能·音视频