【问题标题】:Getting screenshot via CVOpenGLESTextureCacheCreate通过 CVOpenGLESTextureCacheCreate 获取屏幕截图
【发布时间】:2012-09-12 09:15:34
【问题描述】:

我有一个类似于 GLPaint 示例的应用程序(但在 OpenGL ES 2.0 上)。我想在某些时候获取绘图视图的屏幕截图。我已经读过这个topic

但我不明白我应该在什么时候调用 CVOpenGLESTextureCacheCreate 并做其他事情。谁能帮帮我?

【问题讨论】:

    标签: ios opengl-es opengl-es-2.0


    【解决方案1】:

    我在the answer 中描述的代码描述了像素缓冲区的创建、匹配纹理的提取以及将该纹理绑定为帧缓冲区的输出。您使用该代码一次来设置将渲染场景的帧缓冲区。

    每当您想从该纹理中捕获时,您可能需要使用glFinish() 进行阻塞,直到所有 OpenGL ES 渲染完成,然后使用我在此处描述的代码:

    CVPixelBufferLockBaseAddress(renderTarget, 0);
    _rawBytesForImage = (GLubyte *)CVPixelBufferGetBaseAddress(renderTarget);
    // Do something with the bytes
    CVPixelBufferUnlockBaseAddress(renderTarget, 0);
    

    提取包含场景图像的纹理的原始字节。

    iOS 纹理的内部字节顺序是 BGRA,因此您需要使用类似以下的内容从这些字节创建 CGImageRef:

    // It appears that the width of a texture must be padded out to be a multiple of 8 (32 bytes) if reading from it using a texture cache
    NSUInteger paddedWidthOfImage = CVPixelBufferGetBytesPerRow(renderTarget) / 4.0;
    NSUInteger paddedBytesForImage = paddedWidthOfImage * (int)currentFBOSize.height * 4;
    dataProvider = CGDataProviderCreateWithData((__bridge_retained void*)self, _rawBytesForImage, paddedBytesForImage, dataProviderUnlockCallback);
    
    cgImageFromBytes = CGImageCreate((int)currentFBOSize.width, (int)currentFBOSize.height, 8, 32, CVPixelBufferGetBytesPerRow(renderTarget), defaultRGBColorSpace, kCGBitmapByteOrder32Little | kCGImageAlphaPremultipliedFirst, dataProvider, NULL, NO, kCGRenderingIntentDefault);
    

    在上面,我使用dataProviderUnlockCallback() 函数来处理像素缓冲区的解锁和安全恢复渲染,但在您的情况下您可能会忽略它,只需将 NULL 传递给那里的参数。

    【讨论】:

    • 何时应该将纹理绑定为帧缓冲区的输出?在帧缓冲区创建代码中?
    • @miksayer - 是的,正如我在上面所指出的,您需要将其作为帧缓冲区设置的一部分。
    • pastie.org/4712848 是我的帧缓冲设置代码。我在 glBindTexture(CVOpenGLESTextureGetTarget(renderTexture), CVOpenGLESTextureGetName(renderTexture)) 有 EXC_BAD_ACCESS;线。我做错了什么?
    • 我现在已经修复了 EXC_BAD_ACCESS pastie.org/4719978 。但是,如果我尝试使用此代码pastie.org/4719980 获取屏幕截图,我只会得到空的字节数组。我哪里错了?请帮帮我
    【解决方案2】:

    另一种选择是:

    1. 创建一个新的 CGBitmapContext
    2. 调用 [layer renderInContext:yourNewContext]
    3. 从位图上下文中获取 CGImage
    4. 获取像素缓冲区,将 CGImage 放入其中,然后使用 AVAdaptor 将其附加到 AssetWriter。

    祝你好运!

    编辑

    这可能行不通:我现在正在测试,会尽快重新发布。

    【讨论】:

    • 不幸的是,这不适用于 CAEAGLLayer,就像这里使用的一样。 -renderInContext: 不捕获 OpenGL ES 内容。
    • 真的吗?哎呀。很高兴知道。出于好奇:您的渲染到纹理方法是否可以在保留支持的 GL 上下文中工作?
    • 我相信是这样,但我从未尝试过。只要渲染完成到纹理,您就可以从其匹配的 CVPixelBuffer 中提取字节。
    • 在您的框架中记录屏幕的绘画应用程序的目标链是什么? GPUImageView -> GPUImageMovieWriter?反之亦然?
    【解决方案3】:

    试试VideoToolboxVTCreateCGImageFromCVPixelBuffer(适用于iOS 9.x+):

    OSStatus VTCreateCGImageFromCVPixelBuffer(CVPixelBufferRef pixelBuffer, CFDictionaryRef options, CGImageRef  _Nullable *imageOut);
    Parameters
    

    指定将成为 CGImage 图像数据源的像素缓冲区(将 options 设置为 NULL)。

    【讨论】:

      猜你喜欢
      • 2016-09-25
      • 2014-03-18
      • 2010-09-09
      • 1970-01-01
      • 1970-01-01
      • 2014-02-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多