音视频数据流基础 · 第 2 篇
音频流基础:PCM、WAV 与 AAC 编码深度解析
目录
1. 音频流转全链路回顾2. 探秘声音的数字躯壳:PCM2.1 采样定理与核心参数2.2 PCM 数据体积与计算规则2.3 常见的物理存储交错模式3. 给裸奔的数据穿上衣服:WAV 容器3.1 为什么我们需要 WAV?3.2 拆解 RIFF/WAVE 文件头3.3 实战:在十六进制中辨认 WAV4. 极致的听觉欺骗:AAC 编码与心理声学4.1 为什么 AAC 能干掉 MP3?4.2 常见 Profile 与生产环境参数5. AAC 的运输载体:ADTS 帧头深度拆解5.1 ADTS 7 字节 Header 逐字段解析5.2 灵魂拷问:既然浪费带宽,为何还要带 ADTS 头?5.3 容器差异:MP4 中的 AudioSpecificConfig6. 纵向对比总结:PCM、WAV、AAC、MP4 到底是什么关系?7. 常用 FFmpeg 音频处理命令速查1. 音频流转全链路回顾
在开始枯燥的参数解析之前,我们先在脑海中建立音频数据流转的宏观链路。从你对着麦克风说话,到观众在耳机里听到声音,音频数据经历了如下蜕变:
麦克风采集
→ 得到 PCM 原始音频(体积巨大)
→ 送入编码器进行 AAC 压缩(体积骤减)
→ 封装为 ADTS 裸流,或装进 MP4 / FLV 等容器
→ 网络传输
→ 客户端解封装
→ AAC 解码还原
→ 得到 PCM 数据
→ 送入声卡播放在这个链路中,PCM 是声音最原始的物理切片,而 AAC 则是为了网络传输而发明的“听觉欺骗”压缩魔法。
2. 探秘声音的数字躯壳:PCM
PCM(Pulse Code Modulation,脉冲编码调制) 是一种将连续的模拟声波,转换为计算机能够理解的离散数字样本的方法。这项技术早在上世纪 40 年代就由贝尔实验室奠定了理论基础。
2.1 采样定理与核心参数
要理解 PCM,必须掌握以下三个核心物理参数:
| 参数 | 含义 | 常见工程取值 |
|---|---|---|
| Sample Rate(采样率) | 一秒钟内对声波进行多少次切片记录 | 44100 Hz、48000 Hz |
| Bit Depth(位深) | 每次切片记录时,用多少个 bit 来表示声音的振幅大小 | 16-bit、24-bit、32-bit float |
| Channels(声道数) | 同时记录多少条独立的声音轨迹 | 1(单声道)、2(立体声) |
硬核追问:为什么 CD 音质的采样率偏偏是 44.1 kHz? 根据奈奎斯特-香农采样定理,要想无失真地从离散样本中重建出原始波形,采样率必须大于等于信号最高频率的 2 倍。 人类耳朵能听到的极限频率大约是 20 kHz。因此,采样率至少要是 40 kHz。当年为了同时兼容 PAL 和 NTSC 两种电视制式的录像带帧率整除,最终将 CD 的标准定在了 44.1 kHz。同理,早期电话为了节省带宽,只保留了人声核心频率(4 kHz 以内),所以电话的采样率通常只有 8 kHz。
位深(Bit Depth)的物理意义: 16-bit 意味着把声音的振幅从静音到震耳欲聋划分成了 2¹⁶ = 65536 个等级。等级越细腻(如 24-bit 的 1677 万个等级),记录的声音细节越丰富,底噪(量化噪声)也就越小。
2.2 PCM 数据体积与计算规则
PCM 数据是毫无压缩的纯净水,它的体积计算极其简单粗暴:
码率 (bps) = 采样率 × 位深 × 声道数 体积 (Bytes) = 码率 × 时长(秒) / 8
计算举例:
一首 3 分钟(180秒)的标准 CD 音质歌曲(44.1kHz / 16-bit / 双声道),其裸 PCM 体积为:
44100 × 16 × 2 × 180 / 8 = 31,752,000 Bytes ≈ 30.2 MB
仅仅 3 分钟就占用了 30 MB,这在流媒体时代是完全不可接受的,这也是为什么我们需要引入 AAC 等编码技术。
2.3 常见的物理存储交错模式
在内存中,双声道 PCM 的排列方式通常有两种:
- 交错模式(Interleaved):像拉链一样咬合,
L R L R L R...(绝大多数设备和底层 API 默认采用这种格式)。 - 平铺模式(Planar):各自独立存放,先存满左声道,再存右声道
LLLLL... RRRRR...(FFmpeg 内部处理时常用此格式,对应带p的后缀,如fltp)。
3. 给裸奔的数据穿上衣服:WAV 容器
3.1 为什么我们需要 WAV?
想象一下,你手里有一个纯 .pcm 文件,当你把它丢进播放器时,播放器是一脸懵逼的——它完全不知道这个文件是 44.1kHz 还是 48kHz,是单声道还是双声道。
PCM 就像是一堆纯粹的照片像素点,而 WAV 就像是给这堆像素点套上了一个相框,并在相框的背面写上了说明书。
严格来说,WAV 不是一种编码算法,而是一个基于 RIFF 标准的容器格式,它最常见的用途就是用来装 PCM 裸数据。
3.2 拆解 RIFF/WAVE 文件头
一个标准的 WAV 文件,其头部(Header)通常占用 44 个字节。极其重要的一点:WAV 容器头部的数值数据是严格按照小端模式(Little-Endian)存储的。
RIFF Header (12 bytes)
ChunkID: "RIFF" (4 bytes) 默认标志
ChunkSize: 文件总大小 - 8 (4 bytes)
Format: "WAVE" (4 bytes) 默认标志
fmt Chunk (24 bytes,记录音频格式元数据)
Subchunk1ID: "fmt " (4 bytes) 一般为"fmt "
Subchunk1Size: 16 (4 bytes) fmt块大小,不包含 ID 和 Size 字段本身
AudioFormat: 1 (2 bytes) 音频格式(1=PCM, 3=IEEE float, 6=A-law, 7=μ-law)
NumChannels: 1 / 2 (2 bytes) 声道数(1=mono, 2=stereo)
SampleRate: 44100 / 48000 (4 bytes) 采样率
ByteRate: ... (4 bytes) 每秒字节数 = SampleRate × NumChannels × (BitsPerSample/8)
BlockAlign: ... (2 bytes) 块对齐 = NumChannels × (BitsPerSample/8)
BitsPerSample: 16 / 24 / 32 (2 bytes) 位深度
------
(注:在 fmt chunk 与 data chunk 之间,可能还夹杂着 list chunk、fact chunk 等可选分块。它们均遵循 RIFF 通用的 Size+Type+Data 结构)
------
data Chunk (8 bytes + 实际数据)
Subchunk2ID: "data" (4 bytes) 默认标志
Subchunk2Size: PCM 数据大小 (4 bytes) 下面挂载的真实 PCM 数据的大小
Data: PCM 原始数据 (WAV 里的多声道 PCM 一般采用 interleaved 交错存储,如 L0 R0 L1 R1...)3.3 实战:在十六进制中辨认 WAV
如果我们用 010 Editor 或 HexFiend 打开一个 WAV 文件,你能非常清晰地看到 RIFF、WAVE、fmt 和 data 这几个标志性的 ASCII 锚点。
(图:清晰的 RIFF 分块结构,播放器正是通过读取这些块来正确初始化声卡)
4. 极致的听觉欺骗:AAC 编码与心理声学
4.1 为什么 AAC 能干掉 MP3?
AAC(Advanced Audio Coding) 诞生于 1997 年。它的设计初衷就是为了干掉 MP3。 AAC 的核心思想并不是“无脑压缩波形”,而是利用了极其精妙的 “心理声学模型(Psychoacoustic Model)” 进行了彻头彻尾的听觉欺骗:
- 频域变换(MDCT):把时域的声波变换到频域,暴露出声音的频率成分。
- 同时掩蔽(Simultaneous Masking):在同一个时刻,如果有一个震耳欲聋的鼓声,那么它旁边频率极近的一声微弱叹息,人耳是根本听不到的。AAC 编码器会果断把那声叹息的数据扔掉,不分配任何 bit。
- 时间掩蔽(Temporal Masking):在一声巨响发生前后的极短时间内(前向 5ms,后向 50-200ms),人耳依然处于“致盲”状态,这期间的细微声音同样会被丢弃。
凭借更精细的滤波器组和优化的编码策略,在同等听感下,128 kbps 的 AAC 能够媲美 192 kbps 的 MP3。
4.2 常见 Profile 与生产环境参数
AAC 并非一种单一算法,而是一组工具集的统称,主要分为以下几个 Profile:
| Profile | 原理机制 | 适用场景 |
|---|---|---|
| AAC-LC | Low Complexity(低复杂度)。标准的 AAC 核心。 | 最通用,兼容性无敌,广泛用于直播、点播。 |
| HE-AAC | LC + SBR(频段复制)。高频部分只记录特征,由解码器模拟生成。 | 低码率音乐流媒体(如 64kbps)。 |
| HE-AAC v2 | HE-AAC + PS(参数立体声)。彻底丢弃一个声道,只记录左右声道差异参数。 | 极低码率的极限压榨(如 32kbps 立体声)。 |
| AAC-LD/ELD | Low Delay。极度缩短算法带来的缓冲延迟。 | 实时通信、视频会议、连麦。 |
在流媒体直播工程中,最黄金的搭配方案是:AAC-LC, 44.1k/48k, 2ch, 码率96k~128k。
5. AAC 的运输载体:ADTS 帧头深度拆解
在了解 H.264 时,我们知道 NALU 依赖起始码(Start Code)来分割。对于 AAC 裸流(.aac)而言,它的“分割器”叫做 ADTS(Audio Data Transport Stream)。
5.1 ADTS 7 字节 Header 逐字段解析
每一帧独立的 AAC 压缩数据前面,都会固定拼上一个 7 字节(如果带 CRC 校验则是 9 字节)的 ADTS Header。
在十六进制查看器中,它最大的特征就是以 0xFFF (12 bit 的连续 1) 作为同步字(Syncword)。

