☰
4K高帧率视频编码测试:UVG数据集选型与HEVC/VVC评测流程
2026/11/3 22:13:24 网站建设 项目流程

简介:这份资料是 UVG(Ultra Video Group)4K 视频数据集配套论文的 PDF,面向从事视频编码研究、编解码器性能评测与多媒体开发的技术人员。数据集包含 16 个 4K(3840×2160)测试序列,帧率覆盖 50 fps 与 120 fps,以 8 位和 10 位 4:2:0 YUV 原始格式存储,素材由 Sony F65 拍摄,采用非商业 CC BY-NC 许可。论文逐一描述各序列的空间与时间感知信息,并给出在 HEVC/H.265 与 VVC/H.266 参考编解码器上的率失真性能与编码复杂度对比,指出其作为首个覆盖 120 fps 的 4K 测试集,对下一代 VVC 编解码器的主观与客观质量评估具有补充价值。压缩包仅含 1 个 PDF 文件,约 931KB,便于快速通读与引用。已有 142 人学习,适合希望了解高质量测试序列选取、搭建编码实验基线或撰写相关论文的读者。

1. 为什么我把 4K 编码验证从标准测试集挪到了这套 50/120fps 序列

在一次编码器横评里,两版编码器在 2160p 标准测试序列上 BD-rate 差 3% 出头,换成一段 120fps 赛马跟拍素材重跑,排序直接反了。配置没错,编码器也没错,错的是测试集——标准 2160p 那批里几乎没有高帧率内容,而 120fps 恰好是这一代编码工具最吃劲的地方。此后我在所有 4K 视频编码验证里都固定加一组原始高帧率素材,用的就是这套 UVG 4K 视频数据集:16 条 2160p 序列,8 条 120fps、8 条 50fps,原始未压缩 YUV,8-bit 与 10-bit 4:2:0 双版本,每条固定 600 帧。下面讲我怎么在 HEVC 和 VVC 之间做数据集选型、怎么从 16 条里挑出能打的子集、怎么跑出不翻车的 RD 曲线,以及那些让我白跑一整晚的坑。

2. 4K 测试集怎么选:四个维度把候选摆到桌面上

4K 视频数据集看着都差不多,都是 3840×2160 的 YUV 文件,但真正拉进实验里,差异全在你看不见的地方。我一般按四个维度比:数据是不是原始未压缩、帧率覆盖够不够宽、位深与内容覆盖是否成组、许可与可复现性是否过关。前两个决定实验能不能做成,后两个决定结论能不能被采信。

2.1 原始未压缩还是已有压缩:能不能归因的分水岭

市面上能拿来用的 4K 素材分两类。一类是从内容平台拿视频解码回 YUV 的,用起来方便、内容还贴近真实用户,问题是它自带一次编码留下的压缩伪影,块效应、振铃、细节涂抹都在里面。你拿它评编码器增益,测出来的差值里混着「新编码器对旧伪影的处理」和「新编码器本身的编码效率」,两件事搅在一起,永远说不清。

另一类是原始采集、无损落地的素材。这套 UVG 就是后者:16-bit RAW 采集,再用 FFmpeg 转成 10-bit 和 8-bit 4:2:0 YUV,中间没有经过任何有损编码。归因干净,这是它对我最大的价值。核验方法也很朴素——8-bit 4:2:0 下每像素 1.5 字节,3840×2160×600 帧的文件应该正好是 7,464,960,000 字节左右(12,441,600 字节/帧 × 600);如果文件明显偏小,那多半是转过一手的编码件,别拿它做 RD 基准。

维度这套原始 2160p 集合平台视频解码型 4K 集合通用测试条件下的 2160p 子集
数据形态16-bit RAW 采集转 8/10-bit 4:2:0 YUV,无压缩平台视频解码回 YUV,带既有压缩伪影原始,但条数偏少
帧率50 / 120 fps 各 8 条多为 24–30 fps多为 24–60 fps
单条帧数统一 600 帧8–20 秒不等数秒到 10 秒
内容取向人像特写、水面、花田、赛马、夜景用户生成、类别混合通用自然场景
许可非商业 CC BY-NC各异研究用途

2.2 帧率覆盖:50/120 这个组合不是随手凑的

50fps 和 120fps 各占一半,是这套集合最讲究的地方。50fps 是 PAL 体系下常见的高清交付帧率,120fps 是典型的高帧率采集档位,中间没有过渡档。这个设计的好处是变量干净:你不能用它做「帧率连续性」的研究,但你能非常利落地做「同一套编码工具在常规帧率与高帧率下的行为差异」。

