RGB转YUV420平面和半平面?
RGB to YUV420 Planar and Semi-Planar?
在 Android 中,我有 byte[]
个单独的 r、g、b、a 颜色,它们构成图像的像素。
我需要将这些颜色转换为 YUV420 平面或半平面(取决于设备),然后才能使用 Android 的 MediaCodec 和 MediaMuxer 创建这些图片的 MP4。
我目前正在测试我的 Nexus 10,它报告说它使用 COLOR_FormatYUV420Planar
。
这是我必须将 RGB 转换为 YUV420 的代码 planar:
private void convertRGBAtoYUV420P(byte[] rgba, byte[] yuv, int width, int height)
{
final int frameSize = width * height;
final int chromasize = frameSize / 4;
int yIndex = 0;
int uIndex = frameSize;
int vIndex = frameSize + chromasize;
int R, G, B, Y, U, V;
int index = 0;
int rgbaIndex = 0;
for (int j = 0; j < height; j++)
{
for (int i = 0; i < width; i++)
{
R = rgba[rgbaIndex++] + 128; // My rgba bytes are -128 to 127
G = rgba[rgbaIndex++] + 128;
B = rgba[rgbaIndex++] + 128;
rgbaIndex++; // skip A
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;
yuv[yIndex++] = (byte)clamp(Y);
if (j % 2 == 0 && index % 2 == 0)
{
yuv[uIndex++] = (byte)clamp(U);
yuv[vIndex++] = (byte)clamp(V);
}
index++;
}
}
}
我从 this blog 中找到了这段代码。
有效,只是颜色不正确。白色是灰色,所有其他颜色都是错误的。无法完全弄清楚上面的代码有什么问题,但我觉得这可能与我的 r、g、b、a 字节在 -128 到 127 之间的事实有关,但我尝试通过向它们添加 128 来更正。
第二个问题,当我需要从 RGB 转换为 YUV420 semi-planar 时,上面的代码将如何更改?
所以这个问题有一个答案。
问题是将 128 添加到字节值并不能恢复它的原始值。
因为颜色 space 定义为 0 到 255 之间的值。它们不是简单地向下移动到负数以使其适合有符号字节。颜色的所有较高值 (> 127) 都被编码为适合带符号的字节,范围从 -128 到 -1。
为了将值恢复到您想要的值,您需要将 & 0xff
掩码应用到每个字节值。
在 Android 中,我有 byte[]
个单独的 r、g、b、a 颜色,它们构成图像的像素。
我需要将这些颜色转换为 YUV420 平面或半平面(取决于设备),然后才能使用 Android 的 MediaCodec 和 MediaMuxer 创建这些图片的 MP4。
我目前正在测试我的 Nexus 10,它报告说它使用 COLOR_FormatYUV420Planar
。
这是我必须将 RGB 转换为 YUV420 的代码 planar:
private void convertRGBAtoYUV420P(byte[] rgba, byte[] yuv, int width, int height)
{
final int frameSize = width * height;
final int chromasize = frameSize / 4;
int yIndex = 0;
int uIndex = frameSize;
int vIndex = frameSize + chromasize;
int R, G, B, Y, U, V;
int index = 0;
int rgbaIndex = 0;
for (int j = 0; j < height; j++)
{
for (int i = 0; i < width; i++)
{
R = rgba[rgbaIndex++] + 128; // My rgba bytes are -128 to 127
G = rgba[rgbaIndex++] + 128;
B = rgba[rgbaIndex++] + 128;
rgbaIndex++; // skip A
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;
yuv[yIndex++] = (byte)clamp(Y);
if (j % 2 == 0 && index % 2 == 0)
{
yuv[uIndex++] = (byte)clamp(U);
yuv[vIndex++] = (byte)clamp(V);
}
index++;
}
}
}
我从 this blog 中找到了这段代码。
有效,只是颜色不正确。白色是灰色,所有其他颜色都是错误的。无法完全弄清楚上面的代码有什么问题,但我觉得这可能与我的 r、g、b、a 字节在 -128 到 127 之间的事实有关,但我尝试通过向它们添加 128 来更正。
第二个问题,当我需要从 RGB 转换为 YUV420 semi-planar 时,上面的代码将如何更改?
所以这个问题有一个答案。
问题是将 128 添加到字节值并不能恢复它的原始值。
因为颜色 space 定义为 0 到 255 之间的值。它们不是简单地向下移动到负数以使其适合有符号字节。颜色的所有较高值 (> 127) 都被编码为适合带符号的字节,范围从 -128 到 -1。
为了将值恢复到您想要的值,您需要将 & 0xff
掩码应用到每个字节值。