YUV420 or 444?关于视频格式问题
ZHY2020
2021年12月30日 02:57

本文主要通过解释420和444采样区别,来说明一下视频播放的那些事儿,以及我自己视频的格式选择问题。


首先我们来看一个视频的MediaInfo信息(一般播放器右键属性里的东西)

代码块
PHP
自动换行
复制代码
概览
特征 ID                          : 4471562085352589502078746514973104799 (0x35D31083AFED94B2AF67AF2207D9A9F)
完整名称                           : F:\处理\利兹与青鸟\[ZHY] Liz to Aoi Tori [Movie][BDRip][4K-upconv][HEVC-yuv444p10]\[ZHY] Liz to Aoi Tori [Movie][BDRip][YUV444P10_4K][x265_flac].mkv
格式                             : Matroska
格式版本                           : Version 4
文件大小                           : 7.49 GiB
时长                             : 1 时 30 分
总体码率模式                         : 动态码率 (VBR)
总体码率                           : 11.9 Mb/s
电影名称                           : リズと青い鳥
编码日期                           : UTC 2021-11-09 04:17:43
编码程序                           : mkvmerge v61.0.0 ('So') 64-bit
编码函数库                          : libebml v1.4.2 + libmatroska v1.6.4

视频
ID                             : 1
格式                             : HEVC
格式/信息                          : High Efficiency Video Coding
格式配置 (Profile)                 : Format Range@L5@High
编解码器 ID                        : V_MPEGH/ISO/HEVC
时长                             : 1 时 30 分
码率                             : 10.5 Mb/s
宽度                             : 3 840 像素
高度                             : 2 072 像素
画面比例                           : 1.85:1
帧率模式                           : 恒定帧率 (CFR)
帧率                             : 23.976 (24000/1001) FPS
色彩空间                           : YUV
色度抽样                           : 4:4:4
位深                             : 10 位
数据密度 [码率/(像素*帧率)]              : 0.055
流大小                            : 6.61 GiB (88%)
标题                             : ZHY压制
编码函数库                          : x265 3.5+10-82786fccc:[Windows][MSVC 1929][64 bit] 10bit
编码设置                           : cpuid=1049583 / frame-threads=2 / numa-pools=4 / wpp / no-pmode / no-pme / no-psnr / no-ssim / log-level=2 / input-csp=3 / input-res=3840x2072 / interlace=0 / total-frames=0 / level-idc=0 / high-tier=1 / uhd-bd=0 / ref=4 / no-allow-non-conformance / no-repeat-headers / annexb / no-aud / no-eob / no-eos / no-hrd / info / hash=0 / no-temporal-layers / no-open-gop / min-keyint=1 / keyint=360 / gop-lookahead=0 / bframes=6 / b-adapt=2 / b-pyramid / bframe-bias=0 / rc-lookahead=80 / lookahead-slices=0 / scenecut=40 / hist-scenecut=0 / radl=0 / no-splice / no-intra-refresh / ctu=64 / min-cu-size=8 / rect / no-amp / max-tu-size=32 / tu-inter-depth=3 / tu-intra-depth=3 / limit-tu=4 / rdoq-level=2 / dynamic-rd=0.00 / no-ssim-rd / signhide / no-tskip / nr-intra=0 / nr-inter=0 / no-constrained-intra / no-strong-intra-smoothing / max-merge=4 / limit-refs=1 / limit-modes / me=3 / subme=3 / merange=57 / temporal-mvp / no-frame-dup / no-hme / weightp / weightb / no-analyze-src-pics / deblock=-1:-1 / no-sao / no-sao-non-deblock / rd=3 / selective-sao=0 / no-early-skip / rskip / no-fast-intra / no-tskip-fast / no-cu-lossless / b-intra / no-splitrd-skip / rdpenalty=0 / psy-rd=1.70 / psy-rdoq=1.00 / no-rd-refine / no-lossless / cbqpoffs=5 / crqpoffs=5 / rc=crf / crf=15.0 / qcomp=0.65 / qpstep=4 / stats-write=0 / stats-read=0 / vbv-maxrate=55000 / vbv-bufsize=60000 / vbv-init=0.9 / min-vbv-fullness=50.0 / max-vbv-fullness=80.0 / crf-max=0.0 / crf-min=0.0 / ipratio=1.40 / pbratio=1.20 / aq-mode=3 / aq-strength=0.80 / cutree / zone-count=0 / no-strict-cbr / qg-size=8 / no-rc-grain / qpmax=69 / qpmin=0 / no-const-vbv / sar=0 / overscan=0 / videoformat=5 / range=0 / colorprim=1 / transfer=1 / colormatrix=1 / chromaloc=0 / display-window=0 / cll=0,0 / min-luma=0 / max-luma=1023 / log2-max-poc-lsb=8 / vui-timing-info / vui-hrd-info / slices=1 / no-opt-qp-pps / no-opt-ref-list-length-pps / no-multi-pass-opt-rps / scenecut-bias=0.05 / hist-threshold=0.03 / no-opt-cu-delta-qp / no-aq-motion / no-hdr10 / no-hdr10-opt / no-dhdr10-opt / no-idr-recovery-sei / analysis-reuse-level=0 / analysis-save-reuse-level=0 / analysis-load-reuse-level=0 / scale-factor=0 / refine-intra=0 / refine-inter=0 / refine-mv=1 / refine-ctu-distortion=0 / no-limit-sao / ctu-info=0 / no-lowpass-dct / refine-analysis-type=0 / copy-pic=1 / max-ausize-factor=1.0 / no-dynamic-refine / no-single-sei / no-hevc-aq / no-svt / no-field / qp-adaptation-range=1.00 / scenecut-aware-qp=0conformance-window-offsets / right=0 / bottom=0 / decoder-max-rate=0 / no-vbv-live-multi-pass
Default                        : 是
Forced                         : 否
色彩范围                           : Limited
色彩原色                           : BT.709
传输特性                           : BT.709
矩阵系数                           : BT.709

