7、FFmpeg滤镜链实战:使用滤镜实现视频缩放、裁剪、旋转、添加水印,以及音频混音与变速

说实话,滤镜是FFmpeg里最让我着迷的部分。你想想看,一个命令行工具,居然能像搭积木一样把各种音视频效果串起来。我最早接触FFmpeg滤镜时,觉得这东西不就是加个特效嘛,后来才发现——滤镜链的设计思路,其实跟咱们写代码时的管道模式一模一样。

这一章,咱们就动手实操。我会带着你用滤镜链完成视频缩放、裁剪、旋转、加个水印,再顺带把音频的混音和变速也搞定。嗯,都是实战中高频用到的场景。

核心要点:FFmpeg滤镜链的核心是 filtergraph,它用字符串描述滤镜之间的连接关系。每个滤镜节点处理一帧数据,然后传给下一个节点。

7.1 视频缩放:从720p到1080p,一个scale搞定

视频缩放,说白了就是改变画面的宽高。我项目中经常遇到这种情况:用户上传的视频分辨率五花八门,我得统一缩放到某个标准尺寸。FFmpeg的 scale 滤镜就是干这个的。

基本用法:

ffmpeg -i input.mp4 -vf "scale=1920:1080" output.mp4

这里 -vf 是视频滤镜链的入口。 scale=1920:1080 表示宽1920,高1080。但有个坑——如果你直接写死宽高,画面比例可能会被拉伸变形。我刚开始就犯过这个错,结果人脸都变宽了。

我的习惯:scale=1280:-1 或者 scale=-1:720,让FFmpeg自动计算另一边,保持原始宽高比。那个 -1 就是「自动计算」的意思。

如果你想强制缩放到某个尺寸,同时保持比例不变,可以用 force_original_aspect_ratio 参数:

ffmpeg -i input.mp4 -vf "scale=1920:1080:force_original_aspect_ratio=decrease" output.mp4

这个参数会保证画面完整显示,不足的部分用黑边填充。嗯,有点像咱们看电影时上下黑边的效果。

7.2 视频裁剪:只取画面的一部分

裁剪,就是从原画面中切出一块矩形区域。我记得有一次做直播项目,需要把摄像头画面中的某个固定区域截取出来做特写,用的就是 crop 滤镜。

语法:

crop=out_w:out_h:x:y

其中 out_wout_h 是裁剪后的宽高, x:y 是裁剪区域的左上角坐标。比如:

ffmpeg -i input.mp4 -vf "crop=640:480:100:50" output.mp4

这表示从坐标(100, 50)开始,裁剪出640x480的区域。

注意:坐标值不能超出原视频尺寸,否则FFmpeg会报错。我曾经在动态计算坐标时忘了加边界检查,结果线上出了好几次事故。

如果你想裁剪画面中心区域,可以用 in_w/2in_h/2 这种表达式:

ffmpeg -i input.mp4 -vf "crop=640:480:(in_w-640)/2:(in_h-480)/2" output.mp4

这样不管输入视频多大,都能自动居中裁剪。

7.3 视频旋转:转个90度,或者任意角度

旋转滤镜有两个常用方案: transposerotate

transpose 只能做90度、180度、270度旋转,但速度快,适合手机竖屏视频转横屏这种场景:

ffmpeg -i input.mp4 -vf "transpose=1" output.mp4

参数 1 表示顺时针旋转90度。 2 是逆时针90度, 3 是180度。

如果你需要任意角度旋转,就得用 rotate 滤镜。比如旋转45度:

ffmpeg -i input.mp4 -vf "rotate=45*PI/180" output.mp4

注意, rotate 的角度单位是弧度。我每次写这个都要心里默念一遍「弧度=角度×π/180」。另外,旋转后画面边缘会出现黑边,你可以用 fillcolor 参数改成其他颜色:

ffmpeg -i input.mp4 -vf "rotate=45*PI/180:fillcolor=white" output.mp4
避坑指南:我曾经用 rotate 处理一个4K视频,结果发现CPU占用飙到100%,帧率掉到个位数。后来换成 transpose 配合硬件加速,才搞定。所以,能不用 rotate 就别用,除非你真的需要任意角度。

7.4 添加水印:用overlay把图片叠上去

水印,说白了就是一张小图叠在大图上。FFmpeg的 overlay 滤镜就是干这个的。我做过一个视频平台,所有用户上传的视频都要自动加上平台Logo,用的就是这个。

基本用法:

ffmpeg -i input.mp4 -i logo.png -filter_complex "overlay=10:10" output.mp4

这里 -filter_complex 是复杂滤镜链的入口,因为涉及两个输入流(视频+图片)。 overlay=10:10 表示水印放在距离左上角10像素的位置。

如果你想放在右下角,可以这样:

ffmpeg -i input.mp4 -i logo.png -filter_complex "overlay=W-w-10:H-h-10" output.mp4

WH 是主视频的宽高, wh 是水印的宽高。这个表达式就是「主视频右下角,再往左上偏移10像素」。

