推荐用于视频渲染的 8 位 YUV 格式

加里·沙利文和斯蒂芬·埃斯特罗普

Microsoft Corporation

2002 年 4 月,2008 年 11 月更新

本主题介绍建议在 Windows 操作系统中呈现视频的 8 位 YUV 颜色格式。 本文介绍在 YUV 和 RGB 格式之间进行转换的技术,并提供对 YUV 格式进行向上采样的技术。 本文适用于在 Windows 中处理 YUV 视频解码或呈现的任何人。

简介

许多 YUV 格式在整个视频行业都定义。 本文介绍建议在 Windows 中呈现视频的 8 位 YUV 格式。 建议解码器供应商和显示供应商支持本文中所述的格式。 本文不涉及 YUV 颜色的其他用途,例如静态摄影。

本文中所述的格式均使用每个像素位置 8 位来编码 Y 通道 (也称为 luma 通道) ,并使用每个样本 8 位来编码每个 U 或 V 色度样本。 但是,大多数 YUV 格式平均每像素使用不到 24 位,因为它们包含的你的和 V 样本比 Y 少。本文不介绍 10 位或更高 Y 通道的 YUV 格式。

注意

就本文而言,术语 U 等效于 Cb,术语 V 等效于 Cr。

 

本文涵盖以下主题:

YUV 采样

色度通道的采样率可以低于亮度通道,而不会造成任何明显的感知质量损失。 称为“A:B:C”表示法的表示法用于描述相对于 Y 采样和 V 的频率:

  • 4:4:4 表示不对色度通道进行向下采样。
  • 4:2:2 表示 2:1 水平向下采样,没有垂直向下采样。 每条扫描行包含四个 Y 样本,每两个 U 或 V 样本。
  • 4:2:0 表示 2:1 水平向下采样,垂直向下采样为 2:1。
  • 4:1:1 表示 4:1 水平向下采样,没有垂直向下采样。 每个扫描行包含四个 Y 样本,分别用于你和 V 样本。 4:1:1 采样与其他格式相比不太常见,本文未详细讨论。

下图显示了如何针对每个向下采样率对 chroma 进行采样。 Luma 样本由十字表示,色度样本由圆表示。

图 1.色度采样

4:2:2 采样的主要形式在ITU-R建议 BT.601 中定义。 有两种常见的 4:2:0 采样变体。 其中一个用于 MPEG-2 视频,另一个用于 MPEG-1 和ITU-T 建议 H.261 和 H.263。

与 MPEG-1 方案相比,在 MPEG-2 方案与为 4:2:2 和 4:4:4:4 格式定义的采样网格之间转换更简单。 出于此原因,MPEG-2 方案在 Windows 中是首选方案,应被视为 4:2:0 格式的默认解释。

Surface 定义

本部分介绍建议用于视频呈现的 8 位 YUV 格式。 这些类别分为以下几个类别:

首先,应了解以下概念,以了解以下内容:

  • Surface 原点。 对于本文中所述的 YUV 格式,原点 (0,0) 始终位于图面的左上角。
  • 步幅。 图面的步幅(有时称为音调)是图面的宽度(以字节为单位)。 给定左上角的表面原点,步幅始终为正。
  • 对齐方式。 图面的对齐方式由图形显示驱动程序决定。 图面必须始终与 DWORD 对齐;也就是说,图面中的单个线条保证源自 32 位 (DWORD) 边界。 但是,对齐方式可以大于 32 位,具体取决于硬件的需求。
  • 打包格式与平面格式。 YUV 格式分为 打包 格式和 平面 格式。 在打包格式中,Y、U 和 V 组件存储在单个数组中。 像素组织成一组宏像素,其布局取决于格式。 在平面格式中,Y、U 和 V 组件存储为三个单独的平面。

本文所述的每种 YUV 格式都有分配的 FOURCC 代码。 FOURCC 代码是通过串联四个 ASCII 字符创建的 32 位无符号整数。

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

AYUV

建议使用单一 4:4:4 格式,使用 FOURCC 代码 AYUV。 这是一种打包格式,其中每个像素编码为四个连续字节,按下图所示的顺序排列。

图 2.ayuv 内存布局

标记为 A 的字节包含 alpha 的值。

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

建议使用以下 FOURCC 代码使用两种 4:2:2 格式:

  • YUY2
  • UYVY

两者都是打包格式,其中每个宏像素是编码为四个连续字节的两个像素。 这会导致色度水平下采样 2 倍。

