YUV视频格式详解(翻译自微软文档)

时间:2021-03-18 15:25:32

Video Rendering with 8-Bit YUV Formats

Gary Sullivan 和 Stephen Estrop
微软数字媒体部门
四月 2002年
更新于 八月 2003 年

摘要:此文描述了在windows操作系统上推荐的视频格式—-8位的YUV,此文同时也展示了YUV和RGB格式的互相转换计算方法,提供了上采样YUV的方法。这篇文章的适用人群是从事于YUV视频显示和编码的开发人员。

介绍:在整个视频行业里面,YUV定义有很多种类。此文讲解的是微软推荐的适用于windows操作系统的YUV格式。同时,解码器供应商和显示器供应商都是被鼓励支持文中所提到的YUV格式。本文并没有解决YUV彩色的其他用途,如静止摄像。

本文中描述的格式是使用8位像素去编码Y通道(也称为亮度通道)和每个样本使用8位编码U或者V色度通道。然而,大多数的YUV格式并没有24位像素,因为它们含有较少的U或V通道数据,相比Y通道而言。

为了此文章后目的表述,术语U相当于Cb,术语V相当于Cr。

此文接下来会聊聊这些话题:

  1. 确定DirectShow的YUV格式—解释如何描述DirectShow的YUV格式类型
  2. YUV采样—描述最普通的YUV采样方法
  3. 表面定义—描述推荐的YUV定义格式
  4. 颜色空间和色度采样频率转换—RGB和YUV的互相转换

确定DirectShow的YUV格式

本文指定的YUV格式都是4字节,一个4字节代码是一个32位的无符号整型数据,它包含了4个人ASCII字符。
有许多的C/C++的四字节宏定义使得它的能够更加简单的描述。下面是简单的代码

DWORD fccYUY2 = MAKEFOURCC('Y','U','Y','2');
DWORD fccYUY2 = FCC('YUY2');
//解释一下,FCC就是自定义的一个宏。使得上面的两行代码是一个意思。
//下面还有一句更加简单的,也是一个意思
DWORD ffcYUY2 = '2YUY'
//这行代码中,我们发现YUY2发生了位置反转。这是由于windows操作系统采用了小端模式架构

在ASCII中,’Y’=0x59 ‘U’=0x55 ‘2’=0x32,于是可以得到:
‘2YUY’ = 0x32595559

在DirectShow中,格式定义的主要类型是全局唯一标识符和二级全局唯一标识符。由于主要是类型是计算机视频媒体格式,其二级全局唯一标识符可以由4字节代码映射构建。

xxxxxxxx-0000-0010-8000-00AA00389B71
其中的xxxxxxxx代表4字节代码,因此YUY2可以表示为:
32595559-0000-0010-8000-00AA00389B71

这个部分本来还有代码展示的,非YUV视频开发人员就忽略吧。文章最后会附上英文原文地址,有兴趣可以自行阅读。

YUV采样

YUV的优点在于:色度和亮度隔离,并且色度采样频率低于Y通道的,也不会导致图像质量的剧烈下降。
为了简化表达方式,符号A:B:C表示Y:U:V,可以理解为:U和V相对于Y的比例。

总共有4种采样格式:

  1. 4:4:4 表示色度通道没有降采样
  2. 4:2:2 表示2:1的水平降采样和垂直方向没有降采样,简单的理解为采样线条里面有4个Y,2个U,2个V
  3. 4:2:0 表示2:1的水平和垂直方向的降采样
  4. 4:1:1 表示4:1的水平降采样和没有垂直降采样,简单理解为采样线条里面有4个Y,1个U,1个V

下面用图形完成4种格式的理解:
亮度用叉来表示,色度则用圈表示。

第一、4:4:4格式
YUV视频格式详解(翻译自微软文档)
图1. 4:4:4

第二、4:2:2
YUV视频格式详解(翻译自微软文档)
图2. 4:2:2

