如何直接更新像素 – 使用CGImage和直接CGDataProvider
实际问题
几个答案将解决我的问题:
- 我可以像
CGContextDrawImage
一样强制CGImage
从直接数据提供者(使用CGDataProviderCreateDirect
创build)重新加载它的数据吗? 或者有其他的方法可以设置self.layer.contents来做到这一点? - 是否有一个
CGContext
configuration,或者我可以使用CGContextDrawImage
一致呈现1024×768图像至less30 fps的技巧。 - 有没有人能够成功地使用
CVOpenGLESTextureCacheCreateTextureFromImage
实时缓冲区更新与他们自己的纹理数据? 我认为我最大的问题是创build一个CVImageBuffer
因为我从Apples的纹理文档复制了其他属性。 如果任何人有更多的信息,这将是很棒的。 - 任何其他的指导方针,我怎么可以从内存中获取图像在30 fps的屏幕上。
背景(批次):
我正在做一个项目,我需要实时修改NPOT图像数据的像素(最低30帧/秒),并在iOS屏幕上绘制。
我的第一个想法是使用OpenGL与glTexSubimage2D
进行更新,不幸的是,结果是非常慢(在iPad上6 fps),因为驱动程序将每帧的RGB数据转换为BGR。 所以发送它在BGR你说,我也是这样,但由于某种原因,你不能用GL_BGR
去调用GL_BGR
去图。 我知道一些缓慢是因为它是不是2图像数据的力量,但我的要求规定。
更多的阅读导致我CVOpenGLESTextureCacheCreateTextureFromImage
但所有的例子是它使用直接相机input获取CVImageBufferRef
我试图使用文档(没有官方,但只是头注释),使我自己的CVImageBuffer形成我的图像数据,但它不会使用这个(在debugging器中没有错误只是一个空的纹理),这使得我认为苹果公司专门build立了这个处理实时相机数据,除了IDK之外,还没有经过多lesstesting。
无论如何,放弃我的尊严,通过倾倒OpenGL,并将我的想法转换到CoreGraphics我被引导到这个问题最快的方式来绘制iPhone上的屏幕缓冲区 ,build议使用CGImage
支持的CGDataProviderCreateDirect
,它允许您返回一个指向图像数据当CGImage需要它时,真棒吧? 那么它似乎不像广告一样。 如果我使用CGContextDrawImage
那么一切正常。 我可以修改像素缓冲区,每一个绘图,它会像我们的数据提供程序那样请求图像数据,调用CGDataProviderDirectCallbacks
的方法( Note:
它们似乎有一个内置优化,如果它具有相同的地址如前所述)。 CGContextDrawImage是不是超快(约18 fps),即使禁用插值,从6 fps起。 苹果的文档告诉我使用self.layer.contents
将比CGContextDrawImage
快得多。 使用self.layer.contents
适用于第一个作业,但CGImage
从不要求像CGContextDrawImage
那样从数据提供程序重新加载,即使在我调用[layer setNeedsDisplay]
。 在我引用的SO问题中,用户通过每一帧从数据源创build和销毁新的CGImage来解决这个问题,这是一个毫无希望的缓慢过程(是的,我尝试过了),所以真正的问题是时间了。
注意 :我已经剖析了所有这些操作,并且知道问题确实是OpenGL的glTexSubImage
,而CGContextDrawImage
实际上是CoreGraphics的问题,所以没有“go profile”的回答。
演示这种技术的编辑源代码现在可以在http://github.com/narpas/image-sequence-streamingfind
感谢Brad Larson和David H的帮助(请参阅我们在评论中的完整讨论)。 原来使用OpenGL和CoreVideo的CVOpenGLESTextureCache
最终成为将原始图像推送到屏幕上的最快方式(我知道CoreGraphics不可能是最快的!),在iPad 1上给我60fps的全屏1024×768图像。关于这个现在的文件,所以我会尽量帮助人们尽可能的解释:
CVOpenGLESTextureCacheCreateTextureFromImage
允许您创build一个OpenGL纹理,其内存直接映射到您用来创build它的CVImageBuffer
。 这使您可以使用原始数据创buildCVPixelBuffer
,并修改从CVPixelBufferGetBaseAddress
收集的数据指针。 这给你在OpenGL的即时结果,而不需要修改或重新上传实际的纹理。 只需确保在修改像素之前使用CVPixelBufferLockBaseAddress
进行locking,并在完成后解锁。 请注意,目前这在iOS模拟器中不起作用,只能在我推测为来自VRAM / RAM部分的设备上,其中CPU不能直接访问VRAM。 布拉德build议使用条件编译器检查来切换原始glTexImage2D
更新和使用纹理caching。
几件事情要注意(这些组合导致它不适合我):
- 在设备上testing
- 确保你
CVPixelBuffer
是支持与kCVPixelBufferIOSurfacePropertiesKey
见例如链接 (再次感谢布拉德)。 - 对于OpenGL ES 2.0中的NPOT纹理数据,您必须使用
GL_CLAMP_TO_EDGE
- 使用
glBindTexture(CVOpenGLESTextureGetTarget(_cvTexture), CVOpenGLESTextureGetName(_cvTexture));
绑定纹理cachingglBindTexture(CVOpenGLESTextureGetTarget(_cvTexture), CVOpenGLESTextureGetName(_cvTexture));
不要像我这样愚蠢,并使用CVOpenGLESTextureGetTarget
两个参数。 - 不要每一帧都重新创build纹理,只需将图像数据复制到从
CVPixelBufferGetBaseAddress
获取的指针中即可更新纹理。