FFmpeg 命令行

【目录ToC】

  1. FFmpeg 命令行
    1. 基础语法与流程
    2. 主要参数
    3. 视频参数
    4. 音频参数
    5. 字幕参数
    6. 其他参数
    7. FFmpeg 实用例子
      1. 合并视频
      2. 分割视频
      3. 批量格式转换
      4. 截图
      5. 静态图水印
      6. GIF 水印
      7. 外挂字幕
      8. 内嵌字幕
    8. 附录:Windows 的 fonts.conf

本文介绍 FFmpeg 的命令行使用。它可以【快速】地完成音视频的处理,包括剪辑、合并、压制、添加ass字幕;更利于批量生产地,它也可以方便地配合其他编程语言。 FFmpeg 官方网站提供免费下载。在下载之前,请打开命令行输入 ffmpeg,以确认本机是否已安装过 ffmpeg(因为它常常作为一个组件被安装,比如 ImageMagick)。 官方文档页:点击这里

FFmpeg 命令行

基础语法与流程

由于是命令行操作,因此语法也是很简单的。各参数以空格分隔。

ffmpeg [gl-opt] {[input-file-opt] -i input-url} ... {[output-file-opt] output-url} ...

其中,-i 参数表示输入参数;之后的参数是输出参数。 ffmpeg 的一般工作流,是从源文件开始,依次经过分流器、解码器、编码器、混流器,最后完成输出文件。下图是官网给出的示意:

 _______              ______________
|       |            |              |
| input |  demuxer   | encoded data |   decoder
| file  | ---------> | packets      | -----+
|_______|            |______________|      |
                                           v
                                       _________
                                      |         |
                                      | decoded |
                                      | frames  |
                                      |_________|
 ________             ______________       |
|        |           |              |      |
| output | <-------- | encoded data | <----+
| file   |   muxer   | packets      |   encoder
|________|           |______________|

一些基本的概念:

  • 流(stream):视频文件中,一般具有视频流与音频流,有的具有字幕流。它们需要不同的解码/编码器。想要混合/分离视频与音频,就需要混流/分流器。
  • 流复制(stream):如果某种数据流的内容不需要任何改动,那么可以直接跳过该数据流的解码与编码步骤。分离出该数据流后,直接等待参与混流即可。

ffmpeg 在有多个流的情况下,不会全部保留;默认只会选择同类流中质量最佳的。如果质量同样,那么选择索引号靠前的流。你可以选择手动控制流的选择,这需要额外的参数,我们下文介绍。

主要参数

下表中:

  1. <> 包裹的表示由用户具体指定;以 [] 包裹的表示是可选参数,可以指定也可以省略。
  2. 括号内的 i 表示该参数用于输入流,o 表示用于输出流,i/o 表示均可,global 表示全局参数。
  3. 关键字 duration, positionoffset 满足:[-][HH:]MM:SS[.m...] 这种时间戳格式。或者以秒为单位的 SS[.m...] 格式。

常用的如下:

  • -b[:stream_specifier] (o):输出比特率。
  • -f <fmt> (i/o):指定 fmt 作为输入或输出的视频格式。一般会根据文件扩展名自动选择,但有时需要手动指定。
  • -i <filename> (i):指定 filename 作为源文件。
  • -y (global):文件存在时直接覆盖。
  • -n (global):文件存在时不覆盖并立即退出。
  • -bsf[:stream_specifier] <bitstream_filters> (o):设置比特流滤镜。bitstream_filters 是一个逗号分隔的滤镜列表。
  • -stream_loop <num> (i):指定输入流的循环次数。0 表示不循环,-1 表示无限循环。
  • -c[:stream_specifier] <codec> (i/o)-c可写为-codec。选择一个 codec ,即编码器(输出时)或一个解码器(输入时),参与到 stream_specifier 指定的一个或多个流的编码/解码中。在输出时,<codec> 可以被指定为 copy,表示复制数据流。
  • -t <duration> (i/o):(在参数 -i 之前指定)工作持续 duration 时长。一般用于指定剪辑数据流的范围。 它与 -to 参数相互冲突,但本参数优先。
  • -to <position> (o):到 position 位置后,终止输出。与 -t 参数冲突,本参数优先级低。
  • -fs <limit_size> (o):输出文件大小达到 limit_size 后停止输出,单位是 byte.
  • -ss <position> (i/o):(在参数 -i 之前指定)从 position 指定的位置开始工作。注意:大多数情形下,工作起始位置是不精确的。ffmpeg会找到其前部的一个点作为真正的起始,并在结束工作后将该点与用户指定点之间的内容抛弃。然而,如果你使用了 copy 参数,这部分内容却会被保留。
  • -sseof <position> (i/o):类似 -ss 参数,只不过是从数据流末端向前寻找 position。此时 0 表示数据流末。
  • -itsoffset <offset> (i):指定输入流以原时间戳加上 offset 作为其输入时间戳。
  • -metadata[:metadata_specifier] key=value (o):以键值对的形式设置元数据。
  • -frames[:stream_specifier] <num> (o):在输出 num 帧后停止写入。
  • -qscale[:stream_specifier] q (o):使用固定质量(VBR)。
  • stats (global):输出编码过程,是系统默认值。可以使用 -nostats 关闭。
  • -attach <filename> (o):将 filename 文件附加到输出文件。附件流作为文件的最后一个流,只有很少的文件类型被支持(例如字体)。

视频参数

  • -vframes <num>:文件的总帧数。-frames:v 的别名。
  • -r[:steam_specifier] <fps> (i/o):文件的帧率。
  • -s[:steam_specifier] <size> (i/o):帧尺寸。参数 size 需要满足格式 <width>x<height>,例如320x240。 –aspect[:steam_specifier] <asp> (o):宽高比,例如 4:3。如果使用了 -vcodec copy,那么指定容器的宽高比而不是视频的。
  • -vn (o):禁止输出视频。
  • -vcodec <codec> (o):设置视频编码器。-codec:v 的别名。
  • -pass[:stream_specifier] <n>:选择当前编码数(1或者2),常用于二次编码的情况。在第一次编码中,音频输出往往被设置为 NULL,对于 Windows 与 Unix 系统分别是:
    ffmpeg -i foo.mov -c:v libxvid -pass 1 -an -f rawvideo -y NUL
    ffmpeg -i foo.mov -c:v libxvid -pass 1 -an -f rawvideo -y /dev/null

音频参数

  • -aframes <num> (o):文件的总帧数。-frames:a 的别名。
  • -ar[:stream_specifier] <freq> (i/o):采样率。默认输出等于输入。仅当输入文件为真实设备或者 raw 数据时,该参数才能用于输入过程。
  • -aq <q> (o):音频品质(VBR)。 -q:a 的别名。
  • -ac[:stream_specifier] <channel> (i/o):设置音频通道数。默认输出等于输入。仅当输入文件为真实设备或者 raw 数据时,该参数才能用于输入过程。
  • -an (o):禁止输出音频。
  • -acode <codec> (i/o):设置音频的解码器或编码器。-codec:a 的别名。

字幕参数

  • -scodec <codec> (i/o):字幕解码器或编码器。codec:s 的别名。
  • -sn (o):禁止输出字幕。
  • canvas_size <size>:设置字幕渲染区域的尺寸。

其他参数

以下直接在 ffmpeg 后使用,例如:ffmpeg -version

  • -bsfs:可用的比特流滤镜。
  • -h [arg]:帮助。arg 的内容可以是:
    • decoders:可用的解码器。或特指:decoder=<name>
    • encoders:可用的编码器。或特指:encoder=<name>
    • filters:所有滤镜。或特指:filter=<name>
    • formats:可用的分流器与混流器。或特指分流器:demuxer=<name>,或特指混流器:muxer=<name>
  • -protocols:支持的协议。
  • -version:版本信息。

FFmpeg 实用例子

合并视频

参考:FFmpeg Wiki – Concatenate 第一种方案:将这几个视频放在一个新文件夹内,Shift 右键运行 cmd,输入(注意:如果要保存为批处理文件,请循环变量的双写百分号。):

(for %i in (*.flv) do @echo file '%i') > mylist.txt
ffmpeg -f concat -i mylist.txt -c copy output.flv