进阶技巧:如果你想让水印在视频中移动,可以配合 enable 参数做时间控制,或者用 between 表达式。比如只在第5秒到第10秒显示水印:
overlay=10:10:enable='between(t,5,10)'

7.5 音频混音:把两路声音合在一起

音频混音,就是把多个音频流混合成一路。比如给视频配背景音乐,或者把解说和原声混在一起。FFmpeg的 amix 滤镜就是专门干这个的。

假设你有一个视频文件 video.mp4 和一个音乐文件 bgm.mp3,想把它们混在一起:

ffmpeg -i video.mp4 -i bgm.mp3 -filter_complex "[0:a][1:a]amix=inputs=2:duration=first" output.mp4

这里 [0:a][1:a] 分别引用第一个输入和第二个输入的音频流。 amix 的参数 inputs=2 表示混合两路音频, duration=first 表示以第一个音频的时长为准(也就是视频原声的长度)。

如果你想调整两路音频的音量比例,可以用 volume 滤镜先处理一下:

ffmpeg -i video.mp4 -i bgm.mp3 -filter_complex "[0:a]volume=1.0[a0];[1:a]volume=0.3[a1];[a0][a1]amix=inputs=2:duration=first" output.mp4

这样背景音乐的音量就只有原声的30%,不会喧宾夺主。嗯,这个比例我一般根据场景调,如果是纯音乐可以稍微大一点。

注意:混音时如果两个音频的采样率或声道数不一致,FFmpeg会自动转换,但可能会引入一些质量损失。我建议在混音前先用 aresample 滤镜统一参数。

7.6 音频变速:让声音变快或变慢

音频变速,最常用的滤镜是 atempo。它通过改变音频的播放速度来调整时长,同时保持音调不变(或者变化很小)。

比如把音频速度变成原来的1.5倍:

ffmpeg -i input.mp4 -af "atempo=1.5" output.mp4

-af 是音频滤镜链的入口。 atempo 的取值范围是0.5到2.0,低于0.5或高于2.0会报错。如果你需要更极端的变速,可以串联多个 atempo

ffmpeg -i input.mp4 -af "atempo=2.0,atempo=2.0" output.mp4

这样就是4倍速。我做过一个音频剪辑工具,用户要求支持0.25倍到4倍速,就是用这种串联方式实现的。

我的经验:变速后的音频质量跟原始采样率有关。如果原始音频是44.1kHz,变速到2倍速后,高频部分可能会有些失真。建议在变速前先用 aresample 把采样率提高到48kHz,能改善一些。

7.7 综合实战:一个完整的滤镜链

好了,咱们把上面这些知识点串起来。假设你有一个视频,需要做以下处理:

  1. 缩放到1280x720
  2. 裁剪出中心区域
  3. 旋转90度
  4. 加上水印
  5. 混入背景音乐,音量降到30%
  6. 把整体音频速度变成1.2倍

完整的命令如下:

ffmpeg -i input.mp4 -i logo.png -i bgm.mp3 \
-filter_complex \
"[0:v]scale=1280:720,crop=640:480:(1280-640)/2:(720-480)/2,transpose=1[vid]; \
 [0:a]volume=1.0[audio_orig]; \
 [2:a]volume=0.3[audio_bgm]; \
 [audio_orig][audio_bgm]amix=inputs=2:duration=first[audio_mix]; \
 [audio_mix]atempo=1.2[audio_final]" \
-map "[vid]" -map "[audio_final]" output.mp4

这个命令看起来有点长,但拆开看其实很简单:

  • 第一行:视频流经过 scalecroptranspose,输出到 [vid]
  • 第二行:原音频音量设为1.0
  • 第三行:背景音乐音量设为0.3
  • 第四行:两路音频混音
  • 第五行:混音后的音频变速1.2倍

最后用 -map 把处理后的视频和音频流映射到输出文件。

注意:滤镜链的顺序很重要。比如先缩放再裁剪,和先裁剪再缩放,结果完全不同。我建议先做缩放,再做裁剪,这样能保证裁剪区域的分辨率是准确的。

下面这张图展示了整个滤镜链的数据流向:

滤镜链数据流向图 input.mp4 logo.png bgm.mp3 scale=1280:720 crop=640:480 transpose=1 overlay=10:10 volume=1.0 volume=0.3 amix atempo=1.2 output.mp4 视频滤镜 音频滤镜 输入文件 输出文件

嗯,看到这里,你应该对FFmpeg滤镜链有了比较完整的认识。说白了,滤镜链就是一条流水线,每个滤镜负责一道工序。你只要把工序排好顺序,FFmpeg就会自动帮你跑完。

我个人建议,刚开始练习时,先拆开每个滤镜单独测试,确认效果没问题了,再拼成完整的滤镜链。这样出错了也容易定位。我曾经有一次把 overlayscale 的顺序搞反了,结果水印被缩放得面目全非,排查了半天才发现。

最后一个小技巧:如果你不确定滤镜链的语法对不对,可以用 ffmpeg -filter_complex "你的滤镜链" -f null - 来测试,这样不会生成实际文件,只检查语法。能省不少时间。

公众号:蓝海资料掘金营,微信deep3321