繁体   English   中英

使用 OpenGL ES 从 YUV-NV12 转换为 RGB 时,颜色/色度纹理被拉伸

[英]Colour/chroma texture is stretched when converting from YUV-NV12 to RGB using OpenGL ES

我有一个 YUV-NV12 格式的图像数据的字节缓冲区。 当我尝试将其转换为 RGB 时,我得到一个带有拉伸颜色(色度)层的输出,如下图所示。

在此处输入图片说明

我遵循了这个很好的答案,它指导将 YUV-NV21 转换为 RGB。 由于 NV-12 只是带有翻转的 U 和 V 数据的 NV-21,我应该做的唯一更改是替换片段着色器中的uv值。

顶点着色器:

precision mediump float;
uniform mat4 uMVPMatrix;
attribute vec4 vPosition;
attribute vec4 vTextureCoordinate;
varying vec2 position;

void main()
{
   gl_Position = uMVPMatrix * vPosition;
   position = vTextureCoordinate.xy;
}

片段着色器:

precision mediump float;
varying vec2 position;
uniform sampler2D uTextureY;
uniform sampler2D uTextureUV;

void main() 
{
    float y, u, v;
    y = texture2D(uTextureY, position).r;
    u = texture2D(uTextureUV, position).a - 0.5;
    v = texture2D(uTextureUV, position).r - 0.5;

    float r, g, b;
    r = y + 1.13983 * v;
    g = y - 0.39465 * u - 0.58060 * v;
    b = y + 2.03211 * u;

    gl_FragColor = vec4(r, g, b, 1.0);
}

将图像数据拆分并放入 2 个ByteBuffer ,即mYBuffermUVBuffer mSourceImage只是一个Buffer ,其中包含作为byte数据的图像数据。

ByteBuffer bb = (ByteBuffer) mSourceImage;
if (bb == null) {
    return;
}
int size = mWidth * mHeight;

bb.position(0).limit(size);
mYBuffer = bb.slice();
bb.position(size).limit(bb.remaining());
mUVBuffer = bb.slice();

生成纹理:

GLES20.glGenTextures(2, mTexture, 0);

for(int i = 0; i < 2; i++) {
    GLES20.glActiveTexture(GLES20.GL_TEXTURE0 + i);
    GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mTexture[i]);

    GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR);
    GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR);
    GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_CLAMP_TO_EDGE);
    GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_CLAMP_TO_EDGE);
}

将缓冲区数据传递给纹理:

mTextureYHandle = GLES20.glGetUniformLocation(mProgramId, "uTextureY");
mTextureUVHandle = GLES20.glGetUniformLocation(mProgramId, "uTextureUV");

GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mTexture[0]);
GLES20.glTexImage2D(GLES20.GL_TEXTURE_2D, 0, GLES20.GL_LUMINANCE, mWidth, mHeight, 0, GLES20.GL_LUMINANCE, GLES20.GL_UNSIGNED_BYTE, mYBuffer);
GLES20.glUniform1i(mTextureYHandle, 0);

GLES20.glActiveTexture(GLES20.GL_TEXTURE1);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mTexture[1]);
GLES20.glTexImage2D(GLES20.GL_TEXTURE_2D, 0, GLES20.GL_LUMINANCE_ALPHA, mWidth / 2, mHeight / 2, 0, GLES20.GL_LUMINANCE_ALPHA, GLES20.GL_UNSIGNED_BYTE, mUVBuffer);
GLES20.glUniform1i(mTextureUVHandle, 1);

我不明白为什么我会得到这样的输出。 任何帮助将非常感激。

没关系,这是我代码中的一个小错误。

拆分字节缓冲区时,我使用了bb.position(size).limit(bb.remaining())作为 UV 缓冲区。 由于某种原因, bb.remaining()在获得一些帧后变为 0(这实际上是一个相机预览)。 因此,我已将其更改为bb.position(size).limit(size + size / 2)

还有我通过阅读本文所做的假设,

我应该做的唯一更改是替换片段着色器中的 u 和 v 值

似乎是错误的。 观察到GL20.GL_LUMINANCE_ALPHA总是将U字节放入纹理的 A 分量,将V字节放入 R、G、B 分量(您可以使用任何一个)。 因此,无需在片段着色器中交换uv值(我已使用正确的片段着色器代码编辑了我的问题)。

我会保留这个问题,希望这会在将来对某人有所帮助。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM