GPUImage 專注于使用基于openGLES2.0的GPU加速來處理圖像,相機圖像流及視頻,框架中大致的類分布如圖
GPUImage使用的一些技術
快速上傳texture
在Capturing from the Camera using AV Foundation on iOS 5 中的ChromaKey(Bridging CoreVideo and OpenGLES)部分,其目的旨在開發者可以加快處理速度且更好地使用GPU,添加了新的API CVOpenGLESTextureCache,這個Core Foundation類的目的旨在橋接CVPixelBuffer與OpenGLES Texture,而其主要的思想是避免CPU到GPU之間來回的復制(就拿720P的BGRA數據來說,要將它傳入并傳出GPU意味著需要做每秒220MB的拷貝更別說還要將數據來回傳輸,按bradson在stackoverflow中的說法,640*480的texture上傳到GPU的數據為9ms的話,220MB/s的拷貝速度是一個較為可信的瓶頸速度)及進行texture的復用(創建新的texture時需要維護的數據),這些api都定義在<CoreVideo/CVOpenGLESTextureCache.h>中
高效地將pixelBuffer映射為texture的方法:
CVOpenGLESTextureCacheCreateTextureFromImage(
kCFAllocatorDefault,
textureCache, //openGLESTextureCacheRef
pixelBuffer,
NULL, //optional texture attributes
GL_TEXTURE_2D, //the target,唯二的選擇是GL_RENDERBUFFER
GL_RGBA, //internal format
width,
height,
GL_RGBA, //pixel format
GL_UNSIGNED_BYTE, //data type of the pixels
0, //plane index to map(BGRA has only one plane)
&outTexture);
CVOpenGLES Texture綁定
同樣是在2011 wwdc 的session 419, 新的texture綁定概念也誕生了。眾所周知,正常的綁定texture的操作一般是先用glGenTexture生成texture,再獲取CVPixelBufferGetBaseAddress(pixelbuffer),然后用glTexImage2D(....)將pixeldata作為最后一個參數傳進去,這時在底層發生的事情其實相當于用memcpy()復制了這份數據并傳到Texture Image中供Texture Object使用,如下圖:
而cvopengles texture綁定避免了memcpy而直接將pixelbuffer與Texture Image綁定,同時使用api時,也不再傳pixelbuffer中圖像的裸指針,而是直接傳入CVPixelBufferRef,同時獲取生成的texture
openGL命令在CPU與GPU之間的同步
在執行openGL的繪制命令之后,很自然地就會想,如果這時候馬上去讀framebuffer中的圖像會是已經繪制完成的樣子嗎?glDrawArrays或者glDrawElements命令本身是同步的嗎?如stackoverflow上所說,openGL標準定義了"as if"原則,即在執行openGL命令時,假裝之前的所有opengl命令已經同步執行完了,因為在需要同步以確保"as if"原則的時候,openGL實現需要確保進行同步。比如多個繪制命令之后,這些命令本身很大可能是異步的,但如果此時需要調用glReadPixels等,則glReadPixels會block并等待之前所有的繪制命令執行結束再讀取并將內容存儲到用戶內存中。所有原則即是openGL會盡可能地延遲進行阻塞操作,當然,除非你需要顯式同步Sync objects 。
toll bridge 與 內存管理
在使用Avfoundation api的時候需要用到大量的CF對象比如cfdictionary等,通常在將本地OC對象轉成CF對象之后,如果沒有本地顯式釋放,總感覺會有內存泄漏的風險。這時候就需要重溫一下toll bridge轉換的語義了如develop document中所述:
編譯器并不會自動管理CF對象的生命周期,程序員需要顯式地通過<objc/runtime.h>中的cast語法,或者NSObject.h中定義的Core Foundation宏對CF對象ownership進行操作
1.__bridge在OC與Core Foundation之間傳遞指針,但并不進行所屬權的轉移
2.__bridge_retained或者CFBridgingRetain將OC指針轉換為CF指針并將所屬權轉移給程序員,需要手動CFRelease
3.__bridge_transfer或者CFBridgingRelease將非OC指針轉換為OC指針并將所屬權轉移給ARC,ARC對對象生命期負責
所以如果ARC中創建的OC對象通過__bridge轉換為CF對象傳入CF的API并不需要手動釋放