FFmpeg基础回顾:命令行结构、滤镜语法、常用滤镜介绍
在深入滤镜链调试之前,必须先牢固掌握FFmpeg的命令行骨架与滤镜图(filtergraph)的构造规则。调试滤镜链时,绝大多数报错都源于命令行解析顺序、滤镜参数类型或链接端点不匹配。本节将系统梳理FFmpeg命令行的分区结构、滤镜链的文本语法,并介绍调试中最常打交道的几类基础滤镜。
2.1 命令行结构:五个分区
一条完整的FFmpeg命令可以拆解为五个顺序固定的分区,任何参数放错位置都会导致“Option not found”或“Unable to find a suitable output format”之类的错误。五个分区如下:
ffmpeg [全局选项] [输入选项] -i 输入文件 [输出选项] 输出文件
其中,滤镜链属于输出选项的一部分,它通过 -vf(视频滤镜)或 -af(音频滤镜)挂载在输出文件之前。下面用一个实际命令说明分区:
ffmpeg -y -threads 4 -i input.mp4 -vf "scale=640:360,format=yuv420p" -c:v libx264 -b:v 800k output.mp4
- 全局选项:
-y(覆盖输出)、-threads 4,位于最前。 - 输入选项:在
-i之前,如-ss 10(从第10秒开始读取)。 - 输入文件:
-i input.mp4。 - 输出选项:
-vf、-c:v、-b:v,位于输出文件之前。 - 输出文件:
output.mp4。
-vf 是否写在了输出文件之前。若误将 -vf 放在 -i 之前,FFmpeg会将其视为输入选项,导致“Filtergraph '...' was specified for input file but is not supported”的错误。
2.2 滤镜语法:链、图与参数
FFmpeg的滤镜系统采用文本描述图结构。理解三个层级是调试的基础:
- 滤镜(filter):最小处理单元,如
scale、trim。 - 滤镜链(filterchain):用逗号
,分隔的多个滤镜,前一个的输出作为后一个的输入,形成串行流水线。 - 滤镜图(filtergraph):用分号
;分隔的多条链,可形成并行或分支结构。分号表示“前一条链已结束,开始新链”。
参数书写有两种形式:
# 简写形式(位置参数)
scale=640:360
# 全称形式(键值对)
scale=w=640:h=360:force_original_aspect_ratio=1
当滤镜需要多个输入或多个输出时,必须使用 split、merge 等滤镜,并通过 [标签] 命名流。例如将视频缩放后同时输出原色和灰度版本:
ffmpeg -i input.mp4 -vf "split=2[original][copy];[copy]hue=s=0[gray];[original][gray]hstack" output.mp4
这条命令中,split 将输入复制为两路,分别打上标签 [original] 和 [copy];[copy] 经过 hue=s=0 去饱和变成灰度;最后 hstack 将两路并排拼接。分号分隔了三条链,标签则完成了流的重定向。
split=2[original][copy];[copy]hue=s=0[gray] 中的分号误写成逗号,FFmpeg会尝试将 split 的输出直接送给 hue,但 split 有两个输出,而 hue 只接受一个输入,于是报错“Filter hue has an unconnected output”。
2.3 常用滤镜速查
调试滤镜链时,以下滤镜出现频率最高,它们的参数错误也是报错重灾区。下表列出滤镜名称、核心参数与典型用途:
| 滤镜 | 核心参数 | 典型用途 | 调试常见报错 |
|---|---|---|---|
scale |
w, h |
分辨率缩放 | 宽度或高度为0(需用 -1 保持宽高比) |
trim |
start, end, duration |
时间裁剪 | 时间单位混淆(秒 vs 微秒) |
format |
pix_fmts |
像素格式转换 | 指定了不存在的格式名 |
fps |
fps |
帧率转换 | 输出帧率写为小数但未加引号 |
hue |
h, s |
色调/饱和度调节 | 参数范围越界(饱和度应为0~2) |
overlay |
x, y |
画面叠加 | 主、副输入顺序颠倒 |
null |
无 | 调试占位,丢弃输出 | 无(用于测试滤镜链是否通畅) |
其中 trim 的时间单位是微秒(1秒=1,000,000微秒),而 -ss 选项的单位是秒。若在滤镜内写 trim=start=5,实际裁剪的是第5微秒,几乎等于没裁。正确写法是 trim=start=5*1000000 或使用 start=5/TB 表达式。
2.4 滤镜图可视化:从文本到结构
调试复杂滤镜图时,仅靠阅读文本难以发现连接错误。下面这张SVG图展示了本节开头 split+hue+hstack 示例的完整数据流结构,标注了每个端点的标签与数据格式变化:
从图中可以清晰看到:split 产生两个输出端点,分别标记为 [original] 和 [copy];[copy] 进入 hue 后输出 [gray];最后 hstack 接收 [original] 与 [gray] 两个输入。若调试时看到“Filter hstack has an unconnected input”,说明某个标签没有正确传递到 hstack 的输入端。
2.5 调试方法论:从报错到定位
当滤镜链执行失败时,建议按以下顺序排查:
- 检查分隔符:确认逗号与分号的使用是否符合预期逻辑。将长链拆成多段,逐段用
null滤镜测试。 - 验证标签匹配:用
[标签]时,确保每个标签在分号后的链中都有对应的输入引用。FFmpeg不会自动补全未连接的输入。 - 确认参数类型:查看滤镜文档(
ffmpeg -h filter=scale),确认参数是整数、浮点还是布尔值。例如hue=s=0中的s是浮点,而hstack不接受任何参数。 - 使用
-v debug:在命令前加-v debug,FFmpeg会输出每个滤镜的初始化信息,包括输入输出协商的格式与尺寸。 - 分段输出中间结果:在怀疑出错的滤镜后插入
null或直接输出到临时文件,例如-vf "split=2[tmp];[tmp]null" -f null -,验证前段是否正常。
-vf "scale=640:-1,trim=start=10" 报错“Cannot find a matching stream for unlabeled input pad 0 on filter trim”。原因是 trim 的 start 参数被解析为帧号而非时间戳,且 scale 输出格式与 trim 期望的输入格式不匹配。解决方法是显式指定 trim=start=10*1000000,并在 scale 后添加 format=yuv420p 保证格式一致。