19、FFmpeg命令行工具:常用命令参数解析、批量处理脚本、自定义滤镜链

说实话,FFmpeg 这玩意儿,我用了快十年了。每次接手新项目,第一件事就是拿它探路——看看视频是什么编码、音频什么格式、有没有隐藏流。它就像音视频开发者的瑞士军刀,啥都能干。

这一章,咱们就聊聊 FFmpeg 的命令行。别小看它,很多高级功能其实都是命令行参数的组合。我个人习惯把常用命令记在一个小本本上,省得每次都要翻文档。

19.1 核心命令参数解析

先说说最常用的几个参数。你想想看,FFmpeg 的命令结构其实很简单:

ffmpeg [全局参数] [输入文件参数] -i 输入文件 [输出文件参数] 输出文件

就这么个套路。但里面的门道可不少。

19.1.1 常用全局参数

参数 说明 示例
-y 覆盖输出文件,不询问 ffmpeg -y -i input.mp4 output.avi
-n 不覆盖输出文件 ffmpeg -n -i input.mp4 output.avi
-loglevel 设置日志级别 ffmpeg -loglevel debug -i input.mp4 ...
-hide_banner 隐藏编译信息 ffmpeg -hide_banner -i input.mp4 ...

我记得刚入行那会儿,有个同事在服务器上跑 FFmpeg,日志刷了满屏,把监控系统都搞报警了。后来我告诉他加个 -loglevel error,世界清净了。嗯,这里要注意,调试的时候别加,否则看不到错误信息。

19.1.2 视频参数

参数 说明 示例
-c:v 指定视频编码器 -c:v libx264
-b:v 设置视频码率 -b:v 2M
-r 设置帧率 -r 30
-s 设置分辨率 -s 1920x1080
-vf 视频滤镜链 -vf "scale=1280:720"

这里有个坑,我踩过好几次。码率设置 -b:v 2M 这个 M 是大写,小写 m 会被当成毫比特。曾经有个项目,我写成了 -b:v 2m,结果出来的视频糊得没法看,排查了半天才发现是单位写错了。

19.1.3 音频参数

参数 说明 示例
-c:a 指定音频编码器 -c:a aac
-b:a 设置音频码率 -b:a 128k
-ar 设置采样率 -ar 44100
-ac 设置声道数 -ac 2
我的小习惯:转码时我一般先不加音频参数,用默认的。等视频画面没问题了,再单独调音频。这样出了问题好定位。

19.2 批量处理脚本

实际工作中,很少只处理一个文件。我经常要处理几百个视频,这时候就得写脚本了。

19.2.1 Shell 脚本批量转码

#!/bin/bash
# 批量转码脚本:将当前目录下所有 .mov 转为 .mp4

for file in *.mov; do
    filename=$(basename "$file" .mov)
    ffmpeg -i "$file" -c:v libx264 -c:a aac -b:v 2M "${filename}.mp4"
    echo "已处理: $file"
done

这个脚本看着简单,但有个细节——文件名里有空格怎么办?我建议用双引号把变量包起来,就像上面那样。曾经有个同事没加引号,结果文件名带空格的视频全都没转成功,还报了一堆莫名其妙的错。

19.2.2 带参数校验的脚本

#!/bin/bash
# 带参数校验的批量处理脚本

