ios视频处理中CPU和GPU的高效连接桥梁——共享内存(CVPixelBufferRef)

    iphone的cpu对于处理视频来说能力是非常有限的,所以在ios开发中,如果要进行视频处理,比如滤镜、美颜等,都会用到设备的GPU能力,也就是会用到opengl es的api,而CPU和GPU之间的数据传递效率十分低下,尤其是从GPU回传数据到CPU,更是缓慢。如用glReadPixels从GPU读取数据,如果用这种模式,想要做到实时很难。鉴于此,今天主要介绍一下ios中GPU和CPU的共享内存机制,从而避免数据的拷贝。

    满足某种条件的CVPixelBufferRef本身就是共享内存,这个条件就CVPixelBufferRef具有kCVPixelBufferIOSurfacePropertiesKey属性,从ios camera采集出来和从videoToolBox硬解出来的buffer是具有这个属性,也就是这些buffer可以在CPU和GPU之间共享。我们也可以自己建立符合这个条件的buffer,创建方式如下:

            //kCVPixelBufferIOSurfacePropertiesKey属性创建

            CFDictionaryRef empty; // empty value for attr value.

            CFMutableDictionaryRef attrs;

  empty = CFDictionaryCreate(kCFAllocatorDefault, NULL, NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); // our empty IOSurface properties dictionary

 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_ATTACHMENT0GL_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及以上。

参考连接:

    http://allmybrain.com/2011/12/08/rendering-to-a-texture-with-ios-5-texture-cache-api/

    https://github.com/BradLarson/GPUImage

你可能感兴趣的:(ios视频处理中CPU和GPU的高效连接桥梁——共享内存(CVPixelBufferRef))