2、基础命令结构:ffmpeg命令格式解析、全局选项、输入文件选项、输出文件选项

说实话,我见过不少刚接触 FFmpeg 的朋友,第一反应就是去网上复制一段命令。跑通了还好,跑不通就完全懵了。其实 FFmpeg 的命令结构非常规整,你只要搞懂它的骨架,剩下的就是往里面填东西而已。

今天我们就来拆开这个骨架看看。说白了,FFmpeg 的命令就一个套路:

ffmpeg [全局选项] [输入文件选项] -i 输入文件 [输出文件选项] 输出文件

嗯,就这么简单。但简单归简单,里面每个部分都有讲究。我一个个说。

2.1 命令格式总览

先看一个最典型的例子:

ffmpeg -y -i input.mp4 -c:v libx264 -b:v 2M output.mp4

这里面:

  • -y 是全局选项,表示覆盖输出文件时不询问
  • -i input.mp4 是输入文件及其选项
  • -c:v libx264 -b:v 2M 是输出文件选项
  • output.mp4 是输出文件路径

你可能会问:为什么全局选项要放在最前面?其实这是 FFmpeg 解析器的习惯——它先处理全局设置,再处理输入,最后处理输出。顺序错了,有时候选项就不生效了。我在项目中就踩过这个坑,把 -y 写在 -i 后面,结果某些旧版本 FFmpeg 直接报错。

核心原则:全局选项 → 输入选项 + -i 输入文件 → 输出选项 + 输出文件。这个顺序不要乱。

2.2 全局选项

全局选项影响的是整个命令的行为,不针对某个具体的流。常用的就这几个:

选项 作用 我的使用频率
-y 覆盖输出文件,不询问 几乎每次都用
-n 不覆盖输出文件,直接退出 偶尔,批量处理时用
-loglevel 控制日志输出级别 调试时必用
-hide_banner 隐藏编译信息、库版本等 脚本中常用,保持输出干净
-stats 显示编码进度统计 默认开启,一般不用管

举个例子,我写自动化脚本时,通常会这样:

ffmpeg -y -hide_banner -loglevel error -i input.mp4 output.mp4

这样只有出错时才打印信息,平时干干净净。你想想看,如果脚本跑几百个文件,日志里全是库版本信息,那得多烦人。

小技巧:调试时用 -loglevel debug,FFmpeg 会把每一步的决策都打印出来。我曾经靠这个定位过一个音频采样率不匹配的问题,省了大半天时间。

2.3 输入文件选项

输入选项写在 -i 前面,告诉 FFmpeg 怎么读取这个文件。常见的场景:

  • 指定输入格式:-f mp4,强制按某种格式解析
  • 选择输入流:-map 0:v:0,只取第一个视频流
  • 设置输入参数:-ss 00:01:00,从第1分钟开始读取
  • 处理输入编码参数:-hwaccel cuda,启用硬件加速解码

看个实际例子:

ffmpeg -ss 00:00:30 -t 10 -i input.mp4 output.mp4

这个命令从第30秒开始,截取10秒的视频。注意 -ss 写在 -i 前面,这叫「快速定位」模式。FFmpeg 会先跳转到指定时间点,再开始解码,速度很快。如果写在 -i 后面,它会从头解码到那个时间点再开始,慢很多。

注意:输入选项只对紧随其后的 -i 生效。如果你有多个输入文件,每个输入都要单独写选项。我曾经犯过这个错,以为写一次就能作用于所有输入,结果第二个输入完全没按预期走。

2.4 输出文件选项

输出选项是最灵活的部分,也是你真正干活的地方。它控制编码器、码率、分辨率、帧率、封装格式等等。

常用的输出选项分组:

类别 选项示例 说明
视频编码器 -c:v libx264 指定视频编码器
音频编码器 -c:a aac 指定音频编码器
视频码率 -b:v 1M 目标视频码率
音频码率 -b:a 128k 目标音频码率
分辨率 -s 1920x1080 缩放输出分辨率
帧率 -r 30 输出帧率
封装格式 -f mp4 强制输出格式

