在YUV420p上有很多绿色 - > iOS上的OpenGL 2.0着色器中的RGB

时间:2012-06-23 15:15:13

标签: ios opengl-es ffmpeg yuv

我想使用ffmpeg和OpenGL ES 2.0为iOS制作电影播放器 但我有一些问题。输出RGB图像有很多绿色。 这是代码和图像

  • 480x320宽度&高度:
  • 512x512纹理宽度&高度

我从ffmpeg AVFrame获得了一个YUV420p行数据。

    for (int i = 0, nDataLen = 0; i < 3; i++) {
        int nShift = (i == 0) ? 0 : 1;
        uint8_t *pYUVData = (uint8_t *)_frame->data[i];
        for (int j = 0; j < (mHeight >> nShift); j++) {
            memcpy(&pData->pOutBuffer[nDataLen], pYUVData, (mWidth >> nShift));
            pYUVData += _frame->linesize[i];
            nDataLen += (mWidth >> nShift);
        }
    }

为Y,U&amp;准备纹理V频道。

//: U Texture
    if (sampler1Texture) glDeleteTextures(1, &sampler1Texture);

    glActiveTexture(GL_TEXTURE1);
    glGenTextures(1, &sampler1Texture);
    glBindTexture(GL_TEXTURE_2D, sampler1Texture);

    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    // This is necessary for non-power-of-two textures
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
    glEnable(GL_TEXTURE_2D);

    glTexImage2D(GL_TEXTURE_2D, 
                 0, 
                 GL_LUMINANCE, 
                 texW / 2, 
                 texH / 2, 
                 0, 
                 GL_LUMINANCE, 
                 GL_UNSIGNED_BYTE,
                 NULL);

    //: V Texture
    if (sampler2Texture) glDeleteTextures(1, &sampler2Texture);

    glActiveTexture(GL_TEXTURE2);
    glGenTextures(1, &sampler2Texture);
    glBindTexture(GL_TEXTURE_2D, sampler2Texture);

    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    // This is necessary for non-power-of-two textures
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
    glEnable(GL_TEXTURE_2D);

    glTexImage2D(GL_TEXTURE_2D, 
                 0, 
                 GL_LUMINANCE, 
                 texW / 2, 
                 texH / 2, 
                 0, 
                 GL_LUMINANCE,
                 GL_UNSIGNED_BYTE,
                 NULL);

    //: Y Texture
    if (sampler0Texture) glDeleteTextures(1, &sampler0Texture);

    glActiveTexture(GL_TEXTURE0);
    glGenTextures(1, &sampler0Texture);
    glBindTexture(GL_TEXTURE_2D, sampler0Texture);

    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    // This is necessary for non-power-of-two textures
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
    glEnable(GL_TEXTURE_2D);

    glTexImage2D(GL_TEXTURE_2D, 
                 0, 
                 GL_LUMINANCE, 
                 texW, 
                 texH, 
                 0, 
                 GL_LUMINANCE,
                 GL_UNSIGNED_BYTE, 
                 NULL);

渲染部分如下。

int _idxU = mFrameW * mFrameH;
int _idxV = _idxU + (_idxU / 4);

// U data
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, sampler1Texture);
glUniform1i(sampler1Uniform, 1);

glTexSubImage2D(
                GL_TEXTURE_2D, 
                0, 
                0, 
                0, 
                mFrameW / 2,            // source width
                mFrameH / 2,            // source height
                GL_LUMINANCE,
                GL_UNSIGNED_BYTE, 
                &_frameData[_idxU]);

// V data
glActiveTexture(GL_TEXTURE2);
glBindTexture(GL_TEXTURE_2D, sampler2Texture);
glUniform1i(sampler2Texture, 2);

glTexSubImage2D(
                GL_TEXTURE_2D, 
                0, 
                0, 
                0, 
                mFrameW / 2,            // source width
                mFrameH / 2,            // source height
                GL_LUMINANCE,
                GL_UNSIGNED_BYTE,
                &_frameData[_idxV]);

// Y data
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, sampler0Texture);
glUniform1i(sampler0Uniform, 0);

glTexSubImage2D(
                GL_TEXTURE_2D, 
                0, 
                0, 
                0, 
                mFrameW,            // source width
                mFrameH,            // source height
                GL_LUMINANCE,
                GL_UNSIGNED_BYTE,
                _frameData);

Vertex Shader&amp;片段着色器在下面。

attribute vec4 Position;
attribute vec2 TexCoordIn;

