如何使用 FFmpeg

FFmpeg 是一套可以用来记录、转换数字音频、视频,并能将其转化为流的开源计算机程序。采用 LGPL 或 GPL 许可证。它提供了录制、转换以及流化音视频的完整解决方案。它包含了非常先进的音频/视频编解码库 libavcodec,为了保证高可移植性和编解码质量,libavcodec 里很多 code 都是从头开发的。

FFmpeg 几乎可以实现所有的有关数字媒体的常见的操作。因此学习 FFmpeg 的使用是非常必要的。

ffmpeg 文档
https://www.ffmpeg.org/ffmpeg.html

ffmpeg 文档(完整版)
https://www.ffmpeg.org/ffmpeg-all.html

需要注意的几点

在 FFmpeg CLI 中,参数的传递顺序是很重要的,并不能随意更改顺序,否则会影响输出结果。

总之输出文件永远在最后面,对于安全性的设置一定要放在最前面。

ffmpeg [global_options] {[input_file_options] -i input_url} ... {[output_file_options] output_url} ...

如果在 Windows 出现文件乱码:先输入 CHCP 65001 切换到 UTF-8 代码页。

查看信息

ffmpeg -i video.mp4

这种方式查看在开始会有一长串 ffmpeg 的版本等信息。

隐藏 banner 使用

ffmpeg -i video.mp4 -hide_banner

对于 ffprobe 也同样适用。

格式、编码转换

ffmpeg -i video.mp4 video.avi
ffmpeg -i video.flv video.mpeg

如果想要保留输出文件的质量,使用 -qscale 0 参数。

ffmpeg -i input.webm -qscale 0 output.mp4

查看 ffmpeg 支持的所有格式

ffmpeg -formats

提取

下方的命令会将 MP4 转换为 MP3

ffmpeg -i input.mp4 -vn -ab 320 output.mp3
ffmpeg -i input.mp4 -vn -ar 44100 -ac 2 -ab 320 -f mp3 output.mp3

-vn 丢弃视频流(video not allowed) -ar 设置音频的采样率,最常用的是 22050,44100,48000 Hz(audio rate) -ac 设置声道数(audio channels) -ab 设置音频比特率(audio bitrate) -f 设置格式,一般不用指定,可以从文件名中推测(format)

分辨率调整

ffmpeg -i input.mp4 -filter:v scale=1280:720 -c:a copy output.mp4
ffmpeg -i input.mp4 -s 1280x720 -c:a copy output.mp4

压缩文件

ffmpeg -i input.mp4 -vf scale=1280:-1 -c:v libx264 -preset veryslow -crf 24 output.mp4

使用 x264 进行编码会损失视频质量。如果 24 帧太激进了,可以使用 23 帧。

也可以添加以下选项来压缩音频流大小

-ac 2 -c:a aac -strict -2 -b:a 128k

-crf Constant Rate Factor

ffmpeg -i input.mp3 -ab 128 output.mp3

可以使用的音频码率列表

  1. 96kbps
  2. 112kbps
  3. 128kbps
  4. 160kbps
  5. 192kbps
  6. 256kbps
  7. 320kbps

删除流

ffmpeg -i input.mp4 -an output.mp4

使用 -an 后,所有和音频有关的选项都没有作用了,比如 -ab

ffmpeg -i input.mp4 -vn -ab 320 output.mp3

提取图像

ffmpeg -i input.mp4 -r 1 -f image2 image-%2d.png

-r frame rate,帧速率,每秒钟生成多少张图像,默认值是 25 -f 指定输出格式 image-%2d 命名格式:image-01.png image-02.png

裁剪视频

ffmpeg -i input.mp4 -croptop 100 -cropbottom 100 -cropleft 300 -cropright 300 output.mp4

这会印象视频质量,不到万不得已,千万不要这样做。

转换片段

ffmpeg -i input.mp4 -t 50 output.avi

将 MP4 的前 50s 内容转为 AVI 格式。

时间也可以使用 hh.mm.ss 这种格式。

设置宽高比

ffmpeg -i input.mp4 -aspect 16:9 output.mp4

常用的宽高比

  • 16:9
  • 4:3
  • 16:10
  • 5:4
  • 2:21:1
  • 2:35:1
  • 2:39:1

图片循环播放的视频

ffmpeg -loop 1 -i inputimage.jpg -i inputaudio.mp3 -c:v libx264 -c:a aac -strict experimental -b:a 192k -shortest output.mp4

截取视频片段

