AAC 在音视频工程中的位置:从 PCM 到压缩音频的主线理解
前言:为什么很多人知道 AAC 很常见,但一问“它到底在系统里干什么”,脑子里还是会有点空
只要开始接触音视频,AAC 这个名字几乎绕不开。
你会在很多地方看到它:
- MP4 文件里
- FLV / RTMP 链路里
- TS 流里
- 手机录制视频里
- 推流系统里
- FFmpeg 命令里
所以大家通常都会知道一件事:
AAC 很常见。
但“很常见”和“真的理解它在系统里的位置”其实不是一回事。
因为只要你继续往下问几步,很多人就开始有点模糊:
- AAC 和 PCM 到底是什么关系
- 为什么录音设备拿到的通常不是 AAC,而是 PCM
- 为什么播放器最终喂声卡的又不是 AAC,而还是 PCM
- AAC 是不是就等于音频文件格式
- ADTS、AudioSpecificConfig 又是怎么回事
- FFmpeg 里编码 AAC 到底发生在哪一层
你会发现,这些问题表面上在问不同细节,但它们真正都指向同一个核心:
AAC 在音频链路里,到底站在哪一层,它前面接什么,后面又接什么。
所以这篇文章的目标,不是把 AAC 讲成一篇纯标准教材,而是把它放回音视频工程主线里讲清楚。
重点讲清:
- PCM 和 AAC 的关系
- 为什么 AAC 本质上是“压缩音频表示”,而不是最终播放形态
- AAC 在采集、编码、封装、传输、播放链路中的位置
- AAC 常见的外层组织方式是什么
- FFmpeg 里从 PCM 到 AAC 的最小代码骨架长什么样
而且这篇依然按你要求,继续把这些都带上:
- 核心关键代码示例
- 结构图
- 流程图
- 时序图
我希望你读完之后,对 AAC 的感觉不再只是“一个常见音频编码格式”,而是能明确知道:
它到底在替系统解决什么问题,为什么前后都离不开 PCM。
一、先给一句最重要的话:AAC 不是原始音频,也不是播放器最终直接工作的基础形态,它是 PCM 经过有损压缩之后得到的音频码流表示
如果让我先给一句最重要的话,我会这样说:
AAC 的本质,是把 PCM 这类原始数字音频数据压缩之后得到的一种有损音频码流表示。
这句话非常重要。
因为它一下就把 AAC 放回了正确位置:
- 它不是采集设备直接产生的原始数据
- 它也不是音频设备最终最喜欢直接吃的底层形态
- 它站在中间,负责把原始数字音频压缩成更省空间、更适合存储和传输的表示方式
也就是说,它更像音频世界里和 H.264/H.265 对视频所处位置相似的一层:
压缩编码层。
二、先看总图:PCM、AAC、容器、播放到底是什么关系
先上总图。
flowchart LR
A[Mic/文件输入] --> B[PCM样本]
B --> C[AAC编码器]
C --> D[AAC码流]
D --> E[MP4/FLV/TS等容器]
E --> F[文件/网络传输]
F --> G[Demux]
G --> H[AAC码流]
H --> I[AAC解码器]
I --> J[PCM样本]
J --> K[播放设备/算法处理]
这张图最关键的意义是:
- PCM 是原始数字音频工作形态
- AAC 是压缩音频码流层
- 容器 是外层承载组织
- 播放设备 最终往往仍然在 PCM 层工作
如果你把这张图立住,后面很多困惑一下就会顺很多。
三、为什么音频系统前后都绕不开 PCM
这是理解 AAC 的第一步。
3.1 采集侧通常先拿到 PCM
现实里的声音经过麦克风、ADC 之后,数字系统最自然得到的是:
- 采样率明确
- 位宽明确
- 声道数明确
- 一串按时间排列的数字样本
也就是 PCM。
所以录音设备、音频采集 API、算法处理模块,天然更容易直接面对 PCM。
3.2 编码器吃进去的很多时候也是 PCM
AAC 编码器不是直接对“空气里的声音”工作,而是对数字音频样本工作。
也就是说,它的输入往往就是:
PCM 样本块。
3.3 解码器吐出来的通常也还是 PCM
AAC 解码器做的事,本质上是:
- 输入压缩 AAC 数据
- 输出可播放、可处理的原始数字音频样本
而这一步出来的,通常依然是 PCM。
所以你可以很清楚地看到:
- PCM 在前
- AAC 在中间
- PCM 在后
这就是它在系统里的真实位置。
四、AAC 到底在替系统解决什么问题
4.1 核心问题就是:PCM 太大了
如果你还记得上一篇 PCM 的数据量计算,就会知道原始音频其实并不小。
比如:
- 48kHz
- 16bit
- 双声道
每秒大约就是:
1 | |
也就是大约 1.536 Mbps。
这对原始数据处理当然没问题,但如果你要:
- 存储更长时长音频
- 和视频一起打包
- 做网络传输
- 在带宽受限场景里推送
那 PCM 往往就显得太“直给”了。
4.2 AAC 做的就是压缩表达
AAC 的核心价值就在于:
尽量在可接受音质损失下,把原始 PCM 的数据量压下来。
所以它回答的是:
- 怎样更省比特地表示这段音频
- 怎样让存储和传输更划算
- 怎样在有限带宽里还保持不错听感
这也是为什么 AAC 在音视频工程里地位非常稳。
五、AAC 为什么经常跟 MP4、FLV、TS 一起出现,但它们不是同一层
这点和视频那边“容器 vs 码流”的问题是完全平行的。
5.1 AAC 是压缩音频码流层
它关心的是:
- 音频内容怎么被压缩表示
- 解码器怎么从这些比特里恢复音频样本
5.2 MP4 / FLV / TS 是承载层
它们关心的是:
- 音频轨和视频轨怎么组织
- 时间戳怎么放
- packet 怎么装
- 文件或流怎么形成整体结构
所以你看到:
- AAC in MP4
- AAC in FLV
- AAC in TS
一点都不矛盾。
因为这本来就是:
同一种音频码流,被装进不同容器。
六、AAC 常见外层组织方式为什么又会让人继续混
这里只抓工程理解,不往标准细节深潜太多。
6.1 ADTS
ADTS 常常出现在更接近流式、逐帧组织的 AAC 数据表达里。
你可以先粗略理解成:
- 每帧 AAC 数据前面带一个头
- 方便接收端逐帧识别和解析
6.2 AudioSpecificConfig
在 MP4 这类容器里,AAC 参数信息常常不会用 ADTS 那种每帧都带头的方式,而更常通过额外配置描述告诉解码器:
- 采样率是什么
- 声道是什么
- AAC profile 是什么
这就让很多人开始糊涂:
- 明明都是 AAC,为什么长得不一样
答案其实很简单:
里面的压缩音频内容类型还是 AAC,但它外层的组织方式可能不同。
这和你前面文章里讲过的 H.264 Annex B / AVCC 非常像。
七、一张图看懂 AAC 在系统里的分层位置
flowchart TD
A[PCM原始样本] --> B[AAC编码]
B --> C[AAC码流]
C --> D[ADTS或容器内组织]
D --> E[MP4/FLV/TS/网络传输]
E --> F[取出AAC数据]
F --> G[AAC解码]
G --> H[PCM样本]
这张图非常值钱,因为它提醒你:
- AAC 自己是一层
- 它外面还可能再套不同组织方式
- 它前后都和 PCM 紧紧相连
八、第一段核心代码:PCM 数据量和 AAC 目标码率的直觉比较
先给一个非常实用的代码例子。
1 | |
比如:
1 | |
你会看到大概:
- 原始 PCM 大约 1.536 Mbps
- 如果压成 128 kbps AAC
- 压缩比已经很可观
这段代码的意义
它会让你一下看见 AAC 的系统价值不是抽象的,而是非常现实的:
拿更小的码率,换可接受的主观音质。
九、第二段核心代码:FFmpeg 里从 PCM 到 AAC 的最小编码骨架
这一段很关键,因为它直接把“PCM 是输入,AAC 是输出”落成代码。
1 | |
这段代码最该看什么
你要特别注意:
输入侧
编码器吃的是:
- sample_rate
- channel_layout
- sample_fmt
- frame->data 里的 PCM 样本
输出侧
编码器吐出来的是:
- 压缩后的
AVPacket
这就非常清楚地说明了 AAC 编码层的职责:
PCM in,compressed audio packet out。
十、第三段核心代码:为什么 AAC 编码前常常还要做重采样 / 格式转换
真实工程里,采集到的 PCM 不一定正好就是编码器想吃的格式。
比如:
- 采上来是
s16 - 编码器想吃
fltp - 采样率不一致
- 声道布局不一致
这时候中间往往要有一层音频格式桥接。
1 | |
这里说明什么
它说明 AAC 编码在工程里通常不是孤立一步,而往往是:
PCM采集格式 -> 转成编码器想要的 PCM 格式 -> 再送编码器。
这和视频那边像素格式转换再送编码器,本质上是一样的工程逻辑。
十一、第四段核心代码:AAC 解码后为什么最终又回到 PCM
这一段也很关键,因为它能帮你真正把链路闭环。
1 | |
这段代码最值钱的地方
它再一次提醒你:
AAC 不是播放设备最后直接工作的原始层。
解码器最终给出来的,依然是 PCM 风格的样本数据。
也就是说,AAC 的作用不是取代 PCM,而是:
在存储和传输阶段临时把 PCM 压紧。
十二、一张流程图看懂“PCM -> AAC -> PCM”为什么是正常闭环
flowchart TD
A[原始PCM样本] --> B[重采样/格式转换]
B --> C[AAC编码器]
C --> D[AAC压缩Packet]
D --> E[封装/传输]
E --> F[解封装]
F --> G[AAC解码器]
G --> H[PCM样本]
H --> I[播放/算法处理]
这张图特别值钱,因为它能帮你纠正一个很常见的误解:
很多人会潜意识觉得“有了 AAC 之后就一路 AAC 到底”。
其实不是。
在很多系统里更真实的主线是:
PCM 负责原始工作层,AAC 负责压缩传输层,最后又回到 PCM。
十三、一张时序图看懂视频文件里音频轨是怎么被处理的
sequenceDiagram
participant App as Player/App
participant Demux as Demuxer
participant ADec as AAC Decoder
participant AudioDev as Audio Device
App->>Demux: open MP4/FLV/TS
loop read packets
Demux->>ADec: AAC packet
ADec->>AudioDev: PCM samples
end
这张图很适合理解:
播放器里音频轨不是“直接拿 AAC 去播”,而通常是:
- 先 demux 拿出 AAC packet
- 再 decode 成 PCM
- 再交给音频设备
十四、AAC 在工程里最常出现在哪些地方
这一节我给你直接拉回工程视角。
14.1 文件封装里
比如:
- MP4 里的音频轨常见就是 AAC
14.2 推流系统里
比如:
- RTMP 推流时常见音频侧就是 AAC
14.3 采集后压缩存储
比如:
- 摄像录制视频时,视频可能是 H.264,音频可能就是 AAC
也就是说,AAC 在很多系统里扮演的是:
音频侧默认的主力压缩格式之一。
十五、工程里最容易混掉的 4 个问题
问题 1:AAC 是不是文件格式
不是。
更准确说,它是音频编码格式 / 压缩音频码流表示。
问题 2:AAC 是不是采集设备直接吐出来的原始音频
通常不是。
采集侧更常直接拿到的是 PCM。
问题 3:播放器是不是直接把 AAC 喂给音响
通常不是。
播放器通常先把 AAC 解码成 PCM,再交给音频设备。
问题 4:AAC 和 MP4 是不是一个层级
不是。
- AAC 是码流层
- MP4 是容器层
这和你前面那篇“容器 vs 码流”是一模一样的分层逻辑。
十六、最后给一句更像工程师的话:别把 AAC 当成“音频最后长什么样”,它更像“音频为了存储和传输而临时压缩成的样子”
写到这里,最想落下的一句话其实是:
AAC 在工程里的真正位置,不是音频数据的原始形态,也不是最终播放设备最自然的形态,而是为了存储和传输效率而出现的一层压缩表示。
这句话特别值钱。
因为很多人学音频时,最大的问题不是不知道 AAC,而是没把它放回链路里。
一旦你把它放回这条主线:
- PCM 采集
- PCM 处理
- AAC 压缩
- 封装 / 传输
- AAC 解压
- PCM 播放
整个理解就稳了。
这样后面再去看:
- 音频码率
- 音视频封装
- 推流音频链路
- 音频同步
- WebRTC 里的 Opus vs AAC
就都会清楚很多。
十七、总结
最后把这篇收成几句话。
1. AAC 的本质是 PCM 经过有损压缩之后得到的音频码流表示
它属于压缩编码层,不是原始采样层。
2. PCM 在 AAC 前后都存在
- 编码前:AAC 吃 PCM
- 解码后:AAC 吐 PCM
3. AAC 常和 MP4、FLV、TS 一起出现,但它们不是同一层
- AAC:音频码流层
- MP4/FLV/TS:容器层
4. 真正该记住的主线是
PCM -> AAC编码 -> AAC码流 -> 封装/传输 -> AAC解码 -> PCM
5. 一旦这条主线稳了,音频系统在你的整个专栏里就开始真正立起来了
如果你愿意,我下一篇建议直接接:
《GStreamer 的 pipeline 思维是什么:它和 FFmpeg 的差别到底在哪》
因为你现在 FFmpeg 这条线已经越来越厚了,这时候把 GStreamer 接进来,会让整个媒体框架认知一下子完整很多。