更要紧的是时长差异带来的坑。同样 600 帧,120fps 那条只有 5 秒,50fps 那条有 12 秒。5 秒素材里,一次镜头横摇可能只走完一半;12 秒素材里,横摇、变焦、焦点切换全都能完整发生。这直接影响你怎么设 IntraPeriod 和 GOP 长度——按 1 秒 GOP 算,120fps 要设成 120,50fps 设成 50,如果你图省事全填一个数,两条序列的 I 帧密度就不一样了,BD-rate 会莫名其妙飘。我一般会把 IntraPeriod 统一折算成「帧数 = 帧率 × 1」,让两条序列在时间轴上对齐。

2.3 位深与内容覆盖:被低估的两个变量

10-bit 4:2:0 是当前主流的交付与采集格式,8-bit 版本则方便那些还没升级的旧工具链。这套素材两个版本都给,意味着你可以用同一段内容做位深敏感度对比——同一序列,8-bit 输入与 10-bit 输入,在 10-bit 内部位深编码器下跑出来的曲线差值,能直接量化位深损失对编码效率的影响。这种对照在只提供一个位深版本的数据集上做不了。

内容覆盖上它避开了「全是自然风景」的常见毛病。人像特写带噪声背景的、水面波纹加雾景的、暗巷上摇带高对比出口的、固定机位拍蜜蜂的、跟拍赛马带焦点切换的、夜间赛马带大面积暗区的,都在里面。自然序列有个好处:没有人工合成的规律性,编码器没法靠「猜图案」作弊。

2.4 许可与可复现性:能不能写进报告

这套数据以非商业 CC BY-NC 许可公开,个人研究、实验室内部评测、论文里的实验复现都在射程内;要往商业产品的对外性能宣称上搬,得先看清楚条款再决定,别等到发布前才回头改图。

可复现性是另一个隐性指标。这套素材全公开、文件名固定、帧数统一 600、分辨率统一 3840×2160,别人拿到你报告里的配置和序列名,能一比一复算。反过来,来源不明、帧数不统一、同一名字下有好几个版本的「野生 4K 素材」,做出来的对比图没人能验证,写了也白写。

3. 16 条序列逐类拆解:哪几条 120fps 该先进实验队列

16 条全跑一遍 10-bit、四个 QP 点、两个编码器,一台机器要转到下周。所以真实流程一定是先挑子集。挑子集的依据不是「哪条看着好看」,而是内容的空间复杂度、时域变化、对比度三项特征能不能覆盖你想验证的工况。下面这 10 条是我反复跑过的,特征比较有代表性。

序列帧率运动纹理对比典型用途
Beauty120慢 / 大量复杂高人像细节、暗背景噪声
Bosphorus120慢 / 大量复杂低水面波纹、低对比雾景
HoneyBee120快 / 少量复杂低固定机位下的快速小目标
Jockey120快 / 大量平滑高跟拍全局运动、焦点切换
Lips120慢 / 少量平滑高前景虚焦、平滑区域
CityAlley50慢 / 少量复杂高暗部细节、大范围上摇
FlowerFocus50慢 / 少量平滑低变焦、景深变化
FlowerKids50慢 / 大量复杂高镜头抖动、镜头光晕
FlowerPan50慢 / 少量复杂低横摇、高频细节(飞虫)
RaceNight50快 / 大量平滑高夜间大面积暗区、快速运动

3.1 120fps 那 8 条:慢运动复杂纹理与快运动平滑纹理是两类样本

Beauty、Bosphorus、Lips 这三条归一类:镜头基本不动,但画面里的细节密度极高。Beauty 是黑背景前的人脸特写,头发在风里飘,背景还带噪声,高对比加高频细节,压空间预测和变换系数最狠;Bosphorus 是一条黑船在水面上走,水面波纹持续变化,背景是雾里的山丘、海边村落和一座悬索桥,整体低对比,考验编码器在低对比区域的比特分配;Lips 是口红特写,前景人脸的局部失焦,背景纯黑,高对比加平滑纹理,容易暴露量化步长在平坦区的选择问题。

Jockey 和 HoneyBee 归另一类:画面里有快速运动,但局部纹理偏平滑。Jockey 是跟拍赛马,机位跟着马跑,背景高速后退,中途焦点从骑手切到马腿,全局运动加焦点切换叠在一起,运动补偿最容易在这里失效;HoneyBee 是固定机位追一只蜜蜂在花间飞,前景和背景都虚化,只有蜜蜂本体清晰,小目标高速运动,考验小块划分和亚像素精度。