YUY2

在 YUY2 格式中,可以将数据视为无符号 字符 值数组,其中第一个字节包含第一个 Y 样本,第二个字节包含第一个 U (Cb) 样本,第三个字节包含第二个 Y 样本,第四个字节包含第一个 V (Cr) 样本,如下图所示。

图 3.yuy2 内存布局

如果图像以小端字 WORD 值数组的形式寻址,则第一个 WORD 包含最小有效位 (LSB) 的第一个 Y 样本,第一个 U (Cb) 样本包含在最大有效位 (MSB) 。 第二 个 WORD 包含 LSB 中的第二个 Y 示例和 MSB 中的第一个 V (Cr) 示例。

YUY2 是 Microsoft DirectX 视频加速 (DirectX VA) 的首选 4:2:2 像素格式。 这是支持 4:2:2 视频的 DirectX VA 加速器的中期要求。

UYVY

此格式与 YUY2 格式相同,只是字节顺序是反向的,即色度和亮度字节 (图 4) 。 如果图像作为两个 little-endian WORD 值的数组进行寻址,则第一个 WORD 在 LSB 中包含 U,在 MSB 中包含 Y0,第二个 WORD 在 LSB 中包含 V,在 MSB 中包含 Y1。

图 4.uyvy 内存布局

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

建议使用每像素两个 4:2:0 16 位 (bpp) 格式,并使用以下 FOURCC 代码:

  • IMC1
  • IMC3

这两种 YUV 格式都是平面格式。 在水平和垂直尺寸中,色度通道按 2 的一个因子进行子采样。

IMC1

所有 Y 样本首先在内存中显示为无符号 字符 值的数组。 接下来是所有 V (Cr) 示例,然后是所有 U (Cb) 样本。 V 和 U 平面的步幅与 Y 平面相同,导致内存的未使用区域,如图 5 所示。 you 和 V 平面必须从内存边界开始,该边界是 16 行的倍数。 图 5 显示了 352 x 240 视频帧的你和 V 的来源。 你的和 V 平面的起始地址计算如下:

BYTE* pV = pY + (((Height + 15) & ~15) * Stride);
BYTE* pU = pY + (((((Height * 3) / 2) + 15) & ~15) * Stride);

其中 pY 是指向内存数组开头的字节指针,如下图所示。

图 5.imc1 内存布局 (示例)

IMC3

此格式与 IMC1 相同,只是交换了 you 和 V 平面,如下图所示。

图 6.imc3 内存布局

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

建议使用以下 FOURCC 代码使用四种 4:2:0 12-bpp 格式:

  • IMC2
  • IMC4
  • YV12
  • NV12

在所有这些格式中,色度通道在水平和垂直维度中都按 2 的因子进行子采样。

IMC2

此格式与 IMC1 相同,区别如下:V (Cr) 和 U (Cb) 线交错在半步幅边界处。 换句话说,色度区域中的每个全步幅线都以一行 V 样本开头,然后是一条 U 样本线,从下一个半步幅边界开始 (图 7) 。 此布局比 IMC1 更有效地利用地址空间。 它将色度地址空间减半,从而使总地址空间减少 25%。 在 4:2:0 格式中,IMC2 是仅次于 NV12 的第二首选格式。 下图演示了此过程。

图 7.imc2 内存布局

IMC4

此格式与 IMC2 相同,只是交换了 U (Cb) 和 V (Cr) 行,如下图所示。

图 8.imc4 内存布局

YV12

所有 Y 样本首先在内存中显示为无符号 字符 值的数组。 此数组紧跟所有 V (Cr) 示例。 V 平面的步幅是 Y 平面步幅的一半;V 平面包含的线条数是 Y 平面的一半。 V 平面紧跟所有 U (Cb) 样本,其步幅和行数与 V 平面相同,如下图所示。

图 9.yv12 内存布局

NV12

所有 Y 样本首先在内存中显示为具有偶数行数的无符号 字符 值的数组。 Y 平面后面紧跟一组无符号 字符 值,其中包含打包的 U (Cb) 和 V (Cr) 样本。 当组合的 U-V 数组作为 little-endian WORD 值的数组进行寻址时,LSB 包含 U 值,而 MSB 包含 V 值。 NV12 是 DirectX VA 的首选 4:2:0 像素格式。 这是支持 4:2:0 视频的 DirectX VA 加速器的中期要求。 下图显示了 Y 平面以及包含打包的和 V 样本的数组。

