iOS - So zeichnen Sie ein YUV-Bild mit openGL

Derzeit versuche ich, ein Bild mit openGL zu zeichnen (das Bild wird sehr oft aktualisiert und muss daher neu gezeichnet werden). Bisher habe ich mein Bild von YUV in RGB konvertiert und dieses neue Bild dann zum Zeichnen mit openGL verwendet. Alles hat gut funktioniert, aber der Konvertierungsprozess war nicht besonders schnell.

Ich versuche jetzt, den Code so zu ändern, dass die Konvertierung in den openGL-Shadern erledigt wird. Nachdem ich mich umgesehen habe, habe ich ein paar Codefragmente gefunden (insbesondere die Shader und den Großteil meiner renderImage-Funktion), die mir geholfen haben, eine Grundlinie zu erhalten, aber ich kann das Bild scheinbar nicht richtig zeichnen - alles, was ich jemals hatte siehe ist ein schwarzes Bild.

Es ist sehr wahrscheinlich, dass mir etwas sehr Einfaches und Wichtiges fehlt - meine Erfahrung mit openGL ist eher begrenzt. Wenn jemand einen Blick darauf werfen und feststellen kann, dass etwas nicht stimmt, lassen Sie es mich bitte wissen.

Ich sollte darauf hinweisen, ich versuche iOS 4.x zu unterstützen, daher sollte CVOpenGLESTextureCacheCreateTextureFromImage nicht verwendbar sein (und ich bin nicht wirklich sicher, wie ich es einrichten soll, auch wenn ich wollte).

Jede Hilfe wäre dankbar. Code unten -

Mein Vertex-Shader:

attribute vec4 position;
attribute vec4 inputTextureCoordinate;

varying vec2 textureCoordinate;

void main()
{
    gl_Position = position;
    textureCoordinate = inputTextureCoordinate.xy;
}

Fragment Shader:

#ifdef GL_ES
precision mediump float;
#endif

varying vec2 textureCoordinate;

uniform sampler2D videoFrame;
uniform sampler2D videoFrameUV;

const mat3 yuv2rgb = mat3(
                          1, 0, 1.2802,
                          1, -0.214821, -0.380589,
                          1, 2.127982, 0
                          );

void main() {
    vec3 yuv = vec3(
                    1.1643 * (texture2D(videoFrame, textureCoordinate).r - 0.0625),
                    texture2D(videoFrameUV, textureCoordinate).r - 0.5,
                    texture2D(videoFrameUV, textureCoordinate).a - 0.5
                    );
    vec3 rgb = yuv * yuv2rgb;

    gl_FragColor = vec4(rgb, 1.0);
}

Die renderImage Funktion:

-(void)renderImage:(ImageBuffer *)image
{
    if (image)
    {        
        int bufferHeight = image->GetHeight();
        int bufferWidth = image->GetWidth();

        if(!imageTexture){
            // Dealing with the Y portion of the YCbCr
            glActiveTexture(GL_TEXTURE0);
            glGenTextures(1, &imageTexture);
            //Bind Y texture
            glBindTexture(GL_TEXTURE_2D, imageTexture);
            glUniform1i(uniforms[UNIFORM_VIDEOFRAME], 0);
            // For fitting
            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);

            glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, bufferWidth, bufferHeight, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, image->GetPlanePointer(0));

            // Dealing with the CbCr potion of the YCbCr
            glActiveTexture(GL_TEXTURE1);
            glGenTextures(1, &imageTextureUV);
            //Bind CbCr texture
            glBindTexture(GL_TEXTURE_2D, imageTextureUV);
            glUniform1i(uniforms[UNIFORM_VIDEOFRAMEUV], 1);
            // For fitting
            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);

            glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE_ALPHA, bufferWidth/2, bufferHeight/2, 0, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, image->GetPlanePointer(1));

        }

        [self drawFrame];
    }
}

Und zum Schluss die drawFrame-Funktion:

- (void)drawFrame
{
    [self setFramebuffer];

    // Replace the implementation of this method to do your own custom drawing.
    static const GLfloat squareVertices[] = {
        -1.0f, -1.0f,
        1.0f, -1.0f,
        -1.0f, 1.0f,
        1.0f, 1.0f
    };

    static const GLfloat textureVertices[] = {
//        1.0f, 1.0f,
//        1.0f, 0.0f,
//        0.0f,  1.0f,
//        0.0f,  0.0f,
        0.0f, 1.0f,
        1.0f, 1.0f,
        0.0f, 0.0f,
        1.0f, 0.0f
//        0.0f, 0.8f,
//        1.0f, 0.8f,
//        0.0f, 0.2f,
//        1.0f, 0.2f
    };

    static float transY = 0.0f;


    if ([context API] == kEAGLRenderingAPIOpenGLES2) {
        // Use shader program.
        glUseProgram(program);

        glActiveTexture(GL_TEXTURE0);
        glBindTexture(GL_TEXTURE_2D, imageTexture);

        // Update attribute values.
        glVertexAttribPointer(ATTRIB_VERTEX, 2, GL_FLOAT, 0, 0, squareVertices);
        glEnableVertexAttribArray(ATTRIB_VERTEX);
        glVertexAttribPointer(ATTRIB_TEXTUREPOSITON, 2, GL_FLOAT, 0, 0, textureVertices);
        glEnableVertexAttribArray(ATTRIB_TEXTUREPOSITON);

        glActiveTexture(GL_TEXTURE1);
        glBindTexture(GL_TEXTURE_2D, imageTextureUV);

        // Update attribute values.
        glVertexAttribPointer(ATTRIB_VERTEX, 2, GL_FLOAT, 0, 0, squareVertices);
        glEnableVertexAttribArray(ATTRIB_VERTEX);
        glVertexAttribPointer(ATTRIB_TEXTUREPOSITON, 2, GL_FLOAT, 0, 0, textureVertices);
        glEnableVertexAttribArray(ATTRIB_TEXTUREPOSITON);

        // Validate program before drawing. This is a good check, but only really necessary in a debug build.
        // DEBUG macro must be defined in your debug configurations if that's not already the case.
#if defined(DEBUG)
        if (![self validateProgram:program]) {
            NSLog(@"Failed to validate program: %d", program);
            return;
        }
#endif
    } else {
        glMatrixMode(GL_PROJECTION);
        glLoadIdentity();
        glMatrixMode(GL_MODELVIEW);
        glLoadIdentity();
        glTranslatef(0.0f, (GLfloat)(sinf(transY)/2.0f), 0.0f);
        transY += 0.075f;

        glVertexPointer(2, GL_FLOAT, 0, squareVertices);
        glEnableClientState(GL_VERTEX_ARRAY);
    } 

    glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);

    [self presentFramebuffer];
}

Antworten auf die Frage(1)

Ihre Antwort auf die Frage