Render YpCbCr iPhone 4 Camera Frame to an OpenGL ES 2.0 Texture in iOS 4.3

前端 未结 2 1141
孤独总比滥情好
孤独总比滥情好 2021-02-03 13:27

I\'m trying to render a native planar image to an OpenGL ES 2.0 texture in iOS 4.3 on an iPhone 4. The texture however winds up all black. My camera is configured as such:

相关标签:
2条回答
  • 2021-02-03 14:06

    Your code appears to attempt to convert a 32-bit colour in 444-plus-unused-byte to RGBA. That's not going to work too well. I don't know of anything that outputs "YUVA", for one.

    Also, I think the returned alpha channel is 0 for BGRA camera output, not 1, so I'm not sure why it works (IIRC to convert it to a CGImage you need to use AlphaNoneSkipLast).

    The 420 "bi planar" output is structued something like this:

    1. A header telling you where the planes are (used by CVPixelBufferGetBaseAddressOfPlane() and friends)
    2. The Y plane: height × bytes_per_row_1 × 1 bytes
    3. The Cb,Cr plane: height/2 × bytes_per_row_2 × 2 bytes (2 bytes per 2x2 block).

    bytes_per_row_1 is approximately width and bytes_per_row_2 is approximately width/2, but you'll want to use CVPixelBufferGetBytesPerRowOfPlane() for robustness (you also might want to check the results of ..GetHeightOfPlane and ...GetWidthOfPlane).

    You might have luck treating it as a 1-component width*height texture and a 2-component width/2*height/2 texture. You'll probably want to check bytes-per-row and handle the case where it isn't simply width*number-of-components (although this is probably true for most of the video modes). AIUI, you'll also want to flush the GL context before calling CVPixelBufferUnlockBaseAddress().

    Alternatively, you can copy it all to memory into your expected format (optimizing this loop might be a bit tricky). Copying has the advantage that you don't need to worry about things accessing memory after you've unlocked the pixel buffer.

    0 讨论(0)
  • 2021-02-03 14:09

    OK. We have a working success here. The key was passing the Y and the UV as two separate textures to the fragment shader. Here is the final 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);
    } 
    

    You'll need to create your textures along like this:

    int bufferHeight = CVPixelBufferGetHeight(cameraFrame);
    int bufferWidth = CVPixelBufferGetWidth(cameraFrame);
    glBindTexture(GL_TEXTURE_2D, videoFrameTexture);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, bufferWidth, bufferHeight, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, CVPixelBufferGetBaseAddressOfPlane(cameraFrame, 0));
    
    glBindTexture(GL_TEXTURE_2D, videoFrameTextureUV);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE_ALPHA, bufferWidth/2, bufferHeight/2, 0, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, CVPixelBufferGetBaseAddressOfPlane(cameraFrame, 1));
    

    and then pass them like this:

    glActiveTexture(GL_TEXTURE0);
    glBindTexture(GL_TEXTURE_2D, videoFrameTexture);
    
    glActiveTexture(GL_TEXTURE1);
    glBindTexture(GL_TEXTURE_2D, videoFrameTextureUV);
    
    glActiveTexture(GL_TEXTURE0);
    glUniform1i(videoFrameUniform, 0);
    glUniform1i(videoFrameUniformUV, 1);
    

    Boy am I relieved!

    P.S. The values for the yuv2rgb matrix are from here http://en.wikipedia.org/wiki/YUV and I copied code from here http://www.ogre3d.org/forums/viewtopic.php?f=5&t=25877 to figure out how to get the correct YUV values to begin with.

    0 讨论(0)
提交回复
热议问题