在 IOS 上显示 YUV(yuv420p) 不正确
Display YUV(yuv420p) is not correct on IOS
使用 (EAGLRenderingAPI api = kEAGLRenderingAPIOpenGLES2
) 在 iOS 的屏幕上显示 YUV。
但是我遇到了这个问题,如何处理这个问题谢谢。
显示 YUV (size-> 3268:1838) 不正确,显示为:
但是使用相同的代码来显示YUV(size-> 1280:720)是正确的,显示为:
怎么了?任何帮助谢谢。
编码:
EAGLRenderingAPI api = kEAGLRenderingAPIOpenGLES2;
_context = [[EAGLContext alloc] initWithAPI:api];
if (!_context)
{
if([LTJNYJCommon isDebug]){NSLog(@"Failed to initialize OpenGLES 2.0 context");}
exit(1);
}
if (![EAGLContext setCurrentContext:_context])
{
if([LTJNYJCommon isDebug]){NSLog(@"Failed to set current OpenGLES 2.0 context");}
exit(1);
}
int idxU = width * height;
int idxV = idxU + (idxU / 4);
uint8_t *pyuvData = (uint8_t *)[data bytes];
glClearColor(0.0, 0.0, 0.0, 1.0);
glClear(GL_COLOR_BUFFER_BIT);
glViewport(x, y, w, h);
glBindBuffer(GL_ARRAY_BUFFER, _vertexBuffer);
glVertexAttribPointer(_positionSlot, 3, GL_FLOAT, GL_FALSE, sizeof(LTGLVertex), 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _indexBuffer);
glVertexAttribPointer(_texCoordSlot, 2, GL_FLOAT, GL_FALSE, sizeof(LTGLVertex), (GLvoid *)(offsetof(LTGLVertex, TexCoord)));
//----------------------------------------------------
//Y texture
//----------------------------------------------------
if (_samplerYTexture){glDeleteTextures(1, &_samplerYTexture);}
glActiveTexture(GL_TEXTURE0);
glGenTextures(1, &_samplerYTexture);
glBindTexture(GL_TEXTURE_2D, _samplerYTexture);
glUniform1i(_samplerYUniform, 0);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, width, height, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, pyuvData);
//----------------------------------------------------
//U texture
//----------------------------------------------------
if (_samplerUTexture){glDeleteTextures(1, &_samplerUTexture);}
glActiveTexture(GL_TEXTURE1);
glGenTextures(1, &_samplerUTexture);
glBindTexture(GL_TEXTURE_2D, _samplerUTexture);
glUniform1i(_samplerUUniform, 1);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
if (datalength>idxU && pyuvData[idxU]) {
glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, width/2, height/2, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, &pyuvData[idxU]);
}else{
if([LTJNYJCommon isDebug]){NSLog(@"error1");}
}
//----------------------------------------------------
//V texture
//----------------------------------------------------
if (_samplerVTexture){glDeleteTextures(1, &_samplerVTexture);}
glActiveTexture(GL_TEXTURE2);
glGenTextures(1, &_samplerVTexture);
glBindTexture(GL_TEXTURE_2D, _samplerVTexture);
glUniform1i(_samplerVUniform, 2);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
if (datalength>idxV && pyuvData[idxV]) {
glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, width/2, height/2, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, &pyuvData[idxV]);
}else{
if([LTJNYJCommon isDebug]){NSLog(@"error2");}
}
//----------------------------------------------------
//glDrawElements
//----------------------------------------------------
glDrawElements(GL_TRIANGLE_STRIP, sizeof(LTGLIndices)/sizeof(GLubyte), GL_UNSIGNED_BYTE, 0);
//着色器
precision highp float;
uniform sampler2D samplerY;
uniform sampler2D samplerU;
uniform sampler2D samplerV;
varying highp vec2 TexCoordOut;
const highp mat3 yuv2rgb = mat3(1, 1, 1,
0, -0.39465, 2.03211,
1.13983, -0.58060, 0);
void main(void)
{
highp vec3 yuv;
yuv.x = texture2D(samplerY, TexCoordOut).r;
yuv.y = texture2D(samplerU, TexCoordOut).r - 0.5;
yuv.z = texture2D(samplerV, TexCoordOut).r - 0.5;
vec3 rgb = yuv2rgb * yuv;
gl_FragColor = vec4(rgb, 1.0);
}
//
attribute vec4 Position;
attribute vec2 TexCoordIn;
uniform mat4 Projection;
uniform mat4 Modelview;
varying vec2 TexCoordOut;
void main(void)
{
gl_Position = Position;
TexCoordOut = TexCoordIn;
}
默认情况下,OpenGL 假定图像的每一行的开头对齐 4 个字节。这是因为 GL_UNPACK_ALIGNMENT
参数默认为 4.
由于图像有 1 (GL_LUMINANCE
) 个大小为 1 字节的通道,并且排列紧密,行的开头可能未对齐。
将GL_UNPACK_ALIGNMENT
参数改为1,在指定二维纹理图像之前(glTexImage2D
)。
注意glPixelStorei
改变了全局状态,所以在glTexImage2D
指定纹理图像之前设置一次参数就足够了。
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
如果你没有正确设置对齐方式,那么这会导致纹理行的偏移效果,最后图像缓冲区被越界访问。
请注意,问题是由第一个纹理的 width
3268 引起的。所以
widht/2
是1634。1634不能被4整除(1634/4 = 408,5)。
相比之下,第二个纹理的 width
是 1280。widht/2
是 640,可以被 4 整除。
实际上对齐 2 (glPixelStorei(GL_UNPACK_ALIGNMENT, 2);
) 也可以解决问题(在这种特殊情况下)。
使用 (EAGLRenderingAPI api = kEAGLRenderingAPIOpenGLES2
) 在 iOS 的屏幕上显示 YUV。
但是我遇到了这个问题,如何处理这个问题谢谢。
显示 YUV (size-> 3268:1838) 不正确,显示为:
但是使用相同的代码来显示YUV(size-> 1280:720)是正确的,显示为:
怎么了?任何帮助谢谢。
编码:
EAGLRenderingAPI api = kEAGLRenderingAPIOpenGLES2;
_context = [[EAGLContext alloc] initWithAPI:api];
if (!_context)
{
if([LTJNYJCommon isDebug]){NSLog(@"Failed to initialize OpenGLES 2.0 context");}
exit(1);
}
if (![EAGLContext setCurrentContext:_context])
{
if([LTJNYJCommon isDebug]){NSLog(@"Failed to set current OpenGLES 2.0 context");}
exit(1);
}
int idxU = width * height;
int idxV = idxU + (idxU / 4);
uint8_t *pyuvData = (uint8_t *)[data bytes];
glClearColor(0.0, 0.0, 0.0, 1.0);
glClear(GL_COLOR_BUFFER_BIT);
glViewport(x, y, w, h);
glBindBuffer(GL_ARRAY_BUFFER, _vertexBuffer);
glVertexAttribPointer(_positionSlot, 3, GL_FLOAT, GL_FALSE, sizeof(LTGLVertex), 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _indexBuffer);
glVertexAttribPointer(_texCoordSlot, 2, GL_FLOAT, GL_FALSE, sizeof(LTGLVertex), (GLvoid *)(offsetof(LTGLVertex, TexCoord)));
//----------------------------------------------------
//Y texture
//----------------------------------------------------
if (_samplerYTexture){glDeleteTextures(1, &_samplerYTexture);}
glActiveTexture(GL_TEXTURE0);
glGenTextures(1, &_samplerYTexture);
glBindTexture(GL_TEXTURE_2D, _samplerYTexture);
glUniform1i(_samplerYUniform, 0);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, width, height, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, pyuvData);
//----------------------------------------------------
//U texture
//----------------------------------------------------
if (_samplerUTexture){glDeleteTextures(1, &_samplerUTexture);}
glActiveTexture(GL_TEXTURE1);
glGenTextures(1, &_samplerUTexture);
glBindTexture(GL_TEXTURE_2D, _samplerUTexture);
glUniform1i(_samplerUUniform, 1);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
if (datalength>idxU && pyuvData[idxU]) {
glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, width/2, height/2, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, &pyuvData[idxU]);
}else{
if([LTJNYJCommon isDebug]){NSLog(@"error1");}
}
//----------------------------------------------------
//V texture
//----------------------------------------------------
if (_samplerVTexture){glDeleteTextures(1, &_samplerVTexture);}
glActiveTexture(GL_TEXTURE2);
glGenTextures(1, &_samplerVTexture);
glBindTexture(GL_TEXTURE_2D, _samplerVTexture);
glUniform1i(_samplerVUniform, 2);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
if (datalength>idxV && pyuvData[idxV]) {
glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, width/2, height/2, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, &pyuvData[idxV]);
}else{
if([LTJNYJCommon isDebug]){NSLog(@"error2");}
}
//----------------------------------------------------
//glDrawElements
//----------------------------------------------------
glDrawElements(GL_TRIANGLE_STRIP, sizeof(LTGLIndices)/sizeof(GLubyte), GL_UNSIGNED_BYTE, 0);
//着色器
precision highp float;
uniform sampler2D samplerY;
uniform sampler2D samplerU;
uniform sampler2D samplerV;
varying highp vec2 TexCoordOut;
const highp mat3 yuv2rgb = mat3(1, 1, 1,
0, -0.39465, 2.03211,
1.13983, -0.58060, 0);
void main(void)
{
highp vec3 yuv;
yuv.x = texture2D(samplerY, TexCoordOut).r;
yuv.y = texture2D(samplerU, TexCoordOut).r - 0.5;
yuv.z = texture2D(samplerV, TexCoordOut).r - 0.5;
vec3 rgb = yuv2rgb * yuv;
gl_FragColor = vec4(rgb, 1.0);
}
//
attribute vec4 Position;
attribute vec2 TexCoordIn;
uniform mat4 Projection;
uniform mat4 Modelview;
varying vec2 TexCoordOut;
void main(void)
{
gl_Position = Position;
TexCoordOut = TexCoordIn;
}
默认情况下,OpenGL 假定图像的每一行的开头对齐 4 个字节。这是因为 GL_UNPACK_ALIGNMENT
参数默认为 4.
由于图像有 1 (GL_LUMINANCE
) 个大小为 1 字节的通道,并且排列紧密,行的开头可能未对齐。
将GL_UNPACK_ALIGNMENT
参数改为1,在指定二维纹理图像之前(glTexImage2D
)。
注意glPixelStorei
改变了全局状态,所以在glTexImage2D
指定纹理图像之前设置一次参数就足够了。
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
如果你没有正确设置对齐方式,那么这会导致纹理行的偏移效果,最后图像缓冲区被越界访问。
请注意,问题是由第一个纹理的 width
3268 引起的。所以
widht/2
是1634。1634不能被4整除(1634/4 = 408,5)。
相比之下,第二个纹理的 width
是 1280。widht/2
是 640,可以被 4 整除。
实际上对齐 2 (glPixelStorei(GL_UNPACK_ALIGNMENT, 2);
) 也可以解决问题(在这种特殊情况下)。