varying vec2 TexCoordOut;
varying vec2 TexCoordOut_UV;

uniform mat4 Projection;
uniform mat4 Modelview;

void main()
{
    gl_Position = Projection * Modelview * Position;
    TexCoordOut = TexCoordIn;
}



uniform sampler2D sampler0; // Y Texture Sampler
uniform sampler2D sampler1; // U Texture Sampler
uniform sampler2D sampler2; // V Texture Sampler

varying highp vec2 TexCoordOut;

void main()
{
    highp float y = texture2D(sampler0, TexCoordOut).r;
    highp float u = texture2D(sampler2, TexCoordOut).r - 0.5;
    highp float v = texture2D(sampler1, TexCoordOut).r - 0.5;

    //y = 0.0;
    //u = 0.0;
    //v = 0.0;

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

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

Y纹理(灰度)是正确的但U&amp; V有很多绿色。 因此最终的RGB图像(Y + U + V)有很多绿色。 有什么问题?

请帮忙。 感谢。

2 个答案:

答案 0 :(得分:6)

更改uv制服(反之亦然),您将得到正确的结果。

所以像素着色器(保持不变):

uniform sampler2D sampler0; // Y Texture Sampler
uniform sampler2D sampler1; // U Texture Sampler
uniform sampler2D sampler2; // V Texture Sampler

varying highp vec2 TexCoordOut;

void main()
{
    highp float y = texture2D(sampler0, TexCoordOut).r;
    highp float u = texture2D(sampler2, TexCoordOut).r - 0.5;
    highp float v = texture2D(sampler1, TexCoordOut).r - 0.5;

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

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

并渲染代码:

// RENDERING

    int _idxU = mFrameW * mFrameH;
    int _idxV = _idxU + (_idxU / 4);

    // U data
    glActiveTexture(GL_TEXTURE1);
    glBindTexture(GL_TEXTURE_2D, sampler1Texture);

    GLint sampler1Uniform = glGetUniformLocation(programStandard, "sampler2");

    glUniform1i(sampler1Uniform, 1);

    glTexSubImage2D(
                    GL_TEXTURE_2D,
                    0,
                    0,
                    0,
                    mFrameW / 2,            // source width
                    mFrameH / 2,            // source height
                    GL_LUMINANCE,
                    GL_UNSIGNED_BYTE,
                    &_frameData[_idxU]);

    // V data
    glActiveTexture(GL_TEXTURE2);
    glBindTexture(GL_TEXTURE_2D, sampler2Texture);

    GLint sampler2Uniform = glGetUniformLocation(programStandard, "sampler1");
    glUniform1i(sampler2Uniform, 2);

    glTexSubImage2D(
                    GL_TEXTURE_2D,
                    0,
                    0,
                    0,
                    mFrameW / 2,            // source width
                    mFrameH / 2,            // source height
                    GL_LUMINANCE,
                    GL_UNSIGNED_BYTE,
                    &_frameData[_idxV]);

    // Y data
    glActiveTexture(GL_TEXTURE0);
    glBindTexture(GL_TEXTURE_2D, sampler0Texture);

    GLint sampler0Uniform = glGetUniformLocation(programStandard, "sampler0");
    glUniform1i(sampler0Uniform, 0);

    glTexSubImage2D(
                    GL_TEXTURE_2D,
                    0,
                    0,
                    0,
                    mFrameW,            // source width
                    mFrameH,            // source height
                    GL_LUMINANCE,
                    GL_UNSIGNED_BYTE,
                    _frameData);


    //draw RECT
    glVertexAttribPointer(ATTRIB_VERTEX, 3, GL_FLOAT, 0, 0, squareVertices);
    glEnableVertexAttribArray(ATTRIB_VERTEX);

    //ATTRIB_TEXTUREPOSITON
    glVertexAttribPointer(ATTRIB_TEXTUREPOSITON, 2, GL_FLOAT, 0, 0, textureCoords);
    glEnableVertexAttribArray(ATTRIB_TEXTUREPOSITON);

    glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);

    free(_frameData);

    [(EAGLView *)self.view presentFramebuffer];

结论:u <-> v制服。

答案 1 :(得分:0)

由于iOS支持rgb_422纹理,因此使用一个rgb_422纹理而不是使用三个亮度纹理。 http://www.opengl.org/registry/specs/APPLE/rgb_422.txt

编辑: 哎呀YUV480p与YUV422不同。在这种情况下,由于奇怪的布局,您必须在将YUV数据上传为纹理之前将其转换为RGB数据。