封装格式分析-MP4
聲明:MP4 的封裝格式是比較復(fù)雜的,本文不會把 MP4 的各個字段,各種場景用法都羅列出來,那樣會形成一個手冊。
文本主要講解 MP4 這種封裝格式在音視頻開發(fā)中比較常用的字段,還有一些關(guān)鍵的知識點。讓初學(xué)者掌握 MP4 的一些基本概念,然后學(xué)會看MP4標準文檔深入了解。
資源下載:
MP4 格式 是一個 box 的格式,box 容器 套 box 子容器,box 子容器 再套 box 子容器。看起來跟 json 很像。
下圖 是 a.mp4 的 box 結(jié)構(gòu)。使用的軟件是 Mp4Explorer。
解析MP4 格式是這樣的,先讀4個字節(jié)。前4個字節(jié)是 size,代表這個box 有多大。再讀 4 字節(jié),后4字節(jié) 是 type,表明這個 box 是個什么box
請看 a.mp4 文件 的 16進制的表示,推薦使用 notepad ++ 32 位 hexeditor 插件查看,只有32位的才有這個插件。
如上圖所示,用不同顏色畫出了 3個 box。
由第一張圖可以知道, mdata 這個box 之后就是 moov box,如何找到 moov box 的位置呢?
如上可知,mdata box 的起始位置是 00000028 ,mdata 這個box 有 0b5c63 這么大,所以 moov box 的位置等于 0b5c63 + 28 = 000b5c8b。
我們用 notepad ++ 跳轉(zhuǎn)到 000b5c8b 看看能不能找到 moov 這個字符。
000b5c8b 的位置附近果然能看到 moov 這個字符串,moov 的ASII碼是 6d 6f 6f 76。前面的4個字節(jié)數(shù)據(jù) 00 00 26 39 是 moov box的大小。
分析到這里, mp4 的box結(jié)構(gòu)就比較清晰了,很簡單,前面4個字節(jié)是size,后4字節(jié)是 type,后面的數(shù)據(jù)就是這個type類型的box具體的數(shù)據(jù)。
不過 size 有兩個特殊值 0 和 1
- 當(dāng)size等于0時,代表這個Box是文件的最后一個Box。
- 當(dāng)size等于1時,說明Box長度需要更多的位來描述,在后面會定義一個64位的 largesize 用來描述Box的長度。
如圖:
下面繼續(xù)講解 a.mp4 里面 的 moov box。
MP4 最重要的就是 stbl 里面的子 box,眾所周知,MP4 比 FLV 的優(yōu)勢就是可以快速的seek,這是因為MP4 里面有一個數(shù)據(jù)索引表,還有關(guān)鍵幀表。
這些表都在 stbl box 里面
1,stts,全稱 Decoding Time to Sample Box 。
2,ctts,全稱 Composition Time to Sample Box。 時間補償,用來計算出 pts,因為mp4 是按 解碼順序存儲,packet 按 dts 遞增,所以需要 ctts 表計算出packet 的 pts。只有視頻有,音頻沒有。因為音頻 pts dts 是一樣的。
3,stss,全稱 Sync Sample Box,同步 采樣表,表明第幾幀是關(guān)鍵幀,關(guān)鍵幀可以用來同步,所以叫 Sync 沒毛病。視頻流才有這個 box,音頻流沒有。
下面是 stss 這個box 的截圖,可以看到 第 1 幀,第 35 幀,第 152 幀 是關(guān)鍵幀。
4,stsz,全稱 Sample Size Boxes,表明視頻幀或者音頻幀大小,FFmpeg 里面的AVPacket 的size 數(shù)據(jù)大小,就是從這個box中來的。
可以看到,音視頻格式多種多種,flv 肯定沒有stsz這個表,但是 FFmpeg 無論是解析flv,還是解析mp4,出來的 AVpacket 的size還是可以用的。
所以FFmpeg 實際上就是對紛繁復(fù)雜的各種格式進行了封裝,讓編程更通用一點。
下面是 stsz 這個box 的截圖,可以看到 第一幀是比較大的,第一幀是 31945 個字節(jié),因為他是關(guān)鍵幀。
5,stsc,全稱 Sample To Chunk Box。mp4 會把一個或多個 sample 放到一個chunk 里面。就是一個 chunk可能會有多個視頻幀,也可能只有一個,如圖:
上圖 是視頻流的 stsc box 。里面有兩行數(shù)據(jù),第一個chunk里面有2個sample,第二個chunk里面有 1個sample。這個并不是說,這個視頻流只有3個sample,也就是只有3幀,不可能的,而是第三,第四行省略了,也就是說,第三跟第四,等等,后面的chunk 里面都只有1個sample,跟第二個chunk一樣。本視頻流有239個chunk。因為本視頻流一共240幀,第一個chunk里面有2幀,后面的都是1幀,所以計算出來只有239個chunk。
所以他這個 First chunk 在列表是代表 start 開始的chunk,如果有下一行,下一行的值就是end 結(jié)束。。
chunk 跟 sample 這個概念比較重要,MP4 索引定位找到某一幀,就是先找到chunk,再找到sample。
6,stco,全稱 Chunk Offset Box,chunk的位置表。
從上圖可以看出,第一個chunk 在a.mp4文件的 48 的位置,第一個chunk里面有兩幀數(shù)據(jù)。我們用 notepad ++ 跳到 48 的地方,看看具體內(nèi)容。
48 轉(zhuǎn)成 16進制是 30。如下圖:
從上圖可以看到,00000030 的地方,前面緊緊挨著 mdat,mdat 字符后面就是具體的編碼后的數(shù)據(jù)。
通過上面這些索引數(shù)據(jù),我們找到了第一幀視頻數(shù)據(jù)的位置,我們現(xiàn)在來驗證一下對不對,打開 之前搭建好的 Qt creator ffplay的調(diào)試環(huán)境,斷點查看 第一個 packet的數(shù)據(jù)。
我在 av_read_frame() 的位置打了個斷點,可以看到讀出來的第一個 AVPacket 的 pos 值的確是 48,size 等于 31945 也能跟 stsz box表對應(yīng)上。
再來查看一下第一個 AVPacket 的data 里面的數(shù)據(jù),如下圖。
可以看到 FFplay 里面讀出來的 AVPakcet 的data指針的數(shù)據(jù)跟我們在notepad ++ 48位置看到的數(shù)據(jù)是完全一樣的。
第一幀視頻的數(shù)據(jù)位置找到了,那第二幀視頻數(shù)據(jù)怎么找呢?stsc 表里面說明,第一個chunk有兩針數(shù)據(jù),所以第二個視頻幀是緊挨著第一幀的,所以第一幀的位置 48 加上第一幀大小 31945 等于 31993,換算成 16 進制就是 7cf9,所以第二幀數(shù)據(jù) 在文件的 00007cf9 的位置。如圖:
大家可以自行用qt 打印第二個視頻幀的AVPacket的data數(shù)據(jù)驗證位置對不對。
stco (chunk索引表),stsc(sample chunk表),stsz (sample 大小表)。簡單的通過這3個表找到對應(yīng)幀的位置已經(jīng)講解完了。下面來講解 按時間 seek,mp4可以怎么實現(xiàn),例如 要拖動視頻到 第2秒的時候播放,因為 a.mp4 是24幀率的視頻,所以第二秒就是 1* 24 = 24,也就是從24幀開始播放,那24幀的數(shù)據(jù)在哪里呢?因為 stsc 表里面第一個chunk占了 2個幀,后面的chunk都只占一個幀,所以第24幀在第23個chunk里面,所以往 stco表找,找到 第23個chunk的偏移位置,也就是 64626 。如圖:
本文主要只講了 stbl,mdat 這兩個box,因為MP4 最大的區(qū)別就是他有很多索引數(shù)據(jù),例如關(guān)鍵幀索引,普通幀的位置索引等等。
其他的 trak ,tkhd,mdhd,等等,可以自行查看 MP4 的標準進行了解。
音視頻格式紛繁復(fù)雜,下面介紹一種看 標準文檔的方法,例如 mp4 的標準?ISO- 14496Part12?。
例如 之前介紹的 free box 不知道是做什么?我們可以打開 標準文件 w15177_14496-12_5th.-restyle-R5.doc ,然后搜索 free 這個關(guān)鍵詞,就能看到以下說明。
沒錯,free box 的全稱是 Free Space Box。想知道某些 box 的定義,直接在標準文件里面搜全稱 等關(guān)鍵詞即可。
看標準文件的目錄,也能直接看出各種 box 的定義跟作用。
我個人建議可以抽時間把 257 頁的mp4 標準耐心讀一遍,這樣就會對 mp4 格式非常熟悉了。257 頁其實不多。
網(wǎng)上 mp4 的資料比較零碎,包括本文也是只講了一小部分的 MP4 內(nèi)容。完整的內(nèi)容其實就在標準文件里面,所以學(xué)會看標準文件是非常重要的。
擴展知識:
正常情況下 ffmpeg 生成 moov 是在 mdat 寫完成之后再寫入,可以通過參數(shù) faststart 將 moov 容器移動至 mdat 的前面,將 moov 提前 可以 ?持http邊下載邊播放,下面參考一個例子:
./ffmpeg?-i input.flv?-c copy?-f mp4?-movflags faststart output.mp4
相關(guān)閱讀:
由于筆者的水平有限, 加之編寫的同時還要參與開發(fā)工作,文中難免會出現(xiàn)一些錯誤或者不準確的地方,懇請讀者批評指正。如果讀者有任何寶貴意見,可以加我微信 Loken1。
推薦一個零聲學(xué)院免費公開課程,個人覺得老師講得不錯,分享給大家:
Linux,Nginx,ZeroMQ,MySQL,Redis,fastdfs,MongoDB,ZK,流媒體,CDN,P2P,K8S,Docker,TCP/IP,協(xié)程,DPDK等技術(shù)內(nèi)容,立即學(xué)習(xí)
總結(jié)
以上是生活随笔為你收集整理的封装格式分析-MP4的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Echarts 温度计
- 下一篇: 温度矩阵转热图