🎬 第七章 流媒体开源库简介
📄 一句话概括

音频一包 20 毫秒,是「头部开销」与「延迟」的折中结果。 编码之后小得惊人:Opus 只有 PCM 的四十八分之一。

📝 本节和前面几节的关系

7.7.2 讲视频,这一节讲音频。 两者最大的不同是:音频包小、频率高、对丢包更敏感。

一、一包音频有多少字节

公式很简单:字节数 = 采样率 × 时长 × 声道数 × 每样本字节数。

实测三个例子: PCM 48k 单声道 16 位 20 毫秒是 1920 字节; PCM 48k 双声道是 3840 字节; PCM 44.1k 双声道是 3528 字节(除不尽,四舍五入)。

48k 双声道 20 毫秒是 3840 字节,按每秒 50 包算, PCM 的码率就是 1536 kbps——比很多视频还高。 所以音频不压缩是绝对不行的。

二、编码之后小多少

实测对比: PCM 1536 kbps 每 20 毫秒 3840 字节、 Opus 32 kbps 只有 80 字节、 AAC-LC 128 kbps 是 320 字节。

Opus 是 PCM 的四十八分之一。 这个压缩比听着夸张,但语音信号冗余确实极大—— 相邻采样点高度相关,人耳也听不出细微差别。

WebRTC 默认用 Opus,原因有三个: ① 低码率下音质好;② 支持从 6 到 510 kbps 动态调整; ③ 内置丢包隐藏(PLC),丢一包不会明显爆音。

三、为什么偏偏是 20 毫秒

太短了包多、头开销大;太长了延迟高、丢包影响大。 20 毫秒是「头部开销可接受」与「延迟可接受」的折中,成了行业惯例。

算一下头开销就明白为什么不能更短: RTP 头 12 字节、UDP 头 8 字节、IP 头 20 字节,一共 40 字节。 如果每包只有 80 字节载荷,头就占三分之一。

再算一下为什么不能更长: 40 毫秒一包意味着丢一包就丢 40 毫秒的声音, 而且延迟下限也变成 40 毫秒。 所以 20 毫秒是两头都不难受的那个点。

四、动手 Demo:声频分析——20 毫秒一个包是行业惯例

先按公式算三种 PCM 配置的每包字节,再对比编码后的体积。 最后算头开销占比,看为什么不能把包切得更小。

rows = [("PCM 48k 单声道 16 位", 48000, 0.02, 1, 2),
        ("PCM 48k 双声道 16 位", 48000, 0.02, 2, 2),
        ("PCM 44.1k 双声道 16 位", 44100, 0.02, 2, 2)]
for name, sr, sec, ch, bps in rows:
    print("%-26s %d 字节" % (name, int(sr * sec * ch * bps)))

print()
for name, kbps in (("PCM", 1536), ("Opus", 32), ("AAC-LC", 128)):
    print("%-8s %4d kbps -> 每 20 毫秒 %d 字节"
          % (name, kbps, int(kbps * 1000 * 0.02 / 8)))

print()
# 头开销:RTP 12 + UDP 8 + IP 20 = 40 字节
for payload in (80, 160, 320, 3840):
    print("载荷 %4d 字节,头 40 字节,占 %.1f%%"
          % (payload, 40 * 100.0 / (payload + 40)))

实跑输出:

--------------------------------------------------------------------
声频分析——20 毫秒一个包是行业惯例
--------------------------------------------------------------------
**① 一包音频有多少字节**

  **公式:字节数 = 采样率 × 时长 × 声道数 × 每样本字节数。**

  格式                       每 20 毫秒字节
  ---------------------------------------------
  PCM 48k 单声道 16 位       1920
  PCM 48k 双声道 16 位       3840
  PCM 44.1k 双声道 16 位     3528

  **48k 双声道 20 毫秒是 3840 字节,也就是 4 KB 不到。**
  **按每秒 50 包算,PCM 的码率是 1536 kbps——比视频还高。**

**② 编码之后小多少**

  编码       典型码率      每 20 毫秒字节
  -------------------------------------------
  PCM        1536 kbps     3840
  Opus       32 kbps       80
  AAC-LC     128 kbps      320

  **Opus 32 kbps 每 20 毫秒只有 80 字节,是 PCM 的四十八分之一。**

  **为什么偏偏是 20 毫秒?**
  **太短了包多、头开销大;太长了延迟高、丢包影响大。**
  **20 毫秒是「头部开销可接受」与「延迟可接受」的折中,成了行业惯例。**

44.1k 双声道算出 3528 而不是 3528.0,因为一帧不是整数个样本。 Opus 每包只有 80 字节,头 40 字节就要占三分之一。 PCM 每包 3840 字节时头只占 1%,但这时的码率是 1536 kbps。

30 秒实验

  1. 把包长从 20 毫秒改成 10 毫秒,看 Opus 的头开销——载荷 40 字节、头 40 字节,一半都是头。
  2. 把包长改成 40 毫秒,看头开销与延迟——头降到 11%,但延迟下限变成 40 毫秒。
  3. 把 Opus 码率改成 6 kbps,看每包字节——只有 15 字节,头占七成,所以超低码率下必须加大包长。

常见误区

  1. 「音频包越长越省带宽」——省的是头,但延迟与丢包影响都变大。
  2. 「WebRTC 默认用 AAC」——默认 Opus,低码率下更强。
  3. 「PCM 也适合直播」——1536 kbps 根本发不起。
自测三问(点开对答案) 1. 一包 20 毫秒的音频有多少字节? —— **采样率 × 时长 × 声道数 × 每样本字节数**,48k 双声道是 3840。 2. 为什么选 20 毫秒? —— **头开销与延迟的折中**,更短头占比高,更长延迟高。 3. WebRTC 为什么用 Opus? —— **低码率音质好、码率可动态调、内置丢包隐藏。**

相关笔记