FFmpeg - 不仅仅是视频转码工具

前言

很久以前我曾经写过Introduction to FFmpeg,后来基本上弃坑了。最近我又打算略微换一下主题,重新深入介绍一下FFmpeg,准备去投稿洛谷日报。顺便提一下,之前我改编的博客文章Turbo Pascal的进化史有望在最近登上洛谷日报,敬请关注。


我发现,不管是在高中信息技术还是NOIp初赛中,对于多媒体的基础和常见操作并没有多少涉及,有的观念甚至是不正确的。而在信息时代,多媒体是相当重要的,有时就是需要一些格式转换或压缩,为此我写本文来做一些基础的科普。

FFmpeg是一个功能强大、跨平台的开源视频转码工具,被许多播放器和转换工具所使用,例如VLC、MPlayer、暴风影音等播放器,以及格式工厂等转换工具。其中FF是“Fast Forward”的缩写(貌似只在Git里看到过),FFmpeg的读法是先读字母f-f-m-,再读词peg。FFmpeg包含三个部分:ffmpeg、ffplay和ffprobe,分别用于转换、播放和查看信息。本文主要介绍命令行版的FFmpeg。

那么为什么要用FFmpeg而不是格式工厂等工具呢?首先FFmpeg是开源的,而且熟悉之后命令行比图形界面更高效,其扩展性也很好,可以整合许多编解码库,还能用于自己写的程序中。而格式工厂虽然免费但没有开源,所以违反了FFmpeg的GPL协议,曾经登上“耻辱厅”

FFmpeg的很多中文文章并不是很适合入门,除了本文外,还可以浏览一下参考文献中的文章(系列)。本文只要求有一定的命令行基础。

快速入门

仿照The C Programming Language等书的第一章,这里先给出一些常用的例子,而不加以系统说明,以实现快速入门。mp4是最为常见的视频格式,而H.264则是最常见的视频编码。

下载与安装

对于Windows用户,在这个网站下载,我推荐使用稳定版、Shared。

对于Linux以及Mac,直接安装软件包吧,如果觉得版本太老可以尝试自己编译(高级操作)。如果没有ffmpeg,那么找替代品libav,libav是ffmpeg的一个分支,使用方法有一些不同。

简单转换

音视频转换从未那么简单:

1
ffmpeg -i input.mp4 output.avi

这个命令就是把input.mp4转换为output.avi。转换时,可以按q来中止转换。ffmpeg会使用多线程来加速,因此CPU使用会接近100%。

这样转换太慢了?一般转换都比较慢,达不到实时(1x)。不妨试试“快速转换”(下文会作解释),如果格式适合,可以达到文件复制的速度。下面的例子将常见的网络视频格式flv转换为mp4。

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

想要提取视频中的声音?这也很简单。

1
ffmpeg -i input.flv output.mp3

下一个操作是去除视频中的音频,这也很常用。这样视频中将不包含任何音频数据。

1
ffmpeg -i input.flv -an output.mp4

既然有提取,我们也需要合成视频。

1
ffmpeg -i input.mp4 -i input.mp3 -c copy output.mp4

视频压缩

很多时候,由于大小限制或者网速限制,需要把一个视频压缩。下面的例子将一个4K的视频压缩到高清(1280x720,720p)。

1
2
ffmpeg -i 4k.mp4 -s hd720 hd.mp4
ffmpeg -i 4k.mp4 -s 1280x720 hd.mp4

两条命令是等价的,此外ffmpeg还内置了很多标准分辨率。

有时不想改变视频分辨率,而是想改变压缩的参数。

1
ffmpeg -i input.mp4 -crf 18 output.mp4

注意,常见的mp4(其实是H.264)可以用crf来设定压缩质量,推荐在18~28之间,默认是23,数值越小质量越高,文件也越大。

当然,上述两种操作也是可以一起进行的,只要把两个选项都写上即可。

1
ffmpeg -i 4k.mp4 -s hd720 -crf 28 hd.mp4

视频截取与拼接