这两类的差别极关键:前者压的是空间细节,后者压的是时域预测。你要是只跑第一类,会高估编码器在运动场景下的表现;只跑第二类,会低估它在细节保留上的损失。

3.2 50fps 那 8 条:镜头抖动、光晕、变焦这些「非编码友好」内容

FlowerKids 是这批里最不讲道理的:两个小孩在黄色花田里跑,机位手持、全程抖动,背景还有太阳造成的镜头光晕。抖动让全局运动补偿基本失效,光晕是局部亮度突变,两样都是编码器的噩梦,但也正是这种素材能把不同实现之间的差距拉开。FlowerPan 是一条三色花带(红、黄、靛)的横摇,花上有飞虫,横摇带来的整体位移好预测,飞虫这种高频小目标是难点。

CityAlley 是暗巷里缓慢上摇,巷子尽头一座高塔,塔顶站着人,出口处与巷内形成强烈明暗对比。暗部加高动态范围,量化稍重就糊成一片。FlowerFocus 是红花特写,随风摆动,随后镜头上摇、焦点转到背景花丛,景深变化会造成整片区域的模糊程度跳变,参考帧和被参考帧的有效细节量不一致,预测残差会突然变大。RaceNight 是夜间赛马,大面积暗区加快速运动,暗区噪声和运动残差混在一起,很容易在低码率下出块。

3.3 用 SI/TI 二维坐标挑最小子集

我不靠眼睛挑,靠两个数:空间感知信息(SI)和时间感知信息(TI)。SI 是逐帧做 Sobel 边缘检测、取梯度幅值的标准差、再对所有帧取最大值,衡量画面里最多有多少空间细节;TI 是逐帧做相邻帧差、取差值的标准差、再取最大值,衡量画面变化最剧烈时有多大。这两个指标在 ITU 的建议里有明确定义,算出来的数值可以直接横向比。

做法很简单:把候选序列的 SI 和 TI 都算出来,画成散点,按中位数切成四个象限——高 SI 低 TI(细节重)、低 SI 高 TI(变化重)、双高(最难)、双低(最易)。每个象限挑一到两条,凑够 4 到 6 条,就是一套能覆盖工况的最小实验集。我这边的常用配置是 Beauty、Bosphorus、Jockey、FlowerKids、RaceNight 五条,双高的和双低的各留一条做边界验证。

提示:SI/TI 只反映内容和帧间差异,不含任何编码器信息。拿它选子集是合理的,拿它推断编码效率不行——后者还得实跑。

4. 从 YUV 到 RD 曲线:一套能直接抄的评测流程

4.1 先算清存储与 IO 预算

一条 8-bit 4:2:0 的 2160p 序列,每帧 12,441,600 字节,600 帧下来约 7 GiB;10-bit 版本每样本按 2 字节存,每帧 24,883,200 字节,600 帧约 14 GiB。16 条全下,8-bit 约 110 GiB,10-bit 约 220 GiB,两个版本都要就是 330 GiB 上下。这个量级下,别指望放在系统盘上跑。

更要紧的是 IO 会污染你要统计的编码耗时。机械盘顺序读 4K YUV 能跑到一两百 MB/s 就不错了,而参考编码器读一帧要 24 MB,600 帧下来读盘时间可能和编码时间同量级。我一般把当前要跑的 3 到 5 条序列拷到 SSD 上,跑完再换下一批,测耗时的那一轮单独重跑,避免缓存冷热不一致导致的波动。

4.2 用一段脚本把 SI/TI 摸清楚

下面这段读 YUV420P10LE、按均匀间隔抽 30 帧、算 SI 和 TI。抽帧是为了省时间,600 帧全做 4K Sobel 在普通工作站上要跑十几分钟,抽 30 帧够看出量级差异了。

