-f lavfi -i nullsrc=s=1280x720:d=5 就能凭空出一段空屏视频。 纯空画面也占字节,面积越大占得越多,1280×720 是 160×90 的七倍多。
上一节讲参数,这一节把它真编成文件。 空屏视频是剪片、垫片、占位最常用的一招。
一、命令行
一行就够:
ffmpeg -f lavfi -i nullsrc=s=1280x720:d=5 -c:v libx264 -pix_fmt yuv420p out.mp4
-f lavfi 说明这个输入不是文件,是滤镜源。-i 后面跟的是源的名字和参数。
-c:v libx264 不能省:lavfi 给的是原始帧,得有人把它压成 H.264。
-pix_fmt yuv420p 也建议显式写上,否则可能出现「电脑能放、手机打不开」。
这个坑在这一节末尾会细说。
二、三个尺寸量大小
各编 50 帧,看文件多大:
画布 帧数 文件大小 时长
160×90 50 4519 字节 2.00 秒 320×240 50 11047 字节 2.00 秒 1280×720 50 35147 字节 2.00 秒
纯空的画面也占空间,而且面积越大占得越多:最大那块是最小那块的 7.8 倍。 因为编码器不认「这是空的」,它照样要把每一块的残差算一遍、熵编码一遍。
面积比是 64 倍(1280×720 对 160×90),字节只差 7.8 倍, 因为大片纯色里的重复块能被压得很狠。这也是「纯色压缩比高」的具体体现。
三、它到底用在哪
三种典型用法:
用法 说明
垫片 两段视频之间的过渡空白 画布 当 overlay 的底,往上贴东西 占位 测试脚本时先出一段能播的视频
还有一种是「凑时长」:片头片尾要求整分钟,差几秒就拿空屏补上。 补的时候记得用 color 而不是 nullsrc,否则补出来带绿味。
四、两个坑
第一,忘写 duration 就无限长。 它不会自己停,命令行会一直跑到你按 Ctrl+C,磁盘能被写满。
第二,-pix_fmt 最好显式写上。
libx264 能接好几种像素格式,ffmpeg 只会挑一个跟输入最接近的。
挑到 yuv444p 时电脑上的播放器还能放,手机与浏览器就打不开了。
两个坑的共同点是「不报错」。 前者是命令不结束,后者是文件出来了却放不了——都得靠自己检查,命令一声不吭。
五、换成 color 也一样
把 nullsrc 换成 color=c=black,其余一个字不用改——
因为它们是同一种东西:lavfi 源。参数名都叫 size、rate、duration。
所以这一节学的不只是 nullsrc,而是「怎么用 lavfi 造一个输入」。 testsrc、smptebars、color、nullsrc 全是这一套,换名字就换内容。
testsrc 出彩条,smptebars 出标准测试图,都拿来做画面校验。
要「一段能播的东西」,随便挑一个都比空文件强。
六、动手 Demo:三块空画布,三个文件大小
下面这段代码把三个尺寸各编 50 帧,量字节与时长。 注意全程只从 nullsrc 取帧,一个文件都没读。
import os
import av
def make(dst, sid, w, h, nf):
g = av.filter.Graph()
s0 = g.add(u"nullsrc", sid)
sk = g.add(u"buffersink")
s0.link_to(sk)
g.configure()
oc = av.open(dst, u"w")
st = oc.add_stream(u"libx264", rate=25)
st.width, st.height = w, h
st.pix_fmt = u"yuv420p"
n = 0
while n < nf:
o = sk.pull()
for pk in st.encode(o):
oc.mux(pk)
n += 1
for pk in st.encode(None):
oc.mux(pk)
oc.close()
c = av.open(dst)
d = c.duration / 1e6
c.close()
return os.path.getsize(dst), d
for w, h in ((160, 90), (320, 240), (1280, 720)):
nb, d = make(u"ns_%dx%d.mp4" % (w, h),
u"size=%dx%d:rate=25" % (w, h), w, h, 50)
print(u"%-10s 50 帧 %d 字节 %.2f 秒" % (u"%dx%d" % (w, h), nb, d))
实跑输出:
--------------------------------------------------------------------
7.4.5 使用 nullsrc 生成一段空屏视频
--------------------------------------------------------------------
**① 命令行长这样**
`ffmpeg -f lavfi -i nullsrc=s=1280x720:d=5 -c:v libx264 -pix_fmt yuv420p out.mp4`
**`-f lavfi` 说明这个输入不是文件,是滤镜源。`-i` 后面跟的是源的名字和参数。**
**`-c:v libx264` 不能省:lavfi 给的是原始帧,得有人把它压成 H.264。**
**② 三个尺寸各编 50 帧,看文件多大**
画布 帧数 文件大小 时长
------------------------------------------------
160×90 50 4519 字节 2.00 秒
320×240 50 11047 字节 2.00 秒
1280×720 50 35147 字节 2.00 秒
**纯空的画面也占空间,而且面积越大占得越多:最大那块是最小那块的 7.8 倍。**
**因为编码器不认「这是空的」,它照样要把每一块的残差算一遍、熵编码一遍。**
**③ 它到底用在哪**
用法 说明
-----------------------------------------
垫片 两段视频之间的过渡空白
画布 当 overlay 的底,往上贴东西
占位 测试脚本时先出一段能播的视频
**④ 两个坑**
**第一,忘写 duration 就无限长。**
**它不会自己停,命令行会一直跑到你按 Ctrl+C,磁盘能被写满。**
**第二,`-pix_fmt` 最好显式写上。**
**libx264 能接好几种像素格式,ffmpeg 只会挑一个跟输入最接近的。**
**挑到 yuv444p 时电脑上的播放器还能放,手机与浏览器就打不开了。**
**⑤ 换成 color 也一模一样**
**把 `nullsrc` 换成 `color=c=black`,其余一个字不用改——**
**因为它们是同一种东西:lavfi 源。参数名都叫 size、rate、duration。**
三行输出跟本节那张表逐条对上:4519、11047、35147,时长全是 2.00 秒。
50 帧除以 25 帧每秒正好 2 秒,所以时长一致、只有字节数在变。 字节数的增长远慢于面积的增长,这就是纯色可压缩的直观证据。
代码里是手动数满 50 帧就停,没有依赖 duration。 这样即使源是无限的也不会跑飞——比写 duration 更保险。
30 秒实验
- 换帧数:把 50 改成 250(10 秒),看字节是不是差不多线性增长。
- 换编码器:把 libx264 换成 mpeg4,看同一块空画布谁更小。
- 加音频:给它配一条
anullsrc,做成既有画面又有声的垫片。
常见误区
- 不写 duration 也不限帧。命令会一直跑,直到磁盘满。
- 省掉 -pix_fmt。可能出 yuv444p,手机与浏览器放不了。
- 以为空画面文件会很小。1280×720 五十帧也有三十多 KB。
自测三问(点开对答案)
1. `-f lavfi` 是什么意思? —— 说明这个输入是滤镜源,不是磁盘上的文件。 2. 为什么纯空画面还占字节? —— 编码器照样要算残差、做熵编码,纯色只是压得比较狠。 3. 1280×720 是 160×90 面积的 64 倍,为什么字节只差 7.8 倍? —— 大片纯色的重复块压缩率高,面积涨得比字节快。- ☐ (本节完,下一节 7.4.6 使用 color 滤镜生成黑色背景的视频)