3

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

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

换句话说,我需要将 opengl 纹理复制到基于像素缓冲区的纹理对象中。可能吗?如果是,那怎么办?

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

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

    }

感谢您的提示和答案。

PSglGetTexImage在 iOS 上不可用。

更新:

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

看完答案后,我明白我需要:

1- 将像素缓冲区关联的纹理对象作为颜色附件附加到 texFBO。对于每一帧:

2-绑定从API获取的纹理

3-绑定texFBO并调用drawElements

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

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

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

4

2 回答 2

5

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

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

此时,您可以使用glReadPixels()将字节拉回 CVPixelBufferRef 的内部字节数组,或者最好使用纹理缓存来消除读取的需要。我在这个答案中描述了如何为该方法设置缓存,以及如何将其提供给 AVAssetWriter。您需要将屏幕外 FBO 设置为使用 CVPixelBufferRef 的关联纹理作为渲染目标才能使其正常工作。

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

于 2013-05-23T23:01:28.223 回答
1

是的,很不幸 glGetTexImage 不是 ios。当我为 cocos2d 实现我的 CCMutableTexture2D 类时,我遇到了这个问题。

在推送到 gpu 之前缓存图像

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

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

使用 FBO 和 glReadPixels

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

于 2013-05-23T18:04:12.633 回答