3、命令行基础:ffmpeg命令结构、全局选项与流选项、输入输出文件指定、常用参数速查

说实话,很多人学FFmpeg第一步就卡在命令行上。我见过不少同事,拿着网上抄来的一长串命令,跑通了就欢呼,跑不通就抓瞎。其实FFmpeg的命令行结构非常清晰,你只要搞懂它的骨架,剩下的就是往上面填参数而已。

这一章,我就带你把这个骨架彻底拆开看一遍。

3.1 命令的骨架:ffmpeg到底在干什么?

先看一个最典型的命令:

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

这个命令的结构,说白了就是三部分:

  • ffmpeg —— 调用程序本身
  • 全局选项 + 输入文件 —— 告诉它从哪读、怎么读
  • 输出选项 + 输出文件 —— 告诉它往哪写、怎么写

嗯,这里要注意:输入文件必须紧跟 -i 参数,输出文件放在最后。顺序错了,FFmpeg会直接报错。我在项目中遇到过好几次,同事把输出文件写在了中间,结果FFmpeg把它当成了输入文件,然后一脸懵地告诉你“找不到这个文件”。

核心公式:

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

记住这个顺序,你就能看懂90%的FFmpeg命令。

3.2 全局选项 vs 流选项:别搞混了

很多新手分不清全局选项和流选项的区别。我打个比方:全局选项就像你给整个厨房下的指令,比如“今天做中餐”;流选项则是针对每个灶台的具体要求,比如“一号灶台做红烧肉,二号灶台做清蒸鱼”。

常见的全局选项有这些:

选项 作用 我的经验
-y 覆盖输出文件,不询问 脚本里必加,否则卡住
-n 不覆盖,直接跳过 批量处理时防止误覆盖
-loglevel 控制日志输出级别 调试用 debug,生产用 error
-stats 显示编码进度 默认开启,关掉用 -nostats

流选项则更细,它要指定作用于哪一路流。比如:

ffmpeg -i input.mp4 -c:v libx264 -c:a aac output.mp4

这里的 -c:v 只作用于视频流,-c:a 只作用于音频流。你想想看,如果我想让视频用H.264、音频用AAC、字幕保持原样,就得分别指定。

小技巧: 用 -c copy 可以“透传”某个流,不做任何编解码。我经常用这个来快速分离音视频,速度极快。

3.3 输入输出文件:你指定对了吗?

输入文件用 -i 指定,这个大家都知道。但有几个坑,我踩过不止一次。

第一个坑:多个输入文件。 比如你要把视频和音频合并:

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

这里有两个 -i,FFmpeg会按顺序给它们编号:0:0 是第一个文件的视频流,1:0 是第二个文件的音频流。如果你搞混了顺序,出来的画面和声音就对不上。

第二个坑:输出文件格式。 FFmpeg会根据文件扩展名自动判断封装格式。你写 .mp4 它就封装成MP4,写 .mkv 就封装成MKV。但如果你写错了扩展名,比如明明是H.264视频却给了 .avi,FFmpeg会尝试用AVI容器去装,结果往往不兼容。

我曾经有一次,批量转码时脚本里写死了 .mp4,结果有个源文件是HEVC的,转出来播放器死活打不开。后来才发现,HEVC用MP4容器没问题,但我的播放器版本太老……嗯,从那以后我养成了先查兼容性的习惯。

3.4 常用参数速查:一张表搞定

下面这张表,是我自己整理的高频参数。你把它存下来,写命令时直接翻,比去查文档快得多。

分类 参数 说明 示例
视频编码 -c:v libx264 H.264软件编码 最通用,兼容性最好
-c:v libx265 H.265/HEVC编码 压缩率更高,但编码慢
-c:v h264_nvenc NVIDIA硬件编码 速度快,画质略差
音频编码 -c:a aac AAC音频编码 MP4标配
-c:a libmp3lame MP3编码 老格式,但仍有需求
码率控制 -b:v 2M 视频目标码率 2Mbps,适合1080p
-b:a 128k 音频目标码率 128kbps,音质不错
-crf 23 质量恒定模式 数值越小质量越高,18-28常用
分辨率 -s 1920x1080 强制缩放 注意保持宽高比
-vf scale=1280:720 滤镜缩放 更灵活,可配合其他滤镜
帧率 -r 30 输出帧率 会丢帧或插帧
-vsync cfr 恒定帧率模式 直播推流常用

注意: -crf 和 -b:v 不要同时使用。CRF是质量优先,码率是大小优先,两者会打架。我见过有人两个都写上,结果FFmpeg以最后一个为准,前面的等于白写。

3.5 知识体系:一张SVG图看懂

下面这张图,把FFmpeg命令行的整体结构画出来了。你对照着看,思路会清晰很多。

FFmpeg命令行结构总览 ffmpeg 全局选项 -y, -n, -loglevel, -stats -i 输入文件 input.mp4 / input.mkv 输出选项(流选项) -c:v libx264 -c:a aac -b:v 2M -s 1920x1080 -vf scale=1280:720 -r 30 -crf 23 输出文件 output.mp4 顺序固定:ffmpeg → 全局选项 → -i 输入 → 输出选项 → 输出文件 流选项(-c:v, -c:a, -b:v等)必须放在输出文件之前

3.6 实战:从零写一个完整的命令

光说不练假把式。我们拿一个真实场景来走一遍。

需求: 把一个1080p、30fps的MP4视频,转成720p、25fps的H.264视频,音频转成128kbps的AAC,输出到当前目录。

按照我们刚才学的结构,一步步来:

  1. 全局选项: 加个 -y 防止卡住
  2. 输入文件: -i input.mp4
  3. 输出选项:
    • 视频编码:-c:v libx264
    • 分辨率:-vf scale=1280:720
    • 帧率:-r 25
    • 音频编码:-c:a aac
    • 音频码率:-b:a 128k
  4. 输出文件: output_720p.mp4

组合起来就是:

ffmpeg -y -i input.mp4 -c:v libx264 -vf scale=1280:720 -r 25 -c:a aac -b:a 128k output_720p.mp4

你看,是不是很清晰?我建议你每次写命令前,先在脑子里过一遍这个结构,养成习惯后,再复杂的命令也不会乱。

我的习惯: 写长命令时,我会用反斜杠 \ 换行,每行放一类参数。这样既好读,又方便调试。

ffmpeg -y \
  -i input.mp4 \
  -c:v libx264 \
  -vf scale=1280:720 \
  -r 25 \
  -c:a aac \
  -b:a 128k \
  output_720p.mp4

3.7 避坑指南:我踩过的那些坑

最后,分享几个我实际工作中遇到的坑,你遇到了能少走弯路。

  • 坑1: 忘记加 -y,在脚本里运行时卡住等待用户输入。解决方案:脚本里永远加 -y。
  • 坑2: 多个输入文件时,流索引搞混。解决方案:先用 ffprobe 查看流信息,确认 0:0、1:0 分别是什么。
  • 坑3: -vf 和 -filter_complex 混用。解决方案:简单滤镜用 -vf,复杂多流处理用 -filter_complex,不要混在一个命令里。
  • 坑4: 输出文件路径包含空格。解决方案:用引号包起来,比如 "my video.mp4"。

我曾经有一次,在服务器上跑批量转码,脚本里忘了加引号,结果有个文件名带空格,FFmpeg把它当成了两个参数,直接报错退出。那次跑了三个小时的任务,全废了。嗯,从那以后我写脚本都会检查文件名里有没有空格。