封裝格式--2:MP4格式詳解

“本文轉載自:
1.[小夕nike]MP4 封裝格式
2.[weixin_41422027] 音視頻封裝:MP4結構概述和分析工具推薦"

本文相關系列:

1.MP4格式概述

1.1 簡介

??MP4或稱MPEG-4第14部分(MPEG-4 Part 14)是一種標準的數(shù)字多媒體容器格式。擴展名為.mp4。雖然被官方標準定義的唯一擴展名是.mp4,但第三方通常會使用各種擴展名來指示文件的內容:

  • 同時擁有音頻視頻的MPEG-4文件通常使用標準擴展名.mp4;
  • 僅有音頻的MPEG-4文件會使用.m4a擴展名。

??大部分數(shù)據(jù)可以通過專用數(shù)據(jù)流嵌入到MP4文件中,因此MP4文件中包含了一個單獨的用于存儲流信息的軌道。目前得到廣泛支持的編解碼器或數(shù)據(jù)流格式有:

  • 視頻格式:H.264/AVC、H.265/HEVC、VP8/9等
  • 音頻格式:AAC、MP3、Opus等

1.2 術語

??為了后面能比較規(guī)范的了解這種文件格式,這里需要了解下面幾個概念和術語,這些概念和術語是理解好MP4媒體封裝格式和其操作算法的關鍵。

(1)Box
??這個概念起源于QuickTime中的atom,也就是說MP4文件就是由一個個Box組成的,可以將其理解為一個數(shù)據(jù)塊,它由Header+Data組成,Data 可以存儲媒體元數(shù)據(jù)和實際的音視頻碼流數(shù)據(jù)。Box里面可以直接存儲數(shù)據(jù)塊但是也可以包含其它類型的Box,我們把這種Box又稱為container box。

(2)Sample
??簡單理解為采樣,對于視頻可以理解為一幀數(shù)據(jù),音頻一幀數(shù)據(jù)就是一段固定時間的音頻數(shù)據(jù),可以由多個Sample數(shù)據(jù)組成,簡而言之:存儲媒體數(shù)據(jù)的單位是sample。

(3)Track
??表示一些sample的集合,對于媒體數(shù)據(jù)而言就是一個視頻序列或者音頻序列,我們常說的音頻軌和視頻軌可以對照到這個概念上。當然除了Video Track和Audio Track還可以有非媒體數(shù)據(jù),比如Hint Track,這種類型的Track就不包含媒體數(shù)據(jù),可以包含一些將其他數(shù)據(jù)打包成媒體數(shù)據(jù)的指示信息或者字幕信息。簡單來說:Track 就是電影中可以獨立操作的媒體單位。

(4)Chunk
??一個track的連續(xù)幾個sample組成的單元被稱為chunk,每個chunk在文件中有一個偏移量,整個偏移量從文件頭算起,在這個chunk內,sample是連續(xù)存儲的。
??這樣就可以理解為MP4文件里面有多個Track,一個Track又是由多個Chunk組成,每個Chunk里面包含著一組連續(xù)的Sample,正是因為定義了上述幾個概念,MP4這種封裝格式才容易實現(xiàn)靈活、高效、開放的特性,所以要仔細理解。

2.MP4整體結構

2.1 MP4結構概覽

??MP4格式是一個box的格式,box容器套box子容器,box子容器再套box子容器。


mp4_1.PNG

一個box由兩部分組成:box header、box body。

  • box header:box的元數(shù)據(jù),比如box type、box size。
  • box body:box的數(shù)據(jù)部分,實際存儲的內容跟box類型有關,比如mdat中body部分存儲的媒體數(shù)據(jù)。
    ??box header中,只有type、size是必選字段。當size==1時,存在largesize字段。如果size==0,表示該box為文件的最后一個box。在部分box中,還存在version、flags字段,這樣的box叫做Full Box。當box body中嵌套其他box時,這樣的box叫做container box。
    mp4box 圖示如下:

    其中:
  • ftyp(file type box):文件頭,記錄一些兼容性信息
  • moov(movie box):記錄媒體信息
  • mdat(media data):媒體負載

完整的Box結構:

mp4_2.png

每個Box承載的數(shù)據(jù)內容如下:

2.2 Box結構

??mp4 封裝格式采用稱為 box 的結構來組織數(shù)據(jù)。結構如下:

  +-+-+-+-+-+-+-+-+-+-+
  |  header  |  body  |
  +-+-+-+-+-+-+-+-+-+-+

其它所有 box 都在語法上繼承自此基本 box 結構。

2.2.1 box header

??box 分為普通 box 和 fullbox。
(1)普通 box header 結構如下:

字段 類型 描述
size 4 Bytes 包含 box header 的整個 box 的大小
type 4 Bytes 4 個 ascii 值,如果是 "uuid",則表示此 box 為用戶自定義,可忽略
large size 8 Bytes size=1 時才有的字段,用于擴展,例如 mdat box 會需要此字段

(2)fullbox 在上面的基礎上新增了 2 個字段:

字段 類型 描述
version 1 Bytes 版本號
flags 3 Bytes 標識

2.2.2 box body

??一個box可能會包含其它多個box,此種box稱為container box。因此box body可能是一種具體box類型,也有可能是其它box。
??雖然Box的類型非常多,大概有70多種,但是并不是都是必須的,一般的MP4文件都是含有必須的Box和個別非必須Box,我用MP4info這種工具分析了一首MP4的文件,具體的Box顯示如下:


mp4_3.png

??通過上述工具分析出來的結果,我們大概可以總結出MP4以下幾個特點:

  1. MP4文件就是由一個個Box組成,其中Box還可以相互嵌套,排列緊湊沒有多的冗余數(shù)據(jù);
  2. Box類型并沒有很多,主要是由必須的ftyp、moov、mdat組成,還有free,udta非必須box組成即去掉這兩種box對于播放音視頻也沒有啥影響。
  3. Moov一般存儲媒體元數(shù)據(jù),比較復雜嵌套層次比較深,后面會詳細解釋各個box的字段含義和組成。

2.3 ftyp(File Type Box)

??ftyp 一般出現(xiàn)在文件的開頭,用來指示該 mp4 文件使用的標準規(guī)范:

字段 類型 描述
major_brand 4 bytes 主版本
minor_version 4 bytes 次版本
compatible_brands[] 4 bytes 指定兼容的版本,注意此字段是一個 list,即可以包含多個 4 bytes 版本號

一個示例如下:


mp4_4.png

mp4_5.png

2.4 moov(Movie Box)

  1. moov是一個container box,一個文件只有一個,其包含的所有box用于描述媒體信息(metadata)。
  2. moov的位置可以緊隨著 ftyp 出現(xiàn),也可以出現(xiàn)在文件末尾。
  3. 由于是一個 container box,所以除了 box header,其 box body 就是其它的 box。

子Box:

  • mvhd(moov header):用于簡單描述一些所有媒體共享的信息。
  • trak:即 track,軌道,用于描述音頻流或視頻流信息,可以有多個軌道,如上出現(xiàn)了 2 次,分別表示一路音頻和一路視頻流。
  • udta(user data):用戶自定義,可忽略。

一個示例如下:
(1)結構

mp4_6.png

(2)數(shù)據(jù)
mp4_7.png

(3)成分
mp4_8.png

子Box:mvhd
??用于簡單描述一些所有媒體共享的信息。
mp4_9.png

子Box:trak
??track,軌道,用于描述音頻流或視頻流信息,可以有多個軌道,如上出現(xiàn)了 2 次,分別表示一路音頻和一路視頻流。
mp4_10.png

2.5 mvhd(Movie Header Box)

??mvhd 作為媒體信息的 header 出現(xiàn)(注意此header不是box header,而是moov媒體信息的header),用于描述一些所有媒體共享的基本信息。
??mvhd 語法繼承自fullbox,注意下述示例出現(xiàn)的version和flags字段屬于fullbox header。
Box Body:

mp4_11.png

2.6 trak(track)

  1. trak box 是一個 container box,其子 box 包含了該 track 的媒體信息。
  2. 一個 mp4 文件可以包含多個 track,track之間是獨立的,trak box 用于描述每一路媒體流。
  3. 一般情況下有兩個trak,分別對應音頻流和視頻流。

一個示例如下:

mp4_12.png

其中:

  • tkhd(track header box):用于簡單描述該路媒體流的信息,如時長,寬度等。
  • mdia(media box):用于詳細描述該路媒體流的信息
  • edts(edit Box):子Box為elst(Edit List Box),它的作用是使某個track的時間戳產生偏移。

2.7 tkhd(track header box)

  1. tkhd 作為媒體信息的header出現(xiàn)(注意此 header 不是 box header,而是 track 媒體信息的 header),用于描述一些該track的基本信息。
  2. tkhd語法繼承自fullbox,注意下述示例出現(xiàn)的version和flags 字段屬于fullbox header。
    Box Body:
    mp4_13.png

2.8 edts(edit Box)

??它下邊有一個elst(Edit List Box),它的作用是使某個track的時間戳產生偏移??匆幌乱恍┳侄危?/p>

  • segment_duration: 表示該edit段的時長,以Movie Header Box(mvhd)中的timescale為單位,即 segment_duration/timescale = 實際時長(單位s)
  • media_time: 表示該edit段的起始時間,以track中Media Header Box(mdhd)中的timescale為單位。如果值為-1(FFFFFF),表示是空edit,一個track中最后一個edit不能為空。
  • media_rate: edit段的速率為0的話,edit段相當于一個”dwell”,即畫面停止。畫面會在media_time點上停止segment_duration時間。否則這個值始終為1。
  • 需要注意的問題:

??為使PTS從0開始,media_time字段一般設置為第一個CTTS的值,計算PTS和DTS的時候,他們分別都減去media_time字段的值就可以將PTS調整為從0開始的值。
??如果media_time是從一個比較大的值,則表示要求PTS值大于該值時畫面才進行顯示,這時應該將第一個大于或等于該值的PTS設置為0,其他的PTS和DTS也相應做調整。

2.9 mdia(media box)

  1. 定義了track媒體類型以及sample數(shù)據(jù),描述sample信息。
  2. 它是一個container box,它必須包含mdhd,hdlr 和 minf。

一個示例如下:

mp4_14.png

其中:

  • mdhd(Media Header Box):用于簡單描述該路媒體流的信息。
  • hdlr(Handler Reference Box):主要定義了 track 類型。
  • stbl(Media Information Box):用于描述該路媒體流的解碼相關信息和音視頻位置等信息。

2.10 mdhd(Media Header Box)

  1. mdhd 作為媒體信息的header出現(xiàn)(注意此header不是box header,而是media媒體信息的header),用于描述一些該media的基本信息。
  2. mdhd和tkhd ,內容大致都是一樣的。不過tkhd通常是對指定的track設定相關屬性和內容。而mdhd 是針對于獨立的media來設置的。
  3. mdhd語法繼承自fullbox,注意下述示例出現(xiàn)的 version 和 flags 字段屬于fullbox header。
    Box Body:


    mp4_15.png

    注:timescale同mvhd中的timescale,但是需要注意雖然意義相同,但是值有可能不同,下邊stts,ctts等時間戳的計算都是以mdhd中的timescale。

2.11 hdlr(Handler Reference Box)

  1. 主要解釋了媒體的播放過程信息。聲明當前track的類型,以及對應的處理器(handler)。
  2. hdlr 語法繼承自 fullbox,注意下述示例出現(xiàn)的 version 和 flags 字段屬于 fullbox header。
    Box Body:
    mp4_16.png

2.12 minf(Media Information box)

  1. 解釋 track 媒體數(shù)據(jù)的 handler-specific 信息,media handler用這些信息將媒體時間映射到媒體數(shù)據(jù)并進行處理。minf 同樣是個 container box,其內部需要關注的內容是 stbl,這也是 moov 中最復雜的部分。
  2. 一般情況下,“minf”包含一個header box,一個“dinf”和一個“stbl”,其中,header box根據(jù)track type(即media handler type)分為“vmhd”、“smhd”、“hmhd”和“nmhd”,“dinf”為data information box,“stbl”為sample table box。


    mp4_17.png

2.13 *mhd (Media Info Header Box)

??可分為“vmhd”、“smhd”、“hmhd”和“nmhd”,比如視頻類型則為vmhd,音頻類型為smhd。
(1)vmhd

  • graphics mode:視頻合成模式,為0時拷貝原始圖像,否則與opcolor進行合成。
  • opcolor:一組(red,green,blue),graphics modes使用。
    (2)smhd
  • balance:立體聲平衡,[8.8] 格式值,一般為0表示中間,-1.0表示全部左聲道,1.0表示全部右聲道。

2.14 dinf(Data Information Box)

  1. 描述了如何定位媒體信息,是一個container box。
  2. “dinf”一般包含一個“dref”(data reference box)。
  3. “dref”下會包含若干個“url”或“urn”,這些box組成一個表,用來定位track數(shù)據(jù)。簡單的說,track可以被分成若干段,每一段都可以根據(jù)“url”或“urn”指向的地址來獲取數(shù)據(jù),sample描述中會用這些片段的序號將這些片段組成一個完整的track。一般情況下,當數(shù)據(jù)被完全包含在文件中時,“url”或“urn”中的定位字符串是空的。

2.15 stbl(Sample Table Box)

??在介紹stbl box之前,需要先介紹一下mp4中定義的sample與chunk:

  • sample:ISO/IEC 14496-12 中定義 samples 之間不能共享同一個時間戳,因此,在音視頻 track 中,一個 sample 代表一個視頻或音頻幀。
  • chunk:多個 sample 的集合,實際上音視頻 track 中,chunk 與 sample 一一對應。
    mp4_18.png

??stbl box是一個container box,是整個track中最重要的一個box,其子box描述了該路媒體流的解碼相關信息、音視頻位置信息、時間戳信息等。

??MP4文件的媒體數(shù)據(jù)部分在mdat box里,而stbl則包含了這些媒體數(shù)據(jù)的索引以及時間信息。
一個示例如下:

mp4_19.png

其中:

  • stsd(sample description box):存儲了編碼類型和初始化解碼器需要的信息,并與具體編解碼器類型有關。
  • stts(time to sample box):存儲了該 track 每個 sample 到 dts 的時間映射關系。
  • stss(sync sample box):針對視頻 track,關鍵幀所屬sample 的序號。
  • ctts(composition time to sample box):存儲了該 track 中,每個 sample 的 cts 與 dts 的時間差。
  • stsc/stz2(sample to chunk box):存儲了該 track 中每個 sample 與 chunk 的映射關系。
  • stsz(sample size box):存儲了該 track 中每個 sample 的字節(jié)大小。
  • stco/co64(chunk offset box):存儲了該 track 中每個 chunk 在文件中的偏移。

2.16 stsd(sample description box)

??主要存儲了編碼類型和初始化解碼器需要的信息。這里以視頻為例,包含子box:avc1,表示是H264的視頻。


mp4_20.png

2.16.1 h264 stsd

??對于h264視頻,典型結構如下:


mp4_21.png

其上(只列出 avc1 與 avcC,其余 box 可忽略):

  • avc1,是 avc/h264/mpeg-4 part 10視頻編解碼格式的代稱,是一個 container box,但是 box body 也攜帶自身的信息。
    Box Body:
    mp4_22.png
  • avcC(AVC Video Stream Definition Box),存儲 sps && pps,即在 ISO/IEC 14496-15 中定義的 AVCDecoderConfigurationRecord 結構


    mp4_23.png

注:在 srs 中,解析 avcc/AVCDecoderConfigurationRecord 結構解析參見 srs/trunk/src/kernel/srs_kerner_codec.cpp::SrsFormat::avc_demux_sps_pps() 函數(shù)。

2.16.2 aac stsd

??對于 aac 音頻,典型結構如下:

mp4_24.png

可以看到,aac stsd 結構比較復雜,box 眾多。實際上,在 ISO/IEC 14496-3 中,定義了 AudioSpecificConfig 類型,aac stsd 結構主要信息就來自 AudioSpecificConfig。
具體不做分析,可以參看 srs 中:

  • 解析 AudioSpecificConfig 結構的 srs/trunk/src/kernel/srs_kerner_codec.cpp::SrsFormat::audio_aac_sequence_header_demux() 函數(shù)
  • 封裝 aac stsd 結構的 srs/trunk/src/kernel/srs_kernel_mp4.cpp::SrsMp4Encoder::flush() 函數(shù)

2.17 stts(time to sample box)

  1. 存儲了該 track 每個 sample 到 dts 的時間映射關系。
  2. 包含了一個壓縮版本的表,通過這個表可以從解碼時間映射到sample序號。表中的每一項是連續(xù)相同的編碼時間增量(Decode Delta)的個數(shù)和編碼時間增量。通過把時間增量累加就可以建立一個完整的time to sample表。


    mp4_25.png

??這里為了節(jié)約條目的個數(shù),采用了壓縮存儲的方式,即 sample_count 個連續(xù)的 sample 如果 sample_delta 時長一樣,那么用一個條目就能表示了。
一個音頻 track 的示例如下:

mp4_26.png

一個視頻 track 的示例如下:

mp4_27.png

2.18 ctts(composition time to sample box)

  1. 存儲了該 track 中,每個 sample 的 pts 與 dts 時間差(cts = pts - dts):
  2. 如果一個視頻只有I幀和P幀,則ctts這個表就不需要了,因為解碼順序和顯示順序是一致的,但是如果視頻中存在B幀,則需要ctts。


    mp4_28.png

注意:

  • 此 box 在 dts 和 pts 不一樣的情況下必須存在,如果一樣,不用包含此 box。
  • 如果 box 的 version=0,意味著所有 sample 都滿足 pts >= dts,因而差值用一個無符號的數(shù)字表示。只要存在一個 pts < dts,那么必須使用 version=1、有符號差值來表示。
  • 關于 ctts 的生成,可以參看 srs/trunk/src/kernel/srs_kernel_mp4.cpp::SrsMp4SampleManager::write_track() 函數(shù) pts、dts、cts 滿足公式:pts - dts = cts。

