🎬 第十章 SWResample音频重采样理论及案例实战
📄 一句话概括

音频只有三个参数:采样率、声道数、样本格式。 三者相乘就是它一秒占多少字节——没有任何隐藏项。

📝 本节和前面几节的关系

第九章把画面那条链讲完了,这一章换到声音这头。 音频比视频简单得多:时间只有一条公式,参数只有三个。

一、三个参数

声音是一串数字,这三个参数决定这串数字怎么读。 参数 常见取值 管什么


采样率 44100/48000 每秒采多少个点 声道数 1 单/2 立体声 同时记几个方向 样本格式 s16/flt 每个点用几个字节

这三个数缺一个,那串数字就读不出来。这也是裸 PCM 要靠在文件名里写参数的原因。 采样率不是越高越好:44100 已经盖住人耳上限,再高只是多占空间。 专业录音用 96000 是为了后期有余量,不是为了听得更清。

二、一秒占多少字节

采样率乘声道数乘每样本字节,就这一条。 采样率 声道 格式 每秒字节


44100 2 s16 176400 48000 2 s16 192000 44100 2 flt 352800

44.1k 立体声 16 位,一秒 176400 字节,约 172 KB。 一分钟就是 10 MB,一首五分钟的歌就是 50 MB。 这就是音频非压不可的理由。 换成浮点还要翻一倍,所以「用浮点处理、用整数存盘」成了标准做法。

三、素材里那条音轨的真账

五个数就能把一条音轨说清楚。 项 值


编码 aac 采样率 44100 Hz 声道布局 stereo 解码后格式 fltp 帧数×每帧样本 88 × 1024 总样本 90112 时长 2.0434 秒

90112 ÷ 44100 = 2.0434 秒,与视频轨的 2.02 秒差一点, 因为两条轨本来就不是严格等长——音频编码器会补齐到整帧。 这一点点在剪辑里是要处理的:音画同步靠的不是「长度相等」,而是 pts 对齐。 长度差几十毫秒很正常,时间戳错位才是问题。

四、采样率决定能录多高

上限永远是采样率的一半。 采样率 能表达的最高频率


8000 4000 Hz 22050 11025 Hz 44100 22050 Hz 48000 24000 Hz

这叫奈奎斯特定理:要还原一个频率,一个周期至少得采两个点。 所以 44100 这个数字不是随便定的:人耳上限约 20000 Hz, 取 22050 的一半留了点余量,刚好够。 反过来,采样率不够会出事:高于一半的频率不会消失,它会「折」成低频混进来, 听感是金属味的杂音。这叫混叠,10.1.4 还会碰到它。

五、三个参数在代码里叫什么

PyAV 里三个属性一一对应。 参数 帧上的属性 例


采样率 sample_rate 44100 声道 layout stereo 格式 format.name fltp 这一帧多少样本 samples 1024

注意「样本数」是每声道的个数,不是总个数。一帧 stereo、1024 样本,实际有 2048 个数值。 这个约定很容易混:写数组的时候 planar 是 (2, 1024), packed 是 (1, 2048)——同一个帧,两种形状。 记住「samples 指的是每声道」,下面所有算式才不会差一倍。

六、动手 Demo:音频的三个参数,决定它一秒有多大

先算一秒钟占多少字节,再把素材里那条音轨的五个数全查出来。

import av

# 一秒钟多少字节 = 采样率 x 声道 x 每样本字节
for rate, ch, byt in ((44100, 2, 2), (48000, 2, 2), (44100, 2, 4)):
    print(rate, ch, byt, rate * ch * byt)

c = av.open("tiny.mp4")
st = c.streams.audio[0]
cc = st.codec_context
print(cc.name, cc.sample_rate, cc.layout.name, cc.format.name)

total = nf = 0
for pk in c.demux(st):
    if pk.size == 0:
        break
    for fr in cc.decode(pk):
        total += fr.samples
        nf += 1
print(nf, total, total / float(cc.sample_rate))
c.close()

实跑输出:

--------------------------------------------------------------------
音频的三个参数,决定它一秒有多大
--------------------------------------------------------------------

**① 三个参数**

  参数         常见取值                 管什么
  ----------------------------------------------------------
  采样率       44100/48000             每秒采多少个点
  声道数       1(单)/2(立体声)     同时录几个方向
  样本格式     s16/flt                 每个点用几个字节

**② 一秒钟占多少字节:三者相乘**

  采样率     声道     格式     每秒字节
  -----------------------------------------
  44100      2        s16      176400
  48000      2        s16      192000
  44100      2        flt      352800

**44.1k 立体声 16 位,一秒就是 176400 字节**,约 172 KB。
**这是「未经压缩」的账**——一分钟就是 10 MB,一首歌就上百 MB。所以音频也非压不可。

**③ 素材里那条音轨的真账**

  项           值
  --------------------------
  编码         aac
  采样率       44100 Hz
  声道布局     stereo
  样本格式     fltp
  帧数         88
  总样本       90112
  时长         2.0434 秒

**88 帧、每帧 1024 个样本,合计 90112 个样本,除以 44100 得到 2.0434 秒。**
**音频的时长永远是这样算出来的:样本数除以采样率。**

**④ 采样率决定能录多高**

  采样率     能表达的最高频率
  -------------------------------
  8000       4000 Hz
  22050      11025 Hz
  44100      22050 Hz
  48000      24000 Hz

**上限永远是采样率的一半**(奈奎斯特)。
**44.1k 能到 22050 Hz,刚好盖住人耳的上限**——这就是这个数字的来历,不是什么巧合。

90112 ÷ 44100 = 2.0434 秒,比视频轨的 2.02 秒长一点,正常。 采样率的上限永远是它的一半,44100 刚好盖住人耳。

30 秒实验

  1. 把 44100 换成 8000,算一遍 4 秒的音频有多大。
  2. 打印 st.codec_context.layout.nb_channels,看它是不是 2。
  3. 查一下 av.AudioLayout("5.1").nb_channels 是几。

常见误区

  1. 以为采样率越高越好。 超过人耳上限的部分只是占空间。
  2. 把「样本数」当成总个数。 它是每声道的个数,立体声要乘二。
  3. 以为音轨长度必须等于视频长度。 差几十毫秒正常,看的是 pts。
自测三问(点开对答案) 1. 音频的三个参数是什么? —— 采样率、声道数、样本格式。 2. 一秒钟的字节数怎么算? —— 采样率 × 声道数 × 每样本字节数。 3. 44100 这个采样率为什么是它? —— 它的一半 22050 Hz 刚好盖住人耳上限,留了点余量。

相关笔记