1. 程式人生 > >Android進階:自定義視頻播放器開發(上)

Android進階:自定義視頻播放器開發(上)

對象 自定義 wms 成本 重點 一樣在 review 直接 除了

隨著快手,抖音,西瓜視頻等視頻APP的崛起,視頻播放已經成為主流,此時作為Android研發的你,想要提高自己的能力還不知道怎麽開發視頻播放器怎麽行?所以今天就帶著大家一起開發一個簡易播放器:SmallVideoPlayer

需求分析

我們觀察一個視頻播放器,可以看到視頻播放器除了正在播放的視頻還有很多控件,比如播放按鈕,暫停按鈕,播放進度條,播放計時器等。
這麽多控件顯然無法播放視頻,但是他們都在控制視頻的播放。由此可見視頻播放器可以分為兩層,一層為視頻播放器控制層,一層為真正的視頻播放層。

所以實現視頻播放器的時候就可以分為上層控制層,和底層播放層兩層來實現。

視頻播放器播放層實現

技術沈澱

視頻播放內核

我們知道自己開發視頻播放器內核肯定是不現實的,這需要一定的技術成本,單個人很難達到,所以我們就選擇一個最受歡迎的開源的內核即可:bilibili開源的視頻播放器:ijkplayer

視頻播放器

視頻播放這塊需要給大家普及兩個知識點:

SurfaceView  

  先來介紹一下大部分軟件如何解析一段視頻流。首先它需要先確定視頻的格式,這個和解碼相關,不同的格式視頻編碼不同,不是這裏的重點。知道了視頻的編碼格式後,再通過編碼格式進行解碼,最後得到一幀一幀的圖像,並把這些圖像快速的顯示在界面上,即為播放一段視頻。SurfaceView在Android中就是完成這個功能的。

  既然SurfaceView是配合MediaPlayer使用的,MediaPlayer也提供了相應的方法設置SurfaceView顯示圖片,只需要為MediaPlayer指定SurfaceView顯示圖像即可。它的完整API如下:

void setDisplay(SurfaceHolder sh);

  它需要傳遞一個SurfaceHolder對象,SurfaceHolder可以理解為SurfaceView裝載需要顯示的一幀幀圖像的容器,它可以通過SurfaceHolder.getHolder()方法獲得。

  使用MediaPlayer配合SurfaceView播放視頻的步驟與播放使用MediaPlayer播放MP3大體一致,只需要額外設置顯示的SurfaceView即可。

SurfaceView雙緩沖

  上面有提到,SurfaceView和大部分視頻應用一樣,把視頻流解析成一幀幀的圖像進行顯示,但是如果把這個解析的過程放到一個線程中完成,可能在上一幀圖像已經顯示過後,下一幀圖像還沒有來得及解析,這樣會導致畫面的不流暢或者聲音和視頻不同步的問題。所以SurfaceView和大部分視頻應用一樣,通過雙緩沖的機制來顯示幀圖像。那麽什麽是雙緩沖呢?雙緩沖可以理解為有兩個線程輪番去解析視頻流的幀圖像,當一個線程解析完幀圖像後,把圖像渲染到界面中,同時另一線程開始解析下一幀圖像,使得兩個線程輪番配合去解析視頻流,以達到流暢播放的效果。

  下圖為演示了雙緩沖的過程,線程A和線程B配合解析渲染視頻流的幀圖像:
  技術分享圖片

SurfaceHolder

  SurfaceView內部實現了雙緩沖的機制,但是實現這個功能是非常消耗系統內存的。因為移動設備的局限性,Android在設計的時候規定,SurfaceView如果為用戶可見的時候,創建SurfaceView的SurfaceHolder用於顯示視頻流解析的幀圖片,如果發現SurfaceView變為用戶不可見的時候,則立即銷毀SurfaceView的SurfaceHolder,以達到節約系統資源的目的。

  如果開發人員不對SurfaceHolder進行維護,會出現最小化程序後,再打開應用的時候,視頻的聲音在繼續播放,但是不顯示畫面了的情況,這就是因為當SurfaceView不被用戶可見的時候,之前的SurfaceHolder已經被銷毀了,再次進入的時候,界面上的SurfaceHolder已經是新的SurfaceHolder了。所以SurfaceHolder需要我們開發人員去編碼維護,維護SurfaceHolder需要用到它的一個回調,SurfaceHolder.Callback(),它需要實現三個如下三個方法:

  • void surfaceDestroyed(SurfaceHolder holder):當SurfaceHolder被銷毀的時候回調。
  • void surfaceCreated(SurfaceHolder holder):當SurfaceHolder被創建的時候回調。
  • void surfaceChange(SurfaceHolder holder):當SurfaceHolder的尺寸發生變化的時候被回調。

在應用中分別為SurfaceHolder實現了這三個方法,先進入應用,SurfaceHolder被創建,創建好之後會改變SurfaceHolder的大小,然後按Home鍵回退到桌面銷毀SurfaceHolder,最後再進入應用,重新創建SurfaceHolder並改變其大小。

SurfaceView的優點:

如上面所說,SurfaceView可以在一個獨立的線程中進行繪制,不會影響主線程,並且使用雙緩沖機制,播放視頻時畫面更流暢。

SurfaceView的缺陷:

因為這個Surface不在View hierachy中,它的顯示也不受View的屬性控制,所以不能進行平移,縮放等變換,也不能放在其它ViewGroup中,一些View中的特性也無法使用。

TextureView

與SurfaceView一樣繼承View,它可以將內容流直接投影到View中,可以用於實現Live preview等功能。

和SurfaceView不同的是,它不會在WMS中單獨創建窗口,而是作為View hierachy中的一個普通View,因此可以和其它普通View一樣進行移動,旋轉,縮放,動畫等變化。

值得註意的是TextureView必須在硬件加速的窗口中。它顯示的內容流數據可以來自App進程或是遠端進程。從類圖中可以看到,TextureView繼承自View,它與其它的View一樣在View hierachy中管理與繪制。

SurfaceTexture

TextureView重載了draw()方法,其中主要SurfaceTexture中收到的圖像數據作為紋理更新到對應的HardwareLayer中。SurfaceTexture.OnFrameAvailableListener用於通知TextureView內容流有新圖像到來。SurfaceTextureListener接口用於讓TextureView的使用者知道SurfaceTexture已準備好,這樣就可以把SurfaceTexture交給相應的內容源。

Surface

Surface為BufferQueue的Producer接口實現類,使生產者可以通過它的軟件或硬件渲染接口為SurfaceTexture內部的BufferQueue提供graphic buffer。

TextureView優點

支持移動、旋轉、縮放等動畫,支持截圖

TextureView缺點

必須在硬件加速的窗口中使用,占用內存比SurfaceView高,在5.0以前在主線程渲染,5.0以後有單獨的渲染線程。

Android進階:自定義視頻播放器開發(上)