图 10.nv12 内存布局

颜色空间和色度采样率转换

本部分提供有关在 YUV 和 RGB 之间进行转换以及在某些不同 YUV 格式之间进行转换的准则。 本部分将考虑两种 RGB 编码方案: 8 位计算机 RGB(也称为 sRGB 或“全刻度”RGB)和 工作室视频 RGB,或“带头部房间和足部房间的 RGB”。这些定义如下:

  • 计算机 RGB 对红色、绿色和蓝色的每个样本使用 8 位。 黑色由 R = G = B = 0 表示,白色由 R = G = B = 255 表示。
  • 对于红色、绿色和蓝色的每个样本,工作室视频 RGB 使用一定数量的位 N,其中 N 为 8 或更多。 工作室视频 RGB 使用与计算机 RGB 不同的比例系数,并且具有偏移量。 黑色由 R = G = B = 16*2^ (N-8) 表示,白色由 R = G = B = 235*2^ (N-8) 表示。 但是,实际值可能超出此范围。

工作室视频 RGB 是 Windows 中视频的首选 RGB 定义,而计算机 RGB 是非视频应用程序的首选 RGB 定义。 在 RGB 的任一形式中,色度坐标均按照 RGB-R BT.709 中为 RGB 颜色原色的定义所指定。 R、G 和 B 的 (x,y) 坐标分别为 (0.64、0.33) 、 (0.30、0.60) 和 (0.15、0.06) 。 参考白色为 D65,坐标 (0.3127、0.3290) 。 标称伽玛为 1/0.45 (约 2.2) ,精确伽马在ITU-R BT.709 中详细定义。

RGB 与 4:4:4 YUV 之间的转换

我们首先介绍 RGB 与 4:4:4 YUV 之间的转换。 若要将 4:2:0 或 4:2:2 YUV 转换为 RGB,建议将 YUV 数据转换为 4:4:4 YUV,然后从 4:4 YUV 转换为 RGB。 AYUV 格式是 4:4:4 格式,对于 Y、U 和 V 样本,各使用 8 位。 对于某些应用程序,还可以使用每个样本超过 8 位来定义 YUV。

已为数字视频定义了两个基于 RGB 的主导 YUV 转换。 两者都基于称为ITU-R建议BT.709的规范。 第一个转换是为 BT.709 中的 50-Hz 使用定义的旧 YUV 形式。 它与ITU-R建议BT.601中指定的关系相同,也称为其旧名称CCIR 601。 应将其视为标准清晰度电视分辨率 (720 x 576) 和低分辨率视频的首选 YUV 格式。 它的特点是两个常量 KrKb 的值:

Kr = 0.299
Kb = 0.114

第二种转换是在 BT.709 中为 60-Hz 使用定义的较新的 YUV 形式,应将其视为高于 SDTV 的视频分辨率的首选格式。 它的特点是这两个常量的不同值:

Kr = 0.2126
Kb = 0.0722

从 RGB 到 YUV 的转换是从以下各项开始定义的:

L = Kr * R + Kb * B + (1 - Kr - Kb) * G

然后,按如下所示获取 YUV 值:

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

其中

  • M 是每个 YUV 样本的位数 (M >= 8) 。
  • Z 是黑色级别变量。 对于计算机 RGB,Z 等于 0。 对于工作室视频 RGB,Z 等于 16*2^ (N-8) ,其中 N 是每个 RGB 样本的位数 (N >= 8) 。
  • S 是缩放变量。 对于计算机 RGB,S 等于 255。 对于工作室视频 RGB,S 等于 219*2^ (N-8) 。

函数下限 (x) 返回小于或等于 x 的最大整数。 函数 clip3 (x、y、z) 定义如下:

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

注意

clip3 应实现为函数而不是预处理器宏;否则,将多次计算参数。

 

Y 样本表示亮度,you 和 V 样本分别表示蓝色和红色的颜色偏差。 Y 的标称范围为 16*2^ (M-8) 到 235*2^ (M-8) 。 黑色表示为 16*2^ (M-8) ,白色表示为 235*2^ (M-8) 。 你和 V 的名义范围为 16*2^ (M-8) 到 240*2^ (M-8) ,值 128*2^ (M-8) 表示中性色度。 但是,实际值可能超出这些范围。

对于工作室视频 RGB 形式的输入数据,需要执行剪辑操作,以便将 you 和 V 值保持在 0 到 (2^M) -1 范围内。 如果输入为计算机 RGB,则不需要剪辑操作,因为转换公式无法生成超出此范围的值。

