隨着快手,抖音,西瓜視頻等視頻APP的崛起,視頻播放已經成爲主流,此時做爲Android研發的你,想要提升本身的能力還不知道怎麼開發視頻播放器怎麼行?因此今天就帶着你們一塊兒開發一個簡易播放器:SmallVideoPlayerbash
咱們觀察一個視頻播放器,能夠看到視頻播放器除了正在播放的視頻還有不少控件,好比播放按鈕,暫停按鈕,播放進度條,播放計時器等。 這麼多控件顯然沒法播放視頻,可是他們都在控制視頻的播放。因而可知視頻播放器能夠分爲兩層,一層爲視頻播放器控制層,一層爲真正的視頻播放層。ide
因此實現視頻播放器的時候就能夠分爲上層控制層,和底層播放層兩層來實現。動畫
咱們知道本身開發視頻播放器內核確定是不現實的,這須要必定的技術成本,單我的很難達到,因此咱們就選擇一個最受歡迎的開源的內核便可:bilibili開源的視頻播放器:ijkplayerui
視頻播放這塊須要給你們普及兩個知識點:編碼
先來介紹一下大部分軟件如何解析一段視頻流。首先它須要先肯定視頻的格式,這個和解碼相關,不一樣的格式視頻編碼不一樣,不是這裏的重點。知道了視頻的編碼格式後,再經過編碼格式進行解碼,最後獲得一幀一幀的圖像,並把這些圖像快速的顯示在界面上,即爲播放一段視頻。SurfaceView在Android中就是完成這個功能的。spa
既然SurfaceView是配合MediaPlayer使用的,MediaPlayer也提供了相應的方法設置SurfaceView顯示圖片,只須要爲MediaPlayer指定SurfaceView顯示圖像便可。它的完整API以下:線程
void setDisplay(SurfaceHolder sh);
複製代碼
它須要傳遞一個SurfaceHolder對象,SurfaceHolder能夠理解爲SurfaceView裝載須要顯示的一幀幀圖像的容器,它能夠經過SurfaceHolder.getHolder()方法得到。設計
使用MediaPlayer配合SurfaceView播放視頻的步驟與播放使用MediaPlayer播放MP3大致一致,只須要額外設置顯示的SurfaceView便可。code
上面有提到,SurfaceView和大部分視頻應用同樣,把視頻流解析成一幀幀的圖像進行顯示,可是若是把這個解析的過程放到一個線程中完成,可能在上一幀圖像已經顯示事後,下一幀圖像尚未來得及解析,這樣會致使畫面的不流暢或者聲音和視頻不一樣步的問題。因此SurfaceView和大部分視頻應用同樣,經過雙緩衝的機制來顯示幀圖像。那麼什麼是雙緩衝呢?雙緩衝能夠理解爲有兩個線程輪番去解析視頻流的幀圖像,當一個線程解析完幀圖像後,把圖像渲染到界面中,同時另外一線程開始解析下一幀圖像,使得兩個線程輪番配合去解析視頻流,以達到流暢播放的效果。cdn
下圖爲演示了雙緩衝的過程,線程A和線程B配合解析渲染視頻流的幀圖像:
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能夠在一個獨立的線程中進行繪製,不會影響主線程,而且使用雙緩衝機制,播放視頻時畫面更流暢。
由於這個Surface不在View hierachy中,它的顯示也不受View的屬性控制,因此不能進行平移,縮放等變換,也不能放在其它ViewGroup中,一些View中的特性也沒法使用。
與SurfaceView同樣繼承View,它能夠將內容流直接投影到View中,能夠用於實現Live preview等功能。
和SurfaceView不一樣的是,它不會在WMS中單首創建窗口,而是做爲View hierachy中的一個普通View,所以能夠和其它普通View同樣進行移動,旋轉,縮放,動畫等變化。
值得注意的是TextureView必須在硬件加速的窗口中。它顯示的內容流數據能夠來自App進程或是遠端進程。從類圖中能夠看到,TextureView繼承自View,它與其它的View同樣在View hierachy中管理與繪製。
TextureView重載了draw()方法,其中主要SurfaceTexture中收到的圖像數據做爲紋理更新到對應的HardwareLayer中。SurfaceTexture.OnFrameAvailableListener用於通知TextureView內容流有新圖像到來。SurfaceTextureListener接口用於讓TextureView的使用者知道SurfaceTexture已準備好,這樣就能夠把SurfaceTexture交給相應的內容源。
Surface爲BufferQueue的Producer接口實現類,使生產者能夠經過它的軟件或硬件渲染接口爲SurfaceTexture內部的BufferQueue提供graphic buffer。
支持移動、旋轉、縮放等動畫,支持截圖
必須在硬件加速的窗口中使用,佔用內存比SurfaceView高,在5.0之前在主線程渲染,5.0之後有單獨的渲染線程。