3. FFmpeg 命令行基础:三大工具与核心参数
说实话,很多初学者一上来就问我:“FFmpeg 到底怎么用?” 我的回答永远是:先把三个工具搞清楚——ffmpeg、ffprobe、ffplay。它们就像瑞士军刀的三把主刃,各管一摊,但配合起来能解决 90% 的日常问题。
我个人习惯把这三兄弟比作:厨师、质检员和试吃员。ffmpeg 负责加工处理,ffprobe 负责检查原料成分,ffplay 负责快速预览成品。你想想看,如果连工具分工都不清楚,后面那些复杂的封装解析工作根本没法下手。
核心观点: 学 FFmpeg 命令行,先别急着背参数。先把三个工具的定位刻在脑子里——ffmpeg 是主力处理工具,ffprobe 是分析诊断工具,ffplay 是快速预览工具。
3.1 三大工具的分工与定位
咱们一个一个说。
3.1.1 ffmpeg:主力处理工具
这是最核心的。转格式、裁剪、拼接、滤镜、封装解封装…… 几乎所有操作都靠它。我在项目中遇到过最典型的场景:客户给了一个 TS 流,要求转成 MP4 并保留所有字幕轨道。没有 ffmpeg,这活根本没法干。
基本调用方式很简单:
ffmpeg [全局参数] [输入参数] -i 输入文件 [输出参数] 输出文件
嗯,这里要注意:参数顺序是有讲究的。写在 -i 前面的是输入参数,只对当前输入生效;写在 -i 后面、下一个 -i 前面的是输出参数。我见过太多人把参数放错位置,结果死活不出想要的效果。
3.1.2 ffprobe:分析诊断工具
这个工具很多人低估了。说白了,它就是多媒体文件的“CT 机”。能告诉你文件里有多少流、编码格式是什么、码率多少、关键帧间隔多长…… 所有元数据一览无余。
我记得有一次排查一个直播推流卡顿问题,就是靠 ffprobe 发现推流端的关键帧间隔设置成了 10 秒,导致拉流端首屏加载慢得离谱。
最常用的命令:
ffprobe -v quiet -print_format json -show_format -show_streams input.mp4
输出 JSON 格式,方便程序解析。我个人习惯先跑这条命令,看看文件“底细”再动手处理。
3.1.3 ffplay:快速预览工具
这个更简单——就是一个基于 FFmpeg 的播放器。但它比普通播放器强在哪?能直接看原始流。比如你想看某个视频的原始 YUV 数据,或者单独听某个音频轨道,ffplay 都能干。
我曾经用它来调试一个 H.264 码流问题:
ffplay -v debug -i input.h264
加上 -v debug 能看到解码过程中的详细信息,对排查编码参数问题特别有用。
小技巧: 用 ffplay -f lavfi -i "color=c=red:size=1280x720:d=5" 可以生成一个纯色测试画面,调试显示设备时特别好用。
3.2 核心参数详解
参数很多,但真正高频使用的就四个:-i、-c、-f、-map。把这四个吃透,基本就能应付 80% 的工作了。
3.2.1 -i:指定输入文件
这个最简单,但也最容易踩坑。-i 后面跟的是输入文件路径。但注意:FFmpeg 支持多个输入。比如你要拼接两个视频:
ffmpeg -i input1.mp4 -i input2.mp4 -filter_complex "[0:v][0:a][1:v][1:a]concat=n=2:v=1:a=1" output.mp4
这里两个 -i 分别指定了两个输入文件。我曾经在项目里同时处理过 8 个输入流,参数顺序一旦搞错,后面的 -map 就全乱了。
3.2.2 -c:指定编解码器
-c 是 -codec 的缩写,用来指定用哪个编解码器处理流。-c:v 指定视频编解码器,-c:a 指定音频,-c:s 指定字幕。
最常用的场景是“复制流”而不重新编码:
ffmpeg -i input.mp4 -c:v copy -c:a copy output.ts
这里 copy 是个特殊值,意思是“直接复制,不重新编码”。速度极快,而且画质无损。我在做封装格式转换时几乎必用这个参数。
如果要重新编码,就指定具体的编码器名称:
ffmpeg -i input.mp4 -c:v libx264 -c:a aac output.mp4
注意: -c:v copy 虽然快,但并不是所有格式都支持直接复制。比如把 H.264 视频复制到 MP4 没问题,但复制到某些老旧的 AVI 容器就可能失败。原因在于容器格式对编码数据的组织方式有要求。
3.2.3 -f:强制指定格式
-f 用来强制指定输入或输出的封装格式。正常情况下 FFmpeg 会根据文件扩展名自动判断格式,但有时候需要手动指定。
我遇到过最典型的场景:从标准输入读取裸 H.264 流:
cat stream.h264 | ffmpeg -f h264 -i - -c:v copy output.mp4
这里 -f h264 告诉 FFmpeg:输入是裸 H.264 流,别猜了。如果不加这个参数,FFmpeg 会尝试从文件头判断格式,但管道输入没有文件头,就会报错。
输出时也常用:
ffmpeg -i input.mp4 -f flv output.flv
虽然扩展名已经暗示了格式,但显式指定 -f flv 可以避免某些边界情况下的格式误判。
3.2.4 -map:精确选择流
这个参数是很多人的噩梦,但一旦搞懂,你会爱上它。-map 用来精确控制哪些输入流进入输出文件。
默认情况下,FFmpeg 会从每个输入文件里选“最好”的一个视频流、一个音频流和一个字幕流。但实际需求往往更复杂。比如:
ffmpeg -i input.mp4 -map 0:v:0 -map 0:a:2 -c copy output.mp4
这里 0:v:0 的意思是:第一个输入文件的第一个视频流。0:a:2 是第一个输入文件的第三个音频流(索引从 0 开始)。
我曾经处理过一个多语言视频:
ffmpeg -i input.mp4 -map 0:v -map 0:a:0 -map 0:a:1 -c copy output.mp4
这样输出文件里包含视频流、英语音轨和法语音轨,完美保留多语言。
记住这个公式: -map 输入文件索引:流类型:流索引。流类型:v 视频、a 音频、s 字幕、d 数据。
3.3 知识体系总览
下面这张图把三大工具和四个核心参数的关系梳理清楚了。我建议你把它存下来,以后遇到命令行问题先回来看看这张图。
3.4 参数组合实战
光说不练假把式。咱们看几个真实场景下的参数组合。
场景一:MP4 转 TS 并保持编码不变
ffmpeg -i input.mp4 -c:v copy -c:a copy -f mpegts output.ts
这里 -c:v copy -c:a copy 保证不重新编码,-f mpegts 强制输出 TS 格式。速度极快,适合在封装格式之间切换。
场景二:提取视频中的某个音频轨道
ffmpeg -i input.mp4 -map 0:a:1 -c:a copy audio.aac
只提取第二个音频轨道(索引 1),直接复制编码,不重新压缩。
场景三:查看文件详细信息
ffprobe -v quiet -print_format json -show_format -show_streams input.mp4 | jq .
配合 jq 工具格式化输出,一目了然。我每次拿到陌生文件第一件事就是跑这条命令。
调试利器: 如果某个命令没达到预期效果,先加 -v debug 看看 FFmpeg 内部是怎么处理的。它会打印出每一步的决策过程,比如“选择了哪个流”、“用了什么编码器”。
3.5 常见误区与避坑
- 参数顺序搞反: 输入参数必须写在
-i前面,输出参数写在-i后面。我曾经见过有人把-c:v copy写在-i前面,结果 FFmpeg 把它当成了输入参数,直接忽略。 - 滥用 -c copy: 不是所有容器都支持所有编码格式的直接复制。比如把 HEVC 视频复制到 MP4 没问题,但复制到 AVI 就可能失败。先用
ffprobe确认容器兼容性。 - 忽略 -map 的默认行为: 不加
-map时,FFmpeg 会自作主张选“最好”的流。如果你有多个音频轨道,不加-map可能只保留一个。我踩过这个坑,后来养成了显式-map的习惯。 - 管道输入忘记 -f: 从标准输入读取裸流时,必须用
-f指定格式,否则 FFmpeg 无法识别。
重要提醒: 处理重要文件前,先用 ffprobe 摸清文件底细。我见过太多人直接上手转码,结果发现源文件有问题,白白浪费时间。先分析,再动手——这是专业工程师的习惯。
好了,三大工具和四个核心参数就讲到这里。这些是 FFmpeg 命令行的基石,后面的章节会反复用到。你可以在自己的机器上多敲几遍,感受一下参数变化带来的效果差异。实践出真知,命令行这东西,敲多了自然就熟了。