将纹理复制到PixelBuffer(CVPixelBufferRef)

时间:2013-05-23 14:05:38

标签: iphone ios opengl-es textures avassetwriter

我使用的API只给出了纹理对象的整数id,我需要将该纹理的数据传递给AVAssetWriter来创建视频。

我知道如何从像素缓冲区(CVPixelBufferRef)创建CVOpenGLESTexture对象,但在我的情况下,我必须以某种方式复制只有id可用的纹理数据。

换句话说,我需要将一个opengl纹理复制到我的基于pixelbuffer的纹理对象。可能吗?如果是,那么如何?

在我的示例代码中,我有类似的内容:

   void encodeFrame(Gluint textureOb)
    {

    CVPixelBufferPoolCreatePixelBuffer (NULL, [assetWriterPixelBufferAdaptor pixelBufferPool], &pixelBuffer[0]);

    CVOpenGLESTextureCacheCreateTextureFromImage (kCFAllocatorDefault, coreVideoTextureCache, pixelBuffer[0],
                                                          NULL, // texture attributes
                                                          GL_TEXTURE_2D,
                                                          GL_RGBA, // opengl format
                                                          (int)FRAME_WIDTH,
                                                          (int)FRAME_HEIGHT,
                                                          GL_BGRA, // native iOS format
                                                          GL_UNSIGNED_BYTE,
                                                          0,
                                                          &renderTexture[0]);


    CVPixelBufferLockBaseAddress(pixelBuffer[pixelBuffernum], 0);

//Creation of textureOb is not under my control. 
//All I have is the id of texture. 
//Here I need the data of textureOb somehow be appended as a video frame. 
//Either by copying the data to pixelBuffer or somehow pass the textureOb to the Adaptor.

    [assetWriterPixelBufferAdaptor appendPixelBuffer:pixelBuffer[0] withPresentationTime:presentationTime];

    }

感谢您的提示和解答。

P.S。 iOS上无法使用glGetTexImage

更新

@Dr。 Larson,我无法为API设置纹理ID。实际上我不能指示第三方API使用我自己创建的纹理对象。

在完成答案之后,我理解的是我需要:

1-将与pixelbuffer相关联的纹理对象作为颜色附件附加到texFBO。 对于每一帧:

2-绑定从API获得的纹理

3-绑定texFBO并调用drawElements

我在这段代码中做错了什么?

P.S。我还不熟悉着色器,所以我现在很难使用它们。

更新2: 在Brad Larson的帮助下,使用正确的着色器解决了这个问题。我不得不使用着色器,这是Opengl ES 2.0的基本要求

2 个答案:

答案 0 :(得分:5)

要从iOS上的OpenGL ES读取数据,您基本上有两个路径:使用glReadPixels()或使用纹理缓存(仅限iOS 5.0+)。

事实上,你只有一个纹理ID并且没有别的东西,这有点奇怪,并限制你的选择。如果您无法在此第三方API中设置要使用的纹理,则需要将该纹理重新渲染到屏幕外帧缓冲区,以便使用glReadPixels()或者为其提取像素。纹理缓存。要做到这一点,你要使用尺寸与纹理尺寸相同的FBO,一个简单的四边形(构成一个矩形的两个三角形),以及一个只在输出帧缓冲区中显示纹理的每个纹素的直通着色器

此时,您可以使用glReadPixels()将您的字节拉回到CVPixelBufferRef的内部字节数组中,或者最好使用纹理缓存来消除对该读取的需要。我将介绍如何在this answer中为该方法设置缓存,以及如何将其提供给AVAssetWriter。您需要将屏幕外FBO设置为使用CVPixelBufferRef的关联纹理作为渲染目标,以便工作。

但是,如果您可以设置用于此渲染纹理的ID,则可以避免重新渲染它以获取其像素值。像我在上面链接的答案中描述的那样设置纹理缓存,并将该像素缓冲区的纹理ID传递给您正在使用的第三方API。然后它将渲染到与像素缓冲区相关联的纹理中,您可以直接从中进行记录。这就是我在GPUImage框架中用来加速从OpenGL ES录制视频的方法(使用glReadPixels()方法作为iOS 4.x的后备)。

答案 1 :(得分:1)

是的,相当不幸的是glGetTexImage并非如此。当我为cocos2d实现我的CCMutableTexture2D类时,我一直在努力。

在推送到gpu之前缓存图像

如果您查看源代码,您会注意到最后我将图像的像素缓冲区缓存到我的CCMutableTexture2D类中,而不是在它被推送到之后丢弃它的正常路径gpu。

http://www.cocos2d-iphone.org/forum/topic/2449

使用FBO>和glReadPixels

可悲的是,我认为这种方法可能不适合您,因为您使用纹理数据创建某种类型的视频并保留我们缓存的每个像素缓冲区会占用大量内存。另一种方法可能是动态创建FBO,以便使用glReadPixels来填充像素缓冲区。我不太确定这种方法会有多成功,但是这里发布了一个很好的例子: Read texture bytes with glReadPixels?