[英]Android MediaCodec output format: GLES External Texture (YUV / NV12) to GLES Texture (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,我应该做的唯一更改是替换片段着色器中的u
和v
值。
顶点着色器:
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
,即mYBuffer
和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_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 分量(您可以使用任何一个)。 因此,无需在片段着色器中交换u
和v
值(我已使用正确的片段着色器代码编辑了我的问题)。
我会保留这个问题,希望这会在将来对某人有所帮助。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.