回顧
解析(一)
解析(二)
解析(三)
這次介紹的GPUImageContext
、GPUImageFramebufferCache
和GPUImagePicture
。
GPUImageContext
GPUImageContext是GPUImage對OpenGL ES上下文的封裝,添加了GPUImage相關的上下文,比如說Program的使用緩存,處理隊列,CV紋理緩存等。
1、屬性介紹
contextQueue
統一處理隊列
currentShaderProgram
正在使用的program
context
OpenGL ES的上下文
coreVideoTextureCache
CV紋理緩存
framebufferCache
GPUImageBuffer緩存
shaderProgramCache
Program的緩存
shaderProgramUsageHistory
Program的使用歷史
2、方法介紹
useAsCurrentContext()
在useAsCurrentContext設置當前上下文的時候,會先判斷上下文是否是當前context,不是再設置(為了避免上下文切換的性能消耗,即使設置的上下文是同一個上下文也會消耗性能)sizeThatFitsWithinATextureForSize()
會調整紋理大小,如果超過最大的紋理,會調整為不超過最大的紋理寬高。(GLProgram*)programForVertexShaderString:fragmentShaderString:;
shaderProgramCache 是program的緩存,由頂點shader和片元shader字符串拼接起來做key。- (void)useSharegroup:(EAGLSharegroup *)sharegroup;
EAGLSharegroup類管理一個或者多個EAGLContext的OpenGLES資源;這個是一個封閉的類,沒有開發者API。負責管理紋理緩存、頂點緩存、幀緩存、顏色緩存。(textures, buffers, framebuffers, and render buffers)- (EAGLContext *)context;
返回OpenGL ES2.0的上下文,同時設置glDisable(GL_DEPTH_TEST);
,圖像處理管道默認不允許使用深度緩存。
GPUImageFramebufferCache
GPUImageFramebufferCache是GPUImageFrameBuffer的管理類
1、屬性介紹
CacheframebufferCache
緩存字典
framebufferTypeCounts
緩存數量字典
activeImageCaptureList
正在讀取Image數據的GPUImageFrameBuffer列表
framebufferCacheQueue
緩存隊列
2、方法介紹
- (NSString *)hashForSize: textureOptions:onlyTexture:;
根據size、textureOptions和onlyTexture,創建緩存字符串。
緩存字符串+當前緩存數量形成framebufferCache緩存的key。
如果找不到framebufferCache對應的數量,會創建新的緩存。- (void)returnFramebufferToCache:;
回收緩存。根據size、textureOptions和onlyTexture,創建緩存字符串,緩存字符串+當前緩存數量形成framebufferCache緩存的key。(之所以會加上數量,是因為緩存字符串不唯一)- (void)addFramebufferToActiveImageCaptureList:;
- (void)removeFramebufferFromActiveImageCaptureList:
這兩個方法主要用于,當newCGImageFromFramebufferContents()
讀取幀緩存圖像數據時,保持GPUImageFramebuffer的引用。并且讀取完數據后,在dataProviderUnlockCallback()
方法釋放。
GPUImagePicture
GPUImagePicture是PGUImage的圖像處理類,繼承GPUImageOutput,一般作為響應鏈的源頭。
1、屬性介紹
pixelSizeOfImage 圖像的像素大小。
hasProcessedImage 圖像是否已處理。
imageUpdateSemaphore 圖像處理的GCD信號量。
2、方法介紹
- (id)initWithCGImage:smoothlyScaleOutput:
用源圖像newImageSource和是否采用mipmaps來初始化GPUImagePicture。
如果圖像大小超過OpenGL ES最大紋理寬高,或者使用mipmaps,或者圖像數據是浮點型、顏色空間不對等都會采用CoreGraphics重新繪制圖像。
然后通過glTexImage2D把圖像數據發送給GPU,最后釋放掉CPU的圖像數據。- (BOOL)processImageWithCompletionHandler:;
通知targets處理圖像,并在完成后調用complete代碼塊。在處理開始時,會標記hasProcessedImage為YES,并調用dispatch_semaphore_wait()
,確定上次處理已經完成,否則取消這次處理。
-
- (void)addTarget: atTextureLocation:;
添加target到響應鏈。如果hasProcessedImage為YES,表示圖像已經處理完畢,直接設置targets的InputSize,并調用newFrameReadyAtTime()
通知target。
DEMO
用GPUImagePicture處理源圖像,用GPUImageTiltShiftFilter處理模糊效果,用GPUImageView顯示。
效果展示
核心代碼
將GPUImageView設置為self.view,根據face.png,設置GPUImagePicture,然后添加GPUImageTiltShiftFilter到響應鏈,再把GPUImageView作為響應鏈的終點,最后調用processImage,開始處理圖像。
GPUImageView *primaryView = [[GPUImageView alloc] initWithFrame:self.view.frame];
self.view = primaryView;
UIImage *inputImage = [UIImage imageNamed:@"face.png"];
_sourcePicture = [[GPUImagePicture alloc] initWithImage:inputImage];
_sepiaFilter = [[GPUImageTiltShiftFilter alloc] init];
_sepiaFilter.blurRadiusInPixels = 40.0;
[_sepiaFilter forceProcessingAtSize:primaryView.sizeInPixels];
[_sourcePicture addTarget:_sepiaFilter];
[_sepiaFilter addTarget:primaryView];
[_sourcePicture processImage];
總結
最近因為直播用戶增長太快,忙著優化原來的邏輯,研讀源代碼的時間變少。
同時為了寫這篇文章,查了一些關于圖像資料,末尾附上。
下一篇文章可能會介紹今年大火的直播APP的一種速成方案,也可能會是GPUImageMovie的介紹。
喜歡的點一下關注,不迷路。
Mipmap紋理技術是目前解決紋理分辨率與視點距離關系的最有效途徑,它會先將圖片壓縮成很多逐漸縮小的圖片,例如一張6464的圖片,會產生6464,3232,1616,88,44,22,11的7張圖片,當屏幕上需要繪制像素點為2020 時,程序只是利用 3232 和 1616 這兩張圖片來計算出即將顯示為 2020 大小的一個圖片,這比單獨利用 32*32 的那張原始片計算出來的圖片效果要好得多,速度也更快.
kCGImageAlphaLast:alpha 分量存儲在每個像素中的低位,如RGBA。
kCGImageAlphaFirst:alpha 分量存儲在每個像素中的高位,如ARGB。
kCGImageAlphaPremultipliedLast:alpha 分量存儲在每個像素中的低位,同時顏色分量已經乘以了 alpha 值。
kCGImageAlphaPremultipliedFirst:alpha 分量存儲在每個像素中的高位,同時顏色分量已經乘以了 alpha 值。
kCGImageAlphaNoneSkipLast:沒有 alpha 分量。如果像素的總大小大于顏色空間中顏色分量數目所需要的空間,則低位將被忽略。
kCGImageAlphaNoneSkipFirst:沒有 alpha 分量。如果像素的總大小大于顏色空間中顏色分量數目所需要的空間,則高位將被忽略。