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 示例的完整数据流结构,标注了每个端点的标签与数据格式变化:

input.mp4 yuv420p, 25fps split=2 复制为两路 [original] [copy] hue=s=0 去饱和度 [gray] hstack 左右拼接 原始彩色帧 灰度帧 输出:宽为两路宽度之和,高不变 → output.mp4 图例 split 分流 hue 处理 hstack 合并

从图中可以清晰看到:split 产生两个输出端点,分别标记为 [original] 和 [copy];[copy] 进入 hue 后输出 [gray];最后 hstack 接收 [original] 与 [gray] 两个输入。若调试时看到“Filter hstack has an unconnected input”,说明某个标签没有正确传递到 hstack 的输入端。

2.5 调试方法论:从报错到定位

当滤镜链执行失败时,建议按以下顺序排查:

  1. 检查分隔符:确认逗号与分号的使用是否符合预期逻辑。将长链拆成多段,逐段用 null 滤镜测试。
  2. 验证标签匹配:用 [标签] 时,确保每个标签在分号后的链中都有对应的输入引用。FFmpeg不会自动补全未连接的输入。
  3. 确认参数类型:查看滤镜文档(ffmpeg -h filter=scale),确认参数是整数、浮点还是布尔值。例如 hue=s=0 中的 s 是浮点,而 hstack 不接受任何参数。
  4. 使用 -v debug:在命令前加 -v debug,FFmpeg会输出每个滤镜的初始化信息,包括输入输出协商的格式与尺寸。
  5. 分段输出中间结果:在怀疑出错的滤镜后插入 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 保证格式一致。