1. 程式人生 > >Android 特效直播實現原理解析

Android 特效直播實現原理解析

  作者簡介:

  2010年開始從事Android開發工作,網易資深開發工程師,主要負責視訊雲Android端的直播SDK開發與維護工作。

  這篇文章主要講解下目前市面上比較新穎的特效直播,比如Faceu激萌等軟體的具體實現原理。



  如上圖所示,要實現特效直播至少需要實現這五個模組:相機採集、裝置運動方向檢測、人臉識別功能、本地預覽繪製以及編碼傳送。下面我們就逐個介紹下在Android端這個五個功能的大致實現原理。

  Camera採集

  想正常的看到攝像頭所採集的影象?只需要給Camera指定一個SurfaceView,具體來講是給相機設定一個畫布(SurfaceHolder)即通過Camera setPreviewDisplay方法,就可以了。這是由於Android的系統API對Camera進行了很好的封裝,使得我們可以非常快速的開發一個相機應用。


  但在特效直播中,我們需要對相機採集的影象進行處理,比如美顏或是貼上兔耳朵、牙齒等道具圖片。然後將處理過的影象顯示到螢幕上實時進行觀看。這時候讓系統幫我們繪製相機影象顯然就不合適了。

  SurfaceTexture



  這是Android API文件中關於SurfaceTexture的描述,從中我們可以看到SurfaceTexture可以代替SurfaceHolder來接受Camera採集的資料流同時不顯示到螢幕上。由此可見要實現特效直播首先需要將Camera採集的SurfaceHolder模式替換為SurfaceTexture模式。

  方向檢測

  在處理相機預覽時,Android系統為了保證使用者無論怎麼旋轉手機都能看到“正確”的預覽畫面(這個“正確”是指顯示在UI預覽介面的畫面與你人眼看到的眼前的畫面是一致的),系統底層會根據當前手機螢幕的方向對影象Sensor採集到的資料進行了旋轉處理,然後才送給顯示系統進行顯示。因此在採用SurfaceHolder模式下由於系統底層幫我們進行了方向上的處理,因此我們看到的畫面都是正的。但在採用SurfaceTexture模式後,由於系統直接向資料流送給了SurfaceTexture,因此在我們自己繪製以及人臉識別時就需要知道裝置的預覽方向,來保證繪製的角度正確以及人臉識別的成功率。


  在Android上我們可以通過OrientationEventListener來實現實時螢幕方向的監聽。



  具體的實現程式碼也很簡單,只需要實現OrientationEventListener中的onOrientationChanged方法就可以實時獲取到螢幕方向了。





  人臉識別

  Android系統本身就具有人臉識別功能,其中包括靜態人臉檢測和動態人臉檢測。所謂的靜態檢測即通過android.media.FaceDetector 這個類對單張圖片進行識別,然後識別出圖片中的人臉位置。



  在Android 4.0以前需要實現相機實時的人臉識別,只能通過獲取Camera採集回撥onPreviewFrame將Camera採集的幀資料轉化為bitmap送給FaceDetector進行檢測。網上有人也實現過這種方式。








  但這種方式實現效率太低,在直播這種場景下基本沒人這麼做。

  在Android 4.0之後,Camera新增了FaceDetectionListener介面



  我們可以通過在開啟Camera時設定FaceDetectionListener,來讓系統幫我們進行實時的相機人臉檢測。FaceDetectionListener可以檢測出人臉的大小框以及眼睛和嘴巴的位置。這裡有一個需要注意的是檢測到人臉rect預設是以預覽介面為座標系,這個座標系是經過變換的,中心點為(0, 0),左上頂點座標是(-1000, -1000),右下頂點是(1000, 1000).也就是說不管預覽預覽Surfaceview多大,檢測出來的rect的座標始終對應的是在這個變換座標系。而Android裡預設的view的座標系是,左上頂點為(0, 0),橫為x軸,豎為y軸。這就需要把rect座標變換下。



  基本上簡單的需求FaceDetectionListener就可以滿足了。但複雜的需求,如檢測鼻子,眉毛以及平臺通過性和對效能要求極高的場景下FaceDetectionListener也有點力不從心了。

  目前市面上很多的人臉識別都是基於開源專案OpenCV實現的,OpenCV也有Android平臺的實現。對於如何在Android上整合OpenCV的方式,有興趣的同學可以參考下

  OpenGL繪製與編碼

  SurfaceTexture是GPU紋理,天生與openGL親近。因此Camera採用SurfaceTexture方式基本上都是通過GLSurfaceView的Render生成SurfaceTexture紋理然後繫結Camera進行繪製,同時可以將SurfaceTexture上Camera採集的資料直接進行硬體編碼,提供編碼效率。

  SurfaceTexture方式由於需要OpenGL基礎以及硬體編碼相關知識,因此本文中就暫不介紹了,等先普及過OpenGL相關知識後再進行講解。