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

隨着快手,抖音,西瓜視頻等視頻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配合解析渲染視頻流的幀圖像:
Android進階:自定義視頻播放器開發(上)

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以後有單獨的渲染線程。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章