news 2026/8/7 23:18:56

音频为什么不编码成“声卡格式”(例如S16)?因为声卡只负责响,编码器只负责省

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
音频为什么不编码成“声卡格式”(例如S16)?因为声卡只负责响,编码器只负责省

目录

一、先澄清一个巨大误会

核心原因解析

实际工作流程

二、声卡到底要什么?

三、编码器为什么要搞“奇怪格式”?(FLTP 是重灾区)

FLTP 拆解一下:

四、为什么编码器死磕 float planar?

1️.数学精度:量化噪声是编码器第一敌人

2️.Planar 是为了 SIMD,不是为了你爽

3️.编码标准根本不关心“整数”

五、那为什么声卡不用 float planar?

六、FFmpeg 的真相:三层世界模型**

七、声卡格式 vs 编码格式:特性对照表

八、一个你可能踩过的坑

九、总结


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

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

音频不直接编码为"S16"等声卡格式,是因为‌S16 仅是 PCM 裸数据的位深与字节序描述(非完整文件格式),缺乏采样率、声道数等关键元数据且无法压缩存储/传输‌;文件需封装元数据头并采用压缩编码以适配多样场景,而声卡格式仅作为底层播放时的最终转换目标 。‌‌

一句话暴论:声卡格式是物理,采样格式是代数。两者本来就不是一个物种。


一、先澄清一个巨大误会

你看到的:

SDL_OpenAudio(S16) PulseAudio(PCM_S16LE) WASAPI(KSDATAFORMAT_SUBTYPE_PCM)

和 FFmpeg 里的:

AV_SAMPLE_FMT_S16 AV_SAMPLE_FMT_FLTP AV_SAMPLE_FMT_S32P

不是“同一个维度的东西”

  • 声卡:DAC 要吃的电压序列

  • 编码器:比特流要榨的油水

一个管“怎么出声”

一个管“怎么压缩”

核心原因解析

  1. S16 不是完整文件格式‌:S16(Signed 16-bit)仅定义采样点的数值范围和字节序(如 S16_LE),‌不包含采样率、声道数、时长等必要信息‌。一段纯 S16 数据若无外部约定参数,播放器无法知其如何还原声音(例如 44.1kHz 还是 48kHz?单声道还是立体声?)。
  2. 存储与传输效率极低‌:S16 代表未压缩的 PCM 数据。若所有音频文件均以此存储,1 分钟立体声 44.1kHz 音频需约 10MB 空间,且无法通过网络流畅传输;实际需 MP3/AAC/FLAC 等编码进行压缩,仅在播放瞬间由解码器转为声卡支持的 S16/S24 等格式 。
  3. 声卡硬件多样性‌:不同声卡支持的格式各异(部分仅支持 S16_LE,高端卡支持 S24/S32 Float),‌不存在统一的“声卡格式”‌。操作系统音频服务(如 ALSA、Core Audio、WASAPI)负责将多种来源音频统一重采样、转换为目标声卡所需的特定格式 。
  4. 处理灵活性需求‌:音频制作、流媒体、语音识别等场景需保留高位深(如 24bit/32bit Float)以避免中间运算失真,若强制存为 S16 会永久丢失动态范围和精度 。‌‌

实际工作流程

  1. 存储/传输层‌:文件采用含头信息的容器格式(如 WAV/FLAC)或压缩编码(如 AAC/Opus),完整记录采样率、位深、声道等参数。
  2. 解码与混音层‌:播放时解码器还原为 PCM 数据,系统音频引擎将其重采样并转换为统一内部格式(常为 32bit Float)进行混音处理。
  3. 输出层‌:音频服务将最终数据‌实时转换‌为当前声卡硬件支持的特定格式(如 S16_LE @ 48kHz)写入缓冲区,驱动 D/A 转换器发声 。‌‌

简言之,S16 是声卡“吃”的饲料规格,而非仓库里存的“粮食包装”;文件需自带说明书(元数据)和压缩包装(编码),上桌前再由厨房(系统)按需加工成声卡能直接处理的形态


二、声卡到底要什么?

声卡要的是:

时间离散 + 幅度线性 + 连续缓冲区

典型组合:

位宽

16bit / 24bit / 32bit

符号

signed

排列

交错(LRLRLR)

字节序

小端

采样率

44100 / 48000

本质:

DAC 不懂傅里叶,DAC 只会按电压爬梯子

所以声卡必须:

  • 整数

  • 连续内存

  • 固定步进


三、编码器为什么要搞“奇怪格式”?(FLTP 是重灾区)

你第一次见AV_SAMPLE_FMT_FLTP的反应:

float?还 planar?有病吧?

FFmpeg 说得很直白:

我不是写给 DAC 看的,我是写给 MDCT 看的


FLTP 拆解一下:

缩写

含义

FLT

float(32bit IEEE)

P

planar(分通道存),left[], right[]

内存长这样:

planar[0]: L L L L L L planar[1]: R R R R R R

而不是:

L R L R L R

四、为什么编码器死磕 float planar?

1️.数学精度:量化噪声是编码器第一敌人

AAC / Opus / MP3 核心流程:

MDCT → 量化 → 熵编码

MDCT 是啥?

  • 浮点矩阵变换

  • 系数乘来乘去

  • 舍入误差累积

如果用 S16:

short *pcm = buffer; coeff = pcm[i] * win[j] >> shift; // ❌ 灾难

结果:

  • 截断失真

  • 噪声整形失效

  • 心理声学模型崩

float 的好处:

S16

float

动态范围

96 dB

~1500 dB

DC 偏移

难处理

减一下就行

增益

整数倍

乘法无痕

MDCT

数值烂

数值稳


2️.Planar 是为了 SIMD,不是为了你爽

