09|如何使用 FFmpeg 与 Handbrake 做转码?
刘歧
讲述:刘歧大小:10.70M时长:11:43
你好,我是刘歧。
学到这里,不知道你有没有发现一个事情:从开始到现在,我们讲得最多的就是 FFmpeg 的命令行工具和参数,很少讲到界面操作。其实在做视频转码时,大多数人除了经常用 FFmpeg 之外,还会用一些免费的带界面的转码工具,这节课我除了会教你如何使用 FFmpeg 转码之外,还会给你介绍一个非常好用的本地化转码工具 Handbrake。
如何使用 FFmpeg 转码?
在我们专栏开篇的基础部分,我给你讲过音视频相关的图像色彩、编解码、封装(Mux)与解封装(Demux)的基本原理。第 7 节课,我又给你讲了如何高效地使用 FFmpeg 帮助信息和文档。在前面这些内容的基础上,我们来学以致用,讲一讲怎么用 FFmpeg 转码。
首先我们需要确定我们在转码的时候输出文件的应用场景。假如你是希望传到快手这样的内容发布平台,那么我们是需要转换成平台要求的转码规格的。既然要转码,就需要先看一下自己电脑系统的环境是否支持这一操作,比如使用 CPU 做转码,电脑会不会变得很慢,如果电脑上有 GPU,使用 GPU 转码的话,CPU 理所当然地会空出来,这样就不会影响我们继续使用电脑做其他的事情了。
我们先来了解一下怎么使用 CPU 做转码。
用 CPU 转码
使用 CPU 转码的话,通常是用 CPU 解码,然后用 libx264、libx265、librav1e 之类的编码器编码,也叫软编码。当然也有人用 OpenH264 或者其他自己定制的编码器,因为编码参数大多数是与编码的参考标准对应的,通用的或者常见的编码参数在 libx264、libx265、librav1e 里面相差无几,所以这里为了简洁一点,我使用 FFmpeg 与 libx264 来做软编码。我们先来回顾一下转码的基本操作流程。
首先是读取文件后解析文件,然后对文件进行解封装,也就是 demux。将解封装后的音视频流数据进行解码,得到原始数据,也就是我们第 1 节课讲的 YUV 数据或者 PCM 数据,然后用我们设置的目标编码对应的编码器进行编码,编码后的数据写入音频流或者视频流里,封装音频流或者视频流,写入文件里。
使用命令行 ffmpeg -h encoder=libx264 查看一下参数内容。
从帮助信息中可以看到,libx264 编码支持的图像色彩格式主要包括 yuv420p、yuvj420p、yuv422p、yuvj422p、yuv444p、yuvj444p、nv12、nv16、nv21、yuv420p10le、yuv422p10le、yuv444p10le、nv20le、gray、gray10le,我们通常统一编码成 yuv420p 即可。如果确定播放器可以支持 HDR 的话,也可以考虑用 yuv420p10le。但是如果想要在 Web 浏览器上正常播放出来的话,yuv420p 是最稳定的格式。
为了解决设置编码参数时参数太多、太琐碎的问题,libx264 提供了预置模板 preset,在 FFmpeg 里默认用的是 medium 模板,也就是平衡画质与编码速度的最优选择。除了 medium,还可以按照帮助信息里面的提示,通过使用 x264 --fullhelp 查看 x264 的其他 preset,例如还有 ultrafast、superfast、veryfast、faster、fast、slow、slower、veryslow、placebo。
除了 preset 模板,还有调优类型的模板 tune,包括 film、animation、grain、stillimage、psnr、ssim、fastdecode、zerolatency 等不同的模版。
不同的模板支持的参数也略有差别,比如视频编码想做画面延迟低的直播流的话,可以考虑设置 tune 为 zerolatency。因为 zerolatency 模板里已经包含了低延迟编码的参数。
其中宏块树是一种视频编码结构,在编码时它可以增加 slice 处理的层数,降低视频编码的码率,但是复杂度会略有提升,所以耗时也会增加一些。你可以结合极客时间上视频编码及帧内预测相关的课程来理解,这里我就不展开说了。
slice 的的意思是将一帧图像切成多个切片,然后将多个片放到多个线程里处理,从而达到并发处理的的目的。因为 lookahead 是 0,不需要提前预存多个帧做缓存,也没有双向参考帧 B 帧,不需要预读多个帧做缓存,所以最大限度地降低了帧缓存引起的画面延迟。
除了以上两类模板,在给视频转码做转码的时候,有时也会被要求转成恒定码率的视频流,也就是我们常说的 CBR,这个 CBR 可以通过参数 nal-hrd cbr 来设置,但是实际的码率不一定能够控制得很好,所以通常会搭配 FFmpeg 的 maxrate、minrate 与 bufsize 来精确地控制码率,一般 bufsize 控制比 maxrate 小大概 1/3 ~ 1/2 即可,达到的效果如图所示:
如果使用当前 FFmpeg 里面的 libx264 参数无法达到要求,但用 x264 没问题的话,我们就可以通过 FFmpeg 预留的 x264opts 来设置更多 x264 的参数,例如设置 x264 为 OpenGOP 模式,就需要使用参数 -x264opts “open-gop=1”,来达到使用 OpenGOP 的编码模式的目的。
在同画质下,使用 OpenGOP 比 CloseGOP 码率更低一些,但是也可能会引入一些不稳定因素,例如视频切片的时候找不到关键帧,这一点需要我们注意。
说了这么多,接下来我们实际操练一下,使用 FFmpeg 命令行来做转码。
你先下载一个《大雄兔》或者《钢铁之泪》的电影,这两部电影是开放版权的,在互联网上能够搜到对应的视频文件,自己测试的时候可以随便用。先输入命令行:
命令行执行后,输出的内容是这样的:
从输出的内容中可以看到,编码的帧类型里只有 I 帧和 P 帧,设置的 CBR 模式已经生效,你也可以尝试把输入文件改成直播推流。
但是需要注意的是,设置视频编码流为 CloseGOP,关键帧间隔的 -g 设置成 fps 的一半即可,fps 需要使用参数 -r:v 来设置,例如设置 -r:v 为 30,就是 30 fps,那么 -g 可以设置为 15,也就是每隔 15 帧会有一个关键帧,这样可以达到 0.5 秒钟一个关键帧。当然,实际上这么做会很浪费带宽,常规的秀场直播设置 2~5 秒钟一个关键帧就可以了。
如果我们平时用 CPU 转码的话,对 CPU 的消耗会比较高,转码的时候电脑做其他事情会比较慢,一般电脑上有 GPU 的话直接选择用 GPU 转码,这样可以节省一些 CPU 计算资源。
用 GPU 转码
用 GPU 转码之前,你需要先确认一下自己当前电脑里的 GPU 是否可以做转码,然后安装对应的音视频编解码环境(GPU 相关的驱动、软件、开发库等)。
FFmpeg 支持的硬件加速方案,按照各 OS 厂商、Chip 厂商特定方案,还有行业联盟定义的标准来分的话,大致可以分成 3 类:
操作系统:包括 Windows、Linux、macOS /iOS、Android 等。
Chip 厂商的特定方案:包括 Intel、AMD、Nvidia 等。
行业标准或事实标准:包括 OpenMAX 和 OpenCL、Vulkan、OpenGL 还有 cuda 等。
这只是一个粗略的分类,很多时候,这几者之间纵横交错,联系密切,之间的关系并非像列出的这般泾渭分明。
下面就是 Windows 环境下,在 AMD、Intel、Nvidia 的 GPU 上用 dxva2 和 d3d11va 来解码,再使用厂商提供的编码器编码的例子。
AMD AMF
Intel QSV
Nvidia NVENC
比如我自己本机是苹果电脑,那么我使用 videotoolbox 做转码就可以。