这 7 个字节(56 bits)的内部结构非常紧凑。在网络流媒体标准中,ADTS 头部数据是严格按照大端模式(Big-Endian)进行位(bit)级别拼接和读取的:
-- 固定不变的属性(28 bits,通常每帧相同) --
syncword 12 bits 固定 0xFFF,用于帧同步。实际抓包中,开头 2 字节常见 FF F1 (MPEG-4, 无CRC) 或 FF F9 (MPEG-2, 无CRC)
ID 1 bit MPEG 标识,通常 0 表示 MPEG-4,1 表示 MPEG-2
layer 2 bits 固定 00
protection_absent 1 bit 0=有 CRC校验(9字节头), 1=无 CRC校验(7字节头)
profile 2 bits AAC Profile,0=Main, 1=LC, 2=SSR, 3=LTP
sampling_frequency_index 4 bits 采样率索引(见下表)
private_bit 1 bit 保留位
channel_configuration 3 bits 声道数(0=ADTS内部定义, 1=mono单声道, 2=stereo立体声)
original_copy 1 bit
home 1 bit
-- 每帧可变的属性(28 bits,逐帧变动) --
copyright bits 2 bits 版权信息
aac_frame_length 13 bits ADTS 头 + AAC 数据 的总字节长度
adts_buffer_fullness 11 bits 代表 VBR 或 CBR。大多数软件忽略此配置,0x7FF 代表 VBR 可变码率
number_of_raw_data_blocks 2 bits 通常为 0,表示当前 ADTS 包含 1 个原始 AAC 数据帧采样率索引(sampling_frequency_index)速查表: 在解析 ADTS 时,拿到这个 4 bit 的枚举值,去查表就能知道真实的采样率:
0 → 96000 Hz 4 → 44100 Hz 8 → 16000 Hz
1 → 88200 Hz 5 → 32000 Hz 9 → 12000 Hz
2 → 64000 Hz 6 → 24000 Hz 10 → 11025 Hz
3 → 48000 Hz 7 → 22050 Hz 11 → 8000 Hz
5.2 灵魂拷问:既然浪费带宽,为何还要带 ADTS 头?
问题:以 AAC-LC 48kHz 为例,一帧大约包含 1024 个样本,压缩后 Payload 大小在几百字节左右。每帧都额外塞 7 个字节的 ADTS 头,难道不是在浪费网络带宽吗?
解答:这 7 个字节的开销(不到 1%)换来的是极其珍贵的自同步能力。
在不稳定的网络流媒体(如 HLS 切片、TS 广播流)中,客户端可能随时从中间切入播放,或者遇到网络丢包。一旦丢包,播放器只需往后疯狂扫描寻找 0xFFF,就能立刻重新对齐帧边界,满血复活,不需要依赖任何全局头文件!
这就是为什么 .aac 裸流、MPEG-TS、FLV 经常使用 ADTS 的原因。
5.3 容器差异:MP4 中的 AudioSpecificConfig
如果你把 AAC 封装进 .mp4 文件里,那么 ADTS 头就光荣下岗了。
MP4 作为一个高级的结构化容器,它会在全局的 moov/trak/mdia/minf/stbl/stsd 盒子中,存入一个叫做 AudioSpecificConfig (ASC) 的微小数据结构(通常只有 2 个字节)。
AudioSpecificConfig (2 Bytes 示例结构):
┌───────────────┬──────────────┬────────────┐
│ ObjectType │ samplingFreq │ chanConfig │
│ 5 bit (2=LC) │ 4 bit (4=44k)│ 4 bit │
└───────────────┴──────────────┴────────────┘解码器在读取 MP4 时,只需在开头读取一次 ASC 初始化好解码器,后续读取的媒体帧就全是纯净的 AAC Payload 了,做到了真正的零开销。
6. 纵向对比总结:PCM、WAV、AAC、MP4 到底是什么关系?
很多初学者容易被这四个英文单词绕晕,我们最后做个总结表格:
| 文件 / 术语 | 本质定位 | 是否压缩? | 是否自带格式元数据? |
|---|---|---|---|
PCM (.pcm) | 原始波形。没有任何外衣的裸数据。 | 否,体积巨大 | 否,播放器无法直接解析,全是盲猜。 |
WAV (.wav) | 纯净水瓶。专门用来装 PCM 的容器。 | 否(绝大多数情况) | 是,带有 RIFF 头,双击就能精准播放。 |
| AAC | 浓缩药丸。高科技压缩后的核心音频流。 | 是,体积极小 | / |
ADTS (.aac) | 胶囊外壳。AAC流在裸奔时为了安全套上的头。 | / | 是,逐帧携带。丢包也能瞬间恢复。 |
MP4 (.m4a) | 大集装箱。能同时装视频和 AAC 的高级箱子。 | / | 是,全局存了一份 ASC,内部帧无需再带头。 |
7. 常用 FFmpeg 音频处理命令速查
在日常开发排查中,熟练掌握音频的抽离和转换是基本功:
# 1. 提取 AAC(保持原始编码,不重新压缩):
ffmpeg -i input.mp4 -vn -c:a copy output.aac
# 2. 从视频中提取音频并转为 WAV(解压缩为 PCM):
ffmpeg -i input.mp4 -vn -c:a pcm_s16le output.wav
# 3. 提取为无任何头部的裸 PCM 数据(S16LE):
ffmpeg -i input.mp4 -vn -c:a pcm_s16le -f s16le output.pcm
# 4. 将 WAV 压缩为带 ADTS 头的 AAC 裸流:
ffmpeg -i input.wav -c:a aac -b:a 128k -f adts output.aac
# 5. 查看 AAC 音频或 WAV 的详细容器格式信息:
ffprobe -show_streams input.aac音视频数据流基础
共 5 篇
- H264流
- 音频流基础:PCM、WAV 与 AAC 编码深度解析
- 视频底层密码:YUV 颜色空间、内存对齐与格式转换揭秘
- 音视频容器格式剖析:MP4、FLV 与 TS
- FFMpeg 命令记录