现代 CPU:

vmulps ymm0, [l_chan] vaddps ymm1, [r_chan]

Planar:

  • 连续内存

  • 无 stride

  • AVX2 / NEON 直接飞

交错 S16:

  • gather load

  • unpack

  • shuffle

  • 性能直接腰斩

FLTP = 写给 CPU 的格式


3️.编码标准根本不关心“整数”

AAC 标准里写的是:

time-domain input is real-valued sequence

没说:

  • 必须是 short

  • 必须是 LSB aligned

Opus / AAC / LC3 内部:

  • 全浮点 / 定点 Q31

  • 最后才 dither 成 16bit


五、那为什么声卡不用 float planar?

因为 DAC 是模拟世界的奴隶:

限制

DAC

只能线性阶梯

不能向量化

FIFO 硬连线

DMA 只认 LRLR

你给声卡灌 float planar:

  • DMA scatter-gather 复杂

  • 时钟抖动

  • 驱动直接 BSOD

所以:

内核 / WASAPI / ALSA 帮你做了一件事:重采样 + 转换


六、FFmpeg 的真相:三层世界模型**

┌────────────── 编码世界 ───────────────┐ │ FLTP / DBL / S32P │ │ libopus / libfdk_aac / libx264audio │ └────────────── swr_convert ───────────┘ ↓ ┌────────────── 中间层 ────────────────┐ │ AV_SAMPLE_FMT_S16 (interleaved) │ │ SDL / PortAudio / OpenSL ES │ └────────────── 声卡驱动 ──────────────┘ ↓ ┌────────────── 物理世界 ──────────────┐ │ I2S / USB Audio / HDMI LPCM │ │ DAC → 电容 → 空气 → 耳朵 │ └─────────────────────────────────────┘

libswresample 就是那个“翻译官”


七、声卡格式 vs 编码格式:特性对照表

对比项

声卡格式(S16 interleaved)

编码采样格式(FLTP / S32P)

服务对象

DAC

变换域压缩

数值类型

整数

float / Q-fixed

通道排布

packed(LRLR)

planar

是否关心精度

不深

极深

SIMD 友好

一般

极佳

可压缩性

极差

极佳

心理声学友好

硬件直接支持


八、一个你可能踩过的坑

avcodec_decode_audio4() → AV_SAMPLE_FMT_FLTP → 直接 memcpy 给 SDL → 声音炸裂 + 啸叫

正确路径:

swr_alloc_set_opts( AV_SAMPLE_FMT_FLTP, ch_layout, AV_SAMPLE_FMT_S16, ch_layout, rate, rate, 0, NULL ); swr_convert();

FFmpeg 不替你做 DAC 适配,这是设计不是偷懒


九、总结

采样格式不是“谁更先进”,而是“站在哪一边”

  • 靠近人耳:整数交错

  • 靠近算法:浮点分通道

Qt / SDL / WASAPI 负责“响”

FFmpeg / Opus / AAC 负责“小”

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/8/7 23:17:40

Mirendil与谷歌云签署逾亿美元合作协议,推进自我改进AI研究

AI实验室Mirendil已与谷歌云签署一项多年期合作协议,以获取其自我改进AI研究所需的算力资源,TechCrunch独家获悉这一消息。这笔交易折射出当前AI行业的两大趋势:云计算巨头正以大规模基础设施承诺争相招揽初创企业,同时AI公司也在…

作者头像 李华
网站建设 2026/8/7 23:16:40

Windows Auto Dark Mode终极开发指南:Visual Studio 2022配置与高效调试技巧

Windows Auto Dark Mode终极开发指南:Visual Studio 2022配置与高效调试技巧 Windows Auto Dark Mode是一款能够根据时间或日出日落自动切换Windows 10和Windows 11深色/浅色主题的实用工具。本指南将带你从零开始,在Visual Studio 2022中配置开发环境&…

作者头像 李华
网站建设 2026/8/7 23:12:37

51单片机超声波测距系统Proteus仿真全攻略:从原理到代码实现

1. 项目概述与核心价值最近在整理一些老项目的资料,翻到了当年做的一个基于51单片机的超声波测距系统仿真设计。这个项目可以说是很多电子、自动化专业学生课程设计或毕业设计的“老朋友”了。它麻雀虽小,五脏俱全,涵盖了单片机最小系统、传感…

作者头像 李华
网站建设 2026/8/7 23:11:52

wechat-php-sdk 单元测试全攻略:确保你的公众号功能稳定可靠

wechat-php-sdk 单元测试全攻略:确保你的公众号功能稳定可靠 【免费下载链接】wechat-php-sdk 微信公众平台 PHP SDK 项目地址: https://gitcode.com/gh_mirrors/wec/wechat-php-sdk 微信公众平台开发中,功能稳定性直接影响用户体验和业务连续性。…

作者头像 李华
网站建设 2026/8/7 23:09:42

13_矩阵乘法

数组相乘:两个数组相乘进行的是对位乘法矩阵乘法:前行 后列,对应相乘再相加 import numpy as np# 数组相乘进行的是对位乘法 def arrayMulti():# 通过*运算符和np.multiply()对两个数组相乘进行的是对位乘法而非矩阵乘法运算。arr1 np.arr…

作者头像 李华
网站建设 2026/8/7 23:04:42

深度解析Gyroflow:基于陀螺仪数据的专业视频稳定技术实战指南

深度解析Gyroflow:基于陀螺仪数据的专业视频稳定技术实战指南 【免费下载链接】gyroflow Video stabilization using gyroscope data 项目地址: https://gitcode.com/GitHub_Trending/gy/gyroflow 在当今视频内容创作领域,手持拍摄的抖动问题一直…

作者头像 李华