音频
ID                             : 2
格式                             : FLAC
格式/信息                          : Free Lossless Audio Codec
编解码器 ID                        : A_FLAC
时长                             : 1 时 30 分
码率模式                           : 动态码率 (VBR)
码率                             : 1 298 kb/s
声道数                            : 2 声道
声道格式                           : L R
采样率                            : 48.0 kHz
帧率                             : 11.719 FPS (4096 SPF)
位深                             : 24 位
压缩模式                           : 无损
流大小                            : 837 MiB (11%)
标题                             : Original 2.0ch
编码函数库                          : libFLAC 1.2.1 (UTC 2007-09-17)
语言                             : 日语 (Japanese)
Default                        : 是
Forced                         : 否

文本
ID                             : 3
格式                             : PGS
混流模式                           : zlib
编解码器 ID                        : S_HDMV/PGS
编解码器 ID/信息                     : Picture based subtitle format used on BDs/HD-DVDs
时长                             : 1 时 29 分
码率                             : 217 kb/s
元素总数                           : 6849
流大小                            : 139 MiB (2%)
标题                             : Original BD subtitle
语言                             : 日语 (Japanese)
Default                        : 否
Forced                         : 否

菜单
00:00:00.000                   : ja:ありふれた日々
00:07:38.083                   : ja:ひとりぼっちの女の子
00:24:28.634                   : ja:籠の中
00:36:23.640                   : ja:とまどい
00:49:53.824                   : ja:リズと青い鳥
01:01:11.418                   : ja:愛ゆえの決断
01:12:03.653                   : ja:ハッピーアイスクリーム
01:24:57.092                   : ja:エンディング

复制成功

从这段Info中可以易得这是个MKV封装,分辨率 3840x2072 HEVC编码视频流,FLAC无损压缩双声道音频流,并附有PGS图形字幕。

