FFmpeg 音频采样格式(sample_fmt)完全手册:FLTP、S16、S32 到底在吵什么

目录

[一、sample_fmt 到底是什么?](#一、sample_fmt 到底是什么?)

[二、先分清:Packed vs Planar(音频里最容易被忽略)](#二、先分清:Packed vs Planar(音频里最容易被忽略))

Packed(交错)

Planar(平面)

[三、8bit 系列](#三、8bit 系列)

[S8 / U8](#S8 / U8)

四、S16(最经典的"能直接播"的格式)

AV_SAMPLE_FMT_S16(Packed)

AV_SAMPLE_FMT_S16P(Planar)

[五、S32(专业音频 / 高动态范围)](#五、S32(专业音频 / 高动态范围))

[AV_SAMPLE_FMT_S32 / S32P](#AV_SAMPLE_FMT_S32 / S32P)

[六、FLT / FLTP(AAC 解码默认)](#六、FLT / FLTP(AAC 解码默认))

[AV_SAMPLE_FMT_FLT(Packed float)](#AV_SAMPLE_FMT_FLT(Packed float))

[AV_SAMPLE_FMT_FLTP(Planar float)](#AV_SAMPLE_FMT_FLTP(Planar float))

[七、DBL / DBLP(双精度,基本只在滤波链里)](#七、DBL / DBLP(双精度,基本只在滤波链里))

八、各格式对比速查表

[九、Buffer 大小怎么算(新手必错)](#九、Buffer 大小怎么算(新手必错))

[十、Planar → Packed 实战(S16P → S16)](#十、Planar → Packed 实战(S16P → S16))

[十一、AAC 解码标准链路](#十一、AAC 解码标准链路)

十二、三个高频坑

[坑 1:SDL 播音炸裂](#坑 1:SDL 播音炸裂)

[坑 2:声道数变了但 format 没变](#坑 2:声道数变了但 format 没变)

[坑 3:linesize 不等于 sampleschbytes](#坑 3:linesize 不等于 sampleschbytes)

十三、总结


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

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

做音视频的人,几乎都在音频上栽过:AAC 解码出来是 fltp,SDL 播放劈里啪啦,自己 malloc 的 buffer,copy 完全是杂音;av_samples_get_buffer_size算出来的大小跟想的不一样; 混音时发现"数值怎么还有负数还带小数点",问题的根,90% 都在 sample_fmt(音频采样格式),本文就把 FFmpeg 里最常见、最容易混淆的音频采样格式聊一下。


一、sample_fmt 到底是什么?

视频有 pix_fmt,音频对应就是:

复制代码
enum AVSampleFormat;

命令行里叫:

复制代码
-sample_fmt s16

它决定两件事:

  1. 每个采样点用什么类型存(int8 / int16 / int32 / float)

  2. 多声道怎么排(planar or packed)

注意:它不决定采样率,也不决定声道数,只管"一个样本长什么样"。


二、先分清:Packed vs Planar(音频里最容易被忽略)

Packed(交错)

所有声道挤在一起:

复制代码
L R L R L R L R

代表:

  • AV_SAMPLE_FMT_S16

  • AV_SAMPLE_FMT_FLT

Planar(平面)

每个声道独占一块内存:

复制代码
LLLLLLLL
RRRRRRRR

代表:

  • AV_SAMPLE_FMT_S16P

  • AV_SAMPLE_FMT_FLTP

AAC / OPUS / MP3 解码器几乎都输出 Planar

SDL / OpenSL / 声卡 DMA 几乎都吃 Packed

所以你一定会做:

Planar → Packed


三、8bit 系列

S8 / U8

  • AV_SAMPLE_FMT_U8:0--255

  • AV_SAMPLE_FMT_S8:-128--127

早期 PCM、游戏音效、嵌入式喇叭。

动态范围小、量化噪声大,现代编码不用。


四、S16(最经典的"能直接播"的格式)

AV_SAMPLE_FMT_S16(Packed)

  • 16bit 有符号整型

  • 范围:-32768 ~ 32767

  • 布局:int16_t L R L R...

特点:

  • SDL2 默认

  • Linux ALSA 默认

  • WAV 文件常见

  • 不挑平台,性能最好

复制代码
int16_t *pcm = (int16_*)frame->data[0];

AV_SAMPLE_FMT_S16P(Planar)

  • 每个声道一个 int16_t*

  • data[0] = L, data[1] = R

FFmpeg 内部常见,但不能直接丢给声卡


五、S32(专业音频 / 高动态范围)

AV_SAMPLE_FMT_S32 / S32P

  • 32bit 整数

  • 范围:-2147483648 ~ 2147483647

  • 动态范围比 S16 大 48dB

用在:

  • 专业音频工作站

  • 多代混音(防止截断误差累积)

  • FFmpeg 某些滤波器内部

播放前要转 S16,否则声卡不认。


六、FLT / FLTP(AAC 解码默认)

AV_SAMPLE_FMT_FLT(Packed float)

  • 32bit IEEE float

  • 范围:-1.0 ~ 1.0

  • float L R L R...

AV_SAMPLE_FMT_FLTP(Planar float)

  • data[0] = float* L

  • data[1] = float* R

  • AAC / OPUS / Vorbis 默认解码输出

为什么用 float?

  • 滤波器数学运算方便

  • 不会溢出

  • 多代处理误差小

但是:

  • SDL 不能直接播

  • 写 WAV 要转 int

  • 存文件前必须 scale


七、DBL / DBLP(双精度,基本只在滤波链里)

  • AV_SAMPLE_FM_DBL/ DBLP

  • 64bit double

  • 极少见(科学计算、降噪研究)

  • 编解码器不使用


八、各格式对比速查表

sample_fmt 类型 范围 Planar? 典型用途
u8 / s8 int8 0~255 / ±127 老式 PCM
s16 int16 ±32767 SDL/WAV/ALSA
s16p int16 ±32767 FFmpeg 内部
s32 / s32p int32 ±2^31 专业音频
flt float -1~1 某些渲染器
fltp float -1~1 AAC/OPUS 解码
dbl / dblp double -1~1 滤波/科研

九、Buffer 大小怎么算(新手必错)

不要写:

复制代码
size = nb_samples * channels * 2;

要用 FFmpeg API:

复制代码
int buf_size = av_samples_get_buffer_size(
    NULL,
    frame->channels,
    frame->nb_samples,
    frame->format,
    1);  // align

Planar 时:

  • data[0..N]每个声道 nb_samples * bytes_per_sample

  • 总 buffer = 单声道大小 × 声道数(连续分配时)


十、Planar → Packed 实战(S16P → S16)

复制代码
// frame->format == AV_SAMPLE_FMT_S16P
int16_t *dst = out_buf;
for (int i = 0; i < frame->nb_samples; i++) {
    for (int ch = 0; ch < frame->channels; ch++) {
        dst[i * frame->channels + ch] =
            ((int16_t*)frame->data[ch])[i];
    }
}

FLTP → S16(带 clip):

复制代码
float f = ((float*)frame->data[ch])[i];
f = FFMAX(-1.0f, FFMIN(1.0f, f));
dst[i * ch + ch] = (int16_t)(f * 32767);

十一、AAC 解码标准链路

复制代码
AAC packet
   ↓
avcodec_send_packet
   ↓
avcodec_receive_frame
   → sample_fmt = fltp
   ↓
swr_convert (fltp → s16)
   ↓
SDL_QueueAudio (s16 packed)

SwrContext 设置:

复制代码
swr_alloc_set_opts2(&swr,
    &out_layout, AV_SAMPLE_FMT_S16, 48000,
    &in_layout,  AV_SAMPLE_FMT_FLTP, 44100,
    0, NULL);

十二、三个高频坑

坑 1:SDL 播音炸裂

解码是 fltp,直接当 s16播 → 爆音

必须 swr_convert

坑 2:声道数变了但 format 没变

swr 不自动帮你改 layout,要显式设 channel_layout

坑 3:linesize 不等于 sampleschbytes

音频 frame 也有 linesize[0],通常等于单平面字节数,别拿它当总大小。


十三、总结

S16 是"声卡语言",FLTP 是"解码器语言",Planar 是"FFmpeg 内部语言"。

工程里 80% 的音频 bug,都是这三者没接好。

相关推荐
cpp_learners5 小时前
FFmpeg H264视频解码全流程解析
ffmpeg·音视频·解码
YH55269845 小时前
有什么AI工具能将网课和视频播客的内容转化成文档?
人工智能·音视频
程序员老陆7 小时前
FFmpeg 像素格式(pix_fmt)通关指南:从 YUV420P 到 NV12、RGB24 到底怎么选
ffmpeg·音视频·yuv·像素格式
小白学大数据8 小时前
基于Python的抖音网页版视频点赞数增长趋势追踪系统设计与实现
开发语言·爬虫·python·搜索引擎·音视频
DogDaoDao9 小时前
FFmpeg 9.0 “Lei“ 正式发布:十年之后,以你之名
ffmpeg·音视频·实时音视频·视频编解码·ffprobe·ffmpeg 9.0
开开心心_Every9 小时前
电脑文件搜索软件支持内容和拼音搜索
linux·服务器·人工智能·r语言·pdf·音视频·symfony
weixin_495248409 小时前
带硬字幕的老视频也能出海:短剧出海翻译服务商如何擦除重制?
人工智能·音视频
weixin_4462608510 小时前
Video-DeepResearch:面向下一代视频多模态深度研究智能体
人工智能·音视频
硅谷秋水21 小时前
EgoSteer:一种基于第一人称视角视频、实现可控灵巧操作的全栈系统
深度学习·机器学习·语言模型·机器人·音视频