第三、4:2:0
这里有两种常见的变化形式,其中一种形式用于 MPEG-2 视频,另一种形式用于 MPEG-1 以及 ITU-T recommendations H.261 和 H.263。图 3 显示了 MPEG-1 方案中使用的采样网格,图 4 显示了 MPEG-2 方案中使用的采样网格。

YUV视频格式详解(翻译自微软文档)
图3. 4:2:0

YUV视频格式详解(翻译自微软文档)
图4. 4:2:0

表面定义

本节讲述推荐用于视频呈现的 8 位 YUV 格式。这些格式可以分为几个类别:

4:4:4 格式,每像素 32 位

4:2:2 格式,每像素 16 位

4:2:0 格式,每像素 16 位

4:2:0 格式,每像素 12 位

首先,您应该理解下列概念,这样才能理解接下来的内容:
1、表面原点。对于本文讲述的 YUV 格式,原点 (0,0) 总是位于表面的左上角。
2、跨距。表面的跨距,有时也称为间距,指的是表面的宽度,以字节数表示。对于一个表面原点位于左上角的表面来说,跨距总是正数。
3、对齐。表面的对齐是根据图形显示驱动程序的不同而定的。表面始终应该 DWORD 对齐,就是说,表面中的各个行肯定都是从 32 位 (DWORD) 边界开始的。对齐可以大于 32 位,但具体取决于硬件的需求。
4、打包格式与平面格式。YUV 格式可以分为打包 格式和平面 格式。在打包格式中,Y、U 和 V 组件存储在一个数组中。像素被组织到了一些巨像素组中,巨像素组的布局取决于格式。在平面格式中,Y、U 和 V 组件作为三个单独的平面进行存储。

4:4:4 格式,每像素 32 位
这是一个打包格式,其中每个像素都被编码为四个连续字节,其组织顺序如下所示。
YUV视频格式详解(翻译自微软文档)

4:2:2 格式,每像素 16 位,支持两个 4:2:2 格式如下:
YUY2
UYVY
这两个都是打包格式,其中每个像素都是编码为四个连续字节的两个像素。这样会使得色度水平下采样乘以系数 2。
YUV视频格式详解(翻译自微软文档)
YUY2 内存布局

YUV视频格式详解(翻译自微软文档)
UYVY 内存布局

4:2:0 格式,每像素 16 位,支持两个 4:2:0 格式如下:
IMC1
IMC3
这两个都是平面格式,色度频道在水平方向和垂直方向上都要以系数 2 来进行再次采样。

对于IMC1而言,V和U都必须和Y的水平对齐,于是就出现了未使用的Space区域。
YUV视频格式详解(翻译自微软文档)
IMC1 内存布局

YUV视频格式详解(翻译自微软文档)
IMC3 内存布局

4:2:0 格式,每像素 12 位,支持四个 4:2:0 格式如下:
IMC2
IMC4
YV12
NV12
在所有这些格式中,色度频道在水平方向和垂直方向上都要以系数 2 来进行再次采样。

对于IMC2而言,此格式与 IMC1 相同,只是 V (Cr) 和 U (Cb) 行在半跨距边界处进行了交错。每一行都是以V开头,然后在每一行的交界处U再开始存储。
YUV视频格式详解(翻译自微软文档)
IMC2 内存布局

对于IMC4而言,与IMC2是一样的。只是U和V的位置换了而已。
YUV视频格式详解(翻译自微软文档)
IMC4 内存布局

在YV12中,U和V的平面跨度只有Y的一半。
YUV视频格式详解(翻译自微软文档)
YV12 内存布局

对于NV12格式而言,组合的 U-V 数组被视为一个由 little-endian(小断) WORD 值组成的数组时,LSB 包含 U 值,MSB 包含 V 值。
YUV视频格式详解(翻译自微软文档)
NV12 内存布局

RGB和YUV的互相转换

