6月4日 13:52

FFmpeg Filter语法详解:缩放、裁剪、叠加和组合滤镜

FFmpeg 的 Filter 是它区别于其他转码工具的核心能力——不只是格式转换,而是对画面的像素、音频的采样点做任意变换。但 Filter 的语法是出了名的难读:方括号标签、分号逗号混用、多个输入输出的管线。这篇文章先把语法规则讲透,再按场景列举常用滤镜。

Filter 语法:三分钟搞懂

简单滤镜 vs 复杂滤镜

  • -vf "滤镜链":简单视频滤镜,单个输入,单个输出
  • -af "滤镜链":简单音频滤镜,同上
  • -filter_complex "滤镜图":复杂滤镜,可以有多个输入输出、分支和合并

能用 -vf/-af 解决的,不要用 -filter_complex——简单滤镜更快更不容易出错。

语法规则

bash
# 逗号:串联同一链的滤镜,前一个的输出是后一个的输入 -vf "scale=1280:720,crop=640:360" # 分号:分隔不同的滤镜链(用于 -filter_complex) -filter_complex "[0:v]scale=1280:720[v1];[1:v]scale=640:360[v2]" # 方括号标签:给输入/输出命名 -filter_complex "[0:v]scale=1280:720[big];[1:v]scale=640:360[small];[big][small]overlay=10:10"

[0:v] 表示第一个输入的视频流,[0:a] 表示第一个输入的音频流。[big][small] 是自定义标签,后续滤镜用这个标签引用。

最常见的语法错误

bash
# 错误:简单滤镜里用了分号 -vf "scale=1280:720;crop=640:360" # 报错 # 正确:简单滤镜用逗号 -vf "scale=1280:720,crop=640:360" # OK

视频滤镜

缩放(scale)

bash
# 固定分辨率 ffmpeg -i input.mp4 -vf "scale=1280:720" output.mp4 # 保持宽高比(只指定宽度,高度自动计算) ffmpeg -i input.mp4 -vf "scale=1280:-1" output.mp4 # 等比缩小到一半 ffmpeg -i input.mp4 -vf "scale=iw/2:ih/2" output.mp4 # 限制最大尺寸(不超过 1280x720,小的保持原尺寸) ffmpeg -i input.mp4 -vf "scale='min(1280,iw)':'min(720,ih)'" output.mp4

-1 是"自动计算"的写法,FFmpeg 根据原始宽高比算出高度。注意:某些编码器要求宽高都是偶数,如果算出来是奇数会报错,可以用 scale=1280:trunc(ow/2)*2 强制偶数。

裁剪(crop)

bash
# 从中心裁剪 640x480(默认居中) ffmpeg -i input.mp4 -vf "crop=640:480" output.mp4 # 指定裁剪起点(左上角偏移 100,50) ffmpeg -i input.mp4 -vf "crop=640:480:100:50" output.mp4 # 自动检测黑边并裁掉 ffmpeg -i input.mp4 -vf "cropdetect" -f null - 2>&1 | grep crop # 然后用输出的 crop 值 ffmpeg -i input.mp4 -vf "crop=1920:800:0:140" output.mp4

cropdetect 是调优利器——先跑一遍检测黑边参数,再用 crop 裁掉。

叠加(overlay)

给视频加 logo、画中画都用 overlay:

bash
# 左上角加 logo ffmpeg -i video.mp4 -i logo.png -filter_complex "overlay=10:10" output.mp4 # 右下角加 logo(W=视频宽, w=logo宽) ffmpeg -i video.mp4 -i logo.png -filter_complex "overlay=W-w-10:H-h-10" output.mp4 # 居中画中画 ffmpeg -i main.mp4 -i pip.mp4 -filter_complex "[1:v]scale=320:240[pip];[0:v][pip]overlay=(W-w)/2:(H-h)/2" output.mp4

overlay 的坐标用 x:y 格式,支持表达式。WH 是主视频的宽高,wh 是叠加层的宽高。

旋转(transpose)

