iOS CVImageBuffer distorted from AVCaptureSessionDataOutput with AVCaptureSessionPresetPhoto
This was a doozy.
As Lio Ben-Kereth pointed out, the padding is 48 as you can see from the debugger
(gdb) po pixelBuffer<CVPixelBuffer 0x2934d0 width=852 height=640 bytesPerRow=3456 pixelFormat=BGRA# => 3456 - 852 * 4 = 48
OpenGL can compensate for this, but OpenGL ES cannot (more info here openGL SubTexturing)
So here is how I'm doing it in OpenGL ES:
(CVImageBufferRef)pixelBuffer // pixelBuffer containing the raw image data is passed in/* ... */glActiveTexture(GL_TEXTURE0);glBindTexture(GL_TEXTURE_2D, videoFrameTexture_);int frameWidth = CVPixelBufferGetWidth(pixelBuffer);int frameHeight = CVPixelBufferGetHeight(pixelBuffer);size_t bytesPerRow, extraBytes;bytesPerRow = CVPixelBufferGetBytesPerRow(pixelBuffer);extraBytes = bytesPerRow - frameWidth*4;GLubyte *pixelBufferAddr = CVPixelBufferGetBaseAddress(pixelBuffer);if ( [[captureSession sessionPreset] isEqualToString:@"AVCaptureSessionPresetPhoto"] ){ glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, frameWidth, frameHeight, 0, GL_BGRA, GL_UNSIGNED_BYTE, NULL ); for( int h = 0; h < frameHeight; h++ ) { GLubyte *row = pixelBufferAddr + h * (frameWidth * 4 + extraBytes); glTexSubImage2D( GL_TEXTURE_2D, 0, 0, h, frameWidth, 1, GL_BGRA, GL_UNSIGNED_BYTE, row ); }}else{ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, frameWidth, frameHeight, 0, GL_BGRA, GL_UNSIGNED_BYTE, pixelBufferAddr);}
Before, I was using AVCaptureSessionPresetMedium
and getting 30fps. In AVCaptureSessionPresetPhoto
I'm getting 16fps on an iPhone 4. The looping for the sub-texture does not seem to affect the frame rate.
I'm using an iPhone 4 on iOS 5.
Just draw like this.
size_t bytesPerRow = CVPixelBufferGetBytesPerRow(pixelBuffer);int frameHeight = CVPixelBufferGetHeight(pixelBuffer);GLubyte *pixelBufferAddr = CVPixelBufferGetBaseAddress(pixelBuffer);glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, (GLsizei)bytesPerRow / 4, (GLsizei)frameHeight, 0, GL_BGRA, GL_UNSIGNED_BYTE, pixelBufferAddr);
Good point Mats.But as a matter of fact the padding is larger, it's:
bytesPerRow = 4 * bufferWidth + 48;
It works great on the iphone 4 back camera, and solved the issue sotangochips reported about.