anullsrc 凭空造静音,r 管采样率、cl 管声道、-t 管时长。 它默认是 u8 格式,静音的数值是 128,不是 0。
这一节开始讲「凭空造素材」,跟视频那边的 color、nullsrc 是一套。 合成、占位、补时长都要用到它。
一、anullsrc 是什么
跟视频那边的 color、nullsrc 是同一类东西:lavfi 源滤镜,凭空造数据。
anullsrc 造的是静音——全长都是零电平。
ffmpeg -f lavfi -i anullsrc=r=44100:cl=stereo -t 2 -c:a aac silent.m4a
-f lavfi 表示输入来自滤镜而不是文件,-t 2 是时长两秒。
不加 -t 它会一直造下去——跟 nullsrc 一样是无限长的源。
什么时候需要一段静音:给视频补一条空音轨(有些播放器没音轨不出声)、 做转场的空白段、拼多段时对齐时间轴。
二、实测:格式与数值
拉十批出来看,参数是这样:
项 值
采样格式 u8 声道布局 stereo 采样率 44100 每批点数 1024 每批时长 23.2 毫秒 样本数值范围 128 ~ 128
注意最后一行:静音的数值是 128,不是 0。
因为默认采样格式是 u8——无符号 8 位,0 电平存在中点 128。
这是「有符号 / 无符号」的区别:s16 的静音是 0,u8 的静音是 128。
拿 u8 的数据去做「求绝对值找峰值」,静音会算出 128 的峰值,看着像满幅噪声。
所以看音频数据之前,先看采样格式。 这一条在分析任何音频时都成立,不只是 ffmpeg 造的静音。
三、三个参数
常用的就三个:
写法 含义
anullsrc=r=48000:cl=stereo 48 kHz 立体声 anullsrc=r=44100:cl=mono 单声道 anullsrc=r=48000:cl=5.1 5.1 环绕
r 是采样率,cl 是声道布局——这两个参数决定这条静音能不能直接跟视频混。
采样率不一致,混流时 ffmpeg 会插值重采样,白折腾一遍,还可能有杂音。
cl 里还能写 sample_fmt,比如 anullsrc=r=44100:cl=mono:sample_fmt=s16。
要让静音是「数值 0」而不是 128,就得显式指定 s16。
四、想要有声音,用 aevalsrc
aevalsrc 跟 geq 是一对:geq 逐像素写公式,aevalsrc 逐样本写公式。
ffmpeg -f lavfi -i "aevalsrc=sin(2*PI*440*t):s=44100:d=1" tone.wav
sin(2*PI*440*t) 就是一秒 440 Hz 的正弦(标准音 A4),
实测正好 44100 个点、峰值 1.00。
所以「造一段静音」用 anullsrc,「造一段测试音」用 aevalsrc。
两者都是源,都能接 -t 或者 d= 控制长度,也都能直接进 -filter_complex。
测试音在实战里很有用:查「有没有声音」比查「有没有画面」难得多, 用一段已知频率的测试音去跑一遍链,能确认音频到底在哪一环断掉的。
五、动手 Demo:静音的格式与数值、一段测试音
下面这段代码先拉十批 anullsrc 出来,看格式、采样率、每批点数与数值范围; 再用 aevalsrc 造一秒 440 Hz,确认点数是 44100。
import av
print(u"--- anullsrc 的格式与数值")
g = av.filter.Graph()
s = g.add(u"anullsrc", u"r=44100:cl=stereo")
sk = g.add(u"abuffersink")
s.link_to(sk)
g.configure()
tot, n, lo, hi = 0, 0, 999, -999
for _ in range(10):
try:
f = sk.pull()
except Exception:
break
a = f.to_ndarray()
n += 1
tot += f.samples
lo = min(lo, int(a.min()))
hi = max(hi, int(a.max()))
fmt, lay, rate = f.format.name, f.layout.name, f.sample_rate
print(u" 格式 %s 声道 %s 采样率 %d" % (fmt, lay, rate))
print(u" 拉了 %d 批,共 %d 点/声道,数值 %d ~ %d" % (n, tot, lo, hi))
print(u" 每批 %d 点,%.1f 毫秒" % (tot // n, tot / float(n) / rate * 1000))
print(u"--- aevalsrc 造 440 Hz 正弦")
g = av.filter.Graph()
s = g.add(u"aevalsrc", u"sin(2*PI*440*t):s=44100:d=1")
sk = g.add(u"abuffersink")
s.link_to(sk)
g.configure()
n, amp = 0, 0.0
for _ in range(200):
try:
f = sk.pull()
except Exception:
break
n += f.samples
amp = max(amp, float(abs(f.to_ndarray()).max()))
print(u" 1 秒实得 %d 点,峰值 %.2f" % (n, amp))
实跑输出:
--------------------------------------------------------------------
7.16.1 生成静音音频
--------------------------------------------------------------------
**① anullsrc 是「什么都不发出的音频源」**
**跟视频那边的 `color`、`nullsrc` 是同一类东西:lavfi 源滤镜,凭空造数据。**
**`anullsrc` 造的是静音——全长都是零电平。**
`ffmpeg -f lavfi -i anullsrc=r=44100:cl=stereo -t 2 -c:a aac silent.m4a`
**`-f lavfi` 表示输入来自滤镜而不是文件,`-t 2` 是时长两秒。**
**不加 `-t` 它会一直造下去——跟 `nullsrc` 一样是无限长的源。**
**② 实测:格式、声道、每批点数**
项 值
------------------------------
采样格式 u8
声道布局 stereo
采样率 44100
每批点数 1024
每批时长 23.2 毫秒
样本数值范围 128 ~ 128
**注意最后一行:静音的数值是 128,不是 0。**
**因为默认采样格式是 `u8`——无符号 8 位,0 电平存在中点 128。**
**这是「有符号 / 无符号」的区别:`s16` 的静音是 0,`u8` 的静音是 128。**
**拿 `u8` 的数据去做「求绝对值找峰值」,静音会算出 128 的峰值,看着像满幅噪声。**
**遇到这种事,先看采样格式再下结论。**
**③ 换采样格式与声道**
写法 含义
------------------------------------------------
anullsrc=r=48000:cl=stereo 48 kHz 立体声
anullsrc=r=44100:cl=mono 单声道
anullsrc=r=48000:cl=5.1 5.1 环绕
**`r` 是采样率,`cl` 是声道布局。这两个参数决定「这条静音音轨能不能直接跟视频混」——**
**混流时采样率不一致,ffmpeg 会插值重采样,白折腾一遍。**
**④ 想要「有声音但很轻」,用 aevalsrc**
**`aevalsrc` 跟 `geq` 是一对:geq 逐像素写公式,aevalsrc 逐样本写公式。**
**`sin(2*PI*440*t)` 就是一秒 440 Hz 的正弦,实测正好 44100 个点、峰值 1.00。**
**所以「造一段静音」用 `anullsrc`,「造一段测试音」用 `aevalsrc`。**
**两者都是源,都能接 `-t` 控制长度。**
第一段四行就是本节那张表:u8、stereo、44100、每批 1024 点。 数值范围 128 ~ 128 说明整段是平的,一个采样点都没波动。
「每批 1024 点」是 ffmpeg 音频滤镜的默认块大小(abuffersink 一次吐 1024 个样本),换成视频那边的说法就是「一次吐一帧」。
第二段是 440 Hz 正弦:一秒正好 44100 点,峰值 1.00。
点数对得上,说明 d=1 是真的按采样率乘的,不是随便给的。
30 秒实验
- 换采样率:把
r=44100改成r=8000,看每批时长是不是变成 128 毫秒。 - 试 s16:加
:sample_fmt=s16,看数值范围是不是变成0 ~ 0。 - 换频率:把
440改成1000,点数不变、波形变密。
常见误区
- 把 u8 的 128 当「有很大声音」。128 就是 0 电平。
- 不加
-t也不加d=。它会一直造,命令永远不结束。 - 静音音轨采样率跟视频不匹配。混流时会重采样,白折腾。
自测三问(点开对答案)
1. 静音在 u8 格式下的数值是多少? —— 128。u8 是无符号的,0 电平存在中点。 2. 怎么让它一直造下去? —— 不加 `-t` 也不加 `d=`,它就是无限长的源。 3. 造一段 440 Hz 测试音用什么? —— `aevalsrc=sin(2*PI*440*t):s=44100:d=1`。- ☐ (本节完,下一节 7.16.2 生成纯色视频)