您好,登錄后才能下訂單哦!
本篇文章為大家展示了Android視頻開發(fā)中如何進行MP4文件的解析,內容簡明扼要并且容易理解,絕對能使你眼前一亮,通過這篇文章的詳細介紹希望你能有所收獲。
我會主要介紹容器 (container format file) 格式文件的細節(jié),以最常見的 MP4 文件入手。然后會簡短的介紹一個標準的播放器的啟動,解析,播放流程。本篇還是以基礎知識為主,雖然很枯燥,但是對視頻開發(fā)的學習有非常大的好處,我自己個人的感受就是,如果在很多專有名字,概念都不熟悉的情況下,想要去閱讀播放器源碼會是相當困難的事情。比如 Exoplayer,谷歌的分包策略就是根據(jù)播放器的組件來分包。如果不熟悉播放器的基礎構建的話,連哪個部分的代碼在哪個包都不知道。希望大家如果真的想進階的話還是耐心的理解好每個基礎概念。
在上期我們大概介紹了 Mp4 文件的結構
但是這樣抽象的介紹可能還是比較難理解,我們深入一些。
通俗的說,MP4 其實是一種格式的規(guī)范,這個規(guī)范是被 ISO 機構認證的,也就是說,只要你通過 Codec 生成了一個 mp4 文件,那么這個文件的格式必須是按照 ISO 機構的規(guī)矩來。。。。既然是規(guī)范,那么我們看看到底 ISO 對 mp4 做了什么規(guī)范:
請大家打開鏈接->ISO 的 mp4 文件規(guī)范 [1]
大家可能會有點懵逼,看不懂。其實這個規(guī)范很好理解,它定義了一個 MP4 文件里面,哪些數(shù)據(jù)應該放在什么位置 (以字節(jié)為單位),哪些數(shù)據(jù)的長度是多少。我截取了一段:
大家看,上面這一段規(guī)范定義了 ftyp 這個頭文件 header 所在的位置和長度 (以字節(jié)為單位)。至于這些頭文件是有什么用,我在上一篇文章大概提到過,他們屬于 meta data 的一部分。在本章我會更詳細的介紹。
所以說,任何容器,包括 mp4 都是類似的結構化文件,只不過不同的格式文件 ISO 對其有嚴格的要求,數(shù)據(jù)的擺放順序,排列等等不同而已。有興趣的同學可以對比一下 rmvb,mp4,mkv 這些格式的要求有什么不同,優(yōu)劣勢各是什么。
關于 mp4 文件的頭文件格式(meta data),蘋果官網(wǎng)對其進行了詳細的描述(這個介紹是基于 QuickTime 播放器支持的 mp4 文件來介紹的,quciktime 播放器對 mp4 的要求有些許不同,但是差別不大,我們可以忽略):
Movie Atom[2]
我們不追究太多細節(jié),有興趣的同學可以自己查看,我們專注于一些基礎的信息。
首先,在 Meta Data 里面,每一個 Header,頭文件,我們都叫他們 Atom Header(不知道咋翻譯)。Atom Header 分為 Leaf Atom 和 Container Atom。前者代表一個連接著字符串信息的頭文件,后者是一個包含了若干個子 Atom 的頭文件,他們互相之間是有層級關系的 (參考上圖)。每次播放器獲取了 movie atom 之后 (moov),會根據(jù)層級關系,向下,或者向下讀取相關的其他信息。每一個頭文件都會對它的子頭文件保存位置的引用,所以只要根據(jù) mp4 文件的規(guī)范獲取了最頂級的頭文件 moov,就可以順勢往下讀取其他頭文件了。
我們來看看 mp4 的頭文件結構
看起來很復雜,但是對于一個播放器來說,很多信息都不是必須。我們需要知道的最重要的信息是采樣索引表(Sample Table Atoms).對應圖中“**stbl **”這個 atom header。這個索引表保存了 mp4 文件所有的采樣 (sample) 與視頻時間的對應關系 (一般以微秒為單位),還有包括每個采樣的大小,在 mp4 文件中的起始位置 (以自己為單位)。
那么既然我們已經(jīng)知道一個容器文件的格式規(guī)范了,播放器就可以通過解析容器的頭文件來控制播放 (playback) 了。
通常播放器由三個部分構成
讀取器 (Extractor) 渲染器 (TrackRenderer) 加載控制器 (Load Controller) 數(shù)據(jù)源 (Source)
讀取器負責從 source 文件讀取數(shù)據(jù),加載控制器負責控制讀取數(shù)據(jù)的策略 (比如說在線視頻播放的時候緩沖策略),渲染器負責接收讀取器讀取的數(shù)據(jù),并渲染到屏幕上。
在播放器可以把數(shù)據(jù)提交給渲染器之前,播放器需要把必需的頭文件全部解析并存入內存,比如之前說的采樣索引表。一般播放器在解析完畢后,會構建三個個表,一個存放時間對應采樣索引,一個存放采樣索引對應在 mp4 文件中的起始位置 (以字節(jié)為單位),一個存放采樣索引對應大小 (以字節(jié)為單位)。以下圖為例
假設播放器需要從第 1 微秒開始播放,那么需要把第 1 微秒的數(shù)據(jù)放入渲染器。所以會查找下面這三個表。
通過表 1,我們知道該微秒對應第 1 個采樣(sample),從第一個和第二個表我們知道,第 1 個采樣的數(shù)據(jù)范圍 (在 mp4 文件內) 是從第 0 字節(jié)到 300(0+300)字節(jié),那么播放器就會去讀取這個范圍的數(shù)據(jù)并且放入渲染器中進行渲染。
同時,加載器會基于當前已經(jīng)緩存的數(shù)據(jù),決定是否還需要不停的讀取數(shù)據(jù)進入內存。一般來說每個播放器都有默認的緩存值,也會有一個基準線,只有當緩存足夠數(shù)據(jù)才能放進渲染器進行渲染。
最后同理,當我們拖動滑動控制器 (SeekBar) 想快進的時候,我們和第一步一樣,通過我們想滑動的時間獲取采樣的索引,再重新開始讀取數(shù)據(jù)。
綜上所述,播放器在正式播放視頻文件之前,必須要把頭文件全部讀取并解析 (這會是一段非常耗時的程序),這也是在線視頻播放的等待時間的瓶頸。在接下來的章節(jié)我會介紹自適應視頻播放 (Adaptive Streaming),這個技術的發(fā)明使得了分段式 mp4 文件 (Fragmented Mp4) 技術得以誕生,大大的減少了在線視頻播放的等待時間。
在線視頻的播放其實和播放本地視頻的局別就是 Extractor 讀取的 Source,數(shù)據(jù)源不一樣,在線播放需要下載數(shù)據(jù)到內存,再交由 Extractor 讀取分析。但是既然是在線視頻播放,我們肯定不能把整個容器文件下載到內存或者硬盤再開始解析播放。我們希望能控制下載的進度,比如我當前在看第 10s 的視頻內容,所以我只想緩存/下載視頻內容到第 20s 的位置。
我們俗稱的漸進式下載 (Progressive Downloading) 就解決了這一難題。
說的好像是很嚇人的黑科技?。。。?!
其實就是 HTTP1.1 協(xié)議支持的分段式下載而已。。。。。
在 HTTP 請求里面假如一個叫 RANGE 的 header,放入起始字節(jié)和結束字節(jié),就可以只下載對應部分的數(shù)據(jù),這一 header 的支持也是各種下載軟件實現(xiàn)斷點下載的基礎。每次斷網(wǎng)的時候記錄下來已經(jīng)下載的數(shù)據(jù)的字節(jié)數(shù),下次再下載的時候從字節(jié)數(shù)+1 處重新下載并且寫入原有文件就可以了。
上述內容就是Android視頻開發(fā)中如何進行MP4文件的解析,你們學到知識或技能了嗎?如果還想學到更多技能或者豐富自己的知識儲備,歡迎關注億速云行業(yè)資訊頻道。
免責聲明:本站發(fā)布的內容(圖片、視頻和文字)以原創(chuàng)、轉載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權內容。