2.19 stss(sync sample box)

??它包含media中的關鍵幀的sample表。關鍵幀是為了支持隨機訪問。如果此表不存在,說明每一個sample都是一個關鍵幀。


mp4_29.png

一個視頻示例如下:

mp4_30.png

2.20 stsc/stz2(sample to chunk box)

??存儲了該 track 中每個 sample 與 chunk 的映射關系。


mp4_31.png

一個音頻示例如下:

mp4_32.png
  • 第一組 chunk 的 first_chunk 序號為 1,每個 chunk 的 sample 個數(shù)為 1,因為第二組 chunk 的 first_chunk 序號為 2,可知第一組 chunk 中只有一個 chunk。
  • 第二組 chunk 的 first_chunk 序號為 2,每個 chunk 的 sample 個數(shù)為 2,因為第三組 chunk 的 first_chunk 序號為 24,可知第二組 chunk 中有 22 個 chunk,有 44 個 sample。
  • 這個并不是說,這個視頻流只有3個sample,也就是只有3幀,不可能的,而是第三,第四行省略了,也就是說,第三跟第四,等等,后面的chunk 里面都只有1個sample,跟第二個chunk一樣。本視頻流有239個chunk。因為本視頻流一共240幀,第一個chunk里面有2幀,后面的都是1幀,所以計算出來只有239個chunk。

2.21 stsz(sample size box)

??包含sample的數(shù)量和每個sample的字節(jié)大小,這個box相對來說體積比較大的。表明視頻幀或者音頻幀大小,F(xiàn)Fmpeg 里面的AVPacket 的size 數(shù)據(jù)大小,就是從這個box中來的。


mp4_33.png

2.22 stco/co64(chunk offset box)

  1. Chunk Offset表存儲了每個chunk在文件中的位置,這樣就可以直接在文件中找到媒體數(shù)據(jù),而不用解析box。
  2. 需要注意的是一旦前面的box有了任何改變,這張表都要重新建立。


    mp4_34.png
  • stco 有兩種形式,如果你的視頻過大的話,就有可能造成 chunkoffset 超過 32bit 的限制。所以,這里針對大 Video 額外創(chuàng)建了一個 co64 的 Box。它的功效等價于 stco,也是用來表示 sample 在 mdat box 中的位置。只是,里面 chunk_offset 是 64bit 的。
  • 需要注意,這里 stco 只是指定的每個 Chunk 在文件中的偏移位置,并沒有給出每個 Sample 在文件中的偏移。想要獲得每個 Sample 的偏移位置,需要結合 Sample Size box 和 Sample-To-Chunk 計算后取得。

2.23 udta(user data box)

??用戶自定義數(shù)據(jù)。

2.24 free(free space box)

  1. “free”中的內容是無關緊要的,可以被忽略。該box被刪除后,不會對播放產生任何影響。
  2. Ftyp可以是free或skip。

2.25 mdat(media data box)

  1. mdat就是具體的編碼后的數(shù)據(jù)。
  2. mdat 也是一個 box,擁有 box header 和 box body。
  3. mdat 可以引用外部的數(shù)據(jù),參見 moov --> udta --> meta,這里不討論,只討論數(shù)據(jù)存儲在本文件中的形式。
  4. 對于 box body 部分,采用一個一個 samples 的形式進行存儲,即一個一個音頻幀或視頻幀的形式進行存儲。
  5. 碼流組織方式采用 avcc 格式,即 AUD + slice size + slice 的形式。

3.參考資料

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

  • MP4簡介 MP4(MPEG-4 Part 14)是一種常見的多媒體容器格式,它是在“ISO/IEC 14496-...
    FlyerGo閱讀 4,284評論 0 2
  • Mp4是一種非常常見的一種音視頻封裝格式,因為兼容性強,所以被普遍使用。今天總結了一下Mp4格式。 Mp4格式是一...
    幸福有你_abb7閱讀 4,395評論 0 1
  • 原文鏈接: http://blog.sina.com.cn/s/blog_48f93b530100jz4x.htm...
    之江狂徒閱讀 994評論 0 0
  • 目錄 概述 mp4文件基本信息 封裝格式重要概念 重要box介紹 其他box介紹 實用技術 開源軟件 參考 [1]...
    smallest_one閱讀 64,215評論 5 61
  • 目錄 概述 mp4文件基本信息 封裝格式重要概念 重要box介紹 其他box介紹 實用技術 開源軟件 參考 [1]...
    一川煙草i蓑衣閱讀 1,490評論 0 1

友情鏈接更多精彩內容