bash
# 顺时针 90 度 ffmpeg -i input.mp4 -vf "transpose=1" output.mp4 # 逆时针 90 度 ffmpeg -i input.mp4 -vf "transpose=2" output.mp4 # 180 度(两次 90 度) ffmpeg -i input.mp4 -vf "transpose=1,transpose=1" output.mp4 # 水平翻转(镜像) ffmpeg -i input.mp4 -vf "hflip" output.mp4

旋转后分辨率会变(1080x1920 变 1920x1080),如果编码器有分辨率限制需要注意。

文字水印(drawtext)

bash
# 静态文字 ffmpeg -i input.mp4 -vf "drawtext=text='Hello':fontcolor=white:fontsize=24:x=10:y=10" output.mp3 # 带阴影的文字(提高可读性) ffmpeg -i input.mp4 -vf "drawtext=text='Hello':fontcolor=white:fontsize=32:x=10:y=10:shadowcolor=black:shadowx=2:shadowy=2" output.mp4 # 显示时间戳 ffmpeg -i input.mp4 -vf "drawtext=text='%{pts\:hms}':fontcolor=white:fontsize=20:x=10:y=10" output.mp4

drawtext 需要编译时启用 libfreetype。如果报 "Unknown filter 'drawtext'",说明你的 FFmpeg 没有这个支持。

模糊和锐化

bash
# 高斯模糊 ffmpeg -i input.mp4 -vf "gblur=sigma=2" output.mp4 # 锐化 ffmpeg -i input.mp4 -vf "unsharp=5:5:1.0" output.mp4

模糊常用于背景虚化或隐私遮挡,锐化常用于低分辨率素材的提升(但过度锐化会产生光晕伪影)。

音频滤镜

音频滤镜用 -af,语法和视频一样:

bash
# 音量调整 ffmpeg -i input.mp4 -af "volume=2.0" output.mp4 # 淡入淡出 ffmpeg -i input.mp4 -af "afade=t=in:st=0:d=3" output.mp4 # 混合两路音频 ffmpeg -i voice.mp3 -i bgm.mp3 -filter_complex "amix=inputs=2:duration=first" output.mp3 # 延迟 ffmpeg -i input.mp4 -af "adelay=500|500" output.mp4

音频滤镜的详细用法参见"FFmpeg 音频处理"一文。

组合滤镜实战

四宫格

bash
ffmpeg -i v1.mp4 -i v2.mp4 -i v3.mp4 -i v4.mp4 -filter_complex "[0:v]scale=640:360[v0];[1:v]scale=640:360[v1];[2:v]scale=640:360[v2];[3:v]scale=640:360[v3]; [v0][v1]hstack[top];[v2][v3]hstack[bottom];[top][bottom]vstack" output.mp4

hstack 水平拼接,vstack 垂直拼接。所有输入的分辨率必须一致。

视频变速

bash
# 2 倍速 ffmpeg -i input.mp4 -filter_complex "[0:v]setpts=0.5*PTS[v];[0:a]atempo=2.0[a]" -map "[v]" -map "[a]" output.mp4 # 0.5 倍速 ffmpeg -i input.mp4 -filter_complex "[0:v]setpts=2.0*PTS[v];[0:a]atempo=0.5[a]" -map "[v]" -map "[a]" output.mp4

视频用 setpts 调速(乘以系数),音频用 atempo。atempo 范围 0.5-2.0,超出要链式:atempo=2.0,atempo=2.0 达到 4 倍速。

bash
ffmpeg -i input.mp4 -i logo.png -filter_complex "[0:v]drawtext=text='%{pts\:hms}':fontcolor=white:fontsize=20:x=10:y=10[vt]; [vt][1:v]overlay=W-w-10:10" -af "afade=t=in:st=0:d=2" output.mp4

性能提示

滤镜是 CPU 密集操作,优化思路:

  • 滤镜顺序:先 crop 再 scale,减少处理的像素量
  • GPU 滤镜:NVIDIA 用 scale_npp 替代 scalehwupload_cuda 后在 GPU 上做滤镜
  • 避免不必要的滤镜:每个滤镜都增加一帧的处理时间,去掉不必要的
  • 预览时降低分辨率:调参时加 scale=640:360 加快迭代,确认效果后再用原始分辨率输出
标签:FFmpeg