【发布时间】:2016-09-18 07:18:34
【问题描述】:
在 Android 中,我有一个 byte[] 的各个 r,g,b,a 颜色组成图像的像素。
我需要将这些颜色转换为 YUV420 平面或半平面(取决于设备),然后才能使用 Android 的 MediaCodec 和 MediaMuxer 创建这些图像的 MP4。
我目前正在我的 Nexus 10 上进行测试,报告说它使用 COLOR_FormatYUV420Planar。
这是我必须将 RGB 转换为 YUV420 平面的代码:
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 半平面时,上面的代码会如何变化?
【问题讨论】:
-
也许不是将 128 加到字节值上,而是使用
& 0xff来获得0和255之间的值。通过添加 128,您基本上可以减少一半的可用颜色。如果您的红色值为 -64(实际上是 192),那么您将得到 64。或者如果您的值为 -1(这将是一种颜色的最大值 [255]),则通过添加 128 你'得到 127。 -
@Zymus 你说得对。我并没有真正思考,只是假设范围向下移动了 128,所以只需添加 128 就会像往常一样将其变为 0 - 255。 0xff 掩码有效,谢谢!
-
“它有效,只是颜色不正确。白色是灰色,所有其他颜色都是错误的。”:完全正确!它工作正常
-
@gpasch 我知道这听起来多么愚蠢,但我的意思是因为我实际上可以看到图像并辨认出物体等等,所以像素“位置”数据被正确写入,只是使用错误的颜色数据。
-
您的另一个选择是使用 Surface 提供媒体编解码器。在 Surface 上绘制 RGB 像素并让硬件进行 YUV 转换。诀窍是您必须使用 GLES 来执行此操作 - 不支持画布渲染 (b.android.com/61194)。
标签: java android rgb android-mediacodec yuv