import numpy as np W, H = 3840, 2160 FRAME_BYTES = W * H * 3 # YUV420P10LE:1.5 * W * H 个样本,每样本 2 字节 SAMPLE_EVERY = 20 # 每 20 帧取 1 帧,600 帧共取 30 帧 def read_y(path, idx): with open(path, 'rb') as f: f.seek(idx * FRAME_BYTES) y = np.fromfile(f, dtype=np.uint16, count=W * H) # 先看最大值判断位深对齐方式:<=1023 是低位对齐,>1023 说明左移过 if y.max() > 1023: y = y >> 6 return y.astype(np.float32) def sobel_mag(p): # 3x3 Sobel,切片写法天然丢掉最外一圈像素,避开边界卷积 gx = (p[:-2, 2:] + 2*p[1:-1, 2:] + p[2:, 2:]) - (p[:-2, :-2] + 2*p[1:-1, :-2] + p[2:, :-2]) gy = (p[2:, :-2] + 2*p[2:, 1:-1] + p[2:, 2:]) - (p[:-2, :-2] + 2*p[:-2, 1:-1] + p[:-2, 2:]) return np.sqrt(gx*gx + gy*gy) def si_ti(path, total_frames=600): idxs = list(range(0, total_frames, SAMPLE_EVERY)) prev, si, ti = None, 0.0, 0.0 for i in idxs: y = read_y(path, i) si = max(si, float(np.std(sobel_mag(y)))) if prev is not None: # 这里相邻样本实际间隔 20 帧,TI 会偏大,报告里需注明采样策略 ti = max(ti, float(np.std(y - prev))) prev = y return si, ti print(si_ti('Beauty_3840x2160_120fps_10bit_420.yuv'))

几个参数的含义要说清:FRAME_BYTES由像素格式决定,8-bit 版本是这个值的一半,写成W * H * 3 // 2;SAMPLE_EVERY决定采样密度,设成 1 就是逐帧算,最准但最慢;y.max() > 1023那句是位深对齐的自检,不同工具链导出的 10-bit 有的是低位对齐(值域 0–1023),有的是高位对齐(值域 0–65472),不检查就往下算,SI 会大出 64 倍,选子集的结论全错。

TI 那段要老实写上「采样间隔 20 帧」,因为严格定义上 TI 是相邻帧之间的,跳帧算出来的值偏大,跨数据集对比时会被质疑。要做到严格,就把SAMPLE_EVERY设成 1,只在最终报告的那几条序列上跑。

4.3 HM 与 VTM 的随机接入配置

两个参考编码器的命令行参数命名不太一样,混用会直接报错退出。下面是 HEVC 参考软件 16.20 的随机接入配置,10-bit 输入、10-bit 内部位深:

./bin/TAppEncoderStatic \ -c cfg/encoder_randomaccess_main.cfg \ -i Beauty_3840x2160_120fps_10bit_420.yuv \ -wdt 3840 -hgt 2160 -fr 120 -f 600 \ --InputBitDepth=10 --InternalBitDepth=10 \ -q 22 -b out/Beauty_hm_qp22.bin -o /dev/null

VVC 参考软件 8.0 的参数名更长,改成--InputFile=、--SourceWidth=这一套:

./bin/EncoderAppStatic \ -c cfg/encoder_randomaccess_vtm.cfg \ -i Beauty_3840x2160_120fps_10bit_420.yuv \ -wdt 3840 -hgt 2160 -fr 120 -f 600 \ --InputBitDepth=10 --InternalBitDepth=10 \ -q 32 -b out/Beauty_vtm_qp32.bin -o /dev/null

-f 600必须显式给。默认帧数是 1,不明写就会只编一帧,跑完你还以为出了别的毛病。-fr要跟序列实际帧率一致,否则码率换算和时域 QP 偏移的逻辑都会错位。-q是 QP,我固定用 22、27、32、37 四个点算 BD-rate,两点太少拟合不稳,六点又太贵。

批处理就套一层循环:

for q in 22 27 32 37; do for seq in Beauty Bosphorus Jockey FlowerKids RaceNight; do ./bin/EncoderAppStatic -c cfg/encoder_randomaccess_vtm.cfg \ -i in/${seq}_3840x2160_*_10bit_420.yuv \ -wdt 3840 -hgt 2160 -fr 120 -f 600 \ --InputBitDepth=10 --InternalBitDepth=10 \ -q $q -b out/${seq}_q${q}.bin -o /dev/null done done

注意-fr在循环里被写死成 120,50fps 那几条要单独一组,或者把帧率也做成变量。这种小地方漏一次,一整晚的结果全废。

4.4 把编码复杂度的口径钉死

不同编码器之间的耗时对比最容易变成玄学。我的做法是四条硬规矩:同一台机器、同一套编译器与优化选项、固定线程数(我一般设成 1,虽然慢但可复现)、编码前后各跑一次热身序列排除文件系统缓存的影响。测三轮取中位数,不看平均值,一次 GC 或者一次后台更新就能把平均值带偏。

真要横向比复杂度,只看绝对秒数意义有限,我通常用「相对基准编码器在同一序列、同一 QP 下的耗时比值」,把机器性能差异消掉。这个比值配合 RD 曲线一起看,才能回答「多花 30% 时间换来 5% 码率下降值不值」。

5. 避坑与排查:4K 原始序列最容易翻车的五件事

5.1 五条踩坑记录

