1. 程式人生 > >Android實現MP4邊下邊播(邊快取邊播放、線上播放)原理與程式碼

Android實現MP4邊下邊播(邊快取邊播放、線上播放)原理與程式碼

QQ群交流:425219113(計算機語言交流)

播放器Demo預覽圖

邊下邊播方法初試

**剛開始實現這個的時候,我第一下想到的是:**先將MP4檔案單純的從位元組的層次分為若干個檔案,然後播放的時候,不斷從伺服器一邊下載,一邊追加到一個原始檔裡面,最後直接播放這個原始檔就可以了。如圖:
這裡寫圖片描述
這個方法到底可不可行呢?能否播放?如果遇到播放快於下載的情況,會不會出錯呢?
這個方法在一定的情況下是可行的,如果遇到播放錯誤,也只需要給VideoView設定錯誤監聽器setOnErrorListener()就行。如果監聽到錯誤,就顯示載入框,然後繼續下載,下載完了再嘗試播放。
但後來我發現,並不是所有的MP4都支援這種做法,有的MP4這樣做依然是要等到全部下載完了才能播放的。

MP4結構分析 -怎麼才能邊下邊播##

先了解一下MP4的基本結構。
這裡寫圖片描述
簡要地說,MP4檔案主要由ftyp,mdat,moov這三部分組成。

  • ftyp 記錄了mp4格式,編碼格式之類的一些基本資訊
  • mdat記錄了視訊媒體資訊(mdat的體積往往非常的大,幾乎等於MP4總大小)
  • moov是如同檢索表一樣的存在,裡面記錄了每一幀對應的資料在哪裡等等

MP4播放流程大概是

  1. 讀取ftype部分決定解碼方式。
  2. 尋找並讀取moov部分,獲取視訊總時長等資訊。
  3. 根據moov的檢索資訊到mdat裡面讀取相應的媒體資訊,進而播放。

所以,想要播放MP4,一定要讓播放器先讀取到ftyp與moov才行的。但根據我最開始的做法,如果MP4的moov在mdat的前面的話,正常分割,追加,自然可以做到邊下邊播。但是,如果moov在mdat後面的話,就需要等下載完ftyp-mdat-moov(等於下載整個MP4)才能正常播放了。

重要的是,有的甚至是大部分MP4是如上圖的結構的,moov在mdat的後面。

邊下邊播方法再試

那面對moov在mdat後面的MP4,我們應該如何處理呢?怎麼才能讓播放器先讀取到ftyp與moov呢

然後,我想著單純在位元組層次,將moov整個搬到mdat的前面,ftyp的後面。但失敗了,大概是因為moov裡面已經寫死了對應mdat的地址檢索表,所以我們這樣移動定然改變了mdat的原本位置,而導致無法檢索資料。如下圖:
這裡寫圖片描述

這裡注意,播放器播放視訊的時候,大概是不在乎mdat的資料是否正確的,而是哪裡正確則播放到哪裡,直到錯誤報錯。

邊下邊播方法成功

所以我後來受到網上的啟示。先不管mdat這一部分,只下載ftyp與moov部分,並按照其原本的位置放置,而將mdat這一部分架空。最後和方法一同樣,不斷下載mdat的分段檔案並追加到指定位置。(注意,可能有這三者以外的其他資料,所以我將視訊重新分為三部分:head,mDat,foot,head是mDat的前面部分,foot是mDat的後面部分)


分割上傳視訊

下載播放視訊

邊下邊播方法改良

上面已經是很久之前的做法了,從資料結構上來說,分的並不是很合理。現在我改變了一下這裡的邏輯:將head、foot、自定義資料、mDat大小這些資訊在切割的時候就包含子自定義檔案tjbb裡面,然後在下載回來的時候,先下載tjbb檔案就可以瞭解析所有必要資訊了
這裡寫圖片描述

到了這裡,就能實現邊下載邊播放了。但要怎麼樣才能知道ftyp,mdat,moov的位置呢。
這裡就要再瞭解一下mp4結構了。

MP4由多個Box組成,Box可以理解為一種結構規範,另外Box可以層層巢狀,如Moov裡面又有很多個Box。

下面所討論的Box都具備以下特性:以8個位元組開頭,接著就是Box的資料。該8個位元組,前四個位元組包含了整一個Box的大小資訊,後四個位元組包含了該Box的型別(也可以說是名字)。有一種叫footBox不太一樣。

這裡寫圖片描述

我們可以通過將位元組轉化為字串的形式,獲取mdat字元的位置,然後減去4個位元組(儲存大小資訊的部分),就能得到mdat這個box的起始位置了,然後再讀取其大小資訊,獲取mdat的總大小,就能獲取到mdat的結束位置。

特別注意,這裡我們不是講mp4分為type,mdat與moov了,而是分為head,mdat,foot,因為其中間可能還有一些別的Box,而這種分法,還有可能moov在mdat前面的,而導致沒有foot,這也是需要注意的。

另外,查詢mdat位置的時候,不要一次性將mp4讀取到手機記憶體啊,會崩潰的,需要用到緩衝池,我倒是寫了不少演算法,不過也不是很齊全,日後再發了。

到此,這就是我實現mp4邊下邊播的方法了,挺有意思的不是。如果有問題可以評論留言。