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

相关推荐
用户2181697049309 小时前
FFmpeg (一)使用opencv实现马赛克
ffmpeg
昨日之日20069 小时前
【MiniMax H3】TaoMate-H3:3步LoRA让视频生成更快更高效,速度快10倍
人工智能·计算机视觉·音视频
Likeadust9 小时前
上传即转码、分类、嵌入:本地点播/网络点播EasyDSS点播如何撑起企业视频知识库
大数据·音视频·easydss
cpp_learner9 小时前
FFmpeg RTSP播放时钟实现揭秘
ffmpeg
美狐美颜SDK开放平台6 天前
开发直播APP时如何接入视频美颜SDK?开发流程与注意事项
android·人工智能·计算机视觉·音视频·直播美颜sdk
2601_955662466 天前
短剧多人对白怎么配?2026年多角色配音工具对比
大数据·人工智能·音视频·语音识别
开发笔记-阿牛6 天前
蓝牙音乐灯拆解,又一次拆到蓝牙音乐灯芯片CK6865L
人工智能·单片机·嵌入式硬件·音视频·音频
旺仔小馒头wang6 天前
AI 智能手机发布会:赋予人类的五种新能力
人工智能·学习·音视频
纳祥科技6 天前
拆机拆到芯片级:ARC功放机里的NX7026、NX8420、NX6805
单片机·音视频·智能音箱
youandyouyou6 天前
律所内部培训共享的内网部署方案:架构、参数与三步落地
音视频