mp4應該算是一種比較複雜的媒體格式了,起源於QuickTime。之前研究的時候就花了一番的功夫,尤爲是如何把它完美的融入到視頻點播應用中,更是費盡了心思,主要問題是處理mp4文件龐大的「媒體頭」。固然,流媒體點播也能夠採用flv格式來作,flv也能夠封裝H.264視頻數據的,不過Adobe卻不推薦這麼作,人家說畢竟mp4纔是H.264最佳的存儲格式嘛。html
這幾天整理並重構了一下mp4文件的解析 程序,融合了分解與合併的程序,之前是c語言寫的,應用在linux上運行的服務器程序上,如今改爲c++,方便我在其餘項目中使用它,至於用不用移植一 份c#的,暫時用不到,等有必要了再說吧。這篇文章先簡單介紹一下mp4文件的大致結構,以及它的分割算法,以後再寫文章介紹如何把mp4完美應用在點播 項目中。linux
1、MP4格式分析 c++
MP4(MPEG-4 Part 14)是一種常見的多媒體容器格式,它是在「ISO/IEC 14496-14」標準文件中定義的,屬於MPEG-4的一部分,是「ISO/IEC 14496-12(MPEG-4 Part 12 ISO base media file format)」標準中所定義的媒體格式的一種實現,後者定義了一種通用的媒體文件結構標準。MP4是一種描述較爲全面的容器格式,被認爲能夠在其中嵌入 任何形式的數據,各類編碼的視頻、音頻等都不在話下,不過咱們常見的大部分的MP4文件存放的AVC(H.264)或MPEG-4(Part 2)編碼的視頻和AAC編碼的音頻。MP4格式的官方文件後綴名是「.mp4」,還有其餘的以mp4爲基礎進行的擴展或者是縮水版本的格式,包括:M4V, 3GP, F4V等。算法
mp4是由一個個「box」組成的,大box中存放小box,一級嵌套一級來存放媒體信息。box的基本結構是:c#
其中,size指明瞭整個box所佔用的大小,包括header部分。若是box很大(例如存放具體視頻數據的mdat box),超過了uint32的最大數值,size就被設置爲1,並用接下來的8位uint64來存放大小。服務器
一個mp4文件有可能包含很是多的box,在很大程度上增長了解析的複雜性,這個網頁上http://mp4ra.org/atoms.html記錄了一些當前註冊過的box類型。看到這麼多box,若是要所有支持,一個個解析,怕是頭都要爆了。還好,大部分mp4文件沒有那麼多的box類型,下圖就是一個簡化了的,常見的mp4文件結構:ui
通常來講,解析媒體文件,最關心的部分是視頻文件的寬高、時長、碼率、編碼格式、幀列表、關鍵幀列表,以及所對應的時戳和在文件中的位置,這些 信息,在mp4中,是以特定的算法分開存放在stbl box下屬的幾個box中的,須要解析stbl下面全部的box,來還原媒體信息。下表是對於以上幾個重要的box存放信息的說明:編碼
看吧,要獲取到mp4文件的幀列表,還挺不容易的,須要一層層解析,而後綜合stts stsc stsz stss stco等這幾個box的信息,才能還原出幀列表,每一幀的時戳和偏移量。並且,你要照顧可能出現或者可能不出現的那些box。。。能夠看的出來,mp4 把幀sample進行了分組,也就是chunk,須要間接的經過chunk來描述幀,這樣作的理由是能夠壓縮存儲空間,縮小媒體信息所佔用的文件大小。這 裏面,stsc box的解析相對來講比較複雜,它用了一種巧妙的方式來講明sample和chunk的映射關係,特別介紹一下。atom
這是stsc box的結構,前幾項的意義就不解釋了,能夠看到stsc box裏每一個entry結構體都存有三項數據,它們的意思是:「從first_chunk這個chunk序號開始,每一個chunk都有samples_per_chunk個數的sample,並且每一個sample均可以經過sample_description_index這個索引,在stsd box中找到描述信息」。也就是說,每一個entry結構體描述的是一組chunk,它們有相同的特色,那就是每一個chunk包含samples_per_chunk個sample,好,那你要問,這組相同特色的chunk有多少個?請經過下一個entry結構體來推算,用下一個entry的first_chunk減去本次的first_chunk,就獲得了這組chunk的個數。最後一個entry結構體則代表從該first_chunk到最後一個chunk,每一個chunk都有sampls_per_chunk個sample。很拗口吧,不過,就是這個意思:)。因爲這種算法沒法得知文件全部chunk的個數,因此你必須藉助於stco或co64。直接上代碼可能會清楚些:spa
1. 首先直接分析entry
2. 而後,經過stco或co64獲知chunk總個數以後,開始還原映射表
讀出stsc以後,就能夠綜合stbl下的全部box,推算出視頻和音頻幀列表,時戳和偏移量等數據。下面截圖展現獲取到的關鍵幀列表:
有了關鍵幀列表以後,就能夠繼續咱們一下個題目,就是mp4文件的分割。實現mp4的分割,是把mp4應用到點播系統中最關鍵的技術環節,作不到這個,就沒法實現點播播放mp4影片的「拖動」。
2、MP4文件的分割算法
所謂「分割」,就是把大文件切成小文件,要實現mp4的分割,
第一點,上面已經介紹了,第二點,只須要遍歷關鍵幀列表,就能找到離你想要分割的時間段最接近的關鍵幀,第四點就是「copy-paste」的 工做,關鍵在於第三點。由於這一步涉及到stbl下的全部box,必須從新生成entrys,一樣的,其餘的box都還好,只須要保留關鍵幀所對應的 sample和chunk,其他的刪掉便可,只是stsc box的比較麻煩,提及來比較囉嗦,仍是直接看代碼吧:
修改完box以後,須要從新生成moov box,因爲moov box的大小以及時長等信息都發生了改變,因此須要box的大小作相應的修改,這點千萬不能忘記,不然播放器會解析錯誤。從新生成box以後,還要計算一 下分割後的數據的長度,因爲數據長度也發生了改變,因此修改mdat box的大小的同時,要同時修改stbl下全部box的chunk offset,切記!
如下是整個的邏輯過程: