總述
從總體上來講它是容納一個紋理的容器。這個類寫得太別的散,讓人一眼看不出什么主旨要義來封断,可能是因?yàn)樽髡呦褡屵@個類處理太多東西了。它接收一個紋理和這個紋理的大小舶担,然后經(jīng)過一番處理然后生成一個什么東西坡疼,雖然主要就是個圖片而已。此外衣陶,它還涉及到2個重要的操作柄瑰,一個是內(nèi)存上的控制,一個是并發(fā)上的控制剪况。
內(nèi)部構(gòu)成
GLuint framebuffer:這個就是緩沖區(qū)的實(shí)質(zhì)教沾,它就是緩沖區(qū)。
CVPixelBufferRef renderTarget:它就是渲染的目標(biāo)拯欧。
CVOpenGLESTextureRef renderTexture:這是需要被渲染的紋理详囤。
NSUInteger readLockCount: 這個應(yīng)該是讀寫鎖,好像是說只要這個緩沖區(qū)被讀取它就不能被更改镐作,所以上個鎖藏姐。
NSUInteger framebufferReferenceCount:這就是那個引用計(jì)數(shù),每個對象的引用計(jì)數(shù)该贾。這個類似OC對象的引用計(jì)數(shù)羔杨。
BOOL referenceCountingDisabled:這個是引用計(jì)數(shù)的開關(guān)。
-(void)generateFramebuffer:用來生成一個緩沖區(qū)杨蛋,這里面的過程就比較復(fù)雜了兜材。
-(void)generateTexture:用來生成一個紋理理澎,內(nèi)部使用的。
-(void)destroyFramebuffer:用于銷毀幀緩沖區(qū)曙寡。
這里還有兩個C語言的回調(diào)dataProviderReleaseCallback和dataProviderUnlockCallback糠爬。
generateTexture
從這個名字就可以看出來它是用來生成紋理的,具體是怎么生成紋理的举庶,全是都用OpenGL ES 2.0來生成的执隧。這里面首先是要選擇一個待激活的紋理單元,紋理單元的數(shù)量至少是8個户侥。然后是生成紋理的名字镀琉,用一個數(shù)組來存儲存儲生成的名字,有幾個名字?jǐn)?shù)組的元素個數(shù)就是幾個蕊唐。接下來是要把名字和激活的紋理單元綁定屋摔,我想這個過程就是給紋理單元命名吧。最后是把紋理以某種方式映射成像素替梨。反正全都是OpenGL ES的操作钓试。
generateFramebuffer
這個就是生成幀緩沖區(qū),整個過程都是同步執(zhí)行的耙替。在OpenGL ES中生成幀緩沖區(qū)和生成紋理有點(diǎn)相似亚侠。首先指定一下上下文曹体,然后就是幀緩沖區(qū)的專屬部分了俗扇。首先要生成幀緩沖區(qū)的名字,一個幀緩沖區(qū)配一個名字箕别。然后通過名字把對應(yīng)的幀緩沖區(qū)綁定到某目標(biāo)上去铜幽。須知與設(shè)備有關(guān)的一個屬性是在iOS 5.0及以上所有的幀緩沖區(qū)都是備份在紋理的緩存中,所以該方法的邏輯進(jìn)行到這都需要進(jìn)行一個判斷串稀,如果是支持備份的話除抛,是一種處理,否則是另一種處理方式母截。
如果是支持這種特性的到忽,首先要獲取紋理的緩存,這個緩存是CVOpenGLESTextureCacheRef類型的清寇。然后用一個可變字典去獲取屬性喘漏,然后把這些屬性賦值給一個不可變字典。在這個過程中华烟,有一個error對象翩迈,這就好像是一個異常對象一樣,從該對象中可以獲取錯誤信息盔夜。前半過程已經(jīng)處理完了负饲,這一段就是獲取屬性堤魁,獲取完了以后就釋放臨時的變量。接下來是純的OpenGL ES的處理過程返十,簡單就是獲取當(dāng)前的紋理妥泉,并從當(dāng)前的紋理獲取幀緩沖區(qū)。
如果不支持特性洞坑,此時就代表該設(shè)備不支持從紋理緩存獲取幀緩沖區(qū)涛漂。那就新生成1個紋理,然后通過這個紋理獲取幀緩沖區(qū)检诗。
這兩個分支都走完以后匈仗,就獲取緩沖區(qū)的狀態(tài),最后是綁定紋理逢慌,但是為什么最后要綁定紋理呢悠轩?
destroyFramebuffer
很顯然嘛,這就是用來釋放幀緩沖區(qū)用的攻泼。它是同步處理的火架,處理的過程是這樣的。首先獲取上下文忙菠,然后如果緩沖區(qū)不空的話就釋放幀緩沖區(qū)何鸡。接下來的處理過程也分兩種情況,就是如果設(shè)備支持紋理緩存和不支持紋理緩存的情況牛欢,另外還有一個判斷條件是是否允許丟失幀緩沖區(qū)骡男。
如果支持并且還不支持丟失幀緩沖區(qū)的話,那就釋放渲染目標(biāo)和渲染的紋理傍睹。
否則隔盛,直接就刪除紋理即可。
activateFramebuffer
激活幀緩沖區(qū)用的拾稳,但是這里面的實(shí)現(xiàn)極其簡單吮炕,就兩句話。它首先是要把幀緩沖區(qū)綁定到指定目標(biāo)上面访得,然后是要把這個幀緩沖區(qū)轉(zhuǎn)換成一個size大小的圖片紋理龙亲,由此可見幀緩沖區(qū)最終要被轉(zhuǎn)換成一個size的,而且轉(zhuǎn)換的步驟就在此處啊悍抑,不過這個size具體是多大鳄炉,它決定于類外部的設(shè)置。
幀緩沖區(qū)的引用計(jì)數(shù)機(jī)制
這個就是參考了OC對象的引用計(jì)數(shù)機(jī)制传趾,概述一下就是這個緩沖區(qū)被引用的話迎膜,引用計(jì)數(shù)就+1,放棄引用浆兰,引用計(jì)數(shù)就-1磕仅,減到0以后珊豹,按照oc的機(jī)制的話是釋放對象,但是在GPUImage中則是把幀緩沖區(qū)歸還到幀緩沖區(qū)的緩存中榕订。
lock
它是手動增加引用計(jì)數(shù)的方法店茶。它先檢查是否禁用了引用計(jì)數(shù),如果禁用了劫恒,就什么都不做直接返回不从,否則把該緩沖區(qū)的引用計(jì)數(shù)+1.
unlock
這是手動減少引用計(jì)數(shù)的方法亮瓷。如果引用計(jì)數(shù)被禁用了,就直接返回。如果引用計(jì)數(shù)沒有被減的時候就已經(jīng)是0孟抗,則會觸發(fā)斷言猖任,而不是直接歸還到緩存中去尺上。
clearAllLocks
這個沒啥好說的金顿,就是清空引用計(jì)數(shù),但是它沒有歸還幀緩沖區(qū)贰您。
disableReferenceCounting
禁用引用計(jì)數(shù)坏平。
enableReferenceCounting
激活引用計(jì)數(shù)。
圖像捕捉
就是說從幀緩沖區(qū)能夠計(jì)算出圖像锦亦。
dataProviderReleaseCallback
釋放數(shù)據(jù)舶替,一個C語言的語法,看上去有點(diǎn)類似于內(nèi)聯(lián)函數(shù)杠园。這是一個回調(diào)顾瞪,傳進(jìn)來的數(shù)據(jù)就是希望被釋放的數(shù)據(jù)。
dataProviderUnlockCallback
這也是個回調(diào)返劲,它用于把回調(diào)進(jìn)來的數(shù)據(jù)降低它的引用計(jì)數(shù)玲昧。因?yàn)檫@個幀緩沖區(qū)總是要綁定到一個目標(biāo)上的,你不能因?yàn)檫@個幀緩沖區(qū)不要了也不要這個與之綁定的目標(biāo)了篮绿,于是要先恢復(fù)它的渲染目標(biāo)。然后引用計(jì)數(shù)減一吕漂,然后亲配,因?yàn)樗荒茉诒挥糜讷@取圖像了嘛,所以你需要把它從能用于獲取圖片的幀緩沖列表中刪除惶凝。
newCGImageFromFramebufferContents
它是能夠從幀緩沖區(qū)中獲取一個新的cg圖像吼虎。整個過程也是同步進(jìn)行的。首先是要獲取上下文苍鲜。接下來是獲取生成圖片所需要的總的字節(jié)數(shù)思灰,這個字節(jié)數(shù)是圖像的寬度×高度×4,而這個寬度和高度是通過屬性外部設(shè)置的size混滔。
如果設(shè)備是支持紋理緩存的話洒疚,它要從渲染目標(biāo)中獲取每行的像素的字節(jié)數(shù)歹颓,再除以4,得到每行中的單元數(shù)油湖,至于什么單元巍扛,我就不知道了,然后寬度×高度×4乏德,知道尺寸以后撤奸,要先把引用計(jì)數(shù)+1,然后讀取喊括。獲取渲染目標(biāo)的地址胧瓜,通過數(shù)據(jù)獲取數(shù)據(jù)的提供者,這些提供者是什么呀郑什?然后把幀緩沖區(qū)添加入到可以獲取圖片的激活的圖像鏈表中贷痪。
如果設(shè)備不支持紋理緩存的話,則直接激活幀緩沖區(qū)蹦误,然后通過屬性設(shè)置的size來獲取圖片的像素?cái)?shù)和字節(jié)數(shù)劫拢,進(jìn)而得到數(shù)據(jù)提供者,然后幀緩沖區(qū)降低引用計(jì)數(shù)强胰。
接下來舱沧,是從設(shè)備上獲取RGB顏色空間。
如果設(shè)備支持紋理緩存的話偶洋,通過上面的數(shù)據(jù)提供器還有RGB顏色空間并且使用渲染目標(biāo)就可以得到cg圖像熟吏。
如果設(shè)備不支持紋理緩存的話,就通過屬性size設(shè)置的數(shù)據(jù)來獲取cg圖像玄窝。
最后得到結(jié)果牵寺,就是一個cg圖像。
restoreRenderTarget
恢復(fù)渲染的目標(biāo)恩脂。這個實(shí)現(xiàn)很簡單帽氓,也是兩行代碼,就是在讀完以后降低它的引用計(jì)數(shù)俩块,并且釋放渲染目標(biāo)黎休。
數(shù)據(jù)讀取機(jī)制
就是在讀取數(shù)據(jù),控制引用計(jì)數(shù)玉凯。就是在讀的時候引用計(jì)數(shù)+1势腮,不讀的時候引用計(jì)數(shù)-1.
lockForReading
只有設(shè)備支持紋理緩存的時候,才進(jìn)行此操作漫仆,這里面涉及到了另外一個讀計(jì)數(shù)捎拯,一開始的時候計(jì)數(shù)是0就先鎖定像素緩沖區(qū)的基址,然后讀計(jì)數(shù)+1.
unlockAfterReading
它也是只針對支持紋理緩存的設(shè)備而言的盲厌,讀計(jì)數(shù)減1署照,到了0以后就解鎖像素緩沖區(qū)的基址祸泪。
bytesPerRow
它返回圖像紋理每行的字節(jié)數(shù)。如果設(shè)備支持紋理藤树,則只通過渲染目標(biāo)就可以得到每行的字節(jié)數(shù)浴滴。如果不是iPhone或者模擬器或者不支持紋理緩存,則返回通過屬性設(shè)置的size的寬度×4.
byteBuffer
就是通過渲染目標(biāo)獲取像素緩沖區(qū)的基址岁钓,之前要鎖定來讀取升略,之后要解鎖。
pixelBuffer
其實(shí)就是返回渲染目標(biāo)屡限,而對于非iPhone或者模擬器平臺則直接返回NULL品嚣。
texture
用于持久化輸入的紋理。