以上信息如果看过一些关于视频的封装格式和编码格式的科普应该都能分析出,所以这不是本篇的重点,本篇关注的是以下三个参数。

代码块
PHP
自动换行
复制代码
色彩空间                           : YUV
色度抽样                           : 4:4:4
位深                             : 10 位
复制成功

我们可以称这个视频是YUV444P10的,而绝大多数的视频是YUV420P8的。

色彩空间(Color space)

我们应该都知道光的三原色为红绿蓝(Red Green Blue),图像每个像素的颜色可以用RGB对应不同的强度值来表示任何颜色,而我们在视频中所使用的是YUV可以认为是颜色的另一种表示量化方式,用亮度和色度的方式表示颜色。RGB YUV二者之间可以通过乘矩阵来相互变换。

举个例子,将一个图片分别用RGB和YUV(YCbCr)分离表示:

原图

RGB & YUV

我们可以发现RGB下三个通道基本都可以辨别图像,而YUV下仅亮度(Y)通道可辨别,其他几乎无法辨认原图,因为人眼对色度不敏感。因此,如果我们在有损压缩图像时,降低色度通道的质量也不会对图像质量产生明显劣化。诸如H264、HEVC等视频压缩编码,以及jpeg图片压缩都是使用YUV空间对颜色进行量化的,再在此基础上进行压缩编码

色度抽样(Chroma Subsampling)

上面我描述了YUV色彩空间,一般来说每个像素都对应有各自的YUV数值,所以拆分开的三个通道的分辨率都应该是与原图相同的。比如一张分辨率3840x2160的YUV图片,Y通道是3840x2160,UV通道各自应也是3840x2160。这种情况就是所谓的4:4:4采样(YUV444)

上面我们了解了,人眼对色度的不敏感,压缩时可以适当损失UV通道的质量。我们甚至可以直接对UV通道的分辨率进行降低来存储图像,在还原图像时再把UV通道的拉伸回原分辨率,这样产生的画质损失也是比较小的。YUV 4:2:0采样便是将UV通道的分辨率长宽都缩至1/2,还是以3840x2160的图片为例,420采样下,UV通道分辨率仅1920x1080。

在色度抽样下,图像的体积在未进行复杂的压缩处理下,体积便可缩小一半,在压缩编码时处理的数据量就小了,编解码速度也会提升。视频无非就是压缩一堆图片,所以使用420抽样即可提升编码速度和解码压力。

位深(Bit depth)

上面说的不管是RGB空间还是YUV空间,每个像素的都有三个强度值,这些值在计算机中以二进制数表示,位深就是这些二进制数的位数。简单说8位色深可以把最暗到最亮分成2的8次方256个级别,10位色深即2的10次方1024个级别,10位色深的颜色过渡可以比8位更平滑。


视频播放时播放器的工作

一般打开一个视频文件,播放器会调用对应封装格式的分离器读取其中的各个视频流、音频流、以及可能有的字幕等。

视频码流会交给视频解码器,音频码流会交给音频解码器。

视频解码器分硬件解码器和软件解码器,硬解即调用专用解码电路(电脑上一般与GPU整合在一起),软解即使用CPU的通用计算能力解码。硬解码能力是硬件固有的,并且支持程度非常细分与分辨率、编码格式、色度抽样和色深都相关。软件解码,顾名思义只要电脑安装了对应的解码器软件,并且CPU不缺少解码必须的指令集,便可解码该格式,只是CPU的性能是否可以支撑流畅的输出。

不管是硬解还是软解,都是将H264、HEVC等编码流,解码成YUV数据流(也就是YUV空间表示的一堆图片流),一开头所举的视频为例,解码后就是YUV444P10格式的3840x2072图像流。由于显示器的每个像素是用RGB来显示的,YUV需要转RGB空间推给显示器。而且不是所有显示器会与视频分辨率相匹配,YUV三个通道需要各自缩放到显示器的目标分辨率,这项工作就是渲染器在完成。

