图像格式 NV12 存储在内存中

Image formats NV12 storage in memory

我完全理解问题中描述的 NV12 格式的大小

NV12 format and UV plane

现在我正在从两个来源阅读有关以这种格式存储 UV 平面的信息: 一个是 https://msdn.microsoft.com/en-us/library/windows/desktop/dd206750(v=vs.85).aspx

NV12

所有 Y 样本首先作为一个偶数行的 unsigned char 值数组出现在内存中。 Y 平面后面紧跟着一个 unsigned char 值数组,其中包含打包的 U (Cb) 和 V (Cr) 样本。当组合的 U-V 数组作为小端 WORD 值的数组寻址时,LSB 包含 U 值,而 MSB 包含 V 值。 NV12 是 DirectX VA 的首选 4:2:0 像素格式。预计这将成为支持 4:2:0 视频的 DirectX VA 加速器的中期要求。下图显示了 Y 平面和包含压缩 U 和 V 样本的数组。

我的理解是:在UV平面中每个U和V都存储在一个字节中

当我从维基百科上读到这个: https://wiki.videolan.org/YUV#NV12

它说:

NV12

与I420相关,NV12有一个亮度"luminance"平面Y和一个U和V值交错的平面。 在 NV12 中,色度平面(蓝色和红色)在水平和垂直维度上都被二次采样了 2 倍。 对于 2x2 像素组,您有 4 个 Y 样本以及 1 个 U 和 1 V 样本。 将 NV12 视为 U 和 V 平面交错的 I420 可能会有所帮助。 这是 NV12 的图形表示。每个字母代表一位: 对于 1 个 NV12 像素:YYYYYYYY UVUV 对于 2 像素 NV12 帧:YYYYYYYYYYYYYYYY UVUVUVUV 对于50像素的NV12帧:Y*8*50 (UV)*2*50 对于一个n像素的NV12帧:Y*8*n(UV)*2*n

我在这里的理解是:每个U和V在每个字节中都是逐位交错的。所以UV平面的每个字节将包含交错的4U位和4V位。

谁能解开我的疑惑?

TL;DR: MSDN 是正确的

要验证这一点(或至少验证比特级没有交错),可以使用 ffmpeg,这是一种广泛使用的视频工具。我做了以下实验:

  1. 创建一个包含一些文本的文件(我以 Lorem Ipsum 文本为例)
  2. 告诉 ffmpeg 将其读取为 I420 一些小尺寸的视频帧
  3. 告诉ffmpeg将其转换为NV12格式
  4. 打印出来

这是 (2) 和 (3) 的示例命令行:

ffmpeg -s 96x4 -i example_i420.yuv -pix_fmt nv12 example_nv12.yuv

这是我在输出中得到的:

Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sutnett uirn acduilppias cqiunig oeflfiitc,i as edde sdeor uenitu smmooldl itte mapnoirm iindc iedsitd ulnatb ourtu ml.a bLoorree me ti pdsoulmo rdeo lmoarg nsai ta laimqeuta,. cUotn seenci

我用粗体标记了色度(U 和 V)样本。很明显,这些是相同的值(ASCII 字母),只是顺序打乱了。如果执行任何位交织,我会得到不同的值。

所以 VLC wiki 中的描述(顺便说一句,它是 而不是 维基百科)是不正确的。名为 "Edwardw" 的人添加了 "illustration" 提及像素 here, and later changed it to "bits" here。我希望有人改变它以减少误导(维基需要注册所以我不能编辑它)。