截取从1:00开始的20秒内容:

1
2
ffmpeg -i input.mp4 -ss 1:00 -t 20 output.mp4
ffmpeg -i input.mp4 -ss 60 -t 20 output.mp4

可以发现,既可以用分、秒来表示时间,又可以直接用秒来表示。

拼接相对麻烦一点,需要创建一个拼接的文件列表:

concat.txt
1
2
file input1.mp4
file input2.mp4

然后再用ffmpeg:

1
ffmpeg -f concat -i concat.txt -c copy output.mp4

嵌入字幕

对于外挂字幕,一种方法是复制到视频中,需要播放器支持这种字幕,其实和外挂没多少区别;另一种方法是把字幕直接“刻”到视频里,我习惯称为“硬字幕”,这样就无需播放器支持字幕了。

第一种方法类似合成视频和音频:

1
ffmpeg -i input.mp4 -i input.ass -c copy output.mkv

而第二种方法就比较慢了:

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

多媒体基础

一个视频文件,一般包括视频(Video)、音频(Audio),可能还包含字幕(Subtitle)、章节等文本信息,甚至包含附件。所以这个包装方式称为容器(Container),或一般称为格式,与文件后缀有关。

一个容器中可以包含多个视频、音频、字幕,而这些流的格式称为编码,相当于不同的压缩算法。编码方式可以分为有损和无损编码,一般视频不会使用无损编码。

格式(容器)

一些简单的、并不专业的介绍。

Matroska

Matroska是较新的流行格式,开源,支持几乎所有编码,几乎什么都可以塞进去。但是比较旧的播放器可能不支持。推荐用MKVToolnix混流,而不是ffmpeg,前者输出文件的兼容性更好。我推荐自己制作或转码的视频用这个容器。

MPEG-4

MPEG-4也比较常见,大多数播放器都支持。可以使用的编码相比Matroska少,但能满足常见的需要。

AVI

AVI(Audio Video Interleave)是一种相当古老的格式,由微软设计,所以在Windows下支持很好。从Windows 3.1开始的Video for Windows就用这种格式。较新的编码也能支持,但是播放器就不一定了。不应该再使用这种格式。

FLV

FLV(Flash Video)是网络视频常见的格式,支持的编码很有限。

WMV

WMV(Windows Media Video)是微软的另一种容器,现在也已经比较少见了。不过Windows 7自带的视频Wildlife.wmv很经典。其使用的编码是专有的,因此无法用ffmpeg实现编码。

视频编码

H.264(AVC)

H.264是目前使用最为广泛的视频编码,也比较先进,在很多设备上有完善的硬件解码,有些还提供快速的硬件编码。适合1080p及以下,而2160p(4K)就会差些。

HEVC(H.265)

HEVC是较新的视频编码,压缩更为先进高效,但是并不普及。较新的硬件可能支持硬件解码,但是编码一般较慢。在4K上会大大超过H.264,较低的分辨率下也很理想。

VP9

Google开发的与HEVC竞争的视频编码,开源且免费,但是硬件支持可能不如前两个。

AV1(VP10)

宣称是HEVC的下一代视频编码,而且开源免费,效率全面超过以前的编码。但不久前发布,支持很少。优势也需要在4K以上。新的ffmpeg已经提供支持,可以去体验。

音频编码

AAC

与AVC一样流行的音频编码,超过前代的MP3。没有特殊要求一般都用AAC编码音频。

MP3

较为古老但仍然常见的音频编码,在视频中用的已经较少,但单独的容器还很常见。建议用AAC取代。

Opus

更先进的开源音频编码,但是很罕见。可以作为研究,但可能实际意义不大。

FLAC

常见的无损音频编码,同样开源,比raw的WAV要节约空间。如果需要无损音频主要考虑FLAC。

WAV

未压缩的音频数据,只是演示及作为中间状态,应该很少实际应用。

ffmpeg主要选项

常见编码的选项

硬件加速

屏幕录制

PC多媒体简史

参考文献和推荐