提要:大致就是对 https://www.ffmpeg.org/ffmpeg-all.html 的翻译。但对英文不善的人群还是有点用处的,对自己就算是阅读复习了。

ffmpeg做什么:ffmpeg是注重效率和转换质量的开源音视频转换器项目。

命令结构

ffmpeg [global_options] \
{[input_options_1] -i [input_url_1]} ... {[...n] -i [...n]} \
{[output_options_1] output_url_1} ... {[output_options_n] output_url_n}

大白话:ffmpeg根据首先指定的全局参数,从任意数目,用-i参数指定的输入,通过对每个输入可单独指定的输入选项读入数据,经过处理后再根据指定的输出选项,输出到若干个输出url中。

每个-i指定的输入可以包含若干流,如音频流、视频流、字幕流等。

ffmpeg工作流

ffmpeg对一个输入文件的处理流程可以用下图来进行对照分析:

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

这个图的知识背景简要概括就是,我们平时接触到叫“视频”的东西,其实是视频和音频,准确说是视频流和音频流的混合物。混合的方式就是封装,英文叫muxing。我们耳熟能详的flv、mp4、avi等视频扩展名,其实都是代表不同的封装方式。ffmpeg要处理这种混合物,首先需要做demuxing,也就是解封装。解封装后,会得到独立的视频和音频流。但此时的视频和音频流都是经过编码的,无法直接被ffmpeg操作修改。为什么音视频需要编码?因为音视频存在时空冗余问题,不经编码压缩的话存储开销和传输带宽开销会很大。所以ffmpeg需要先按照音频流视频流的编码方式,使用对应的解码器进行解码后,才能得到原始的帧,用于ffmpeg的后续处理。“后续处理”其实一般是叫做使用filter,把原始的音视频流经过filter处理后得到期望的转换后的音视频流。之后还会对处理后的原始音视频流进行编码,对编码后的音视频流进行再封装,得到我们通常意义上的音视频文件。

filter:filter完全可以类比数字信号课程中filter的概念。ffmpeg把filter做了simple和complex的分类。

  • simple:就是指一输入一输出,输入输出的流种类相同的filter。
  • complex:指输入和输出类型不同,或存在多输入或输出情况的filter。

copy:可以对输入文件的某一种流的输出指定copy参数。指定copy参数后,会跳过对该流的解码->filter->编码阶段,解封装后的这一路流直接置入输出文件对应的流中。

流选择

ffmpeg指定输入时,顺序是重要的。指定输入顺序牵涉到中段命令如何去指涉到某一具体的输入流。类似数组索引,第一个-i指定的输入我们认为它编号为0,第二个编号为1,以此类推。

-vn -an -sn -dn四参数分别是指定不选择原输入中的视频、音频、字母、data流。

不使用 -map 参数的话,ffmpeg会尝试自动选择输入流以进行后续处理。选择的规则如下:

  • 对视频,选择若干输入流中分辨率最高的视频流。
  • 对音频,选择输入流中频道最多的音频流。
  • 对字母,选择按序第一次出现的字幕流。如果考虑文字字幕流和图片字幕流共存的情况,则选择输出封装格式默认的字幕编码器支持的字幕类型(基于图片 or 基于文字)

使用 -map 参数时,则只有 -map 指定到的流会输出到输出文件中。

-map 参数使用的一个例子:

ffmpeg -i A.avi -i B.mp4 out1.mkv out2.wav -map 1:a -c:a copy out3.mov

前两个输出文件适用于之前提到自动选择的规则,而我们关注第三个输出文件中-map的作用。对第三个输出文件,-map只指定了1:a,则可判定输出文件指包括输入文件的饮品流。而1代表取到的是第2个输入文件,也就是B.mp4。音频的编码使用了copy参数,则不会存在解码->filter->再编码过程,直接将输入流的编码音频置于输出的mov下。如果我们尝试播放out3.mov,会发现这个mov文件没有视频信息,会播放出B.mp4的音频。感兴趣的读者可以用该条命令进行实验。

ffmpeg的命令参数非常多,去直接记忆意义并不大。一部分参数其实是和怎么去描述音视频的知识相关,先学了数字图像处理的课程,自然而然能理解记忆。另一部分操作音视频的参数和filter,我观点是可以先大致过一遍,清楚什么功能可以做到,项目中遇到了对应需求再去翻文档搞懂详细用法。之后应该会在数字图像处理的内容上发点力。