一个完整的例子:

ffmpeg -i input.mp4 -c:v libx264 -b:v 2M -c:a aac -b:a 128k -s 1280x720 -r 30 output.mp4

这个命令把输入视频转成 H.264 + AAC,码率分别是 2Mbps 和 128kbps,分辨率缩到 720p,帧率 30fps。很典型的转码场景。

我的习惯:输出选项我一般按「视频编码→视频参数→音频编码→音频参数→其他参数」的顺序写。这样别人看你的命令,一眼就能找到关键信息。团队协作时,这个习惯特别有用。

2.5 知识结构图

下面这张图把 FFmpeg 命令的骨架画出来了。你以后写命令时,就照着这个结构填空:

FFmpeg 命令结构图 FFmpeg 命令结构 ffmpeg [全局选项] [输入选项] -i 输入文件 [输出选项] 输出文件 全局选项 输入选项 输出选项 全局选项示例 -y 覆盖输出文件 -n 不覆盖输出文件 -loglevel 日志级别 -hide_banner 隐藏版本 -stats 显示进度 影响整个命令的行为 输入选项示例 -ss 00:01:00 跳转到1分 -t 10 只读10秒 -f mp4 强制格式 -map 0:v 选择视频流 -hwaccel cuda 硬件解码 写在 -i 前面,只对当前输入生效 输出选项示例 -c:v libx264 视频编码器 -b:v 2M 视频码率 -c:a aac 音频编码器 -s 1280x720 分辨率 -r 30 帧率 写在输出文件前,控制编码行为

2.6 多输入多输出

FFmpeg 支持多个输入和多个输出,这在处理复杂任务时特别有用。比如合并视频和音频:

ffmpeg -i video.mp4 -i audio.mp3 -c:v copy -c:a aac output.mp4

这里两个 -i,第一个是视频,第二个是音频。输出选项 -c:v copy -c:a aac 同时作用于输出文件。

再看一个多输出的例子:

ffmpeg -i input.mp4 \
  -c:v libx264 -b:v 1M output_1M.mp4 \
  -c:v libx264 -b:v 2M output_2M.mp4 \
  -c:v libx264 -b:v 4M output_4M.mp4

这个命令一次生成三个不同码率的版本。我经常在给客户准备多码率素材时这么干,一条命令搞定,省得反复跑。

注意:多输出时,每个输出文件前面都要写完整的输出选项。不要想着「共用选项」,FFmpeg 不会帮你继承。我曾经偷懒少写了一组参数,结果第三个输出用了默认编码器,文件大了一倍。

2.7 流映射基础

默认情况下,FFmpeg 会从每个输入中选择「最好的」一个视频流和一个音频流。但有时候你需要手动指定。这时候就用 -map:

ffmpeg -i input.mp4 -map 0:v:0 -map 0:a:1 -c copy output.mp4

这个命令只取第一个视频流和第二个音频流。为什么会有这种需求?我遇到过一种情况:一个视频文件里有两条音轨,一条是中文,一条是英文。客户只要英文的,那就用 -map 0:a:1 精确选择。

流映射的格式是 输入索引:流类型:流索引。输入索引从0开始,流类型是 v(视频)、a(音频)、s(字幕)。

小技巧:先用 ffprobe input.mp4 查看文件里的流信息,确认每个流的索引,再写 -map。我每次处理不熟悉的文件都会先跑一下 ffprobe,避免选错流。

2.8 总结一下

FFmpeg 的命令结构其实就一句话:全局选项管全局,输入选项管读取,输出选项管编码。你只要记住这个顺序,剩下的就是查参数、填参数的事。

我个人建议,刚开始不要背参数,而是理解结构。结构对了,参数可以随时查。我到现在也经常翻文档,但命令的骨架从来没变过。