Metal Camera開(kāi)發(fā)4:渲染到CVPixelBuffer

Metal Camera開(kāi)發(fā)1:讀取渲染結(jié)果生成UIImage第5節(jié):讀取Metal渲染結(jié)果并生成UIImage介紹了讀取屏幕(MTLTexture的數(shù)據(jù))并由Core Graphics創(chuàng)建UIImage,類似于OpenGL ES,這一過(guò)程按我理解是存在多余的內(nèi)存拷貝操作(GPU管理的內(nèi)存塊拷貝到CPU管理的內(nèi)存塊)。為提高性能與簡(jiǎn)化視頻編碼步驟,本文檔介紹Metal渲染到CVPixelBuffer的實(shí)現(xiàn)。

文檔結(jié)構(gòu):

  1. OpenGL ES渲染到CVPixelBuffer實(shí)現(xiàn)代碼
  2. Metal渲染到CVPixelBuffer實(shí)現(xiàn)代碼
  3. 參考資料
  4. 致謝
渲染到CVPixelBuffer

1. OpenGL ES渲染到CVPixelBuffer實(shí)現(xiàn)代碼

1.1. 創(chuàng)建GL_TEXTURE_2D及glFramebufferTexture2D

GPUImage使用了此方式,基于我之前的代碼測(cè)試可正常運(yùn)行。最關(guān)鍵的地方是創(chuàng)建CVPixelBuffer需指定kCVPixelBufferIOSurfacePropertiesKey屬性為空字典。基于OpenGL ES 3.0的實(shí)現(xiàn)代碼如下所示。

CVReturn status = CVOpenGLESTextureCacheCreate(
            NULL, 
            NULL, 
            context, 
            NULL, 
            &textureCache);

NSDictionary *pixelBufferAttributes = @{(__bridge NSString*)kCVPixelBufferIOSurfacePropertiesKey: @{}};
status = CVPixelBufferCreate(
            NULL, 
            renderbufferWidth, 
            renderbufferHeight, 
            kCVPixelFormatType_32BGRA, 
            (__bridge CFDictionaryRef)pixelBufferAttributes, 
            &offlinePixelBuffer);

status = CVOpenGLESTextureCacheCreateTextureFromImage(
                                                      NULL,
                                                      textureCache,
                                                      offlinePixelBuffer,
                                                      NULL, // texture attributes
                                                      GL_TEXTURE_2D,
                                                      GL_RGBA, // OpenGL format
                                                      renderbufferWidth,
                                                      renderbufferHeight,
                                                      GL_BGRA, // native iOS format 
                                                      GL_UNSIGNED_BYTE,
                                                      0,
                                                      &offlineTexture);
glFramebufferTexture2D(
            GL_FRAMEBUFFER, 
            GL_COLOR_ATTACHMENT0, 
            GL_TEXTURE_2D, 
            CVOpenGLESTextureGetName(offlineTexture), 
            0);

有趣的是,format參數(shù)設(shè)置為GL_RGBA也可以正常創(chuàng)建CVOpenGLESTextureRef對(duì)象。無(wú)論format參數(shù)設(shè)置為什么值,使用時(shí)都得通過(guò)glFramebufferTexture2D將offlineTexture綁定到幀緩沖區(qū)。

1.2. 創(chuàng)建GL_RENDERBUFFER及glFramebufferRenderbuffer

這里嘗試了使用CVOpenGLESTextureCacheCreateTextureFromImage創(chuàng)建成GL_RENDERBUFFER,配合glFramebufferRenderbuffer可正常工作。創(chuàng)建成GL_RENDERBUFFER必須將format參數(shù)設(shè)置為GL_BGRA,否則創(chuàng)建失敗并報(bào)錯(cuò)Failed to create IOSurface image (texture)。另外,官方給的internalFormat為GL_RGBA8,這是OpenGL ES 1.0的宏定義,基于OpenGL ES 3.0開(kāi)發(fā)時(shí),換成GL_RGBA即可。參考代碼如下。

status = CVOpenGLESTextureCacheCreateTextureFromImage(
                                                      NULL,
                                                      textureCache,
                                                      offlinePixelBuffer,
                                                      NULL, // texture attributes
                                                      GL_RENDERBUFFER,
                                                      GL_RGBA8, // OpenGL format
                                                      renderbufferWidth,
                                                      renderbufferHeight,
                                                      GL_BGRA, // native iOS format 
                                                      GL_UNSIGNED_BYTE,
                                                      0,
                                                      &offlineTexture);

glFramebufferRenderbuffer(
            GL_FRAMEBUFFER, 
            GL_COLOR_ATTACHMENT0, 
            GL_RENDERBUFFER, 
            CVOpenGLESTextureGetName(offlineTexture));

1.3. 關(guān)于GL_TEXTURE_2D與GL_RENDERBUFFER

關(guān)于應(yīng)該使用GL_TEXTURE_2D還是GL_RENDERBUFFER,@紅豬和我討論了一段時(shí)間。建議直接參考官方文檔Drawing to Other Rendering Destinations。

2. Metal渲染到CVPixelBuffer實(shí)現(xiàn)代碼

參考OpenGL ES渲染到CVPixelBuffer的實(shí)現(xiàn),很容易模仿出Metal版本,如下代碼已通過(guò)驗(yàn)證。

CVMetalTextureCacheCreate(
            kCFAllocatorDefault, 
            nil, 
            device!, 
            nil, 
            &textureCache)
let pixelBufferAttri = [kCVPixelBufferIOSurfacePropertiesKey as NSObject: [:] as CFDictionary] as CFDictionary
let s = CVPixelBufferCreate(
            kCFAllocatorDefault, 
            1080, 
            1920, 
            kCVPixelFormatType_32BGRA, 
            pixelBufferAttri, 
            &offlinePixelBuffer)

let result = CVMetalTextureCacheCreateTextureFromImage(
    kCFAllocatorDefault,
    textureCache!,
    offlinePixelBuffer!,
    nil,
    self.colorPixelFormat,
    1080,
    1920,
    0,
    &offlineTexture)

3. 參考資料

  1. Rendering to a texture with iOS 5 texture cache api. GPUImage在源碼中標(biāo)明了它參考此鏈接,目前來(lái)看,所有的實(shí)現(xiàn)都源自于此鏈接,似乎是因?yàn)閃WDC Session 419主講人沒(méi)分享代碼給大家,而此博主寫了一份可行的示例代碼,所以大家都用他的代碼的。
  2. Capturing from the Camera using AV Foundation on iOS 5 蘋果官方講座描述了OpenGL ES渲染到CVPixelBuffer的細(xì)節(jié)。

4. 致謝

感謝@紅豬和我一起討論OpenGL ES渲染到CVPixelBuffer細(xì)節(jié)。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容