Android實現MP4邊下邊播(邊緩存邊播放、在線播放)原理與代碼

對於這套方法我已經封裝成庫,可以直接下載使用。
MP4Info1.0.2.jar下載
配套的視頻播放器終於出來了,可自定義性很大。
MP4Player1.0.1.jarDemo下載
另外寫了一個查看MP4結構的軟件,安卓版的
(下載安卓版MP4Info查看MP4結構)
碼雲項目
MP4Info-碼雲開源

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

播放器Demo預覽圖


邊下邊播方法初試

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


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

先了解一下MP4的基本結構。(可以用百度手機助手下載MP4Info查看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邊下邊播的方法了,挺有意思的不是。如果有問題可以評論留言。

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