音视频基础系列(一):下一篇是啊鸡入坑音视频之《流媒体封装篇》。
“这个 SDK 支持 MP4 解码吗?”
这句话在日常沟通里完全听得懂,但如果拿来设计接口或定位故障,问题就来了:MP4 是容器,不是编解码器;打开一个 MP4,通常需要先解封装,再分别解码其中的视频和音频。所谓“MP4 解码”,实际可能同时涉及 MP4 Demux、H.264 / H.265 Decode 和 AAC Decode。
音频开发里,许多混乱都来自把不同层次统称为“格式”或“编解码”。只要先拆开三类对象,整条链路就会清楚很多:
- Raw Data:尚未压缩的媒体数据,音频常见 PCM,视频常见 YUV 或 RGB;
- Codec:决定媒体数据如何编码和解码,例如 AAC、Opus、H.264、H.265;
- Container:决定不同码流、时间戳和元数据如何组织,例如 MP4、MKV、Ogg、WAV。
一句话概括:Codec 负责内容如何压缩,Container 负责内容如何装在一起。

1. 声音如何变成数字音频
现实中的声音是连续变化的模拟信号。麦克风将声波转换为电信号,再通过 ADC(Analog-to-Digital Converter,模数转换器)进行采样,得到数字音频。
现实声音
↓
麦克风
↓
模拟电信号
↓ ADC
PCM Samples
PCM(Pulse Code Modulation,脉冲编码调制)是最常见的原始数字音频表示。它本身并不只由一个名称决定,至少还要说明三个参数:
- Sample Rate(采样率):每秒采多少次,例如 8 kHz、16 kHz、44.1 kHz、48 kHz;
- Sample Format / Bit Depth(采样格式 / 位深):每个采样怎样表示,例如 S16、S16LE、S32、Float;
- Channel / Channel Layout(声道 / 声道布局):Mono、Stereo、5.1、7.1 等。
比如 48 kHz / Stereo / S16LE 表示每秒每个声道采样 48,000 次,每次使用 16 位有符号小端整数,并包含左右两个声道。
PCM 的数据量可以直接计算:
码率 = 采样率 × 位深 × 声道数
以 48 kHz / 16 bit / Stereo 为例:
48,000 × 16 × 2 = 1,536,000 bit/s
也就是 1536 kbps,约 192 KB/s、11.5 MB/min。这个体积说明了为什么实时传输和长期存储通常不能直接使用原始 PCM,而需要 Codec 压缩。

2. Encode 与 Decode 做了什么
编码(Encode)把 Raw Data 转成编码码流,解码(Decode)再把编码码流恢复为可播放或处理的 Raw Data:
PCM
↓ Encode
AAC / Opus / MP3
↓ Decode
PCM
Codec 是 Coder / Decoder 的合称,通常包含编码和解码所遵循的规则。常见音频 Codec 包括:
| Codec | 类型 | 常见场景 |
|---|---|---|
| AAC | 有损 | 视频、录像、流媒体 |
| Opus | 有损 | WebRTC、实时语音、视频会议、对讲 |
| G.711 | 有损 | 电话、SIP、IPC、传统对讲设备 |
| MP3 | 有损 | 音乐分发与高兼容性播放 |
| FLAC / ALAC | 无损 | 音乐存档、编辑与高质量归档 |
无损编码要求解码后的 PCM 与原始 PCM 一致;有损编码则会借助心理声学模型,舍弃人耳不敏感的信息,以更低码率换取可接受的听感。
同样是 64 kbps,不同 Codec 的听感也可能完全不同。因此,码率只能描述每秒使用多少 bit,不能脱离 Codec、内容类型和编码参数直接比较质量。
3. Mux 与 Demux 为什么不是编解码
编码得到的只是码流。实际文件还需要保存轨道、时间戳、字幕和元数据,这些内容由 Container 组织。
例如,一个 MP4 可以包含:
MP4
├── Video Track: H.265
├── Audio Track: AAC
├── Subtitle Track
└── Metadata
把这些内容写入容器叫 Mux(Multiplexing,封装或复用);从容器拆出各条码流叫 Demux(Demultiplexing,解封装或解复用)。
H.265 Video + AAC Audio
↓ Mux
MP4
↓ Demux
H.265 Video + AAC Audio
因此,严格定义下有两组独立动作:
Encode / Decode 处理 Raw Data 与 Codec Bitstream 的转换
Mux / Demux 处理 Codec Bitstream 与 Container 的组织
常见文件扩展名也不能单独证明内部 Codec:
| 扩展名 | Container | 常见 Codec |
|---|---|---|
.mp4 | MP4 | H.264 / H.265 + AAC |
.m4a | MP4 | AAC / ALAC |
.mkv | Matroska | H.264 / H.265 / AV1 + AAC / Opus |
.webm | WebM | VP9 / AV1 + Opus |
.ogg | Ogg | Vorbis / Opus |
.wav | RIFF/WAVE | PCM 最常见,但并非只能装 PCM |
M4A 不等于 AAC,Ogg 不等于 Opus,WAV 也不严格等于 PCM。它们之所以经常被画上等号,只是因为某些组合非常常见。
没有放入 Container 的单一编码流通常称为 Elementary Stream(ES,基本流或裸流),例如裸 AAC、裸 H.264。播放器从容器中 Demux 出来的编码数据块通常称为 Packet;Decoder 消费 Packet 后输出 Frame。音频 Frame 通常是一段连续 Samples,而不是一张“画面”。
4. 一条完整的播放链路
播放媒体文件时,数据会经过下面几层:
File / Network
↓
Demuxer
↓
Encoded Audio Packet
↓
Decoder
↓
PCM
↓
Resample / Convert
↓
Audio Buffer
↓
Audio Renderer
↓
OS Audio API
↓
Speaker

Decoder 输出的 PCM 不一定符合播放设备要求。例如,来源可能是 16 kHz / Mono / S16,设备却要求 48 kHz / Stereo / Float。这时还需要做:
- Sample Rate Conversion;
- Sample Format Conversion;
- Channel Layout Conversion。
FFmpeg 中,这类工作通常由 libswresample 完成。到了系统层,iOS / macOS 常见 Core Audio、AVAudioEngine,Android 常见 AudioTrack、AAudio,Windows 常见 WASAPI。
实时语音链路还可能在编码前加入:
- AEC(Acoustic Echo Cancellation):减少扬声器声音被麦克风再次录入形成的回声;
- NS(Noise Suppression):抑制风扇声、环境声等背景噪声;
- AGC(Automatic Gain Control):自动调整输入增益,让音量保持在更可用的范围。
一个双向对讲上行链路可能是:
Microphone → PCM → AEC / NS / AGC
→ Opus / G.711 Encode → Network
→ Decode → PCM → Speaker
这里网络传输层还可能涉及 RTP、RTSP 或私有协议。它们不属于 Codec,却同样决定数据怎样分包、传输和恢复。
5. Remux 与 Transcode 的区别
如果只改变 Container,而不改变内部 Codec,这个过程叫 Remux(重新封装):
MKV (H.264 + AAC)
↓ Demux
H.264 + AAC
↓ Mux
MP4 (H.264 + AAC)
Remux 不需要重新编码,通常速度快、CPU 消耗低,也不会引入有损重编码造成的质量下降。但目标 Container 必须能够承载原来的 Codec 和相关参数。
Transcode(转码)则要从一种 Codec 转换为另一种 Codec:
AAC
↓ Decode
PCM
↓ Encode
Opus
或者:
H.264
↓ Decode
YUV
↓ Encode
H.265
转码需要 Decode 和 Encode,成本更高;如果输入和输出都是有损 Codec,还可能进一步损失质量。
所以,当需求只是“把 MKV 变成 MP4”时,第一步不是立即转码,而是先确认现有码流能否直接 Remux。能不重新编码,就不要重新编码。

6. Frame、Packet 与时间戳怎样配合
音频和视频并不是一帧对一帧播放。假设视频是 30 fps,每帧约 33.3 ms;AAC 在 48 kHz 下常见每帧 1024 samples,每帧约 21.3 ms。两者天然不等长,只能依靠同一时间轴同步。
这里最重要的两个时间戳是:
- PTS(Presentation Timestamp):这一帧应该何时播放或显示;
- DTS(Decoding Timestamp):这一帧应该何时送入 Decoder。
视频存在 B Frame 时,解码顺序和显示顺序可能不同,因此 PTS 与 DTS 可能不同。音频通常简单一些,但仍然需要 PTS、Timeline 和 Clock 与视频同步。
这也解释了为什么 Container 不只是“装东西的文件壳”:它还负责保存轨道、时序和同步所需的信息。只有 Codec 而没有正确的时间戳,播放器依旧可能出现音画不同步、跳帧或缓冲异常。
7. 工程沟通中怎样避免歧义
日常交流中,“编解码模块”泛指完整媒体处理能力很常见,没有必要逐句纠正。但进入技术方案、接口命名、性能分析和故障定位后,应明确使用具体阶段:
Demux → Decode → Process → Encode → Mux
例如,“文件打不开”至少还要继续问:
- Container 是否受支持?
- Demux 是否成功识别轨道和时间戳?
- 内部 Codec 是否受支持?
- Decoder 是否初始化成功?
- Bitstream 是否损坏或缺少必要参数?
- 解码后的格式转换和 Renderer 是否正常?
同样,“MP4 解码失败”也可能实际发生在 Demux 阶段;“编码成 MP4”通常包含视频编码、音频编码和 MP4 Mux。把问题定位到正确层次,才能找到正确模块和指标。
8. 用一条链路记住所有概念
最后,把核心关系压缩成一条往返链路:
Raw Media
PCM / YUV
↓ Encode
Codec Bitstream
AAC / Opus / H.264 / H.265
↓ Mux
Container
MP4 / MKV / Ogg / WAV
↓ Demux
Codec Bitstream
↓ Decode
Raw Media
PCM / YUV
只需要记住三个边界:
- PCM / YUV 是原始数据;
- AAC、Opus、H.264、H.265 是 Codec;
- MP4、MKV、Ogg、WAV 是 Container。
Encode / Decode 解决“如何压缩与恢复”,Mux / Demux 解决“如何组织与拆分”。口头上可以把它们统称为媒体处理,落到设计和排错时,则应该把每一层写清楚。
Discussion
留言与讨论
想法、补充和不同意见都欢迎。