RGB转YUV420平面和半平面格式?

3

在安卓系统中,我有一个由单独的r、g、b和a颜色组成的byte[]数组,这些颜色构成了一幅图像的像素。

在使用安卓的MediaCodec和MediaMuxer创建MP4文件之前,我需要将这些颜色转换为YUV420平面或半平面格式(取决于设备)。

我目前正在测试我的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++;
        }
    }
}

我从这个博客中找到了这段代码。
它能运行,但颜色不正确。白色变成了灰色,其他所有颜色都是错误的。我不太清楚上面的代码有什么问题,但我感觉可能与我的r、g、b、a字节范围为-128至127有关,但我尝试通过将它们加上128来纠正这个问题。
第二个问题是,当我需要将RGB转换为YUV420半平面格式时,以上代码会如何更改?

1
也许不要将 128 添加到字节值中,而是改为执行 & 0xff 操作,以获取介于 0255 之间的值。通过添加 128,您基本上削减了可用颜色的一半。如果您有一个红色值为-64(实际上是192),则实际上会得到64。或者,如果您有一个值为-1(颜色的最大值[255]),则通过添加128您将获得127。 - Zymus
@Zymus 你说得完全正确。我没有好好思考,只是假设范围向下移动了128,所以只需添加128即可将其带到0-255像正常一样。0xff掩码起作用了,谢谢! - yesbutmaybeno
它可以工作,只是颜色不正确。白色是灰色,所有其他颜色都是错误的。 - gpasch
@gpasch 我知道这听起来很蠢,但我的意思是我实际上可以看到图像并辨认出对象和其他东西,所以像素的“位置”数据被正确编写,只是颜色数据错误。 - yesbutmaybeno
1
你的另一个选择是使用Surface来提供给mediacodec。在Surface上绘制RGB像素,让硬件进行YUV转换。诀窍在于你必须使用GLES来完成它 - Canvas渲染不支持此操作(http://b.android.com/61194)。 - fadden
1个回答

5

为了回答这个问题,让我来帮忙翻译一下。

问题在于将字节值加上128并不能恢复它的原始值。

因为颜色空间是在0到255之间定义的值。它们不会简单地向负数方向移动以适应有符号字节。所有高于127的颜色值都编码为有符号字节,范围从-128到-1。

为了将值恢复到所需的值,您需要对每个字节值应用& 0xff掩码。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接