这样速度很快也没有中间文件,原则上要求文件规格相近。 另一种方案:先将这几个视频无损地转为 mpegts 文件,再通过 concat 协议合并。以常见的 H.264 视频与 aac 音频为例:

ffmpeg -i "1.flv" -c copy -bsf:v h264_mp4toannexb -f mpegts 1.ts
ffmpeg -i "2.flv" -c copy -bsf:v h264_mp4toannexb -f mpegts 2.ts
ffmpeg -i "concat:1.ts|2.ts" -c copy -bsf:a aac_adtstoasc "All.mp4"

这种方案是早期方案,支持更广,包括非 mpeg 容器的 mpeg 编码内容(H.264, MPEG4, MPEG2, AAC, MP3等)。不过这样会产生中间文件。

分割视频

指定视频的起始与持续时长就可以分割视频了。下例截取了视频的前 5 秒(00:05:00),注意-t后接“截取视频段长度”而不是“截取终点时刻”:

ffmpeg -i "input.mp4" -ss 00:00:00 -t 5 -c copy "output.mp4"

建议使用规范的 mp4 格式文件,否则可能出现视频无法正常混流的现象。

批量格式转换

比如,对于数据流用 mpeg 编码的一个 flv 文件,可以这样转为 mp4 文件:

ffmpeg -i "input.flv" -c copy "output.mp4"

因此一个批量转换也很容易通过 for 语句实现(%~n 表示保留不含扩展名的文件名):

for %i in (*.mp4) do ffmpeg -i "%i" -c copy "%~ni.flv"

截图

其实我觉得播放器内置的截图可能更好用。

静态图水印

下例添加 png 或其他静态格式的水印,放置在距左侧 20 像素,距顶端 40 像素的地方。水印与视频的基准点都是左上角点。

ffmpeg -i input.mp4 -i wm.png -filter_complex "overlay=20:40" output.mp4

如果要放在右下角使用overlay= main_w-overlay_w:main_h-overlay_h,参数的含义应该较好理解。 如果要指定水印的大小,比如 384×216:

ffmpeg -i input.mp4 -i wm.png -filter_complex "[1:v]scale=384:216[wm];[0:v][wm]overlay=0:0" output.mp4

参数 0:v 表示第1个输入的视频流(本例即input.mp4的视频流),1:v 表示第2个输入的视频流(本例即wm.gif)。分号前的[wm]用于引用。

GIF 水印

添加 gif 水印与静态图水印有一些不同之处:

  • 需要将 ignore_loop 参数指明为 0,表示 gif 无限循环。
  • 需要用到复合过滤器 filter_complex
  • 需要过滤器的 shortest=1 选项,表示至少在一个视频流循环一次后,再终止输出。如果不加该选项,输出将无法自行停止。

一个指定 50×50 大小 GIF 水印在左上角的例子:

ffmpeg -y -i input.mp4 -ignore_loop 0 -i wm.gif -filter_complex "[1:v]scale=50:50[wm];[0:v][wm]overlay=0:0:shortest=1" output.mp4

外挂字幕

将字幕作为单独的数据流(而不是混入视频流中),封装到容器内。一般对此特性有良好支持的容器是 mkv。在封装时,一般需要转为 ass 格式。

ffmpeg -i input.mp4 -i input.srt -c:v copy -c:a copy -c:s ass output.mkv

一些注意点:

  • 字幕文件请用 UTF-8 编码。
  • Windows 系统缺少一个字体接口,因此需要自己配置 fonts.conf 文件,放在 %FONTCONFIG_PATH% 这个环境用户变量里(往往需要你自己新建)。该变量应该指向C:\Users\用户名\

网上流传了一份 fonts.conf 文件内容(见附录),请复制后粘贴到你对应文件夹的 fonts.conf 文件中。

内嵌字幕

在播放器不支持独立字幕流的场合,需要将字幕混入视频流中(因此需要重编码)。

ffmpeg -i input.mp4 -vf subtitles=input.srt output.mp4

如果字幕以字幕流的形式位于一个视频文件中,可以直接调用:

ffmpeg -i input.mkv -vf subtitles=input.mkv output.mp4

同样,Windows 用户需要配置 fonts.conf 文件。

附录:Windows 的 fonts.conf

参考页面:该用户的 Github

上一篇
下一篇