開源一個上架 App Store 的相機 App

Hawk0620發表於2017-02-19
Osho 相機是我獨立開發上架的一個相機 App,App Store地址:點我。它支援1:1,4:3,16:9多種解析度拍攝,濾鏡可在取景框的實時預覽,拍攝過程可與濾鏡實時合成,支援分段拍攝,支援回刪等特性。下面先分享分享開發這個 App 的一些心得體會,文末會給出專案的下載地址,閱讀本文可能需要一點點 AVFoundation 開發的基礎。

1、GLKView和GPUImageVideoCamera

一開始取景框的預覽我是基於 GLKView 做的,GLKView 是蘋果對 OpenGL 的封裝,我們可以使用它的回撥函式 -glkView:drawInRect: 進行對處理後的 samplebuffer 渲染的工作(samplebuffer 是在相機回撥 didOutputSampleBuffer 產生的),附上當初簡版程式碼:

這樣的實現在低端機器上取景框會有明顯的卡頓,而且 ViewController 上的列表幾乎無法滑動,雖然手勢倒是還可以支援。 因為要實現分段拍攝與回刪等功能,採用這種方式的初衷是期望更高度的自定義,而不去使用 GPUImageVideoCamera, 畢竟我得在 AVCaptureVideoDataOutputSampleBufferDelegateAVCaptureAudioDataOutputSampleBufferDelegate 這兩個回撥做文章,為了滿足需求,所以得在不侵入 GPUImage 原始碼的前提下點功夫。

怎麼樣才能在不破壞 GPUImageVideoCamera 的程式碼呢?我想到兩個方法,第一個是建立一個類,然後把 GPUImageVideoCamera 裡的程式碼拷貝過來,這麼做簡單粗暴,缺點是若以後 GPUImage 升級了,程式碼維護起來是個小災難;再來說說第二個方法——繼承,繼承是個挺優雅的行為,可它的麻煩在於獲取不到私有變數,好在有強大的 runtime,解決了這個棘手的問題。下面是用 runtime 獲取私有變數:

至此取景框實現了濾鏡的渲染並保證了列表的滑動幀率。

2、實時合成以及 GPUImage 的 outputImageOrientation

顧名思義,outputImageOrientation 屬性和影像方向有關的。GPUImage 的這個屬性是對不同裝置的在取景框的影像方向做過優化的,但這個優化會與 videoOrientation 產生衝突,它會導致切換攝像頭導致影像方向不對,也會造成拍攝完之後的視訊方向不對。 最後的解決辦法是確保攝像頭輸出的影像方向正確,所以將其設定為 UIInterfaceOrientationPortrait,而不對 videoOrientation 進行設定,剩下的問題就是怎樣處理拍攝完成之後視訊的方向。

先來看看視訊的實時合成,因為這裡包含了對使用者合成的 CVPixelBufferRef 資源處理。還是使用繼承的方式繼承 GPUImageView,其中使用了 runtime 呼叫私有方法:

直奔重點——CVPixelBufferRef 的處理,將 renderTarget 轉換為 CGImageRef 物件,再使用 UIGraphics 獲得經 CGAffineTransform 處理過方向的 UIImage,此時 UIImage 的方向並不是正常的方向,而是旋轉過90度的圖片,這麼做的目的是為 videoInput 的 transform 屬性埋下伏筆。下面是 CVPixelBufferRef 的處理程式碼:

而 videoInput 的 transform 屬性設定如下:

經過這兩次方向的處理,合成的小視訊終於方向正常了。此處為簡版的合成視訊程式碼:

可以看到關鍵點還是在於上面繼承自 GPUImageView 這個類獲取到的 renderTarget 屬性,它應該即是取景框實時預覽的結果,我在最初的合成中是使用 sampleBuffer 轉 UIImage,再通過 GPUImage 新增濾鏡,最後將 UIImage 再轉 CIImage,這麼做導致拍攝時會卡。當時我幾乎想放棄了,甚至想採用拍好後再加濾鏡的方式繞過去,最後這些不純粹的方法都被我 ban 掉了。

既然濾鏡可以在取景框實時渲染,我想到了 GPUImageView 可能有料。在閱讀過 GPUImage 的諸多原始碼後,終於在 GPUImageFramebuffer.m 找到了一個叫 renderTarget 的屬性。至此,合成的功能也告一段落。

3、關於濾鏡

這裡主要分享個有意思的過程。App 裡有三種型別的濾鏡。基於 glsl 的、直接使用 acv 的以及直接使用 lookuptable 的。lookuptable 其實也是 photoshop 可匯出的一種圖片,但一般的軟體都會對其加密,下面簡單提下我是如何反編譯“借用”某軟體的部分濾鏡吧。使用 Hopper Disassembler 軟體進行反編譯,然後通過某些關鍵字的搜尋,幸運地找到了下圖的一個方法名。

reverse 只能說這麼多了….在開原始碼裡我已將這一類敏感的濾鏡剔除了。

小結

開發相機 App 是個挺有意思的過程,在其中邂逅不少優秀開原始碼,向開原始碼學習,才能避免自己總是寫出一成不變的程式碼。最後附上專案的開源地址 https://github.com/hawk0620/ZPCamera,希望能夠幫到有需要的朋友,也歡迎 star 和 pull request。

打賞支援我寫出更多好文章,謝謝!

打賞作者

打賞支援我寫出更多好文章,謝謝!

開源一個上架 App Store 的相機 App

相關文章