以我自己的播放器配置为例:MPC-BE + LAV Filter + MadVR + XySubFilter

LAV Filter 中包含了分离器和音视频解码器,MadVR即渲染器,XySubFilter即字幕渲染器。

下面展示一些播放时MadVR的OSD,来加深对YUV420和YUV444的理解。

1.3840x2072 YUV444 目标2560x1440显示

OSD显示image以SSim算法缩小至目标,因为YUV三通道分辨率相同,均为3840x2072。

2.3840x2072 YUV420 目标2560x1440显示

OSD显示Chroma色度以NGU Anti-alias (med) 放大,image以SSim算法缩小至目标。这时视频的UV色度分辨率为1920x1036,MadVR将其放大2倍,再与Y平面一起缩小至目标

3.3840x2072 YUV420 目标1920x1036显示

OSD显示luma以SSim算法缩小至目标,这里的目标分辨率与色度的相同,MadVR仅对Y亮度平面进行了缩小。


对我现在的4K视频格式的说明

目前我的4K视频的源视频(上传给B站的文件)的格式是MKV封装,HEVC编码YUV420P10,音频格式视素材源而定,尽量无损FLAC。

写这篇文章,主要是有人对我之前的无聊测试(cv12560715)中的YUV444P10视频表示疑问。他的疑问主要是444全采样与420清晰度画质没区别,没必要压制444的视频;素材是8bit的没必要压制10bit。

其实这些问题在早年的VCB科普中都可以解答(cv1859841 B站转载版),虽然当时我介绍了这个科普,但我还是觉得自己详细回答一下。

首先简要描述我的处理4K超分辨率视频的流程,拿到一个视频(一般都是420采样的色深有8bit也有10bit)会对其进行UV色度升频(放大)并转换成RGB24(8bit色深的RGB)。

这里可能会有疑问,10bit视频怎么会降色深?目前这是软硬件的限制,我使用的超分软件TVE要输出16bit的只能选择未压缩,一个视频下来硬盘占用太大,理想情况下是应该全程16bit精度的。并且这是8bit的RGB不是8bit的YUV,对于RGB来说降低精度不会像YUV强行降低精度产生色带等问题。

接着,RGB数据会以PNG无损压缩输出成图片序列,使用TVE超分,得到高分辨率的PNG RGB24图片序列,再组合图片序列,添加帧率信息,转YUV空间,输出给x265编码器压制成视频。

回答第一个问题,关键在最后的从RGB转回YUV的操作RGB是没有420采样一说的,它和YUV444是可以通过特定的矩阵互向可逆变换的,在最终输出时没必要降采UV色度的。我在前文所说影响YUV图像效果主要是Y平面,只要Y平面分辨率没有损失,画质不会有太大的损失。444解决的主要是一些特定情况的颜色失真,在动画中不太明显。压制444视频是在最大限度的颜色保真。实际生活中遇到的很少,我自己通常还是以420视频为主,444视频的编解码压力很大。

至于10bit的色深,YUV与RGB的互转是个浮点计算,使用提高精度输入转换后的精度更准,实际RGB 8bit转YUV444P16是可以填充多出来的8位,在者我在处理过程需要添加滤镜(抗色带等),这些滤镜也是16bit精度的。所以如编码器允许我甚至可以输出YUV420P16。但是x265最高12bit,考虑到播放的压力以及10bit完全可做到看不出色带,最终选择YUV420P10。(YUV420P8其实也可通过添加噪点等手段来掩盖色带,但这会付出更大体积的代价)


参考资料:https://vcb-s.com/archives/2726

YUV与RGB互转进阶:

https://vcb-s.nmm-hd.org/Templar%20Archive/

[教程18]YUV与RGB的互转(1)  主要涉及YUV420的Chroma placement 对齐的问题,以及RGB与YUV互转的几种matrix。