9

实际问题

几个答案将解决我的问题:

  1. 我可以像这样强制 aCGImage从直接数据提供者(使用 创建CGDataProviderCreateDirect)重新加载其数据CGContextDrawImage吗?还是有其他方法可以设置 self.layer.contents 来做到这一点?
  2. 是否有CGContext配置或技巧可以用来渲染 1024x768 图像,至少 30 fps 与CGContextDrawImage.
  3. 有没有人能够成功地使用CVOpenGLESTextureCacheCreateTextureFromImage他们自己的纹理数据进行实时缓冲区更新?我认为我最大的问题是创建一个CVImageBuffer,因为我从 Apples 的纹理文档中复制了其他属性。如果有人对此有更多信息,那就太棒了。
  4. 关于如何以 30 fps 从内存中获取图像到屏幕上的任何其他指南。

背景(批次):

我正在做一个项目,我需要实时修改 NPOT 图像数据的像素(最低 30 fps)并将其绘制在 iOS 的屏幕上。

我的第一个想法是使用 OpenGLglTexSubimage2D进行更新,不幸的是最终速度非常慢(iPad 上为 6 fps),因为驱动程序将我的 RGB 数据每帧转换为 BGR。所以用你说的 BGR 发送它,我也是,但由于某种原因你不能glTexSubImage2DGL_BGRgo figure 调用。我知道有些慢是因为它不是 2 图像数据的幂,但我的要求决定了这一点。

更多阅读使我想到,CVOpenGLESTextureCacheCreateTextureFromImage但所有示例都是使用直接相机输入来获取CVImageBufferRef我尝试使用文档(没有官方但只是标题注释)来使我自己的 CVImageBuffer 形成我的图像数据,但它不适用于此(否错误只是调试器中的一个空纹理),这让我认为Apple专门为处理实时相机数据而构建了它,并且除了IDK之外,它还没有在这个领域之外进行过太多测试。

无论如何,在通过转储 OpenGL 并将我的想法切换到 CoreGraphics 来放弃我的尊严之后,我被引导到这个问题,这是在 iPhone 上绘制屏幕缓冲区的最快方法, 它建议使用CGImagebacked by CGDataProviderCreateDirect,它允许您在CGImage 需要它,很棒吧?好吧,它似乎并不像宣传的那样有效。如果我使用CGContextDrawImage,那么一切正常。我可以修改像素缓冲区,每次绘制时,它都会像它应该的那样从我的数据提供者那里请求图像数据,调用CGDataProviderDirectCallbacks(Note:他们似乎有一个内置的优化,如果更新的指针与之前的地址相同,则忽略更新的指针)。即使禁用插值,CGContextDrawImage 也不是超快(大约 18 fps),这从 6 fps 提高了。Apple 的文档告诉我使用self.layer.contents会比CGContextDrawImage. usingself.layer.contents适用于第一次分配,但即使我CGImage调用. 在我引用的 SO 问题中,用户通过每帧从数据源创建和销毁一个新的 CGImage 来展示他对问题的解决方案,这是一个非常缓慢的过程(是的,我确实尝试过),所以是时候提出真正的问题了。CGContextDrawImage[layer setNeedsDisplay]

注意:我已经分析了所有这些操作,并且知道问题确实glTexSubImage出在 OpenGL 上,并且CGContextDrawImage确实是 CoreGraphics 的问题,所以没有“go profile”的答案。

编辑演示此技术的源代码现在可以在http://github.com/narpas/image-sequence-streaming找到

4

1 回答 1

9

感谢 Brad Larson 和 David H 提供的帮助(请参阅我们在评论中的完整讨论)。事实证明,使用 OpenGL 和 CoreVideoCVOpenGLESTextureCache最终成为将原始图像推送到屏幕的最快方式(我知道 CoreGraphics 不可能是最快的!),在 iPad 1 上为我提供 60 fps 的全屏 1024x768 图像。几乎没有文档现在就这一点,所以我将尝试尽可能多地解释以帮助人们:

CVOpenGLESTextureCacheCreateTextureFromImage允许您创建一个 OpenGL 纹理,其内存直接映射到CVImageBuffer您用于创建它的内存。这允许您使用原始数据创建 aCVPixelBuffer并修改从 收集的数据指针CVPixelBufferGetBaseAddress。这为您在 OpenGL 中提供即时结果,无需修改或重新上传实际纹理。只需确保CVPixelBufferLockBaseAddress在修改像素之前锁定并在完成后解锁。请注意,目前这在 iOS 模拟器中不起作用,仅在我推测来自 VRAM/RAM 部门的设备上工作,其中 CPU 无法直接访问 VRAM。glTexImage2DBrad 建议使用条件编译器检查在原始更新和使用纹理缓存之间切换。

需要注意的几件事(这些因素的组合导致它对我不起作用):

  1. 在设备上测试
  2. 确保您CVPixelBuffer得到支持,例如kCVPixelBufferIOSurfacePropertiesKey查看链接(再次感谢布拉德)。
  3. 您必须GL_CLAMP_TO_EDGE在 OpenGL ES 2.0 中使用 NPOT 纹理数据
  4. 绑定纹理缓存 glBindTexture(CVOpenGLESTextureGetTarget(_cvTexture), CVOpenGLESTextureGetName(_cvTexture));不要像我一样愚蠢并CVOpenGLESTextureGetTarget用于两个参数。
  5. 不要每帧都重新创建纹理,只需将图像数据复制到从中获取的指针中CVPixelBufferGetBaseAddress即可更新纹理。
于 2012-09-01T03:13:50.253 回答