多媒體文件格式之MP4


[時間:2016-06] [狀態:Open]

學習多媒體容器格式的目的

主要是為了回答以下問題:

  1. 該容器中數據是如何組織的?
  2. 該容器包含哪些編碼格式的數據?這些數據是如何存儲的?
  3. 該容器包含哪些元數據信息?包含哪些節目信息?
  4. 對於支持多節目的容器格式,如何找到對應的音頻流、視頻流、字幕流?
  5. 如何確定該容器的節目播放時長?
  6. 如何從該容器中提取音頻、視頻、字幕數據,並交給解碼器解碼,有時間戳否?
  7. 該容器是否支持seek?有哪些輔助信息?
  8. 是否支持直接流化?
  9. 哪里可以找到該容器格式最標准的文檔資料?
  10. 有哪些可用的工具,方便分析容器格式異常或者錯誤?

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中需要做如下工作:

  1. 使用timescale將目標時間標准化。
  2. 通過time-to-sample box找到指定track的給定時間之前的第一個sample number。
  3. 通過sync sample table查詢sample number之前的第一個sync sample。
  4. 通過sample-to-chunk table查找到對應的chunk number。
  5. 通過chunk offset box查找到對應chunk在文件中的起始偏移量。
  6. 最后使用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文件的參考。

參考資料

  1. "ISO/IEC 14496-12:ISO base media file format"(c068960_ISO_IEC_14496-12_2015)。
  2. MP4文件格式解析
  3. http://blog.chinaunix.net/uid-20758197-id-5056943.html


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM