服务端阅读 06月4日 13:52
FFmpeg Filter语法详解:缩放、裁剪、叠加和组合滤镜
FFmpeg 的 Filter 是它区别于其他转码工具的核心能力——不只是格式转换,而是对画面的像素、音频的采样点做任意变换。但 Filter 的语法是出了名的难读:方括号标签、分号逗号混用、多个输入输出的管线。这篇文章先把语法规则讲透,再按场景列举常用滤镜。Filter 语法:三分钟搞懂简单滤镜 vs 复杂滤镜-vf "滤镜链":简单视频滤镜,单个输入,单个输出-af "滤镜链":简单音频滤镜,同上-filter_complex "滤镜图":复杂滤镜,可以有多个输入输出、分支和合并能用 -vf/-af 解决的,不要用 -filter_complex——简单滤镜更快更不容易出错。语法规则# 逗号:串联同一链的滤镜,前一个的输出是后一个的输入-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] 是自定义标签,后续滤镜用这个标签引用。最常见的语法错误# 错误:简单滤镜里用了分号-vf "scale=1280:720;crop=640:360" # 报错# 正确:简单滤镜用逗号-vf "scale=1280:720,crop=640:360" # OK视频滤镜缩放(scale)# 固定分辨率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)# 从中心裁剪 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.mp4cropdetect 是调优利器——先跑一遍检测黑边参数,再用 crop 裁掉。叠加(overlay)给视频加 logo、画中画都用 overlay:# 左上角加 logoffmpeg -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.mp4overlay 的坐标用 x:y 格式,支持表达式。W 和 H 是主视频的宽高,w 和 h 是叠加层的宽高。旋转(transpose)# 顺时针 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)# 静态文字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.mp4drawtext 需要编译时启用 libfreetype。如果报 "Unknown filter 'drawtext'",说明你的 FFmpeg 没有这个支持。模糊和锐化# 高斯模糊ffmpeg -i input.mp4 -vf "gblur=sigma=2" output.mp4# 锐化ffmpeg -i input.mp4 -vf "unsharp=5:5:1.0" output.mp4模糊常用于背景虚化或隐私遮挡,锐化常用于低分辨率素材的提升(但过度锐化会产生光晕伪影)。音频滤镜音频滤镜用 -af,语法和视频一样:# 音量调整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 音频处理"一文。组合滤镜实战四宫格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.mp4hstack 水平拼接,vstack 垂直拼接。所有输入的分辨率必须一致。视频变速# 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 倍速。加 logo + 时间戳 + 淡入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 替代 scale,hwupload_cuda 后在 GPU 上做滤镜避免不必要的滤镜:每个滤镜都增加一帧的处理时间,去掉不必要的预览时降低分辨率:调参时加 scale=640:360 加快迭代,确认效果后再用原始分辨率输出