
使用 FFmpeg 的 drawtext 复合滤镜添加多行水印时,若未正确连接滤镜链,第二行将因输入源冲突而失效;必须将前一个 drawtext 的输出作为下一个的输入,形成串行滤镜流。
使用 ffmpeg 的 `drawtext` 复合滤镜添加多行文字水印时,若未正确连接滤镜链,第二行将因输入源冲突而失效;必须将前一个 `drawtext` 的输出作为下一个的输入,形成串行滤镜流。
在 FFmpeg 的 complexFilter 中,多个 drawtext 滤镜不能同时以 [0:v] 为输入源——因为它们会竞争同一视频流,FFmpeg 默认只保留最后一个有效输出(或因覆盖导致前序效果被丢弃),从而造成“仅第一行可见”的现象。
正确做法是构建滤镜链(filter chain):将第一个 drawtext 的输出显式命名(如 [filter_1]),再将其作为第二个 drawtext 的输入。这样确保两行文字依次叠加在同一视频帧上,而非相互覆盖或被忽略。
以下是修复后的完整代码示例(适配 Node.js 中的 fluent-ffmpeg):
ffmpeg()
.input(tempLocalPath)
.complexFilter([
// 第一行水印 → 输出命名为 [filter_1]
`[0:v]drawtext=text='${watermarkTextLine1}':x=(w-tw)/2:y=(h-460):fontsize=24:fontcolor=white:fontfile=/Windows/Fonts/arial.ttf[filter_1]`,
// 第二行水印 → 输入来自 [filter_1],而非 [0:v]
`[filter_1]drawtext=text='${watermarkTextLine2}':x=(w-tw)/2:y=(h-200):fontsize=32:fontcolor=red:fontfile=/Windows/Fonts/arial.ttf`,
])
.output(
path.join(tempLocalDir, video_cid.replace(".mp4", "-") + "watermarked.mp4")
)
.on("end", () => {
res.download(
path.join(
tempLocalDir,
video_cid.replace(".mp4", "-") + "watermarked.mp4"
),
"video.mp4",
(err) => {
if (err) console.error("Download error:", err);
fs.unlink(tempLocalPath, (unlinkErr) => {
if (unlinkErr) console.error("Cleanup error:", unlinkErr);
});
}
);
})
.inputFormat("mp4")
.run();
⚠️ 注意事项:
- 所有 drawtext 必须使用唯一且可引用的输出标签(如 [filter_1]、[filtered]),中间不可省略;
- y 坐标需合理错开(如示例中 h-460 和 h-200),避免文字重叠;
- fontfile 路径需确保运行环境可访问(Linux/macOS 应使用 /usr/share/fonts/truetype/dejavu/DejaVuSans.ttf 等路径,Windows 注意转义或使用双反斜杠);
- 若启用 reload=1 动态文本,需额外配置时间戳参数(如 timecode='00:00:00:00'),否则可能报错;
- 推荐在生产环境添加 .on('error', ...) 监听滤镜语法错误(如标签不匹配、字体缺失等),便于快速定位问题。
通过显式声明滤镜依赖关系,即可稳定实现多行水印叠加,这是 FFmpeg 复合滤镜设计的核心原则之一。











