命令从 4.x 到 7.x 一个字没变,能不能跑却取决于编译时有没有带 freetype。 「装了 5.0」跟「能用 5.0 的 drawtext」是两件事。
第六章做过跑马灯,第十章讲过 \, 转义,这一节补最后一块: 为什么同一套命令,在别人机器上能跑、在自己机器上连滤镜都找不到。
一、命令还是那条命令
第六章与第十章那条:
ffmpeg -i in.mp4 -vf "drawtext=text='Hello':x=w-mod(t*100\,w+tw):y=10" \
out.mp4
语法从 4.x 到 7.x 没动过——drawtext 的选项名、表达式语法、\, 的规矩,全都一样。
所以这一节在「命令怎么写」上没有新东西。
新的是另一件事:这条命令在你机器上根本可能跑不了, 而且报的错跟「参数写错」长得完全不一样。
二、滤镜在不在,是编译时决定的
实测本机这套二进制里,跟文字有关的三个滤镜一个都没有:
滤镜 本机有吗 没有意味着什么
drawtext 没有 文字画不进画面 subtitles 没有 字幕烧不进画面 ass 没有 ASS 字幕也烧不了 overlay 有 贴图这条路还在
原因不在版本,在编译开关:
drawtext 要靠 freetype 和 fontconfig,subtitles 与 ass 还要 libass。
这套二进制编的时候没带它们,所以 468 个滤镜里就是没有这几个。
换 5.0、换 7.0、换 git master,只要编译时不带 freetype,drawtext 就永远不在。
这就是「版本新 ≠ 功能全」最实在的一个例子:
决定你能不能用某个滤镜的,是编译选项,不是版本号。
报错长什么样也值得先看一眼:不是「参数不对」,而是
No such filter: 'drawtext'——它在说「根本没有这个滤镜」。
很多人看到这句会去怀疑拼写、怀疑版本、怀疑引号,
实际上该做的是查一下清单里有没有。
三、所以第六章那条 Pillow 退路,不是凑数
第六章在沙箱里做跑马灯时,没有走 drawtext,
而是用 Pillow 把字画成一张带透明通道的图,再用 overlay 贴上去。
当时看起来像是在「绕路」,现在有了清单就清楚了:
那不是绕路,那是这套环境下唯一能走通的路。
overlay 在、scale 在、hflip 在,所以「先画成图再贴」这条路全程无障碍。
更普遍地说:当一个滤镜不存在时,有两条对策—— 换一个带了它的构建,或者用「现成的滤镜 + 自己算」拼出同样的效果。 前者改环境,后者改方案; 在别人的机器上交付脚本时,后者往往更可靠,因为你控制不了对方的编译开关。
四、硬字幕、软字幕与字体依赖
drawtext 画的是硬字幕:像素烤进画面,播放器关不掉。
软字幕是另一条流,播放器可以选、可以关。
两条路对环境的依赖完全不同:
做法 依赖什么 缺了会怎样
drawtext 硬字幕 freetype + fontconfig 滤镜整个不存在 subtitles 烧进画面 libass 滤镜整个不存在 软字幕流 只要容器支持 mp4 只收 mov_text
第三行是「依赖最少」的一条:只要目标容器认这种字幕格式, 就不需要任何额外库。 代价是播放器得支持——观众那边可能什么都不显示。
五、查法:一条命令,比试错快十倍
别猜,直接问:
ffmpeg -filters | grep drawtext
在 Python 里等价的一句是 "drawtext" in av.filter.filters_available。
查到了才有后面所有事;查不到就别再折腾参数了——
该做的是换一个带 freetype 的构建,或者像第六章那样用 Pillow 绕过去。
这条「先查清单再写命令」的习惯,能省掉一大半试错。
它对所有滤镜都成立:gblur、transpose、overlay,一个道理。
六、动手 Demo:查清单:文字类滤镜到底有几个
下面这段把跟文字/字幕有关的滤镜逐个查一遍。 结果比任何解释都直接:没有就是没有,跟参数无关。
import av.filter
F = set(av.filter.filters_available)
print("滤镜总数 %d" % len(F))
for nm in ("drawtext", "subtitles", "ass", "overlay",
"scale", "hflip", "transpose", "gblur"):
print(" %-10s %s" % (nm, "有" if nm in F else "没有"))
实跑输出:
--------------------------------------------------------------------
11.3 使用 FFmpeg 5.0 实现文字跑马灯
--------------------------------------------------------------------
**① 先查一件事:这套二进制里到底有没有 `drawtext`**
**第六章花了不少篇幅绕开 `drawtext`,改用 Pillow 画字再 `overlay`。**
**现在有了完整清单,可以直接把原因摆出来:**
滤镜 本机有吗 没有意味着什么
--------------------------------------------------------
drawtext 没有 文字画不进画面
subtitles 没有 字幕烧不进画面
ass 没有 ASS 字幕也烧不了
overlay 有 贴图这条路还在
**`drawtext` 要靠 freetype 和 fontconfig 编进来,`subtitles` 还要 libass。**
**这套二进制编的时候没带这三个,所以 468 个滤镜里就是没有它们。**
**这跟版本号一点关系都没有——换 5.0、换 7.0、换 git master,**
**只要编译时不带 freetype,`drawtext` 就永远不在。**
**这就是「版本新 ≠ 功能全」最实在的一个例子:**
**决定你能不能用某个滤镜的,是编译选项,不是版本号。**
**② 所以「5.0 上的跑马灯命令」该怎么看**
**书上那条命令本身没错,语法从 4.x 到 7.x 一个字都没变:**
ffmpeg -i in.mp4 -vf "drawtext=text='Hello':x=w-mod(t*100\,w+tw):y=10" \
out.mp4
**但它能不能跑,取决于你手上那个 ffmpeg 是不是带 freetype 编的。**
**所以「装了 5.0」跟「能用 5.0 的 drawtext」是两件事——**
**这跟第九章那条「打开成功不等于能用」是同一类陷阱,只是发生在编译期。**
**③ 查法只有一条,记牢**
ffmpeg -filters | grep drawtext
**在 Python 里等价的一句是 `"drawtext" in av.filter.filters_available`。**
**查到了才有后面所有事,查不到就别再折腾参数了——**
**该做的是换一个带 freetype 的构建,或者像第六章那样用 Pillow 绕过去。**
前三行全是「没有」,后五行全是「有」——这个分界不是偶然: 前三个都要外部库(freetype/libass),后五个都是 FFmpeg 自己实现的。
这条分界可以直接当判据用:一个滤镜如果依赖外部库, 那你换一台机器就得重新查一遍;如果它是自带的,基本跟着版本走。
30 秒实验
- 把
drawtext换成gblur跑一遍:看同一个查法在两种情况下输出什么。 - 在 Linux 上装
libfreetype6-dev再编译一次:看drawtext是否出现。 - 查
fc-list | wc -l:字体装了多少个,跟drawtext能不能用没关系。
常见误区
- 以为
No such filter是参数写错。它的意思是这个滤镜不存在。 - 以为装了新版就一定有 drawtext。要看编译时有没有
--enable-libfreetype。 - 在别人机器上交付依赖 drawtext 的脚本。对方的构建不一定带 freetype。
自测三问(点开对答案)
1. `drawtext` 依赖哪两个库? —— freetype 和 fontconfig;`subtitles` 与 `ass` 还要 libass。 2. 「版本新 ≠ 功能全」这句话怎么解释? —— 能不能用某个滤镜由编译开关决定,跟版本号高低没有必然关系。 3. 滤镜不存在时,除了换构建还有什么办法? —— 用现成滤镜拼:比如 Pillow 画字 + overlay 贴上去,效果等价。- ☐ 11.3 完——下一节 11.4 使用 FFmpeg 5.0 实现音视频特效