我们首先描述了RGB和YUV4:4:4格式之间的转换。为了把4:2:2或者4:2:0转换为RGB格式,我们一般是把它们转换为4:4:4以后,然后把4:4:4格式转换为RGB。这个4:4:4的YUV格式,为每个Y、U和V都采用8为数据。在其他的应用里面,也可以使用超过8位的来表示YUV格式。

从RGB转换到两个主要的YUV格式都是为数字视频而定义的。这两个都是基于ITU-R所推荐的BT.709。第一个转换可以称之为老的YUV,基于BT.709的50Hz,它和ITU-R推荐的BT.601是一样的,他有一个旧称—-CCIR601。这种格式更加适用于标清及以下分辨率的电视视频。它有两个特征常量:

Kr = 0.299
Kb = 0.114

第二个转换可以称之为新的YUV,基于BT.709的60Hz,这种格式更加适用于标清分辨率以上的电视视频。它也有两个特征常量:

Kr = 0.2126
Kb = 0.0722

接下来就是RGB转换为YUV的定义:

//常数L
L = Kr * R + Kb * B + (1 – Kr – Kb) * G
//Y分量
Y = floor(2^(M-8) * (219*(L–Z)/S + 16) + 0.5)
//U分量
U = clip3(0, 2^M-1, floor(2^(M-8) * (112*(B-L) / ((1-Kb)*S) + 128) + 0.5))
//V分量
V = clip3(0, 2^M-1, floor(2^(M-8) * (112*(R-L) / ((1-Kr)*S) + 128) + 0.5))

上面变量以及函数定义解释:
M : YUV样本的位数
Z : 黑色的值,对于计算机RGB,Z=0;对于电视视频RGB,Z=16*2^(N-8),这里的N代表电视视频RGB每个分量的位数。
S : 缩放比例,对于计算机RGB,S=255;对于电视视频RGB,S=219*2^(N-8),这里的N同上。

函数floor(x)表示返回大于或者等于x的最大整数。
函数clip3(x,y,z)定义如下:

clip3(x, y, z) = ((z < x) ? x : ((z > y) ? y : z))

这个Y分量代表亮度,U和V分别代表色差里面的blue和red。下面只YUV三个分量的范围:

16*2^(M-8) ≤ Y ≤ 235*2^(M-8)//左边代表黑色,右边代表白色

16*2^(M-8) ≤ U ≤ 240*2^(M-8)

16*2^(M-8) ≤ V ≤ 240*2^(M-8)

这三个范围只是理论上的范围。实际上的值往往会超过这个范围。

如果输入数据是计算机RGB格式,那么这个clip3函数是无效的。
如果输入数据是电视视频RGB格式,clip3函数是为了保证U和V的值在0~ 2^M-1之间。

接下来会有2个转换公式:

RGB888转换到YUV4:4:4
如果是计算机RGB输入,YUV4:4:4输出,那么上面的公式可以近似简化为:

Y = ((66 * R + 129 * G +  25 * B + 128) >> 8)+16
U = ((-38 * R - 74 * G + 112 * B + 128) >> 8)+128
V = ((112 * R - 94 * G - 18 * B + 128) >> 8)+128

YUV4:4:4转换到RGB888

//第一步:
Y = round( 0.256788 * R + 0.504129 * G + 0.097906 * B) + 16
U = round(-0.148223 * R - 0.290993 * G + 0.439216 * B) + 128
V = round( 0.439216 * R - 0.367788 * G - 0.071427 * B) + 128

//第二步
C = Y - 16
D = U - 128
E = V - 128

//第三步
R = clip(round(1.164383*C+1.596027*E ))
G = clip(round(1.164383*C-(0.391762*D)-(0.812968 * E)))
B = clip(round(1.164383*C+2.017232*D))

//第四步,上面的公式可以近似为下面公式
R = clip(( 298 * C + 409 * E + 128) >> 8)
G = clip(( 298 * C - 100 * D - 208 * E + 128) >> 8)
B = clip(( 298 * C + 516 * D + 128) >> 8)