[時間:2016-06] [狀態:Open]
學習多媒體容器格式的目的
主要是為了回答以下問題:
- 該容器中數據是如何組織的?
- 該容器包含哪些編碼格式的數據?這些數據是如何存儲的?
- 該容器包含哪些元數據信息?包含哪些節目信息?
- 對於支持多節目的容器格式,如何找到對應的音頻流、視頻流、字幕流?
- 如何確定該容器的節目播放時長?
- 如何從該容器中提取音頻、視頻、字幕數據,並交給解碼器解碼,有時間戳否?
- 該容器是否支持seek?有哪些輔助信息?
- 是否支持直接流化?
- 哪里可以找到該容器格式最標准的文檔資料?
- 有哪些可用的工具,方便分析容器格式異常或者錯誤?
1. MP4文件內部結構
MP4文件是有多個box嵌套構成的,所有數據都必須保存在box中,而且必須包含一個File Type box。
box的定義
其基本存儲結構box(或者atom),其定義如下:
==========
BoxHeader
----------
BoxData
==========
其中BoxHeader定義如下:
| Field name | Type | Size(bits) |
|---|---|---|
| box size | uint32 | 32 |
| box type | uint32 | 32 |
| largesize | uint64 | 0/64 |
| usertype | uint8[16] | 0/128 |
其中box size為1時,表示largesize域存在,size為0時,表示該box持續到文件結尾;box長度是64位無符號整數。當box type是"uuid"時,usertype域存在,表示自定義的box。
在解析時,可以忽略所有無法識別的box。
還有一種FullBox,作為Box的擴展,僅在header中添加了以下兩個字段:
| Field name | Type | Size(bits) |
|---|---|---|
| boxHeader | - | - |
| version | uint8 | 8 |
| flag | uint24 | 24 |
在解析時可以忽略所有無法識別的version。
MP4頂部視圖
MP4文件的整體結構如下:
| 表1 MP4 file structure |
|---|
| ftyp |
| pdin |
| moov |
| - |
| - |
| - |
| - |
| moof |
| - |
| - |
| - |
| mfra |
| - |
| - |
| mdat |
| free |
| skip |
| - |
| meta |
| - |
| - |
| - |
| - |
| - |
| - |
| - |
| - |
| - |
| - |
| - |
| meco |
| - |
| styp |
| sidx |
| ssix |
| prft |
Box是可以相互嵌套的。上面表格中加黑的box類型是比較常見的,需要重點關注下。這個表中也僅給出了box的第二層嵌套關系。更詳細的建議參考標准文檔的6.2節。
從表1中可以看出movie數據是存儲在mdat box中,但是如何解析這個box需要參考moov box。
接下來的部分也主要是與moov box解析有關。
2. Movie Structure('moov' box)
Movie Box在mp4文件中有且僅有一個。
Movie Header Box
Movie Header Box包含在Movie Structure Box中,通常包含媒體無關的信息,比如說播放時長、創建時間等。它是FullBox("mvhd")
其結構定義如下:
| Field name | Type | Size(bits) |
|---|---|---|
| FullBoxHeader | - | - |
| creation time | uint32/uint64 | 32/64 |
| modify time | uint32/uint64 | 32/64 |
| timescale | uint32 | 32 |
| duration | uint32/uint64 | 32/64 |
| rate | uint32 | 32 |
| volume | uint16 | 16 |
| reserved | uint8 | 80 |
| matrix | uint32[9] | 9*32 |
| pre_defined | uint32[6] | 6*32 |
| next_track_ID | uint32 | 32 |
對於version為1時,上面表格中選擇數據類型為uint64,對於version為0時,選擇類型為uint32。
這里解釋下,timescale表示單位時間內的精度,即1秒內經過的時間單位計數;舉個例子,正常的時間系統里以毫秒為單位,timescale就是1000。
duration中記錄的是最長的track的播放長度。rate是16.16的格式,表示優先選擇的播放速度,比如ox00010000表示1.0的播放速度。volume是浮點數的8.8的格式,表示優先選擇的播放音量,0x0100表示1.0的音量大小。next_track_ID主要用於添加新的track,通常會大約當前文件最大track-ID。
Track Structure('trak' box)
一個mp4文件至少包含一個media trak box,不同的Track box是相互獨立的。每個track box都攜帶獨立的時域空域信息,同時包含相關的media box。track box有兩種:media track和hint track,前者用於保存media相關信息,后者包含用於流媒體的打包信息。
track box包含的sub-box如下:
| 'trak' box |
|---|
| tkhd |
| tref |
| trgr |
| edts |
| --- |
| meta |
| mdia |
| --- |
| --- |
| --- |
| --- |
| --- |
.1 track header box('tkhd')
這里邊有一個字段,track_ID,用於唯一的表示當前track。
另一個字段,duration,用於記錄當前track的播放長度。
.2 track media box('mdia')
track media box包含用於聲明當前track信息的所有對象。以下sub-box需要關注:
- handler box('hdlr')
可獲取track類型信息,主要是有字段handler_type(uint32_t)區分,具體含義如下:- 'vide' Video track
- 'soun' Audio track
- 'hint' Hint track
.3 media infomation box ('minf')
先看看media infomation box的構成,如下表:
| minf |
|---|
| vmhd |
| smhd |
| hmhd |
| sthd |
| nmhd |
| dinf |
| --- |
| stbl |
| --- |
| --- |
| --- |
| --- |
| --- |
| --- |
| --- |
| --- |
| --- |
| --- |
| --- |
| --- |
| --- |
| --- |
| --- |
| --- |
| --- |
| --- |
| --- |
'minf' box中的header box是根據'hdlr' box中媒體類型一致的,只能出現一個。
.4 Sample Tables('stbl')
可以說stbl box是mp4中最復雜,包含媒體信息最多的box。主要包含時間和media samples的數據映射表,使用這部分數據可以按照時間檢索sample的位置、類型、大小、實際偏移位置。
- sample description box ('stsd')
主要描述當前track有關的編碼信息,以及用於初始化解碼的附加信息。 - Time to Sample box('stts' 'ctts')
比較常見的'stts' box,decoding time to sample,通過這個box可以實現時間到sample number的映射。 - sync sample box('stss')
這個box提供了可以用於同步的sample索引號,並嚴格按照sample number遞增順序排列。如果不存在這個box,表示所有sample都是可以用於同步。對視頻而言,sync sample通常指的關鍵幀。 - sample size box('stsz' 'stz2')
這個box記錄每個sample的大小。'stsz' box存儲格式如下:
| Filed name | type | Size(bits) |
|---|---|---|
| FullBox Header | --- | --- |
| sample_size | uint32 | 32 |
| sample_count | uint32 | 32 |
| entry_size | uint32[] | varies |
sample_size中表示sample長度,如果是0表示每個sample長度不定,會記錄在entry_size中;否則每個sample長度一樣,並且entry_size域不存在。
'stz2' box中的entry_size是compact的,長度由特定字段指定。
- sample to chunk box('stsc')
'stsc' box中記錄了每個chunk中包含多少sample,其結構定義如下:
| Filed name | type | Size(bits) |
|---|---|---|
| FullBox Header | --- | --- |
| entry_cout | uint32 | 32 |
| chunk_entry | uint32[3] | varies |
chunk_entry包含三個字段:
first_chunk: uint32
samples_per_chunk: uint32
sample_description_index: uint32
每個entry表示從first_chunk開始的每個chunk都包含samples_per_chunk個samples,這些sample都可以用使用sample_description_index信息解碼。
通過這個box,可以構建出當前track的chunk結構,及其包含的sample。
- chunk offset box('stco' 'co64')
這個box記錄了chunk對應的offset,只是包含字段一個是32為('stco'),一個是64位('co64')。
chunk offset box中記錄都是相對文件的偏移量,可以直接通過這些信息讀取。
Track Structure小結
由於'mdat' box中的多媒體數據是沒有結構的,只能參考moov的trak box解析。反過頭來。我們看一下針對單個track中的media信息存儲應該是下面的結構:
|chunk #0| chunk#1| ... | chunk #n|
每個chunk的構成是下面的結構:
|sample #0|sample #1| ... | sample #n|
從trak box中的minf中可以看出,每個chunk的長度不定,其所包含的sample數目不同,每個sample的長度也不完全相同。
3. mp4中的節目信息有哪些? 如何獲取?
每個'trak' box表示一個media,其類型記錄在stsd中,對於視頻,其中包括我們最關心的寬高信息、編碼器,保存在VisualSampleEntry;對於音頻,其中也包括采樣率、聲道數、編碼方式等,這些信息保存在AudioSampleEntry或AudioSampleEntryV1中。
對於單節目的mp4文件,不需要選擇流。從標准上來看'tkhd'中有一個字段alternate_group,估計這個是表示選擇節目的一個標志。
4. 如何實現seek?
第2部分介紹moov的結構時,里面有很多信息是跟seek相關的,比如time-sample映射。那么為了實現seek到指定時間,在mp4中需要做如下工作:
- 使用timescale將目標時間標准化。
- 通過time-to-sample box找到指定track的給定時間之前的第一個sample number。
- 通過sync sample table查詢sample number之前的第一個sync sample。
- 通過sample-to-chunk table查找到對應的chunk number。
- 通過chunk offset box查找到對應chunk在文件中的起始偏移量。
- 最后使用sample-to-chunk box和sample size box的信息計算出該chunk中需要讀取的sample數據,即完成seek。
當然標准中還有關於edit list box的使用,這里多數情況下不涉及,所以不做額外介紹。
5. 其他問題
這里解釋下上面沒有涉及的問題。
該容器包含哪些元數據信息?包含哪些節目信息?
MP4中包含'meta' box,從中可以解析出需要的metadata,具體建議參考標准。
是否支持直接流化?
mp4支持流化,直接通過特定協議及hint track完成。后續會有介紹。
哪里可以找到該容器格式最標准的文檔資料?
標准文檔的全稱是"ISO/IEC 14496-12:ISO base media file format"(c068960_ISO_IEC_14496-12_2015)。
我是從ISO.org的以下地址下載:http://www.iso.org/iso/home/store/catalogue_ics/catalogue_detail_ics.htm?csnumber=61988。
有哪些可用的工具,方便分析容器格式異常或者錯誤?
比較經典的工具是mp4info或者elecard streameye,但是如果對mp4熟悉了的話,直接二進制查看還是不錯的。
總結
本文主要是關於mp4文件解析的介紹,是我第一次深入的了解mp4文件格式,雖然可用的測試文件不是很多,但是足夠理解文件結構了。
本文內容主要作為我個人后續分析mp4文件的參考。
參考資料
- "ISO/IEC 14496-12:ISO base media file format"(c068960_ISO_IEC_14496-12_2015)。
- MP4文件格式解析
- http://blog.chinaunix.net/uid-20758197-id-5056943.html
