【问题标题】:Copy A Texture to PixelBuffer (CVPixelBufferRef)将纹理复制到 PixelBuffer (CVPixelBufferRef)
【发布时间】:2013-05-18 22:34:01
【问题描述】:

我正在使用一个 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];

    }

感谢您的提示和回答。

附: glGetTexImage 在 iOS 上不可用。

更新:

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

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

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

2- 绑定API获取的纹理

3- 绑定texFBO并调用drawElements

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

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

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

【问题讨论】:

    标签: iphone ios opengl-es textures avassetwriter


    【解决方案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?

    【讨论】:

    • 如果你要创建纹理,从 iOS 5.0 开始有一种更快的方法来访问它背后的字节。您可以使用纹理缓存直接读取和写入纹理后面的支持字节,正如我在这里描述的那样:stackoverflow.com/questions/9550297/…。这是不依赖glReadPixels()glTexImage2D()的直接内存访问。
    【解决方案2】:

    对于在 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 的后备方法)。

    【讨论】:

    • 非常感谢,请查看我的“更新”部分问题。
    • @Usman.3D - 如果您无法提供用于纹理的 ID,并且您无法访问纹理的渲染时间,则需要重新渲染它到屏幕外 FBO 以提取它的颜色字节。然后,您可以使用我描述的任何一种方法:glReadPixels() 从 FBO 中提取,或绑定纹理与纹理缓存配对以更快地捕获结果。
    • 非常感谢拉森博士。非常感谢您的帮助。我正在为你刚才提到的内容编写代码。
    • 博士。拉尔森,我再次需要你的宝贵意见。请参阅更新2。非常感谢。
    • @Usman.3D - 你的 glReadPixels() 在哪里?如果您没有使用它读取像素,则需要正确设置纹理缓存并将相关纹理绑定到渲染 FBO。确保您遵循此处的所有设置步骤:stackoverflow.com/questions/9550297/…,并且您使用相同的 OpenGL ES 上下文进行纹理上传和纹理缓存。
    猜你喜欢
    • 2014-06-13
    • 2011-03-16
    • 2014-07-21
    • 2016-09-13
    • 1970-01-01
    • 2012-07-29
    • 1970-01-01
    • 1970-01-01
    • 2016-09-21
    相关资源
    最近更新 更多