音频只有三个参数:采样率、声道数、样本格式。 三者相乘就是它一秒占多少字节——没有任何隐藏项。
第九章把画面那条链讲完了,这一章换到声音这头。 音频比视频简单得多:时间只有一条公式,参数只有三个。
一、三个参数
声音是一串数字,这三个参数决定这串数字怎么读。 参数 常见取值 管什么
采样率 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 秒实验
- 把 44100 换成 8000,算一遍 4 秒的音频有多大。
- 打印
st.codec_context.layout.nb_channels,看它是不是 2。 - 查一下
av.AudioLayout("5.1").nb_channels是几。
常见误区
- 以为采样率越高越好。 超过人耳上限的部分只是占空间。
- 把「样本数」当成总个数。 它是每声道的个数,立体声要乘二。
- 以为音轨长度必须等于视频长度。 差几十毫秒正常,看的是 pts。
自测三问(点开对答案)
1. 音频的三个参数是什么? —— 采样率、声道数、样本格式。 2. 一秒钟的字节数怎么算? —— 采样率 × 声道数 × 每样本字节数。 3. 44100 这个采样率为什么是它? —— 它的一半 22050 Hz 刚好盖住人耳上限,留了点余量。- ☐ (本节完,下一节 10.1.2 PCM简介)