【问题标题】:Display YUV(yuv420p) is not correct on IOS在 IOS 上显示 YUV(yuv420p) 不正确
【发布时间】:2020-01-24 02:43:06
【问题描述】:

使用 (EAGLRenderingAPI api = kEAGLRenderingAPIOpenGLES2) 在 iOS 的屏幕上显示 YUV。 但是我遇到了这个问题,以及如何处理这个问题谢谢。

显示 YUV (size-> 3268:1838) 不正确,显示为:

但是使用相同的代码TO Display 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;
}

【问题讨论】:

  • 在指定纹理图像之前尝试glPixelStorei(GL_UNPACK_ALIGNMENT, 1);glTexImage2D 之前)。
  • @Rabbid76 不错的尝试,它对我有用。请把它放在ANSWER.THEN设置固定。

标签: ios opengl-es glsl textures opengl-es-2.0


【解决方案1】:

默认情况下,OpenGL 假定图像的每一行的开头对齐 4 个字节。这是因为GL_UNPACK_ALIGNMENT参数默认为4。
由于图像有 1 个 (GL_LUMINANCE) 通道,大小为 1 字节,并且紧密排列,因此行的开头可能未对齐。
在指定二维纹理图像(glTexImage2D)之前,将GL_UNPACK_ALIGNMENT参数更改为1。

注意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);) 也可以解决问题(在这种特殊情况下)。

【讨论】:

  • 在4字节对齐模式下,OpenGL会读取32字节的数据,会导致glTextImage中函数的读取越界,从而彻底crash,会出现这种情况吗?
  • @JNYJ 这是一个问题吗?可能会发生崩溃(由于内存被读取,它取决于内存是否可访问)并且确实数组被读取超出范围。
猜你喜欢
  • 1970-01-01
  • 2018-07-21
  • 2022-08-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-04-19
  • 1970-01-01
相关资源
最近更新 更多