这些是没有近似的确切公式。 本文档中的所有内容都派生自这些公式。 本节介绍下列转换:

将 RGB888 转换为 YUV 4:4:4

对于计算机 RGB 输入和 8 位 BT.601 YUV 输出,我们认为上一节中提供的公式可以合理地近似于以下公式:

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

这些公式使用不需要超过 8 位的无符号 () 精度的系数生成 8 位结果。 中间结果最多需要 16 位精度。

将 8 位 YUV 转换为 RGB888

从原始 RGB 到 YUV 公式中,可以派生 BT.601 的以下关系。

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

可以将 YUV 转换为 RGB 的公式派生如下:

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                   ) )

其中 clip() 表示剪辑到 [0..255] 范围。 我们认为这些公式可以合理地近似于以下公式:

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)

这些公式使用一些系数,这些系数需要超过 8 位的精度才能生成每个 8 位结果,而中间结果需要超过 16 位的精度。

若要将 4:2:0 或 4:2:2 YUV 转换为 RGB,建议将 YUV 数据转换为 4:4:4 YUV,然后从 4:4:4 YUV 转换为 RGB。 以下各节介绍了将 4:2:0 和 4:2:2 格式转换为 4:4:4 的一些方法。

将 4:2:0 YUV 转换为 4:2:2 YUV

将 4:2:0 YUV 转换为 4:2:2 YUV 需要垂直向上转换 2。 本部分介绍执行向上转换的示例方法。 方法假定视频图片是渐进式扫描。

注意

4:2:0 到 4:2:2 隔行扫描转换过程存在非典型问题,难以实现。 本文不解决将隔行扫描从 4:2:0 转换为 4:2:2 的问题。

 

让输入色度样本的每一条垂直线都是一个介于 0 到 N - 1 之间的数组 Cin[] 。 输出图像上的相应垂直线将是一个介于 0 到 2N - 1 的数组 Cout[] 。 若要转换每条垂直线,请执行以下过程:

Cout[0]     = Cin[0];
Cout[1]     = clip((9 * (Cin[0] + Cin[1]) - (Cin[0] + Cin[2]) + 8) >> 4);
Cout[2]     = Cin[1];
Cout[3]     = clip((9 * (Cin[1] + Cin[2]) - (Cin[0] + Cin[3]) + 8) >> 4);
Cout[4]     = Cin[2]
Cout[5]     = clip((9 * (Cin[2] + Cin[3]) - (Cin[1] + Cin[4]) + 8) >> 4);
...
Cout[2*i]   = Cin[i]
Cout[2*i+1] = clip((9 * (Cin[i] + Cin[i+1]) - (Cin[i-1] + Cin[i+2]) + 8) >> 4);
...
Cout[2*N-3] = clip((9 * (Cin[N-2] + Cin[N-1]) - (Cin[N-3] + Cin[N-1]) + 8) >> 4);
Cout[2*N-2] = Cin[N-1];
Cout[2*N-1] = clip((9 * (Cin[N-1] + Cin[N-1]) - (Cin[N-2] + Cin[N-1]) + 8) >> 4);

其中,clip () 表示剪辑到 [0..255] 范围。

注意

处理边缘的公式可以从数学上简化。 它们以这种形式显示,以说明图片边缘的固定效果。

 

实际上,此方法通过在四个相邻像素上内插曲线来计算每个缺失值,并加权到两个最接近的像素的值 (图 11) 。 此示例中使用的特定内插方法使用一种称为Catmull-Rom内插(也称为三次卷积内插)的已知方法,在半整数位置生成缺失样本。

图 11.显示 4:2:0 到 4:2:2 向上采样的示意图

