FFMPEG将H264转HEVC时,码率缩小多少好,以及如何通过SSIM(Structural Similarity Index结构相似性指数)衡量转码损失
最近整理一些视频,我发现太多了,就想把一些本来就需要转码的视频缩小一下。因为转码的时候为了弥补损失,我将码率增大了 10-20%,但是如果将 H264 转 HEVC(当然也可以是其他格式),那么或许不用增大码率甚至可以减少码率。
但是码率缩小多少好呢?
HEVC 的体积一般是 H264 的 50-80%,但是这个跨度也不小。
肉眼观察太难评了,而且每次都这样很麻烦,我就找了一些技术评判方法,来找到合理的缩小值。
FFMPEG 支持 SSIM(Structural Similarity Index,结构相似性指数),可以评估两个视频之间的差别。我们就使用这个指标。
在转码的时候,我们首先要考虑原视频的码率。因为码率极大的情况下,码率哪怕只有原来的 5%,效果也不会下降太多。而在低码率的情况下,下降 50% 就会带来很大的影响。
其次我们需要考虑我们能接受的损失程度是多少。要做到这点,需要通过实验,建立 SSIM 和人肉眼看到的情况之间的关系。
SSIM 测试
这里需要说明一下,SSIM 只是一个参考,它只是从某种角度上表示转码前后的损失度,重点还是我们肉眼看到的情况。
首先这个测试分两类:第一次我用 Blackmagic Camera 这个 App 拍摄 220Mbps 码率的 4K H264 视频,文件大小 80MB;第二次我截取一个 5700Kbps 1080P 流媒体电影片段,文件大小 100 MB,分别代表两种可能的情况。
本节转码时,编码均使用显卡加速。
对比测试命令如下:
ffmpeg -i 第一个文件路径 -i 第二个文件路径 -lavfi "[0:v]settb=AVTB,setpts=PTS-STARTPTS[main];[1:v]settb=AVTB,setpts=PTS-STARTPTS[ref];[main][ref]ssim" -f null -
这里我使用的是
-lavfi "[0:v]settb=AVTB,setpts=PTS-STARTPTS[main];[1:v]settb=AVTB,setpts=PTS-STARTPTS[ref];[main][ref]ssim"
,而不是网上常见的-filter_complex ssim
,是因为我的两个视频如果用这个会识别错误。你可以根据你自己的情况修改一下。
你会看到一个类似编码的过程,然后看到最终的结果:
SSIM Y:0.986175 (18.593297) U:0.995715 (23.680221) V:0.995205 (23.192565) All:0.989270 (19.693974)
它分别显示了 YUV 和总共的 SSIM。
可以看到在高码率的情况下,视频压到 10% 码率的时候曲线才出现了波动,当然在肉眼观察的时候也发现此处开始,画质有明显的下降,比如没有那么锐利了(由于素材不咋地,就不放截图了)。
我们把图表纵轴上下限修改一下,可以更精确的看到变化情况:
当在常见的流媒体码率下,只要压到 50% 左右,SSIM 就开始有较大损失,虽然肉眼可以发现画质损失了,但是不明显,依旧属于能看。但是当压到 10% 的时候,那就很无语了。
注意下图的上下限和上图不一样。
下面第一张是原文件,第二张是 45% 码率的,第三张是 10% 码率的。可以看到第三张的画质损失严重:
根据数据可以发现,如果码率相比 100% 码率的情况下, SSIM 差距达到 0.01,那么画质会有肉眼可见的损失。如果达到 0.05 -0.1,那么会有很严重的画质损失。
SSIM 仅供参考
这里再次强调一下,SSIM 只是一个参考,它只是从某种角度上表示转码前后的损失度,重点还是我们肉眼看到的情况。不要本末倒置。
比如在一些特殊情况下,两个完全不同的视频的 SSIM 可能能达到 0.9 的级别。只不过我们在测试原视频和转码文件的时候这个指标可以当做参考。
同码率下转码一定有损失
首先这种换编码的转化一定有损失,那怕不降低码率甚至提高 20% 的码率也会有损失,上面的测试中你也可以看到 100% 的时候 SSIM 也不为 1(5700K 测试 为 0.992643,而 220m 的结果为 0.896002)。如果你使用--lossless
可以保证无损,但是码率会高很多,不划算。
关于无损转码的详细说明可以看 x265 - readthedocs。
选择 75% 码率
根据上面的测试,我们可以看到 50% 左右一定会损失画质,只是不明显罢了,但是 50% 到 100% 这区间,可以看到变化不大,我们可以取中间值。
此外,在 Blackmagic Camera App 中, H264 的编码为 220Mbps,而 HEVC 的编码为 160Mbps,约为73%。
所以选择 75% 码率是一个比较合理的选项。
在完整转码一个约 680 MB 的文件视频后,得到 SSIM 为 0.989270,肉眼可见没啥区别。证明这个比例是比较合适的,节约了四分之一的体积,虽然小文件没什么区别,但是 1TB 变成 0.75 TB,还是差距巨大的
H264 转 HEVC
在使用 FFMPEG 将 H264 转为 HEVC,请使用以下命令:
ffmpeg -c:v h264_cuvid -i 输入文件路径 -c:v hevc_nvenc -b:v 码率 -tag:v hvc1 输出文件路径
解释一下:
-c:v libx265
:表示使用 libx265 软件编码器。-b:v 码率
:这里设置码率,需要注意如果是大码率,比如上面的 220Mbps 这种级别,不要使用220m
,而是应该使用220000k
,因为前者可能会导致转码后的码率非常低,比如我在测试过程中发现,使用220m
转码后只有7562 kb/s
,这差距太大了。-tag:v hvc1
:这部分是为了支持 Apple 的 HEVC,不然你转码完的视频会发现无法使用 Mac 等苹果设备的播放器播放。
如果你需要使用 Nvidia 硬件加速,那么使用以下命令:
ffmpeg -c:v h264_cuvid -i 输入文件路径 -c:v hevc_nvenc -b:v 码率 -tag:v hvc1 输出文件路径
解释一下:
-c:v h264_cuvid
表示使用硬件解码器。如果你的格式出现问题,那么不要用这个,使用软件解码兼容性更高,而且速度没啥区别,就是 CPU 利用率高。-c:v hevc_nvenc
:表示使用 NVENC 的 HEVC 硬件编码器。
希望能帮到有需要的人~
参考资料/扩展阅读
Structural similarity index measure - Wikipedia:SSIM 的维基百科,里面解释了 SSIM 是如何计算的。
H.265/HEVC Video Encoding Guide - FFMPEG:FFMPEG 官方关于 HEVC 的编码指南。如果你需要使用 HEVC 编码,那么建议看看这个指南。
11.237 ssim - FFmpeg Filters Documentation:FFMPEG 关于 SSIM 的文档。
此外感谢豆包帮我把输出转换成表格,方便我制图。