1. 程式人生 > >ios視訊處理中CPU和GPU的高效連線橋樑——共享記憶體(CVPixelBufferRef)

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

參考連線: