实际问题
有几个答案可以解决我的问题:
- 我可以强制
CGImage
从直接数据提供者(使用创建的CGDataProviderCreateDirect
) like CGContextDrawImage
做?或者有其他方法可以设置 self.layer.contents 来做到这一点吗?
- 有没有
CGContext
我可以使用配置或技巧来渲染 1024x768 图像至少 30 fps 一致CGContextDrawImage
.
- 有没有人能够成功使用
CVOpenGLESTextureCacheCreateTextureFromImage
使用自己的纹理数据进行实时缓冲区更新?我认为我最大的问题是创建一个CVImageBuffer
因为我从苹果的纹理文档中复制了其他属性。如果有人有更多这方面的信息那就太好了。
- 关于如何以 30 fps 的速度从内存中获取图像到屏幕上的任何其他指南。
背景(很多):
我正在开发一个项目,需要实时修改 NPOT 图像数据的像素(至少 30 fps)并将其绘制在 iOS 的屏幕上。
我的第一个想法是使用 OpenGLglTexSubimage2D
更新一下,不幸的是,最终速度非常慢(iPad 上为 6 fps),因为驱动程序会调整并将每帧的 RGB 数据转换为 BGR。所以你说用 BGR 发送,我也是,但由于某种原因你不能打电话glTexSubImage2D
with GL_BGR
去搞清楚。我知道速度有些慢是因为它不是 2 图像数据的幂,但我的要求决定了这一点。
更多的阅读让我CVOpenGLESTextureCacheCreateTextureFromImage
但所有示例都是使用直接相机输入来获取CVImageBufferRef
我尝试使用文档(没有官方但只有标题注释)来使我自己的 CVImageBuffer 形成我的图像数据,但它不适用于此(没有错误,只是调试器中的空纹理),这让我认为苹果专门构建了这个处理实时相机数据,除了 IDK 之外,它还没有在该领域之外进行过太多测试。
无论如何,在放弃我的尊严、放弃 OpenGL 并将我的想法转向 CoreGraphics 之后,我被引出了这个问题在 iPhone 上绘制屏幕缓冲区的最快方法建议使用CGImage
受支持CGDataProviderCreateDirect
,它允许您在 CGImage 需要时返回指向图像数据的指针,很棒吧?嗯,它似乎并不像广告中所说的那样有效。如果我使用CGContextDrawImage
然后一切正常。我可以修改像素缓冲区,并且每次绘制时,它都会像应该的那样从我的数据提供程序请求图像数据,调用中的方法CGDataProviderDirectCallbacks
(Note:
他们似乎有一个内置的优化,如果更新的指针与先前的地址相同,则忽略更新的指针)。即使禁用插值,CGContextDrawImage 也不是超级快(大约 18 fps),这将其从大约 6 fps 提高了。苹果的文档告诉我使用self.layer.contents
会比CGContextDrawImage
. Using self.layer.contents
适用于第一个作业,但CGImage
永远不会像这样从数据提供者请求重新加载CGContextDrawImage
即使我打电话时也是如此[layer setNeedsDisplay]
。在我引用的SO问题中,用户通过每帧从数据源创建和销毁一个新的CGImage来展示他对问题的解决方案,这是一个极其缓慢的过程(是的,我确实尝试过),所以是时候讨论真正的问题了。
Note:我已经分析了所有这些操作并知道问题确实在于glTexSubImage
对于 OpenGL 和CGContextDrawImage
这确实是 CoreGraphics 的问题,所以没有“转到配置文件”答案。
EDIT现在可以在以下位置找到演示此技术的源代码http://github.com/narpas/image-sequence-streaming
感谢 Brad Larson 和 David H 帮助解决了这一问题(请参阅评论中的完整讨论)。结果使用 OpenGL 和 CoreVideoCVOpenGLESTextureCache
最终成为将原始图像推送到屏幕的最快方式(我知道 CoreGraphics 不可能是最快的!),在 iPad 1 上为我提供 60 fps 的全屏 1024x768 图像。现在关于此的文档很少,所以我会尝试并尽可能多地解释以帮助人们:
CVOpenGLESTextureCacheCreateTextureFromImage
允许您创建一个 OpenGL 纹理,其内存直接映射到CVImageBuffer
你用来创建它。这允许您创建一个CVPixelBuffer
使用您的原始数据并修改从收集的数据指针CVPixelBufferGetBaseAddress
。这可以在 OpenGL 中为您提供即时结果,无需修改或重新上传实际纹理。请务必锁定CVPixelBufferLockBaseAddress
在修改像素之前并在完成后解锁。请注意,目前这在 iOS 模拟器中不起作用,仅在我推测来自 VRAM/RAM 分区的设备上起作用,其中 CPU 无法直接访问 VRAM。 Brad 建议使用条件编译器检查来在原始版本之间切换glTexImage2D
更新并使用纹理缓存。
有几件事需要注意(这些因素的结合导致它对我不起作用):
- 在设备上测试
- 确保你
CVPixelBuffer
支持kCVPixelBufferIOSurfacePropertiesKey
see link例如(再次感谢布拉德)。
- 你必须使用
GL_CLAMP_TO_EDGE
用于 OpenGL ES 2.0 的 NPOT 纹理数据
- 绑定纹理缓存
glBindTexture(CVOpenGLESTextureGetTarget(_cvTexture), CVOpenGLESTextureGetName(_cvTexture));
不要像我一样愚蠢并使用CVOpenGLESTextureGetTarget
对于这两个参数。
- 不要每帧重新创建纹理,只需将图像数据复制到从
CVPixelBufferGetBaseAddress
更新纹理。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)