if [ $# -lt 2 ]; then
    echo "用法: $0 <输入目录> <输出目录> [码率]"
    exit 1
fi

input_dir="$1"
output_dir="$2"
bitrate="${3:-2M}"

mkdir -p "$output_dir"

for file in "$input_dir"/*.mp4; do
    if [ -f "$file" ]; then
        filename=$(basename "$file")
        ffmpeg -i "$file" -b:v "$bitrate" -y "$output_dir/$filename"
    fi
done

echo "批量处理完成!"
注意:批量处理前,一定要先拿一个文件测试。我曾经一次性处理了 200 个视频,结果参数设错了,全部重来,浪费了大半天。

19.3 自定义滤镜链

滤镜链是 FFmpeg 最强大的功能之一。说白了,就是把多个滤镜串起来,像流水线一样处理视频。

19.3.1 滤镜链的基本语法

ffmpeg -i input.mp4 -vf "filter1=param1=value1,filter2=param2=value2" output.mp4

滤镜之间用逗号分隔,按顺序执行。我刚开始学的时候,老是把分号和逗号搞混。记住:逗号是串联,分号是并联。

19.3.2 常用滤镜组合

这里分享几个我项目中常用的滤镜链:

# 缩放+裁剪+添加文字水印
ffmpeg -i input.mp4 -vf "scale=1280:720,crop=1200:680:40:20,drawtext=text='Hello':fontsize=24:fontcolor=white:x=10:y=10" output.mp4

# 去噪+调色+变速
ffmpeg -i input.mp4 -vf "hqdn3d=4:3:6:4,eq=brightness=0.1:contrast=1.2,setpts=0.8*PTS" output.mp4

# 画中画效果
ffmpeg -i main.mp4 -i overlay.mp4 -filter_complex "[0:v][1:v]overlay=10:10" output.mp4

我记得有个项目要做画中画,客户要求小窗口能拖动。我折腾了半天,最后发现 FFmpeg 的 overlay 滤镜支持动态位置,用 overlay=x='if(gte(t,2),100,10)':y=10 就能实现两秒后自动移动。嗯,这个技巧后来成了我的保留节目。

19.3.3 复杂滤镜图

当滤镜链变得复杂时,可以用 -filter_complex 参数。它支持更灵活的分流和合并:

ffmpeg -i input.mp4 -filter_complex \
"[0:v]split[base][overlay]; \
 [base]scale=1280:720[bg]; \
 [overlay]scale=320:240[small]; \
 [bg][small]overlay=W-w-10:H-h-10" \
output.mp4

这个例子把视频分成两路,一路做背景,一路缩小后叠加到右下角。你想想看,这种效果在直播推流、视频会议里特别常见。

核心要点:滤镜链的命名规则是 [输入标签]滤镜名=参数[输出标签]。标签可以自定义,方便后续引用。我习惯用 v0、v1、v2 这样的命名,简单好记。

19.4 知识体系图

下面这张图,是我整理的本章知识结构。你可以把它当成一个快速索引:

FFmpeg 命令行工具知识体系 命令参数解析 批量处理脚本 自定义滤镜链 全局参数:-y, -n, -loglevel 视频参数:-c:v, -b:v, -r, -s 音频参数:-c:a, -b:a, -ar, -ac Shell 循环批量转码 参数校验与错误处理 目录遍历与输出管理 滤镜串联:逗号分隔 常用组合:缩放/水印/去噪 复杂滤镜图:-filter_complex 实战要点:先测试 → 再批量 → 最后优化参数 三个模块相互独立,但实际项目中往往需要组合使用

19.5 避坑指南与实战经验

最后,分享几个我这些年踩过的坑:

  • 路径问题:Windows 下路径用反斜杠,但 FFmpeg 里最好用正斜杠或者双反斜杠。我曾经在 Windows 上写脚本,路径里用了单反斜杠,结果 FFmpeg 把它当成了转义符。
  • 编码器选择:不是所有编码器都支持所有参数。比如 libx264 支持 -preset-crf,但硬件编码器 h264_nvenc 就不支持 -crf。我建议先 ffmpeg -encoders | grep 264 看看有哪些可用。
  • 滤镜顺序:滤镜的执行顺序会影响最终效果。比如先缩放再裁剪,和先裁剪再缩放,结果完全不同。我一般先做几何变换(缩放、裁剪),再做色彩调整,最后加文字水印。
  • 内存管理:处理 4K 视频时,滤镜链可能会消耗大量内存。如果遇到内存不足,可以试试 -threads 4 限制线程数,或者用 -vf "scale=1920:1080" 先降低分辨率。
我的调试技巧:遇到滤镜效果不对时,我会先用 -vf "null" 看看原始画面,然后逐个添加滤镜,每加一个就输出一帧看看效果。这样能快速定位是哪个滤镜出了问题。

好了,这一章的内容就到这里。FFmpeg 命令行工具看着简单,但真正用好它,需要大量的实践和踩坑。我建议你找个视频文件,把上面这些命令都跑一遍,感受一下参数变化带来的效果差异。只有亲手试过,才能真正理解。


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