2013年9月5日 星期四

Camera特效篇

--ios

在ios實作上基本上是比較困難的。basic on api supported and some technique issue and below .

Since then, Apple has ported some of their Core Image framework from the Mac to iOS. Core Image provides an interface for doing filtering of images and video on the GPU. Unfortunately, the current implementation on iOS has some limitations. The largest of these is the fact that you can't write your own custom filters based on their kernel language, like you can on the Mac. This severely restricts what you can do with the framework. Other downsides include a somewhat more complex interface and a lack of iOS 4.0 support. Others have complained about some performance overhead, but I've not benchmarked this myself.

但是實際上有了這個framework GPUImage ..

https://github.com/BradLarson/GPUImage

基本上使用起image camera video等特效可以說是非常簡單,甚至比使用一般framework的function還要簡單些,可以這麼說。

他也是基於opengl es 2.0下去撰寫的framework,內建的濾鏡多到看了就花了,即使如此還是支援glsl , opengl shader language . 關於這點我並沒有看太熟。

所謂的濾鏡為一個shader language,有五個
主要部分可以去作宣染著色,相較於opengl 1.0擁有更flexible , efficient的功能。


整個code flow先要一個GPUImageStillCamera的instance , 這instance為一個camera的畫面,並且可自行跟換濾鏡,而後濾鏡丟進stillcamera的instance之後隨即表現至螢幕上,使用拍照功能後則instance會丟出目前的image data出來。

我目前所寫的demo,我將我撈出來的所有濾鏡直接做成list可以更換,其中各種濾鏡都有參數可以去作調整,但是所有參數全都不一,所以目前下方的slider bar還沒有連結至各濾鏡,並且我並沒有去一一看各種濾鏡的效果,只有將會crash的濾鏡刪除而已。

這只是我撈濾鏡所使用的方法,並不需要看懂。
grep -Rl ": GPUImageFilter" * | sed -e s/framework\\/Source\\///g | sed -e s/\\.h//g | awk '{printf "@\"" ; printf $0 ; printf "\"," ; printf "\n" ;}' > ha.txt

to sum up , GPUImage提供了一般user很輕易的就能使用opengl es 2.0的功能來達到image video processing,甚至可以連內容都不用管的情況下來使用他內建的特效。


--android

android端真的就得一步一步來了,基本上整個flow不會太難,難的部份還是opengl 2.0去實現的部份,因為全程自己來所以下面的technique issue比較雜。

首先進入點是onPreviewFrame這個interface ,在於camera PreviewCallback,

public void onPreviewFrame(byte[] yuvs, Camera camera) 
在此camera這層會傳給你一組data stream called yuvs , as it says這image format為yuvs420的格式
http://en.wikipedia.org/wiki/YUV

而如果需要使用需要轉為rgb的格式,所以透過一個jni傳至c層去作decode。
public native void yuv420sp2rgb(byte[] in, int width, int height, int textureSize, byte[] out);
可以稍微簡介一下jni,他是個java native interface,千萬不要覺得他很難,他就是個java層對應到c層一個one-one mapping的function而已,你可以想像整個framework層就是透過一堆jni去將driver層的資料porting到framework層,扯遠了,總之他有個一固定的format可以讓你在java層可以使用c層的function,比較要注意的是package class name得跟native那層完全對應才行。

透過這個jni可以將資料轉為rgb格式,分別存在兩段buffer,在opengl層bind一個空材質texture,然後透過glTexSubImage2D不斷將指針指向這兩段buffer來作動畫的效果,既然傳進了gl這層,就可以透過shader來做到各種特效了,很遺憾的是我們得實作shader這層,這個open source有一些寫好的shader可以作參考。

簡略的講一下glsurfaceview的flow,在view create的時候call

public void onSurfaceCreated(GL10 gl, EGLConfig config)
在整個view的layout有改變時call
public void onSurfaceChanged(GL10 gl, int width, int height)
其餘整個frame會call
public void onDrawFrame(GL10 gl)
最好的情況,沒修改default的話每秒的frame是60個,也就是60fps,也就是說onDrawFrame會call六十次每秒。


等到拍照時,將當時的opengl pixels讀取出來,透過GLES20.glReadPixels,在opengl層的argb跟bitmap格式的argb的blue and red是對調的,所以要交換,然後透過bitmap factory將data轉存bitmap,就是整個android camera effect的特效了。

沒有留言:

張貼留言