600 帧不等于 5 秒。现象是报告里写「5 秒素材」的那条 50fps 序列,被评审问为什么码率换算对不上。原因在于 600 帧在 120fps 下是 5 秒,在 50fps 下是 12 秒,同一批素材时长并不统一。解决办法是把「帧数」和「时长」分开记,配置里只写帧数,报告里两个都写。

10-bit 序列喂给了 8-bit 编译的编码器。现象是编码正常跑完,PSNR 却好得反常,曲线平滑得不像话。原因是参考编码器默认编译只支持 8-bit,遇到 10-bit 输入会截断或按错误步长读取,相当于你测的根本不是原始数据。解决方式是编译时开高位深支持,跑之前先看编码器启动日志里打印的输入位深,对不上立刻停。

SI/TI 算出来所有序列都差不多。现象是散点图糊成一团,选不出子集。原因多半是位深对齐没检查,10-bit 值域被当成 16-bit 用,或者 Sobel 没去边界导致外圈像素把标准差拉平。解决办法是先打印每帧的 min/max/mean 三个值,正常 10-bit 数据的 max 应该在 1000 上下,明显偏大就是对齐问题。

编码耗时统计波动超过 20%。现象是同一配置跑三次差出一大截,复杂度结论没法下。原因是 4K YUV 单帧 24 MB,读盘时间被算进了编码时间。解决方式是把待测序列拷到 SSD、跑前热身一次、固定线程数、取三次中位数,并把 IO 时间单独打点。

四个 QP 点跑出反号的 BD-rate。现象是新编码器在 QP 22 上明显赢,在 QP 37 上明显输,拟合出来的 BD-rate 接近零甚至为负。原因是 QP 点太少且分布不均,曲线在高码率段交叉。解决办法是固定 22/27/32/37 四个点,先看四条 R-D 点是否单调、是否两次交叉,交叉严重就追加 QP 17 和 42 各一个点确认趋势。

5.2 开跑前的检查清单

序列文件名里带上分辨率、帧率、位深、像素格式四要素,别只写Beauty.yuv;确认文件大小等于帧数 × 每帧字节数,差一点都说明文件有问题;确认编码器日志里的输入位深、分辨率、帧数与预期一致;确认 IntraPeriod 按帧率 × 1折算过;确认许可条款允许你当前的使用方式。这五条对完,一次批量跑废的概率能降一大半。

6. 落到选型结论:三类人各拿哪几条序列,附一个固定习惯

做了这么多轮,结论其实很直接。

做下一代编码标准前沿验证的,直奔 120fps 那 8 条。Beauty 和 Bosphorus 看空间细节与低对比区比特分配,Jockey 看全局运动加焦点切换,HoneyBee 看小目标高速运动。这四条能覆盖高帧率下时域工具的主要失效模式,比在 30fps 素材上反复调参有意义得多。

做产品级编码器调优、关心实际交付质量的,50fps 那 8 条更贴近真实工况。FlowerKids 的手持抖动加镜头光晕、CityAlley 的暗部、RaceNight 的夜间快速运动,这三条基本能把编码器在「不友好内容」上的短板全暴露出来。我见过不少在标准序列上表现优秀的配置,一到 FlowerKids 上就原形毕露。

做主观质量评估、要攒测试集的,按 SI/TI 四象限各挑一到两条,凑 8 条左右,把慢运动复杂纹理、快运动平滑纹理、低对比雾景、暗区高动态这四种极端都占住。别只挑好看的,主观实验最怕素材同质化。

至于在 HEVC 和 VVC 之间怎么选参考编码器——两个都跑。HEVC 的参考软件是当前工业界的事实基线,VVC 的参考软件代表下一代工具集的上限,你只有同时拿到两条曲线,才能说清「这套序列对新一代工具的区分度」。这套集合的评估结果里有个很关键的信号:它能补充现有 2160p 测试集在高帧率维度上的空白,换句话说,拿它做 VVC 阶段的主观和客观评估,不会和标准测试集重复,而是互补。

最后留一个我每次开跑前都强制走一遍的习惯:先只跑一条 Beauty,四个 QP 点,把码率、PSNR、耗时全打出来,跟上一轮的记录对一遍。对得上,再放批处理;对不上,就停在原地查配置。这个习惯是有一年赶进度时养成的——那次我把 IntraPeriod 漏配成默认值,批处理跑到第二天早上才发现整批数据的时间轴和上一轮不可比,所有曲线要重画。从那以后,我再急也会先跑这一条「哨兵序列」,哪怕只花二十分钟。希望这套流程能帮你少走一遍我踩过的路。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询