23、视频滤镜链:多个滤镜串联使用、滤镜图(filter graph)的概念与构建
说实话,滤镜链这个概念,我第一次接触的时候也觉得有点绕。但说白了,它就是「把多个滤镜像串糖葫芦一样串起来」。你想想看,一个滤镜处理完,输出给下一个滤镜,下一个再处理,再传给下一个……这就是滤镜链。
但光有链还不够。有时候我们需要更复杂的结构——比如一个画面拆成两路,一路做模糊,一路做锐化,最后再合并。这时候就需要滤镜图(filter graph)了。嗯,咱们今天就把这两个东西彻底讲明白。
滤镜链:最简单的串联方式
滤镜链,就是滤镜一个接一个地处理。每个滤镜的输出,自动成为下一个滤镜的输入。在 FFmpeg 里,我们用逗号 , 来连接它们。
举个例子:我想先缩放视频到 640x480,再旋转 90 度,最后加一个模糊效果。命令是这样的:
ffmpeg -i input.mp4 -vf "scale=640:480,transpose=1,boxblur=2:1" output.mp4
这里 scale、transpose、boxblur 三个滤镜用逗号串起来。数据流就是:
- 原始帧 → scale → 缩放后的帧 → transpose → 旋转后的帧 → boxblur → 模糊后的帧 → 输出
我在项目中遇到过一个问题:滤镜顺序搞反了。比如先旋转再缩放,和先缩放再旋转,结果完全不一样。你想想看,先旋转再缩放,旋转后的画面尺寸变了,缩放参数就得重新算。所以顺序很重要,千万别搞混。
-vf "filter1,filter2,filter3" 这种写法,一目了然。
滤镜图:更复杂的处理结构
滤镜链只能处理「一条路走到黑」的情况。但实际工作中,我们经常需要分路、合并、交叉处理。这时候就要用到滤镜图了。
滤镜图用分号 ; 来分隔不同的滤镜「段落」,用方括号 [label] 来标记输入输出节点。说白了,就是给每个滤镜的输入输出起个名字,然后手动连接它们。
来看一个经典例子:把视频分成两路,一路做边缘检测,另一路做颜色反转,最后叠加在一起。
ffmpeg -i input.mp4 -vf "
[0:v]split[base][edge];
[edge]edgedetect[edge_out];
[base]negate[neg_out];
[edge_out][neg_out]overlay
" output.mp4
这个图的结构是这样的:
[0:v]是输入视频流split把画面复制成两路:[base]和[edge][edge]走edgedetect滤镜,输出[edge_out][base]走negate滤镜,输出[neg_out]- 最后
[edge_out]和[neg_out]通过overlay叠加
你看,这就是一个典型的滤镜图。有分叉,有合并,比单纯的链灵活多了。
[out],结果 FFmpeg 报错说「标签冲突」。排查了半天才发现是命名重复了。
滤镜图的构建规则
构建滤镜图其实有套路。我总结了几条核心规则:
- 每个滤镜都要有明确的输入和输出——用
[输入标签]滤镜名[输出标签]的格式 - 标签名可以任意起——但建议用有意义的名称,比如
[scaled]、[rotated] - 分号分隔不同的滤镜段落——每个段落可以是一个滤镜,也可以是一个滤镜链
- 最后一个滤镜的输出就是最终输出——不需要显式指定标签
举个例子,一个稍微复杂点的图:先缩放,然后分两路,一路做模糊,一路做锐化,最后叠加。
ffmpeg -i input.mp4 -vf "
[0:v]scale=640:480[scaled];
[scaled]split[blur_in][sharpen_in];
[blur_in]boxblur=2:1[blur_out];
[sharpen_in]unsharp=5:5:1.0[sharpen_out];
[blur_out][sharpen_out]overlay=format=auto
" output.mp4
这个图有 5 个滤镜段落,4 个标签。数据流清晰,每个节点都能追踪。嗯,这就是我推荐的做法——标签名起得好,调试起来省一半时间。
用 SVG 画一张滤镜图结构
光说可能不够直观。我画了一张图,展示上面那个「缩放→分路→模糊+锐化→叠加」的滤镜图结构。
这张图里,每个矩形代表一个滤镜,箭头代表数据流向。标签名标在节点旁边。你看,数据从左边进来,经过 scale,到 split 分叉,然后分别走 boxblur 和 unsharp,最后在 overlay 合并输出。结构一目了然。
实际项目中的避坑指南
我在实际项目中用过不少滤镜图,踩过一些坑。分享几个经验:
- 标签名不要用数字开头——FFmpeg 会把
[1v]误解为输入流编号。我吃过这个亏,后来统一用字母开头加下划线,比如[v1]、[v_out] - 滤镜图里不要有「悬空」的输入输出——每个标签要么被定义,要么被使用,不能有未连接的节点。否则 FFmpeg 会报错
- 复杂滤镜图建议先画草图——我习惯在纸上画一遍结构,再写命令。尤其是分路超过 3 路的时候,脑子容易乱
- 用
-filter_complex代替-vf——滤镜图建议用-filter_complex,它支持多输入多输出,更灵活。-vf只能处理单路视频
好了,滤镜链和滤镜图的概念就讲到这里。说白了,它就是 FFmpeg 里最灵活、最强大的视频处理方式。你想想看,只要你能画出数据流图,FFmpeg 就能帮你实现。这就是它的魅力所在。