城市街景题材 SDR 4K 视频的 HEVC(H.265)压制配置参考
城市街景题材 SDR 4K 视频的 HEVC(H.265)压制配置参考
丁俊尧缘由
自我在 2020 年 4 月末购买了 GoPro 运动相机后,我便开始了 4K 视频的拍摄。
GoPro 在硬件层面上支持 HEVC(也就是 H.265)编码,它相比于常用的 H.264 编码,能够以更低的码率存储同样的视频内容,节省设备空间。不过,以我当时的电脑性能,连播放都困难,更别提剪辑了。所以我基本上都是把这个功能关掉,实在需要的时候再开;剪辑前,先把编码格式转换为 H.264——前面也说过,电脑连播放都困难,转换就更慢了。
后来我组装了电脑,显卡买的是 GTX 1660S,可以硬解 HEVC。不过常用的视频平台仍然只接受 H.264 编码的视频,否则会遭到二压,极大影响视频画质。另外,我当时买了 3 TB 的硬盘,终于不需要考虑磁盘空间的限制了。因此,我输出的视频仍然使用 H.264 编码。至于拍摄的视频,就看设备的默认选项。
顺带一提,我 2022 年把 GoPro 卖掉,买车之后,买了大疆 Pocket 2,在驾驶时把大疆 Pocket 2 固定在车前,拍摄行程街景,也就是有些人常说的 POV(Point of View)视频。 自驾 POV 视频相较于其他的(如列车、公交) POV 视频,视野受外部干扰小,对他人影响小,接受度和质量更高。成片一般都是快放若干倍,但考虑到后期处理方便、能够同时生成原速视频用于直播等场景,以及与其他的录制(如导航录屏)同步,我使用的是一般的录制功能,而不是延时摄影。加上大疆 Pocket 2 录制的视频编码固定为 H.264,导致生成的文件特别大,一般来说,64 GB 只能录制不到一个半小时的 4K 25 fps 视频。
这样一来,那个 3 TB 的硬盘明显捉襟见肘。于是我又买了块 4 TB 的硬盘。结果,到了现在,我连那块硬盘都不够用了。
于是我萌生了一个想法:将硬盘里面的素材视频都压制成较小占用空间的格式。
这时,各大视频平台已经陆续支持了 HEVC 和 AV1 编码格式。AV1 相较于 HEVC,压缩率和画质都占优势。只可惜,我的显卡不支持 AV1 硬解,且我常用的 Adobe Premiere 目前还不支持该编码,所以目前还是考虑 HEVC 编码。
我一开始是在导出视频时,即设置为以 HEVC 编码导出。自己看不出画质差别有多大,上传到视频网站后,平台二压之后的结果就更看不出了。
但是,压制视频到 HEVC 编码的事情,我以前也不是没做过,但是当时网上的资料太少,我就自己摸索参数配置,结果给我的感觉是:画质缩水太严重。所幸现在我能够搜索到许多相关的资料,而且车出车祸了,我也暂停了拍摄计划;加之天气炎热,电脑也闲了下来。所以,我正好有时间去让电脑去测试压制视频的最佳方案。
环境
- CPU:AMD Ryzen 7 3700X
- GPU:NVIDIA GeForce GTX 1660 SUPER
- 系统:Windows 11 专业版 22H2
- 其他软件:
- HandBrake(开源的视频处理工具,可设置项很多,本例中使用 x265 或 NVENC 编码视频)
- 小丸工具箱(我平常较常用的压制工具,本例中使用 x265 编码视频)
- Adobe Media Encoder(视频处理工具,较常用于 Adobe Premiere 和 Adobe After Effects,也可以用于压制视频)
- FFmpeg(开源的多媒体处理工具,以 VMAF 模型评估视频质量)
- Adobe Premiere Pro 2023(我平常较常用的视频剪辑工具,从原始素材生成 H.264 视频作为待压制视频、生成 HEVC 视频作为对照视频)
Adobe 相关的软件均开启 GPU 加速。
测试视频信息
测试视频为我于 2023-05-13 发布于各大视频平台的《南京“中轴线”(中央北路-铁心桥大道)自驾 POV》。它帧率较高,画面、场景变换较复杂,用来测试画质效果较明显。
其中一个使用大疆 Pocket 2 拍摄的素材,小丸工具箱内使用 MediaInfo 解析信息如下:
1 | DJI_0002.MP4 |
工程先前已生成 H.264 视频,以此测试各配置的压制效果。解析信息如下:
1 | 南京“中轴线”(中央北路-铁心桥大道)自驾 POV.mp4 |
用 Adobe Premiere Pro 从工程文件中生成 HEVC 视频,以“4K UHD”为蓝本修改,一些参数如下:
- 视频
- 基本视频设置:匹配源,以最大深度渲染、使用最高渲染质量
- 编码设置:
- 性能:硬件加速
- 配置文件:主要(匹配源)
- 级别:5.1(匹配源)
- 层:高
- 比特率设置
- 比特率编码:VBR, 1 次
- 目标比特率 [Mbps]:60
- 质量:好
预设名为 adobe
,作为对照视频,作为参考。
压制选项
整个测试过程中,因设备、时间等限制,我均会考虑前面的测试结果,忽略无意义的测试组合,动态调整接下来的测试预设。限于篇幅,我仅给出测试方法和最终的测试结果,而实际上我会多次比对已有的测试结果,制定接下来的测试组合。
我主要采用 HandBrake 进行压制。
在 HandBrake 中,我以自带预设“Vimeo YouTube HQ 2160p60 4K”为蓝本,修改如下(下列选项如有斜杠,表示此处有多种预设的排列组合,实际上仅取部分组合进行测试,以测试结果为准):
- 尺寸 > 分辨率限制:无
- 视频
- 编码器:H.265 (x265 / NVEnc)
- 帧率:Same as source,固定帧率
- 编码器预设:
- x265:Medium / Slow / Slower
- NVEnc:Medium / Slowest
- 质量:固定质量:
- x265:21 / 18 / 17 RF
- NVEnc:21 / 18 / 0 CQ
- 音频 > 编码:AAC (avcodec) Bitrate: 320
最后生成的视频有以下预设,放到文件前缀,此后对比也采用此名称:
handbrake_cq21_nvenc_medium
handbrake_cq21_nvenc_slowest
handbrake_crf21_x265_medium
handbrake_crf21_x265_slow
handbrake_crf21_x265_slower
handbrake_crf17_x265_medium
handbrake_crf17_x265_slow
handbrake_cq18_nvenc_medium
handbrake_cq18_nvenc_slowest
handbrake_crf18_x265_medium
handbrake_crf18_x265_slow
handbrake_cq0_nvenc_medium
handbrake_cq0_nvenc_slowest
小丸工具箱中,我设置如下:
- 编码器:x265_64-8bit[gcc].exe
- 音频模式:复制音频流
- CRF:18
- 保持原分辨率
预设名为 maruko_crf18_x265
。
另外,我使用 Adobe Media Encoder 进行了测试,配置与
adobe
一样,预设名为
adobeme
。两者的区别是:前者从工程文件中生成视频,后者根据已生成的视频文件压制视频。
写这篇文章的时候,我才发现,上面 HandBrake 相关的预设里面原先有一些高级选项参数,但因为它原本是为了进行 H.264 编码,故切换到 H.265 编码时,高级选项内容为空。H.265 相关的预设中,是有一些高级选项的。简单查了一下参数表达的含义后,我想:如果有参数的话,结果应该还会有不同吧。
于是,我又以自带预设“H.265 MKV 2160p60”为蓝本,修改如下:
- 摘要 > 格式:MP4,网页优化、音视频起始对齐、保留常见元数据
- 尺寸 > 分辨率限制:无
- 视频
- 编码器:H.265 (x265 / NVEnc)
- 帧率:Same as source,固定帧率
- 编码器预设:Medium
- 高级选项(实际上我未动,是预设带出的):
- x265:
strong-intra-smoothing=0:rect=0:aq-mode=1
- NVEnc:
rc-lookahead=10
- x265:
- 质量:固定质量:
- x265:18 RF
- NVEnc:18 CQ
- 音频 > 编码:AAC Passthru
由于时间限制,我参考此前的结果,只做了两种预设的排列组合。预设名如下:
handbrake_crf18_x265_medium_prefs
handbrake_crf18_nvenc_medium_prefs
视频质量分析
考虑到素材可能还要用,我优先考虑视频的画质。
但是,如果仅凭肉眼,视频画质并不好对比。如果画质差别明显的话,还好对比;但是如果不明显的话,就很难看出来了;此外,我的每个视频都挺长的,就更难凭肉眼比对了。所幸,我可以凭借 VMAF 来让电脑评价视频质量。
VMAF(Video Multimethod Assessment Fusion,视频多方法评估融合)是 Netflix 与南加州大学、南特大学以及德克萨斯大学奥斯汀分校联合开发的开源视频质量评价指标,通过转码视频和原视频每一帧画面对比评分,最后给出所有帧的平均分即为转码视频的画质质量。
FFmpeg 集成了 VMAF 的画质模型,对于 4K 的视频,可以借助下面的命令使用:
1 | ffmpeg -i 检测文件路径 -i 对照文件路径 -lavfi libvmaf=model=version=vmaf_4k_v0.6.1:log_fmt=json:log_path=对比JSON结果文件.json -f null - |
如:
1 | ffmpeg -i 'F:\output\h265_test\handbrake_crf18_x265_medium_prefs-南京“中轴线”(中央北路-铁心桥大道)自驾 POV.mp4' -i "F:\output\南京`“中轴线`”(中央北路-铁心桥大道)自驾 POV.mp4" -lavfi libvmaf=model=version=vmaf_4k_v0.6.1:log_fmt=json:log_path='handbrake_crf18_x265_medium_prefs.json' -f null - |
一般来说这种对比是取一小段的,对时长为 13 分 38 秒的视频,对比花费的时间就超过了 5 小时。
本例中,我均以 H.264 视频作为对照文件,包括工程生成的 HEVC 视频也是以 H.264 视频对照。
执行最后会输出一个平均的 VMAF 值:
1 | [Parsed_libvmaf_0 @ 0000015a33ca5700] VMAF score: 97.402266 |
一般可以把它当成百分数看,表示相比于对照文件,检测文件的画质。
据网上他人的说法,98 分以上和原片几乎无法区分,95 分以上基本没有差异,93 ~ 95 分能感知到差异但可接受,91 分以下通常差异比较明显。
实际上,熟悉压制的人应该知道,不能简单拿一个平均值去评价画质。视频里各片段的复杂度不尽相同,一些简单的片段很容易压制好,而复杂的片段用相同的标准去压制,就会一团糟。
如下面的例子:
A 和 B 截取自 H.264 视频的不同帧,C 和 D 截取自预设为
handbrake_cq21_nvenc_medium
的 HEVC 压制视频的对应帧处。在 Adobe Photoshop 中将 A 覆盖在 C 上、B 覆盖在 D 上,设置 A、B 的图层模式为“差值”,再使用曲线工具,在反色的基础上调整,得 E 和 F。G 为 A 的局部,H、I 为 B 的局部;J、K 和 L 分别与 G、H 和 I 在同一位置上,但截取自 C 和 D;M、N 和 O 分别与 G、H 和 I 在同一位置上,但截取自 E 和 F。
我们可以发现,同样的预设下,较为复杂的帧易出现失真严重的情况。因此,我们需要得到每一帧的画质信息。
之前执行 FFmpeg 命令的时候,输出最终结果的时候,FFmpeg 会把每一帧的对比结果输出到上面给定的 JSON 文件中,格式形如:
1 | { |
对于我来说,需要取每帧的 VMAF 值,以检查画质是否出现极端情况(如某些帧的 VMAF 远小于平均值)。所以,需要把每帧的 VMAF 值取出来,编写 Python 脚本如下:
1 | import json |
以上会对每个 JSON 文件在原位输出一个名称相同的 UTF-8 带 BOM 的 CSV 文件,以便用 Excel 打开。其实改一下可以合并到一个文件里面,但是我懒得改了。
最后,把所有数据放在 Excel 中,并处理。
当原视频与原视频对比时,VMAF 不一定能到 100 分,不过足够接近。所以我进行了该对比,结果为 100。因此,可以将每帧的 VMAF 值视为画质相较于源文件的质量的百分比。
这里我放一张图,展示两个预设在每帧上的 VMAF ,以及 VMAF 的 180 周期(3 s)移动平均值的变化情况。
数据处理
Excel 内的源数据除了每帧的 VMAF 值、文件的平均 VMAF 值
avg_vmaf
外,还有如下的指标:
- 编码用时
time
- 压制后文件大小(我取的是相较于源文件的压缩比)
sizex
另外,对于 VMAF,我按照前面提到的 VMAF 值与画质的关系,划分了 4 个区间:
- VMAF ≥ 98
- 95 ≤ VMAF < 98
- 93 ≤ VMAF < 95
- VMAF < 91
计算属于对应区间的帧的比例。由于也可视为某一帧落在对应区间上的概率,故可以概率的方式记做
p(条件)
。
另外,我还计算下面的值:
- VMAF < 98 的帧中,VMAF ≥ 95 的比例
p(vmaf>=95|vmaf<98)
- VMAF < 95 的帧中,VMAF ≥ 93 的比例
p(vmaf>=93|vmaf<95)
除此之外,我引入了 VMAF 积分的概念,为落在不同 VMAF 区间的帧的 VMAF 值赋予权重。权重如下:
- VMAF ≥ 98:1
- 95 ≤ VMAF < 98:0.6
- 93 ≤ VMAF < 95:0.2
- 91 ≤ VMAF < 93:-0.5
- VMAF < 91:-1
结果为各帧的 VMAF 值乘以各自权重的结果之和。
我想把结果绘制成雷达图。为了保证数值增长方向的一致性(数值越大表示越好),以下指标需要取倒数:
- 编码用时
- 压缩比
- VMAF < 91 的帧的比例
各记为 1/指标
。
本来我还要把倒数处理到 1 以下。但是,我发现前面关于 VMAF 比例的计算结果过于集中,放在雷达图上会挤成一片。为了能够在雷达图上呈现明显的差别,我决定最后把得到的值以指标为集合,最差值记为 0,最好值记为 1,转换为 0-1 区间。可以由下面的公式得出:
1 | f(x) = (x - min(x 的集合)) / (max(x 的集合) - min(x 的集合)) |
由于一些预设的效果太差,我并没有对全部生成的视频做上述的检测与分析。
数据可视化与比对
由于数据量太大,处理花了很长时间,这里只放排名前的计算结果:
预设 | time | avg_vmaf | sizex | 1/time_in_day | 1/sizex | p(vmaf>=98) | p(95<=vmaf<98) | p(93<=vmaf<95) | p(vmaf>=95 in vmaf<98) | p(vmaf>=93 in vmaf<95) | p(vmaf<91) | 1/p(VMAF<91) | vmaf 积分 |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|
handbrake_crf21_x265_medium | 2:04:22 | 95.73243 | 0.304 | 11.57867 | 3.289474 | 0.237052 | 0.366042 | 0.221193 | 0.479774 | 0.557294 | 0.049002 | 20.40715 | 19086 |
handbrake_crf21_x265_slow | 4:57:03 | 96.83463 | 0.346 | 4.847669 | 2.890173 | 0.41364 | 0.328624 | 0.160057 | 0.560447 | 0.621011 | 0.019666 | 50.84886 | 28693.6 |
handbrake_crf21_x265_slower | 21:11:38 | 96.94906 | 0.367 | 1.132402 | 2.724796 | 0.423555 | 0.333652 | 0.152382 | 0.57881 | 0.62762 | 0.017529 | 57.04994 | 29484.4 |
handbrake_cq21_nvenc_slowest | 0:24:54 | 91.3346 | 0.153826 | 57.83133 | 6.500853 | 0.103929 | 0.2102 | 0.137561 | 0.234579 | 0.200564 | 0.388457 | 2.574289 | -10355.6 |
handbrake_crf18_x265_medium | 2:47:12 | 97.07845 | 0.502 | 8.61244 | 1.992032 | 0.443506 | 0.333327 | 0.141409 | 0.598976 | 0.633643 | 0.012785 | 78.21656 | 30676 |
handbrake_crf18_x265_slow | 5:41:15 | 97.70669 | 0.581 | 4.21978 | 1.72117 | 0.518852 | 0.312256 | 0.117427 | 0.64898 | 0.695275 | 0.008184 | 122.1891 | 34377.4 |
handbrake_cq18_nvenc_slowest | 0:24:54 | 91.33465 | 0.154 | 57.83133 | 6.493506 | 0.104214 | 0.21024 | 0.137561 | 0.234699 | 0.200659 | 0.388518 | 2.573884 | -10333.9 |
handbrake_cq0_nvenc_medium | 0:18:32 | 91.31031 | 0.154 | 77.69784 | 6.493506 | 0.097333 | 0.209121 | 0.137134 | 0.23167 | 0.197728 | 0.399247 | 2.504717 | -11179.6 |
handbrake_cq0_nvenc_slowest | 0:24:54 | 91.40775 | 0.154 | 57.83133 | 6.493506 | 0.102911 | 0.212846 | 0.136564 | 0.237263 | 0.199583 | 0.389434 | 2.567829 | -10345.9 |
handbrake_crf17_x265_medium | 3:06:40 | 97.40227 | 0.597 | 7.714286 | 1.675042 | 0.480965 | 0.328135 | 0.126059 | 0.632202 | 0.660339 | 0.009121 | 109.6429 | 32717.7 |
handbrake_crf17_x265_slow | 6:07:37 | 97.92056 | 0.69 | 3.917124 | 1.449275 | 0.570297 | 0.273921 | 0.114047 | 0.637466 | 0.732096 | 0.006657 | 150.2141 | 36017.9 |
maruko_crf18_x265 | 22:45:00 | 47.56214 | 0.645018 | 1.054945 | 1.550345 | 0.022313 | 0.000957 | 0.00116 | 0.000979 | 0.001188 | 0.971112 | 1.029748 | -46674.9 |
adobe | 2:08:00 | 96.30186 | 0.312177 | 11.25 | 3.203313 | 0.303441 | 0.384039 | 0.191144 | 0.551337 | 0.611621 | 0.025835 | 38.70764 | 24485.7 |
handbrake_crf18_x265_medium_prefs | 2:35:05 | 95.95199 | 0.401 | 9.28533 | 2.493766 | 0.268261 | 0.354805 | 0.218445 | 0.484879 | 0.57953 | 0.040941 | 24.42566 | 20881.8 |
handbrake_cq18_nvenc_medium_prefs | 0:19:27 | 91.23279 | 0.423 | 74.03599 | 2.364066 | 0.097801 | 0.20625 | 0.13866 | 0.228608 | 0.199239 | 0.399756 | 2.501528 | -11260.2 |
adobeme | 0:11:43 | 96.48743 | 0.311696 | 122.9018 | 3.208252 | 0.327748 | 0.374959 | 0.191775 | 0.557766 | 0.645073 | 0.023941 | 41.76871 | 25854.3 |
排名、制作图表时,我分了这几种情况去排名:
- 全部预设参与排名(Adobe 相关预设主要用以对照,下同)
- 软解 + Adobe 相关预设参与排名(因为硬解相关画质结果普遍不好)
- 软解 - 小丸工具箱 + Adobe 相关预设参与排名(小丸工具箱压制的视频 VMAF 太低,但检查视频发现画质并不低,故需排除,以查看其他软解预设的数据)
由于软解用时普遍偏高,而用以对照的 adobeme
预设用时极低,在雷达图上难以看清各软解预设的压缩用时效率,故另外画条形图展示软解相关预设的用时情况。
结果如图:
上面的图中,不带星号
*
的指标都是越高越好,带星号的指标仅为参考用。
上述过程花费 10 天左右。
无法通过计算发现的问题
此前提到过,小丸工具箱生成的视频,VMAF 非常低,但是实际观看视频发现,画质并没有像 VMAF 一样有着非常大的下降。但除此之外,还有一个仅凭上述计算无法发现的问题。
原视频 1:31 ~ 1:41 处,画面右侧的居民楼上有百叶箱。
但是压制后, handbrake_
开头的预设的文件中出现了严重的摩尔纹:
没有出现该情况的预设,除了 Adobe 的那两个外,就只有小丸工具箱的了。应该是小丸工具箱对 x265 有另外传入的参数。
查看日志,当时处理视频时的参数如下,供参考:
1 | D:\MarukoToolbox>"D:\MarukoToolbox\tools\ffmpeg.exe" -i "F:\output\南京“中轴线”(中央北路-铁心桥大道)自驾 POV.mp4" -strict -1 -f yuv4mpegpipe -an - | D:\MarukoToolbox\tools\x265_64-8bit[gcc].exe --y4m --crf 18.0 --preset slower --tu-intra-depth 3 --tu-inter-depth 3 --rdpenalty 2 --me 3 --subme 5 --merange 44 --b-intra --no-rect --no-amp --ref 5 --weightb --bframes 8 --aq-mode 1 --aq-strength 1.0 --rd 5 --psy-rd 0.7 --psy-rdoq 5.0 --rdoq-level 1 --no-sao --no-open-gop --rc-lookahead 80 --scenecut 40 --max-merge 4 --qcomp 0.7 --no-strong-intra-smoothing --deblock -1:-1 --qg-size 16 -o "D:\MarukoToolbox\temp\南京“中轴线”(中央北路-铁心桥大道)自驾 POV_vtemp.hevc" - |
在自定义命令行中,我将 --preset
改为 medium
,压制时速度明显提升。但是,视频在定点播放时,播放器卡得不行。后来发现,小丸工具箱直接把其他参数忽略了。但是,视频中的百叶箱还是比较正常的。
但是我把上面一长串参数放进 HandBrake,生成的视频里面又出现之前的摩尔纹了。不知道是为什么。
分析结果
正如标题所述,这次测试结果仅能代表城市街景题材 SDR 4K 视频的情况,其他的我手头没什么资料。
- 硬解仅在压缩用时上占优势,画质远远不如软解。但软解耗时远超过硬解。如果必须用硬解,优先选择 Adobe 的工具。
- 相较于压制时设定的质量([C]RF/CQ),编码器预设对画质、耗时的影响更大。
- 以
_prefs
为后缀的预设中,高级选项的加入仅对耗时和压缩率有轻微的正面影响,对画质反而起到反作用。 - 如果用 x265 压制,编码器预设最慢调至 slow 即可, slower 的画质提升效果不明显,且极为耗时。
- 上面添加的高级选项并未对压制起到正向效果。
- 如果优先考虑画质,
handbrake_crf17_x265_slow
预设不错。 - 如果稍微考虑一下时间,可以考虑
handbrake_crf17_x265_medium
预设。 - 小丸工具箱压制出的视频,虽然 VMAF 值极低,但是目测画质并不差;而且也没有出现上面提到的摩尔纹的情况。
结尾
总之,十几天的测试,耗费了我不小的力气。可惜,结果还是没有我满意的。没法调动显卡算力,单靠 CPU 得压制到猴年马月——我这次测试的是 13 分半的视频,原文件 19.5 GB,此前积累的素材少说有几个 T 了,就算是电脑 24 小时开机,我什么都不做,也要两个多月。更别说还要抽查画质、清理文件、干别的事情了。这两个多月,就算是电费也要花一大笔钱。
我还是决定:手头有钱了,把电脑主板找人修一下(此前装硬盘时,用力过猛,螺丝刀直接撞在一块电容上,把电容撞掉了,于是目前的主板只能识别两个 SATA 通道),再买块硬盘装上吧。
当然,就算你压制得再好,如果以流媒体方式分享的话,平台仍然会给你二压到极致。比如说哔哩哔哩,这次使用的视频发布时,4K 下压缩到 8% 的体积,代价是 83% 的帧的 VMAF 值都低于 91。与小丸工具箱的情况不同,视频质量明显差了一大截。更别说其他分辨率下的情况了。
这十几天也不算是白费力气,至少给了大家这篇文章吧。