2013-10-23 41 views
2

我正在使用OpenGL ES 2.0编写一个iOS视频应用程序来执行图像处理。在OpenGl ES 2.0 for iOS中写入单通道像素缓冲区

我的输入和输出格式是YUV 4:2:0,这是iPhone 3GS之后大多数设备的原生像素格式。对于A5处理器及更高版本,我只需创建一个亮度纹理和色度纹理,然后将它们附加到屏幕外帧缓冲区。创建我texutre如下:

CVOpenGLESTextureCacheCreateTextureFromImage(kCFAllocatorDefault, 
                _videoTextureCache, 
                pixelBuffer, 
                NULL, 
                GL_TEXTURE_2D, 
                GL_RED_EXT, 
                (int)CVPixelBufferGetWidthOfPlane(pixelBuffer, 0), 
                (int)CVPixelBufferGetHeightOfPlane(pixelBuffer, 0), 
                GL_RED_EXT, 
                GL_UNSIGNED_BYTE, 
                0, 
                &lumaTexture); 

,然后我把它安装到程序,如:

glActiveTexture([self getTextureUnit:textureUnit]); 
glBindTexture(CVOpenGLESTextureGetTarget(texture), CVOpenGLESTextureGetName(texture)); 
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); 
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); 
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); 
if(uniform != -1) 
{ 
    glUniform1i(uniforms[uniform], textureUnit); 
} 

在我的着色器那么我可以简单地做:

gl_FragColor.r = texture2D(SamplerY, textureRead).r; 

来分配亮度值添加到缓冲区,并将生成的视频帧保存到磁盘。

不幸的是我遇到了iPhone 4的问题,因为它没有使用A5处理器,因此不支持GL_RED_EXT

然后我试图找出一种方法来写入OpenGL ES中的1通道luma缓冲区,但仍然遇到问题。我尝试将GL_RED_EXT更改为GL_LUMINANCE,但发现无法写入GL_LUMINANCE

我然后试图登记颜色附件和深度附件为:

GLuint colorRenderbuffer; 
glGenRenderbuffers(1, &colorRenderbuffer); 
glBindRenderbuffer(GL_RENDERBUFFER, colorRenderbuffer); 
glRenderbufferStorage(GL_RENDERBUFFER, GL_RGB8_OES, (int)CVPixelBufferGetWidthOfPlane(renderData.destinationPixelBuffer, 0), (int)CVPixelBufferGetHeightOfPlane(renderData.destinationPixelBuffer, 0)); 
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, 
           GL_RENDERBUFFER, colorRenderbuffer); 

GLuint depthRenderbuffer; 
glGenRenderbuffers(1, &depthRenderbuffer); 
glBindRenderbuffer(GL_RENDERBUFFER, depthRenderbuffer); 
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, (int)CVPixelBufferGetWidthOfPlane(renderData.destinationPixelBuffer, 0), (int)CVPixelBufferGetHeightOfPlane(renderData.destinationPixelBuffer, 0)); 
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, 
           GL_RENDERBUFFER, depthRenderbuffer); 

写入深度缓冲器在我的片段着色器:

gl_FragDepth.z = texture2D(SamplerY, textureRead).r; 

然后将结果写入到像素缓冲器作为:

glReadPixels(0, 0, (int)CVPixelBufferGetWidthOfPlane(renderData.destinationPixelBuffer, 0), (int)CVPixelBufferGetHeightOfPlane(renderData.destinationPixelBuffer, 0), GL_LUMINANCE, GL_UNSIGNED_BYTE, CVPixelBufferGetBaseAddressOfPlane(renderData.destinationPixelBuffer, 0)); 

但我再次读到的规格,OpenGL ES 2.0没有支持直接写入深度缓冲区。

所以我没有明显的方式来创建一个单通道颜色附件,我不知道如何写入到RGB颜色附件,只复制一个通道到我的像素缓冲区。

对不起,很长的文章,只是想给尽可能多的信息。

任何想法?

+0

如果我正确理解你,你想要通过OpenGL ES处理保持Y和UV通道分离,而不是像大多数情况下那样简单地将它们转换为RGB?我不确定在整个过程中保持YUV内容的好处将抵消必须为Y和UV渲染场景两次的缺点。唯一可能会受益的情况是AV基金会最终录制的电影,但即使在那里,它似乎也很好地利用BGRA帧。 –

+0

您好@BradLarson,实际上如果您在内存中保存了几帧用于流畅的视频录制,那么保留YUV420帧可能会有好处,因为它们占用的内存要少得多。任何想法如何在一次传递中将YUV帧渲染为YUV? –

+0

@DeepakSharma - OpenGL ES纹理是RGBA,因此您需要为整个Y和UV维护单独的平面。同样,您需要执行多个渲染通道或使用OpenGL ES 3.0并具有多个渲染目标。你需要编写所有的片段着色器来在每个阶段支持这些独立的平面。 –

回答

0

所以我最终解决这个问题的方法是使用GL_LUMINANCE和GL_LUMINANCE_ALPHA而不是RED和RG(如果扩展名不可用)。然后,我会在渲染通道后添加一个步骤,以使用glReadPixels将像素手动复制到预分配的像素缓冲区的预期格式。

相关问题