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

问题描述

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

enter image description here

我遵循了出色的answer,该指南指导将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,b,1.0);
}

将图像数据分割并放入2个ByteBuffermYBuffer的{​​{1}}中。 mUVBuffer只是一个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_TEXTURE_WRAP_S,GLES20.GL_CLAMP_TO_EDGE);
    GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D,GLES20.GL_TEXTURE_WRAP_T,GLES20.GL_CLAMP_TO_EDGE);
}

我不知道为什么得到这样的输出。任何帮助将不胜感激。

解决方法

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

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

也是我通过阅读this做出的假设,

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

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

我将继续提出问题,希望这对以后的人有所帮助。