FFmpeg filter_complex 实战:画中画、拼接、水印与调色的完整工作流
很多同学用 FFmpeg 只会 -i in.mp4 out.mp4 转个封装,一旦要"把两段视频叠在一起""给成片加 Logo""批量打水印""统一调色",就只能在网上到处抄命令,改一个参数就满屏报错。这篇文章把 -filter_complex 的完整工作流拆开讲透,让你遇到这类需求能自己拼出命令。
一、为什么需要 filter_complex
单路简单滤镜 -vf(等价于 -filter:v)只能处理"一条输入流 → 一条输出流",而且只能串一条滤镜链。当你需要:
- 把两个视频叠加(画中画);
- 把多条流拼接成一条;
- 在同一画面里同时做缩放、裁剪、水印、调色;
就必须用 -filter_complex,它支持多条输入/输出、滤镜图(filtergraph)和带标签的链路。
经验法则:只要输入或输出不止一路,或者要在一条命令里同时改画面和声音,就用
-filter_complex。
二、滤镜语法基础
2.1 简单滤镜 -vf
ffmpeg -i in.mp4 -vf "scale=1280:720" out.mp4
滤镜之间用逗号分隔:scale=1280:720,eq=brightness=0.05。
2.2 复杂滤镜 -filter_complex
语法是 [输入][输入]滤镜=参数[输出]:
ffmpeg -i main.mp4 -i sub.mp4 -filter_complex "[1:v]scale=480:-1[pip];[0:v][pip]overlay=W-w-20:20" -map "[v]" out.mp4
要点:
[0:v]表示第一个输入文件的视频流,[1:a]表示第二个输入文件的音频流;[pip]是自定义的临时标签,分号;分隔多条滤镜链;- 最后的
-map "[v]"指定把哪条输出写进结果文件; - 如果忘了
-map,FFmpeg 会按默认规则选流,常常选错,务必显式-map。
下面这张表是本文用到的核心滤镜:
| 滤镜 | 作用 | 典型参数 |
|---|---|---|
| scale | 缩放分辨率 | scale=1280:720 / scale=-1:720 |
| overlay | 叠加(画中画) | overlay=W-w-20:20 |
| concat | 拼接多条流 | concat=n=2:v=1:a=1 |
| drawtext | 文字水印 | text='VidDown':fontsize=24 |
| crop | 裁剪 | crop=in_w:in_h-100:0:0 |
| eq | 亮度/对比/饱和 | eq=brightness=0.06:contrast=1.1 |
| hue | 色相 | hue=h=30 |
| pad | 加边填充 | pad=iw+40:ih+40:20:20 |
三、实战一:画中画(PiP)
最经典的"主画面 + 右下角小窗"效果:
ffmpeg -i main.mp4 -i sub.mp4 -filter_complex ^
"[1:v]scale=480:-1[pip];[0:v][pip]overlay=W-w-20:20" ^
-map "[v]" -map "0:a" -c:a copy out.mp4
注意 -map "0:a" 直接拷贝主视频的音轨,避免重编码声音。
3.1 动态位置表达式
overlay 支持 main_w、main_h、overlay_w、overlay_h 四个内置变量,分别表示主画面和叠加层的宽高,因此:
- 右上角:
overlay=W-w-20:20 - 居中:
overlay=(W-w)/2:(H-h)/2 - 跟随底部滚动字幕区:
overlay=20:H-h-80
3.2 圆形遮罩小窗
把小窗裁成圆角,可叠加 format=rgba,geq 或先用 mask 预生成 PNG 再 overlay,生产环境更推荐用一张带透明通道的圆形蒙版 PNG 做 overlay,性能更稳。
四、实战二:多段视频拼接
有两种主流做法。
4.1 concat 滤镜(需参数一致)
ffmpeg -i a.mp4 -i b.mp4 -filter_complex ^
"[0:v][0:a][1:v][1:a]concat=n=2:v=1:a=1[v][a]" ^
-map "[v]" -map "[a]" out.mp4
要求两段视频分辨率、编码、帧率一致,否则会花屏或卡顿。
4.2 concat demuxer(推荐,避免重编码)
新建 list.txt:
file 'a.mp4'
file 'b.mp4'
file 'c.mp4'
ffmpeg -f concat -safe 0 -i list.txt -c copy out.mp4
-c copy 直接拼接,速度快、不损画质,但前提仍是编码参数一致。参数不一致时先统一转码再拼。
五、实战三:批量加水印
5.1 drawtext 文字水印
ffmpeg -i in.mp4 -vf ^
"drawtext=text='VidDown':fontcolor=white@0.6:fontsize=24:^
x=w-tw-20:y=h-th-20:box=1:boxcolor=black@0.3:boxborderw=4" ^
out.mp4
white@0.6 表示白色 60% 不透明度;box=1 给文字加半透明底框,提升在亮背景上的可读性。
5.2 图片 Logo 水印与平铺
单角 Logo:
ffmpeg -i in.mp4 -i logo.png -filter_complex "overlay=20:20" out.mp4
四角平铺防盗水印:用 tile 或多次 overlay 复制标签,再分别定位到四个角。批量处理建议写成脚本遍历目录:
for f in *.mp4; do
ffmpeg -i "$f" -i logo.png -filter_complex "overlay=20:20" "wm_$f"
done
六、实战四:调色与基础校正
统一的观感往往靠 eq 即可:
ffmpeg -i in.mp4 -vf "eq=brightness=0.06:contrast=1.1:saturation=1.2" out.mp4
brightness:亮度,±1 之间,0.05 左右最自然;contrast:对比度,1.0 为原值;saturation:饱和度,1.2 更鲜艳;- 色相偏移用
hue=h=30(角度)。
需要进一步风格化(电影感 LUT)可用 lut3d 加载 .cube 调色文件:
ffmpeg -i in.mp4 -vf "lut3d=file=teal_orange.cube" out.mp4
七、性能与硬件加速注意点
- 滤镜默认在 CPU 上逐帧计算,开销大;若用 NVIDIA 显卡,用
hwupload_cuda把帧上传显存再接scale_cuda、overlay_cuda。 - 把
scale放在滤镜链最前面,先缩小数据量再叠加/调色,能显著省 CPU。 - 编码侧用
-preset veryfast -crf 23平衡速度与体积。 drawtext会对每帧重绘文字,开启其内置缓存可降开销;大量静态水印场景可考虑先烧录一次再批量。
八、排错清单
| 现象 | 可能原因 | 排查办法 |
|---|---|---|
| 输出没有声音 | 漏写 -map 音轨 |
显式 -map "[a]" 或 -map 0:a |
| 画中画位置错乱 | overlay 坐标用了固定像素 | 改用 W-w-20 等相对变量 |
| 拼接后花屏 | 两段参数不一致 | 先统一转码再 concat |
滤镜链报 No such filter |
编译未带该滤镜 | ffmpeg -filters 查是否支持 |
| 中文水印乱码 | 缺字体 | fontfile= 指定中文字体路径 |
九、小结
-filter_complex 不是黑魔法,本质就是"给每一路流贴标签、用滤镜链描述变换、最后 -map 选输出"。掌握 scale / overlay / concat / drawtext / eq 这五个,就能覆盖 80% 的视频后期自动化需求。把它们写成脚本,配合 VidDown 的批量处理能力,就能把重复的视频加工变成一键任务。