在iOS 4.3中将YpCbCr iPhone 4相框渲染为OpenGL ES 2.0纹理

我正在尝试在iPhone 4上的iOS 4.3中将本机平面图像渲染为OpenGL ES 2.0纹理。然而,纹理全部变黑。 我的相机configuration如下:

[videoOutput setVideoSettings:[NSDictionary dictionaryWithObject:[NSNumber numberWithInt:kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange] forKey:(id)kCVPixelBufferPixelFormatTypeKey]]; 

我像这样将像素数据传递给我的纹理:

 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, bufferWidth, bufferHeight, 0, GL_RGB_422_APPLE, GL_UNSIGNED_SHORT_8_8_REV_APPLE, CVPixelBufferGetBaseAddress(cameraFrame)); 

我的战斗着色器是:

 varying highp vec2 textureCoordinate; uniform sampler2D videoFrame; void main() { lowp vec4 color; color = texture2D(videoFrame, textureCoordinate); lowp vec3 convertedColor = vec3(-0.87075, 0.52975, -1.08175); convertedColor += 1.164 * color.g; // Y convertedColor += vec3(0.0, -0.391, 2.018) * color.b; // U convertedColor += vec3(1.596, -0.813, 0.0) * color.r; // V gl_FragColor = vec4(convertedColor, 1.0); } 

和我的顶点着色器是

 attribute vec4 position; attribute vec4 inputTextureCoordinate; varying vec2 textureCoordinate; void main() { gl_Position = position; textureCoordinate = inputTextureCoordinate.xy; } 

这工作得很好,当我正在使用BGRA图像,而我的片段着色器只有

 gl_FragColor = texture2D(videoFrame, textureCoordinate); 

如果我在这里错过了什么? 谢谢!

好。 我们在这里取得了成功。 关键是将Y和UV作为两个单独的纹理传递给片段着色器。 这是最后的着色器:

 #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); } 

你需要像这样创build你的纹理:

 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)); 

然后像这样传递它们:

 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); 

男孩,我松了一口气!

PS yuv2rgbmatrix的值从这里http://en.wikipedia.org/wiki/YUV和我从这里复制代码http://www.ogre3d.org/forums/viewtopic.php?f=5&t=25877弄清楚如何获得正确的YUV值。

您的代码似乎试图将444加上未使用的字节中的32位颜色转换为RGBA。 这不会工作得很好。 我不知道任何输出“YUVA”的东西。

此外,我认为返回的alpha通道为BGRA相机输出,而不是1,所以我不知道为什么它工作(IIRC将其转换为CGImage你需要使用AlphaNoneSkipLast)。

420“双平面”输出结构如下:

  1. 一个标题,告诉你飞机在哪里(由CVPixelBufferGetBaseAddressOfPlane()和朋友使用)
  2. Y平面:height×bytes_per_row_1×1个字节
  3. Cb,Cr平面:高度/ 2×bytes_per_row_2×2个字节(每个2×2块2个字节)。

bytes_per_row_1大约是widthbytes_per_row_2大约是width/2 ,但是你会想要使用CVPixelBufferGetBytesPerRowOfPlane()来提高健壮性(你也许想要检查..GetHeightOfPlane和… GetWidthOfPlane的结果)。

你可能有运气把它作为1分量宽度*高度纹理和2分量宽度/ 2 *高度/ 2纹理。 您可能需要检查每行字节数,并处理不是简单的宽度*组件数量的情况(尽pipe对于大多数video模式来说这可能是正确的)。 在调用CVPixelBufferUnlockBaseAddress()之前,您还需要刷新GL上下文。

另外,你可以将它全部复制到你想要的格式(优化这个循环可能有点棘手)。 复制的优点是,在解锁像素缓冲区之后,您不必担心访问内存的事情。