命令行基础:FFmpeg 结构解析与实战技巧

说实话,我见过太多人一上来就甩一串长长的 FFmpeg 命令,跑通了就欢呼,跑不通就抓瞎。其实 FFmpeg 的命令行结构非常清晰,你只要掌握了它的骨架,剩下的就是往里面填参数而已。

这一章,我们就把它拆开揉碎了讲。嗯,我保证不绕弯子。

1. FFmpeg 命令行核心骨架

任何一个 FFmpeg 命令,本质上都长这样:

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

就这么简单。你想想看,左边是输入,右边是输出,中间是各种控制开关。我在项目中带新人时,总让他们先把这行结构默写三遍——真的管用。

核心记忆口诀:「全局在前,输入在中,输出在后,-i 是输入的门牌号」

2. 全局参数:控制整个转码过程的开关

全局参数放在最前面,影响的是整个命令的行为,而不是某个具体的流。我个人习惯把全局参数分成三类:

类别 常用参数 说明
日志控制 -loglevel、-v、-report 控制控制台输出多少信息,调试时必用
覆盖/追加 -y、-n -y 直接覆盖输出文件,-n 拒绝覆盖
基准测试 -benchmark、-benchmark_all 输出转码耗时和 CPU 使用情况

举个例子,调试时我几乎必加这两项:

ffmpeg -y -loglevel debug -i input.mp4 output.avi

-y 省得每次确认覆盖,-loglevel debug 能把每一帧的处理细节都吐出来。我曾经在排查一个音频同步问题时,就是靠 debug 日志发现容器时间基算错了——这种坑,光看报错信息根本看不出来。

我的习惯:写脚本时用 -loglevel error 只显示错误;手工调试时用 -loglevel info 或 debug。别一上来就开 debug,信息量太大反而眼花。

3. 输入文件指定:-i 不是万能的,但没有 -i 是万万不能的

-i 后面跟的就是输入文件路径。但这里有几个细节,我踩过坑才记住的:

  • 路径有空格? 用双引号包起来,比如 -i "my video.mp4"
  • 多个输入文件? 写多个 -i,比如 -i video.mp4 -i audio.mp3
  • 输入是设备或网络流? 照样用 -i,比如 -i rtsp://... 或 -i /dev/video0

还有一个容易被忽略的点:输入参数要放在对应的 -i 前面。比如你想强制把输入当成某种格式:

ffmpeg -f rawvideo -pix_fmt yuv420p -s 1920x1080 -i input.yuv output.mp4

这里的 -f rawvideo、-pix_fmt、-s 都是针对后面那个 -i input.yuv 的输入参数。如果你把它们放到 -i 后面,FFmpeg 会当成输出参数处理——那就全乱套了。

注意:输入参数只对紧随其后的 -i 生效。多个输入文件时,每个输入都可以有自己的参数组。我曾经在拼接多段视频时,因为把输入参数顺序搞反了,结果画面花了一整屏——嗯,从那以后我再也不敢乱放参数位置了。

4. 输出文件指定:你想要的格式,写在最后

输出文件没有 -i,直接写路径就行。FFmpeg 会根据文件扩展名自动猜测封装格式。比如:

  • output.mp4 → MP4 容器
  • output.ts → MPEG-TS 容器
  • output.mkv → Matroska 容器

如果你想强制指定格式,用 -f 参数:

ffmpeg -i input.mp4 -f mpegts output.ts

输出参数放在输出文件前面,比如设置视频码率、分辨率、音频采样率等。这些我们后面几章会详细讲,这里先记住位置就行。

5. 帮助文档查阅技巧:别死记硬背,学会查

FFmpeg 的参数成百上千,没人能全记住。我自己的做法是:记住几个关键的查询命令,剩下的现场查。

你想查什么 命令
所有可用的封装格式 ffmpeg -formats
所有可用的编码器 ffmpeg -encoders
所有可用的解码器 ffmpeg -decoders
某个编码器的详细参数 ffmpeg -h encoder=h264_nvenc
某个封装格式的详细参数 ffmpeg -h muxer=mp4
所有像素格式 ffmpeg -pix_fmts
所有滤镜 ffmpeg -filters

举个例子,我想查 H.264 的软件编码器 libx264 有哪些可调参数:

ffmpeg -h encoder=libx264

输出会列出所有可用选项,包括 crf、preset、profile 等。你想想看,与其去网上搜一篇可能过时的博客,不如直接查官方帮助——这才是最准的。

一个小技巧:用 ffmpeg -h long 可以显示更详细的帮助信息。如果某个参数看不懂,试试 ffmpeg -h full | grep 参数名 来快速定位。

6. 知识体系总览

下面这张图,是我自己整理 FFmpeg 命令行结构时画的。每次写命令前,我都会在脑子里过一遍这个流程:

FFmpeg 命令行结构总览 全局参数 输入参数 -i 输入文件 输出参数 输出文件 💡 多个输入文件? 写多个 -i,每个 -i 前面可以跟各自的输入参数。顺序很重要! 🔍 记不住参数? 用 ffmpeg -h encoder=xxx 或 ffmpeg -h muxer=xxx 现场查,比百度靠谱。

你看,从左到右,从上到下,逻辑非常清晰。全局参数控制整体行为,输入参数告诉 FFmpeg 怎么读,输出参数告诉它怎么写。中间那个 -i 就是分水岭。

7. 实战:一个完整的命令拆解

我们来拆一个真实项目中的命令。这是我去年帮一个客户做视频转码时用的:

ffmpeg -y -loglevel warning \
  -f rawvideo -pix_fmt yuv420p -s 1920x1080 -r 25 -i input.yuv \
  -c:v libx264 -preset medium -crf 23 -c:a aac -b:a 128k \
  output.mp4

拆开看:

  • -y -loglevel warning → 全局参数:覆盖输出,只显示警告和错误
  • -f rawvideo -pix_fmt yuv420p -s 1920x1080 -r 25 → 输入参数:告诉 FFmpeg 输入是原始 YUV 数据,分辨率 1080p,帧率 25
  • -i input.yuv → 输入文件
  • -c:v libx264 -preset medium -crf 23 → 输出参数:视频用 H.264 编码,中等编码速度,CRF 23 质量
  • -c:a aac -b:a 128k → 输出参数:音频用 AAC,码率 128k
  • output.mp4 → 输出文件

我第一次写这种命令时,把 -f rawvideo 放到了 -i 后面,结果 FFmpeg 死活不认——它以为我要把输出也设成 rawvideo。这种错,犯一次就记住了。

避坑指南:我曾经在生产环境遇到过一个问题——忘记加 -y,结果转码脚本在半夜卡住,因为 FFmpeg 在等用户确认是否覆盖文件。从那以后,所有自动化脚本里我都强制加上 -y。

8. 本章小结

这一章我们只讲了一件事:FFmpeg 命令行的骨架。全局参数、输入参数、-i、输出参数、输出文件,顺序不能乱。再加上几个查询帮助的技巧,你就能自己摸索出 90% 的常用命令了。