iPhone 的 CPU 对于处理视频来说能力是非常有限的,如果要进行视频处理,比如滤镜、美颜等,都会用到设备的 GPU 能力,也就是会用到 openGL ES 的 api。
CPU 和 GPU 之间的数据传递效率十分低下,尤其是从 GPU 回传数据到 CPU,更是缓慢。比如使用 glReadPixels
从 GPU 读取数据这种模式,想要做到实时很难。
那么,在 iOS 中想要提高 GPU 和 CPU 数据传递效率,就需要使用到共享内存,避免数据拷贝。
根据文档可以知道包含 kCVPixelBufferIOSurfacePropertiesKey
属性的 CVPixelBufferRef
对象的内存是共享的。比如,从 iOS Camera 采集出来和从 VideoToolBox
硬解出来的 buffer 都具有这个属性,也就是这些 buffer 可以在 CPU 和 GPU 之间共享。
我们可以自己建立符合这个条件的 buffer,创建方式如下:
// 创建 kCVPixelBufferIOSurfacePropertiesKey 属性
CFDictionaryRef empty = CFDictionaryCreate(kCFAllocatorDefault, NULL, NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
CFMutableDictionaryRef attrs = CFDictionaryCreateMutable(kCFAllocatorDefault, 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
CFDictionarySetValue(attrs, kCVPixelBufferIOSurfacePropertiesKey, empty);
// 创建具有 kCVPixelBufferIOSurfacePropertiesKey 属性的 CVPixelBufferRef 实例 renderTarget
CVPixelBufferRef renderTarget;
CVReturn err = CVPixelBufferCreate(kCFAllocatorDefault, (int)_size.width, (int)_size.height, kCVPixelFormatType_32BGRA, attrs, &renderTarget);
...
这样我们就获得了自定义的具有共享内存性质的 CVPixelBufferRef renderTarget。
在 Camera 采集 buffer,硬解 VideoToolBox buffer 和我们自定义的具有共享内存性质的 CVPixelBufferRef renderTarget 基础上,可以通过以下接口创建具有共享内存的 texture,将 CVPixelBufferRef 与 Texture 关联起来,一方的变化将引起另一方的变化:
CVOpenGLESTextureRef renderTexture;
CVOpenGLESTextureCacheCreateTextureFromImage (
kCFAllocatorDefault,
textureCache,
renderTarget,
NULL, // texture attributes
GL_TEXTURE_2D,
GL_RGBA, // opengl format
640,
480,
GL_BGRA, // native iOS format
GL_UNSIGNED_BYTE,
0,
&renderTexture);
这样我们就可以在 openGL 中使用我们创建的具有共享内存的 renderTexture,使用方法如下:
glBindTexture(CVOpenGLESTextureGetTarget(renderTexture), CVOpenGLESTextureGetName(renderTexture));
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glBindFramebuffer(GL_FRAMEBUFFER, renderFrameBuffer);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, CVOpenGLESTextureGetName(renderTexture), 0);
这样如果在 openGL 中 texture 发生了变化,那么对应的 CVPixelBufferRef 也会发生变化。
如果要取回内容,可用下面方式:
if (kCVReturnSuccess == CVPixelBufferLockBaseAddress(renderTarget, kCVPixelBufferLock_ReadOnly)) {
uint8_t* pixels = (uint8_t*)CVPixelBufferGetBaseAddress(renderTarget);
CVPixelBufferUnlockBaseAddress(renderTarget, kCVPixelBufferLock_ReadOnly);
}
通过上述方法实现了 CPU 和 GPU 数据直接共享,避免数据拷贝,上述接口需要在 iOS 5 及以上系统才可用。
参考链接
本文为原创文章,版权归字节时代所有,欢迎分享本文,转载请保留出处!
你可能也喜欢
- ♥ 在越狱设备调试任意 iOS App 的 WebView04/05
- ♥ iOS 平台使用 Frida 简明指南04/29
- ♥ 使用 IDA microcode 去除 ollvm 混淆06/20
- ♥ CentOS 7 配置VNC远程桌面并安装火狐浏览器04/27
- ♥ WCDB 简明使用指南07/30
- ♥ macOS 提升应用执行权限的方案04/05