ffmpeg -i input.mp4 -ss 00:00:50 -codec copy -t 50 output.mp4
ffmpeg -i audio.mp3 -ss 00:01:54 -to 00:06:53 -c copy output.mp3

在截取的时候,并不会精确地截取相应片段,而是截取到附近的关键帧。

分割视频到多个片段

ffmpeg -i input.mp4 -t 00:00:30 -c copy part1.mp4 -ss 00:00:30 -codec copy part2.mp4

第一个片段从头开始截取 30s,第二个片段从 30s 开始到视频结尾。

合并

当视频容器是 MPEG-1、MPEG-2 等时,可以使用 concat 命令。(类似 Windows 的 copy /b *.ts out.ts

ffmpeg -i concat:"1.mpg|2.mpg" -c copy out.mpg

从文本文件读取文件并合并。(要求格式和性质均一致,应该可以合并 MPEG-1 和 MPEG-2 之外的格式。)

ffmpeg -f concat -i Cam01.txt -c copy Cam01.mp4

文件列表的格式

/home/sk/myvideos/part1.mp4
/home/sk/myvideos/part2.mp4
/home/sk/myvideos/part3.mp4
/home/sk/myvideos/part4.mp4

file 'path/to/file001.ts'
file 'path/to/file002.ts'
...

有时可能还需要指定 -safe 0,来保证当文件名出现特殊内容(比如一个文件名中包含 URL)时也可以继续顺利执行。

# inputs.txt
file 'http://www.example1.com/video1.mp4'
file 'https://www.example2.com/video2.mp4'
ffmpeg -f "concat" -i "./inputs.txt" -codec "copy" "./concated.mp4"
[concat @ 0x00] Unsafe file name 'http://www.example1.com/video1.mp4'
./inputs.txt: Operation not permitted

提示 Unsafe file name 就可以添加 -safe 0 参数。

Fix for FFmpeg “protocol not on whitelist” Error for HTTP(S) URLs https://blog.yo1.dog/fix-for-ffmpeg-protocol-not-on-whitelist-error-for-urls/

添加字幕到视频

ffmpeg -i input.mp4 -i subtitle.srt -map 0 -map 1 -c copy -c:v libx264 -crf 23 -preset veryfast output.mp4

使用 ffplay 播放

ffplay video.mp4
ffplay audio.mp3

增加或减少音频的播放速度

ffmpeg -i inputvideo.mp4 -vf "setpts=0.5*PTS" outputvideo.mp4
ffmpeg -i inputvideo.mp4 -vf "setpts=4.0*PTS" outputvideo.mp4

20 FFmpeg Commands For Beginners - OSTechNix https://www.ostechnix.com/20-ffmpeg-commands-beginners/

HLS 中的应用

从 m3u8 获得分片的文件信息,并将多个 TS 文件合并为一个 MP4 文件。(可以读取 AES 加密的内容)

ffmpeg -allowed_extensions ALL -i "%s.m3u8" -c copy "%s.mp4"

-allowed_extensions ALL 默认情况下,FFmpeg 处于安全性考虑,不允许读取除了多媒体文件以外的其他类型文件。该选项可以运行从非媒体文件读取内容,比如 HLS 中的 AES 密钥文件 xxx.key

(除了这种方式,也可以将密钥文件重命名为 key.m3u8,这样 FFmpeg 就会认为他是一个媒体文件了。)

如果从本地文件读取 m3u8 文件,而 AES 密钥在某个 HTTP 服务器上的话,可以会出现不允许的协议提示信息。因此可以将所有能够使用的协议都添加到白名单。

ffmpeg -allowed_extensions ALL -protocol_whitelist file,http,https,tcp,tls,crypto -i "%s.m3u8" -c copy "%s.mp4"

FFmpeg 有点很烦的就是默认会加上 ecoder 的头部信息,导致不同版本的 FFmpeg 合并的出来的流可能完全一样,而 encoder 的版本信息就不一样(如 Lavf58.12.100),文件就会出现不一致的问题。

# no effect
ffmpeg -allowed_extensions ALL -protocol_whitelist file,http,https,tcp,tls,crypto -i "%s.m3u8" -c copy -metadata encoder="" "%s.mp4"

通过设定 -metadata 可以设定一些 title 之类的头部信息,然而对 encoder 是无效的,因此这个方法无效。经过测试 -flags +bitexact 也无效。唯一的解决方法就是自行修改并编译 FFmpeg。

$ ffmpeg -hide_banner -i On_My_Way_Home_Sting.mp3 -metadata encoder=abc out.mp3
[mp3 @ 0000024dd2eba380] Estimating duration from bitrate, this may be inaccurate
Input #0, mp3, from 'On_My_Way_Home_Sting.mp3':
  Metadata:
    title           : On My Way Home (Sting)
    artist          : The 126ers
    album           : YouTube Audio Library
    genre           : Country & Folk
    encoder         : Google
  Duration: 00:00:20.22, start: 0.000000, bitrate: 128 kb/s
    Stream #0:0: Audio: mp3, 44100 Hz, stereo, fltp, 128 kb/s
Stream mapping:
  Stream #0:0 -> #0:0 (mp3 (mp3float) -> mp3 (libmp3lame))
Press [q] to stop, [?] for help
Output #0, mp3, to 'out.mp3':
  Metadata:
    TIT2            : On My Way Home (Sting)
    TPE1            : The 126ers
    TALB            : YouTube Audio Library
    TCON            : Country & Folk
    TSSE            : Lavf58.12.100
    Stream #0:0: Audio: mp3 (libmp3lame), 44100 Hz, stereo, fltp
    Metadata:
      encoder         : Lavc58.18.100 libmp3lame
size=     317kB time=00:00:20.21 bitrate= 128.3kbits/s speed=16.1x
video:0kB audio:316kB subtitle:0kB other streams:0kB global headers:0kB muxing overhead: 0.113609%
$ ffmpeg -hide_banner -i On_My_Way_Home_Sting.mp3 -metadata:s encoder=abc out.mp3
[mp3 @ 000001d964baa380] Estimating duration from bitrate, this may be inaccurate
Input #0, mp3, from 'On_My_Way_Home_Sting.mp3':
  Metadata:
    title           : On My Way Home (Sting)
    artist          : The 126ers
    album           : YouTube Audio Library
    genre           : Country & Folk
    encoder         : Google
  Duration: 00:00:20.22, start: 0.000000, bitrate: 128 kb/s
    Stream #0:0: Audio: mp3, 44100 Hz, stereo, fltp, 128 kb/s
Stream mapping:
  Stream #0:0 -> #0:0 (mp3 (mp3float) -> mp3 (libmp3lame))
Press [q] to stop, [?] for help
Output #0, mp3, to 'out.mp3':
  Metadata:
    TIT2            : On My Way Home (Sting)
    TPE1            : The 126ers
    TALB            : YouTube Audio Library
    TCON            : Country & Folk
    TSSE            : Lavf58.12.100
    Stream #0:0: Audio: mp3 (libmp3lame), 44100 Hz, stereo, fltp
    Metadata:
      encoder         : abc
size=     317kB time=00:00:20.21 bitrate= 128.3kbits/s speed=16.1x
video:0kB audio:316kB subtitle:0kB other streams:0kB global headers:0kB muxing overhead: 0.113609%

#6507 (Can’t remove “encoder” metadata field) – FFmpeg
https://trac.ffmpeg.org/ticket/6507

#6602 (Can’t set or remove encoder metadata) – FFmpeg
https://trac.ffmpeg.org/ticket/6602

#7027 (Encoder of (OGV) metadata non-customizable) – FFmpeg
https://trac.ffmpeg.org/ticket/7027

#6465 (wrong metadata for the DNxHD codec prevent playback on Specialized Broadcast Hardware) – FFmpeg
https://trac.ffmpeg.org/ticket/6465

ffmpeg - Removing MP4 encoding information - Video Production Stack Exchange
https://video.stackexchange.com/questions/18227/removing-mp4-encoding-information

Regular ffmpeg won’t do this. You’ll need a combination of two tools to carry this out.

#1 Use ffmpeg from direct264, a modded version of an old ffmpeg build with a custom filter to modify H264 bitstreams. This build is crippled in most other ways, so rename it or don’t put it in your path.

ffmpeg -i in.mp4 -vcodec copy -acodec copy -vbsf h264_changesps=removesei -map_metadata -1 out.mp4

#2 Use mp4box from the GPAC suite to strip the writing application metadata

mp4box -add out.mp4 -new stripped.mp4

如果直接有现成的 m3u8 文件的 URL,可以直接使用 ffmpeg 进行合并,不用加这些参数。

ffmpeg -i https://foair.me/xxx.m3u8 -c copy out.mp4

相关资源

globocom/m3u8: Python m3u8 Parser for HTTP Live Streaming (HLS) Transmissions
https://github.com/globocom/m3u8