在信号处理术语中,垂直上转换理想情况下应包括相移补偿,以考虑相对于输出 4:2:2 采样网格) 的输出 4:2:0 采样线和其他 4:2:2 采样线的位置之间的半像素垂直 (偏移量。 但是,引入此偏移量会增加生成样本所需的处理量,并且无法从向上采样的 4:2:2 图像中重建原始的 4:2:0 样本。 这也使得无法将视频直接解码为 4:2:2 图面,然后将这些图面用作参考图片来解码流中的后续图片。 因此,此处提供的方法不考虑样本的精确垂直对齐。 在相当高的图片分辨率下,这样做在视觉上可能并不有害。

如果从使用 H.261 中定义的采样网格的 4:2:0 视频开始, H.263 或 MPEG-1 视频,输出 4:2:2 色度样本的相位也将相对于光度采样网格上的间距进行半像素水平偏移, (相对于 4:2:2 色度采样网格) 间距的四分之一像素偏移。 但是,MPEG-2 形式的 4:2:0 视频可能更常用在电脑上,并且不会遇到此问题。 此外,在相当高的图片分辨率下,这种区别在视觉上可能并不有害。 尝试更正此问题将创建与垂直相位偏移讨论的相同类型问题。

将 4:2:2 YUV 转换为 4:4:4 YUV

将 4:2:2 YUV 转换为 4:4:4 YUV 需要水平上转换 2。 前面描述的垂直向上转换的方法也可以应用于水平向上转换。 对于 MPEG-2 和ITU-R BT.601 视频,此方法将生成具有正确相位对齐的样本。

将 4:2:0 YUV 转换为 4:4:4 YUV

若要将 4:2:0 YUV 转换为 4:4:4 YUV,只需遵循前面所述的两种方法即可。 将 4:2:0 图像转换为 4:2:2,然后将 4:2:2 图像转换为 4:4:4。 还可以切换两个上转换过程的顺序,因为操作顺序对结果的视觉质量并不重要。

其他 YUV 格式

其他一些不太常见的 YUV 格式包括:

  • AI44 是一种淡化 YUV 格式,每个样本 8 位。 每个样本在 4 个最有效位 (MSB) 中包含一个索引, (LSB) 包含 4 个最小有效位中的 alpha 值。 索引引用 YUV 调色板条目的数组,这些条目必须在格式的媒体类型中定义。 此格式主要用于亚图片图像。
  • NV11 是 4:1:1 平面格式,每像素 12 位。 Y 示例首先显示在内存中。 Y 平面后跟一组打包的 U (Cb) 和 V (Cr) 样本。 当组合的 U-V 数组作为小端 WORD 值的数组进行寻址时,U 样本包含在每个 WORD 的 LSB 中,V 样本包含在 MSB 中。 (此内存布局类似于 NV12,尽管色度采样不同。)
  • Y41P 是 4:1:1 打包格式,每四个像素水平采样一次你和 V。 每个宏像素包含 8 个像素(以 3 个字节为单位),并具有以下字节布局: U0 Y0 V0 Y1 U4 Y2 V4 Y3 Y4 Y5 Y6 Y7
  • Y41T 与 Y41P 相同,但每个 Y 样本的最小有效位指定色度键 (0 = 透明,1 = 不透明) 。
  • Y42T 与 UYVY 相同,但每个 Y 样本的最小有效位指定色度键 (0 = 透明,1 = 不透明) 。
  • YVYU 等效于 YUYV,但交换了 you 和 V 样本。

在媒体基础中识别 YUV 格式

本文所述的每种 YUV 格式都有分配的 FOURCC 代码。 FOURCC 代码是通过串联四个 ASCII 字符创建的 32 位无符号整数。

可通过各种 C/C++ 宏更轻松地在源代码中声明 FOURCC 值。 例如, MAKEFOURCC 宏在 Mmsystem.h 中声明, FCC 宏在 Aviriff.h 中声明。 按如下所示使用它们:

DWORD fccYUY2 = MAKEFOURCC('Y','U','Y','2');
DWORD fccYUY2 = FCC('YUY2');

还可以直接通过反转字符顺序将 FOURCC 代码声明为字符串文本。 例如:

DWORD fccYUY2 = '2YUY';  // Declares the FOURCC 'YUY2'

由于 Windows 操作系统使用小端体系结构,因此必须反转顺序。 “Y”= 0x59,“U”= 0x55,“2”= 0x32,因此“2YUY”为0x32595559。

在 Media Foundation 中,格式由主要类型 GUID 和子类型 GUID 标识。 计算机视频格式的主要类型始终MFMediaType_Video 。 可以通过将 FOURCC 代码映射到 GUID 来构造子类型,如下所示:

XXXXXXXX-0000-0010-8000-00AA00389B71 

其中 XXXXXXXX 是 FOURCC 代码。 因此,YUY2 的子类型 GUID 为:

32595559-0000-0010-8000-00AA00389B71 

最常见的 YUV 格式 GUID 的常量在头文件 mfapi.h 中定义。 有关这些常量的列表,请参阅 视频子类型 GUID

关于 YUV 视频

视频媒体类型