将 YUY2 转换为 YV12

Convert YUY2 to YV12

本文关键字:YV12 转换 YUY2      更新时间:2023-10-16

我几乎可以肯定这比我想象的要简单得多,但是我已经在互联网上搜索了比我愿意承认的时间更长,试图弄清楚frig如何转换这两种格式。 我能够从无符号字节流(无符号字符(中提取 Y0、Cb、Y1、Cr 数据,但我不知道这些字节在 YV12 中是如何排列的 - 这个文档是否暗示各种值实际上包含在不同的行中?

我真的整天都在搜索"c++ 将 YUY2 转换为 YV12"之类的东西,并且完全没有找到任何教程或代码示例。 我认为这将有某种形式的文档可供我使用,但关于这个特定主题的信息似乎很少。

看起来 YUY2 上的链接条目以及 YV12 上的维基百科文章非常清楚地表明了这一点:

  • YUY2 将每两个相邻的水平像素存储为四个字节,[Y1, U, Y2, V] .

  • YV12将整个M × N帧存储在一个连续的M*N + 2 * (M/2 * N/2)字节数组中。我们将数组称为byte frame[M * N * 3 / 2] 。我们有:

    • [0, M * N)iframe[i]是像素的 Y 值。
    • [M * N, M * N * 5/4)jframe[j]是每个 2 ×  2 像素切片的 V 值。
    • [M * N * 5/4, M * N * 6/4)kframe[j]是每个 2 ×  2 像素磁贴的 U 值。

因此,当您从 YUY2 转换为 YV12 时,您必须将 UV 数据量减半,可能通过取两个相邻行的平均值。

例:

byte YUY2Source[M * N * 2] = /* source frame */;
byte YV12Dest[M * N * 3/2];
for (unsigned int i = 0; i != M * N; ++i)
{
    YV12Dest[i] = YUY2Source[2 * i];
}
for (unsigned int j = 0; j != M * N / 4; ++j)
{
    YV12Dest[M * N + j]       = ( YUY2Source[N*(j / N/2    ) + 4 * j + 3]
                                + YUY2Source[N*(j / N/2 + 1) + 4 * j + 3] ) / 2;
    YV12Dest[M * N * 5/4 + j] = ( YUY2Source[N*(j / N/2    ) + 4 * j + 1]
                                + YUY2Source[N*(j / N/2 + 1) + 4 * j + 1] ) / 2;
}
  1. 将 Y、U 和 V 值分隔到单独的数组中。
  2. 将 U 和 V 数组的偶数线和奇数线的值平均在一起,将两条线合并为一条。这会将这些数组的高度减半。Y 数组将w * h ,U 和 V 数组现在将w/2 * h/2
  3. 连接 Y、V 和 U 数组。