MP4文件結構解析

MP4相關文檔

ISO標準文檔

MPEG標準相關鏈接

MP4分析工具

MP4 Reader:展示MP4 Box的16進制數據,同時顯示這些數據代表的信息。

Mp4Info : 簡單顯示MP4 Box的結構信息。

Elecard HEVC Analyzer:一個及其強大的媒體解析工具,解析的內容非常詳細,不僅限於MP4。

分析Mp4結構:一個在線解析MP4信息的網站

術語和縮略語

  • box:由唯一的標誌符和長度限定的面向對象的結構塊,在某些規格中被稱爲atom,它們是一個意思。一個MP4文件是一個個box組成,一個Box中可以包含另一個Box,這種Box被稱爲Container Box
  • track:媒體文件中samples集合關於時間的序列。通常,一個track表示一個音頻或者視頻時間序列。
  • chunk:一個track中,連續的sample集合。
  • hint track:特殊的track,不包含媒體數據,而是包含了將一個或多個track打包成媒體流的指令信息。
  • hinter:在僅包含媒體的文件上運行的工具,用於向文件添加一個或多個提示軌道,從而便於流式傳輸。
  • sample:即媒體數據的採樣,對於非hint track 而言 sample中包含一幀或多幀音頻或視頻數據。對於hint track來說,則定義了一個或者多個流媒體包格式。
  • sample table:打包方式,規定track中sample的時序和物理佈局。

Mp4文件的組織結構

MP4文件由一系列的box對象組成,所有的數據都包含在這些box中,除此以外,文件中再無其它數據。此外,所有的Mp4文件中,首先有且僅有一個File Type 類型的Box。

Box對象結構

Box由包含了size(Box大小)和type(Box 類型)的Box Header開始。Header允許緊湊或擴展的size(32位或64位)和緊湊擴展的type(32位或者完整的通用唯一標識符,即UUID)。

大多數標準的Box使用的都是32位size和32位type,只有包含了媒體數據的Box需要使用64位size。

這裏的size,指的是包括Header在內的整個Box佔用的大小。在size指定的空間中,除了Box header佔用的空間外,其它空間由真實的數據(BoxData)數據佔據。這些數據,可能包括其它子Box、也可能是媒體數據。

我們可以利用該信息對MP4文件進行分析。需要注意的是,數據存儲使用大端字節序。

在ISO標準文檔中,對於Boxheader的定義僞代碼是:

class Box (unsigned int(32) boxtype, optional unsigned int(8)[16]  extended_type) {
    unsigned int(32) size;
    unsigned int(32) type = boxtype;
    if (size==1) {
        unsigned int(64) largesize;
    } else if (size==0) {
        // box extends to end of file
    }
    if (boxtype==‘uuid’) {
        unsigned int(8)[16] usertype = extended_type;
    }
}

轉化爲下圖:
在這裏插入圖片描述

  • size字段:一般情況,BoxHeader只包含32位的size,除了BoxHeader佔用的空間外,剩餘的size保存了Box的數據。此外,有兩種特殊情況:
  1. 當size爲1時,BoxHeader中將多出一個64位的largesize,此時Box的大小由largesize決定。
  2. 當size爲0時,表示當前Box是文件中最後一個Box,並且從該Box的Header開始直到文件末尾都是該Box的數據(通常用於保存Media Data)。
  • type字段:type字段定義了Box的類型,通常該類型都是通過緊湊類型,也就是32位表示。當type的值等於uuid時,表示該Box的類型爲用戶擴展類型,用長度爲16的int類型無符號數組表示該擴展類型。

type字段對於Box而言,非常重要,如果Box的type類型無法識別,該Box應該被忽略或者跳過不處理。

FullBox對象結構

FullBox結構是對Box結構的一種擴展,除了包含所有Box結構的字段外,還包含了version和flags字段:

  • version字段:version是一個整數值(int),用於表示該Box的版本。
  • flags字段: 是一個map類型的標誌。

FullBox的僞代碼和結構圖如下:

class FullBox(unsigned int(32) boxtype, unsigned int(8) v, bit(24) f) extends Box(boxtype) {
    unsigned int(8) version = v;
    bit(24) flags = f;
}

在這裏插入圖片描述
在讀取或使用FullBox結構時應該注意,無法識別的version應該被忽略或者跳過不處理。

常見的Box

File Type Box

Box類型:‘ftyp’

容器: 文件

是否強制:是

數量: 1個

ISO_IEC_14496-12_2015版本規範規定,Mp4格式文件中必須有且只有一個’ftyp’類型的Box。

爲了與早期沒有’ftype’類型的版本兼容。當文件中,包含FTYP類型的Box,且該Box包含範圍Major_brand='mp41', minor_version=0,以及單獨指定兼容性compatible_brands=‘mp41’,則該文件需要按照有FTYP Box的方式讀取。

File Type Box的語法定義如下:

class FileTypeBox extends Box('ftyp') {
    unsigned int(32) major_brand; // 一個品牌的標誌符
    unsigned int(32) minor_version; // 是主要品牌的次要版本的信息,爲一個整數
    unsigned int(32) compatible_brands[]; // 兼容的品牌列表
}

我們很少見到純粹的'ftyp'類型的Box,而FileTypeBox這種爲了兼容而存在的Box相對比較常見一些。

一個典型的FileTypeBox的結構數據如下(用MP4 Reader查看):
在這裏插入圖片描述

Movie 結構

Movie Box

Box類型:‘moov’

容器: 文件

是否強制:是

數量: 1個

用於展示的媒體數據,都包含在moov中,包括音頻、視頻,同時也包含metedata數據。該Box一般緊跟在ftyp後面,moov佔用了大部分的文件空間。'moov’類型的Box主要功能是包含其它類型的Box。

Movie Header Box

Box類型:'mvhd ’

容器: Movie Box (‘moov’)

是否強制:是

數量: 1個

該Box定了與媒體數據無關,與媒體文件相關的整體信息。定義語法爲:

class MovieHeaderBox extends FullBox('mvhd', version, 0) {
    if (version==1) { // 當version==1時
        unsigned int(64) creation_time;
        unsigned int(64) modification_time;
        unsigned int(32) timescale;
        unsigned int(64) duration;
    } else { // version==0
        unsigned int(32) creation_time;
        unsigned int(32) modification_time;
        unsigned int(32) timescale;
        unsigned int(32) duration;
    }
    template int(32) rate = 0x00010000; // typically 1.0
    template int(16) volume = 0x0100; // typically, full volume
    const bit(16) reserved = 0;
    const unsigned int(32)[2] reserved = 0;
    template int(32)[9] matrix =
    { 0x00010000,0,0,0,0x00010000,0,0,0,0x40000000 };
    // Unity matrix
    bit(32)[6] pre_defined = 0;
    unsigned int(32) next_track_ID;
}

各字段含義:

字段 含義
version Box的版本,在FullBox中定義
creation_time 整數,用於表示圖像的創建時間(秒爲單位,從1904.01.01 00:00開始)
modification_time 整數,表示圖像最近的修改時間(秒爲單位,從1904.01.01 00:00開始)
timescale 整數,指定整體圖像文件的時間尺度,表示一秒鐘的時間單位數。例如時間座標軸上,一秒鐘分爲60個單位,那麼時間尺度爲60。該值與duration一起計算媒體播放時長。
duration 整數,申明媒體持續時長(在指定的時間尺度下),該值和最長的track持續時間的值保持一致。如果無法確定,值將被設置爲1s。實際播放時間計算公式:duration/timescale秒。
rate 播放速度,通常爲1.0
volume 播放音量,值爲1.0時表示最高音量
matrix 視頻變換矩陣(不明白是幹啥用的)
next_track_ID 非零整數,用於表示繼續往文件中追加track時使用的id值。該值肯定比已有trackID大

Track Box

Box類型:'trak ’

容器: Movie Box (‘moov’)

是否強制:是

數量: 1個或多個

Track Box表示包含了單個track媒體數據的容器Box(Container Box)。通常一個Mp4文件媒體數據中,包含一個或多個track,每個track都包含自己的時間和空間信息,且彼此獨立。每個track中,也包含了與之相關的媒體信息。

在這裏,Track存在的目的有兩個

  1. 包含媒體數據(media track)。
  2. 包含流協議的分組化信息(hint track)。

Track Box就是一個簡單的Container Box,它會包含兩個關鍵Box,Track Header BoxMedia Box

Track Header Box

Box類型:‘tkhd’

容器: Track Box (‘trak’)

是否強制:是

數量: 1個

該Box用於描述Track的基本屬性,一個track中有且只有一個Track Header Box。

媒體軌道的flag標誌的默認值爲7(即111:track_enabled,track_in_movie,track_in_preview)。如果在媒體數據中所有軌道都沒有設置track_in_movie和track_in_preview,則應將所有軌道視爲在所有軌道上都設置了兩個標誌。

服務器提示軌道(hint track)應將track_in_movie和track_in_preview設置爲0,以便在本地回放和預覽時忽略它們。

定義語法:

class TrackHeaderBox extends FullBox('tkhd', version, flags){
    if (version==1) {
        unsigned int(64) creation_time;
        unsigned int(64) modification_time;
        unsigned int(32) track_ID;
        const unsigned int(32) reserved = 0;
        unsigned int(64) duration;
    } else { // version==0
        unsigned int(32) creation_time;
        unsigned int(32) modification_time;
        unsigned int(32) track_ID;
        const unsigned int(32) reserved = 0;
        unsigned int(32) duration;
    }
    const unsigned int(32)[2] reserved = 0;
    template int(16) layer = 0;
    template int(16) alternate_group = 0;
    template int(16) volume = {if track_is_audio 0x0100 else 0};
    const unsigned int(16) reserved = 0;
    template int(32)[9] matrix=
    { 0x00010000,0,0,0,0x00010000,0,0,0,0x40000000 };
    // unity matrix
    unsigned int(32) width;
    unsigned int(32) height;
}

定義中,很多字段在前面都已經解釋過了。下面將未解釋和需要補充說明的列出:

字段 含義
track_ID 當前track的ID,該值全局唯一,不能重複使用且不能爲0
duration 整數,申明媒體持續時長(在Movie Header Box指定的時間尺度下)。如果無法確定,值將被設置爲1s。
layer 指定視頻track的前後順序,該值通常爲0。如果有-1和0兩個track,那麼-1所在track將在0所在track的前方顯示。
alternate_group 是一個整數,指定一組或一組軌道,該值默認爲0,表示沒有和其它軌道關聯。(不懂)

需要特別說明的字段是flag,這是一個佔用24bit空間的整數,用於定義以下屬性:

  • Track_enabled :表示該track是否可用,Flag值爲0x000001。一個不可用狀態的track(Flag值爲0x000000)數據會被當做不顯示處理。
  • Track_in_movie :表示該track被用於播放,Flag值爲0x000002。
  • Track_in_preview :表示該track用於預覽媒體文件。Flag值爲0x000004。
  • Track_size_is_aspect_ratio :表示track的寬高字段不是以像素爲單位,且該值表示寬高比。Flag值爲0x000008。

width&height

  • 對於文字或者字幕track,寬高取決於編碼格式,用於描述推薦渲染區域的尺寸。對於這樣的軌道,值0x0也可用於指示數據可以以任何大小呈現,並沒有指定最優顯示尺寸,它的實際大小可以通過外部上下文或通過重用另一個軌道的寬高來確定。對於這種軌道,也可以使用標誌track_size_is_aspect_ratio。
  • 對於可不見內容的track(例如音頻文件)寬高都應該設置爲0。
  • 除此之外的其他track,width&height指定了可見track的寬高。

Media Box

Box類型:‘mdia’

容器: Track Box (‘trak’)

是否強制:是

數量: 1個

Media Box包含聲明有關軌道中媒體數據信息的所有對象。這就是個簡單的容器對象,沒有別的需要說明了。

Media Header Box

Box類型:‘mdhd’

容器: Media Box (‘mdia’)

是否強制:是

數量: 1個

Media Header Box 申明整體的媒體信息,這些信息也和track中的媒體特性相關。

定義語法:

class MediaHeaderBox extends FullBox('mdhd', version, 0) {
    if (version==1) {
        unsigned int(64) creation_time;
        unsigned int(64) modification_time;
        unsigned int(32) timescale;
        unsigned int(64) duration;
    } else { // version==0
        unsigned int(32) creation_time;
        unsigned int(32) modification_time;
        unsigned int(32) timescale;
        unsigned int(32) duration;
    }
    bit(1) pad = 0;
    unsigned int(5)[3] language; // ISO-639-2/T語言編碼
    unsigned int(16) pre_defined = 0;
}

總共有三個額外字段:

  • pad :一個佔位符,默認值爲0,佔用一個bit。
  • language:當前track的語言,該字段總長爲16bit,和pad字段組成兩個字節。
  • pre_defined:默認值爲0。

Handler Reference Box : ‘hdlr’

Box類型:‘hdlr’

容器: Media Box (‘mdia’)或者Meta Box(‘meta’)

是否強制:是

數量: 1個

該Box申明瞭track的媒體類型,因此決定了track中媒體數據播放的處理過程。

例如,向解碼器傳送視頻格式數據的媒體數據將被存儲在video track中,這些數據將由視頻處理程序處理。

當該Box位於Meta Box中時,該Box申明Meta Box內容的結構和格式。

定義語法:

class HandlerBox extends FullBox('hdlr', version = 0, 0) {
    unsigned int(32) pre_defined = 0;
    unsigned int(32) handler_type;
    const unsigned int(32)[3] reserved = 0;
    string name;
}
  • handler_type:
    1. 當該Box位於Media Box中,表示當前track的處理類型。如:video、audio、hint track、meta track等。
    2. 當存在於Meta Box中時,包含指定Meta Box的內容格式。 可以在住Meta Box中使用值’null’來指示它
      僅用於保存資源。
  • name:是一個以UTF-8字符結尾的以null結尾的字符串,它爲軌道類型提供了一個人類可讀的名稱(用於調試和檢查)。

handler_type的值,實際上就是字符串對應的16進制編碼,如:

  • 視頻:vide 0x76, 0x69, 0x64, 0x65, 0x00, 0x00, 0x00, 0x00
  • 音頻:soun 0x73, 0x6F, 0x75, 0x6E, 0x00, 0x00, 0x00, 0x00

Media Information Box : 'minf ’

Box類型:'minf ’

容器: Media Box (‘mdia’)

是否強制:是

數量: 1個

該box包含了track中申明瞭媒體特徵信息的所有對象。這是一個普通的Box,定義如下:

class MediaInformationBox extends Box('minf') {}

Video media header : ‘vmhd’ & ‘smhd’

‘vmhd’,對應視頻

Box類型:‘vmhd’

容器: Media Information Box (‘minf’)

是否強制:是

數量: 1個

video track中的視頻相關的媒體信息。定義如下:

aligned(8) class VideoMediaHeaderBox
    extends FullBox(‘vmhd’, version = 0, 1) { // flag = 1
    template unsigned int(16) graphicsmode = 0; // copy, see below
    template unsigned int(16)[3] opcolor = {0, 0, 0};
}

對於視頻而言,flag字段值應該爲1.

  • graphicsmode :指定此視頻軌道的合成模式,來自以下枚舉集,可以通過派生規範進行擴展:copy = 0複製現有圖像
  • opcolor :是一組3原色值(紅色,綠色,藍色),供graphicsmode 使用。

‘smhd’,對應音頻

Box類型:‘smhd’

容器: Media Information Box (‘minf’)

是否強制:是

數量: 1個

和視頻類似,該Box包含音頻相關的媒體信息。該Header對於所有包含了audio的track適用。定義如下:

aligned(8) class SoundMediaHeaderBox extends FullBox(‘smhd’, version = 0, 0) {
    template int(16) balance = 0;
    const unsigned int(16) reserved = 0;
}
  • balance:是一個固定小數點表示單聲道音軌(track)在立體聲空間中的位置。0表示中間(通常都爲0),-1.0表示聲道,1.0表示右聲道。

Track Data Layout Structures : ‘dinf’

Box類型:‘dinf’

容器: Media Information Box (‘minf’)或者Meta Box (‘meta’)

是否強制:是

數量: 1個

該Box包含媒體信息在track中的位置信息。本身就是一個簡單的Box,包含一個’dref’類型的Box:

aligned(8) class DataInformationBox extends Box('dinf') {}

Data Reference Box : 'dref ’

Box類型:'dref ’

容器: Data Information Box (‘dinf’)

是否強制:是

數量: 1個

Box類型:‘url’ ‘urn’

容器: Data Information Box ('dref ')

是否強制:是(‘dref’中,至少有一個’url’或者’urn’)

數量: 1個或多個

Data Reference Box對象包含一個數據引用表(通常是URL),用於聲明播放需要使用到的媒體數據的位置。

引用表中的數據索引(index)和track中的數據綁定。通過這種方式,一個track可能被分割爲多個sources。

定義:

aligned(8) class DataEntryUrlBox (bit(24) flags) extends FullBox('url', version = 0, flags) {
    string location;
}
aligned(8) class DataEntryUrnBox (bit(24) flags) extends FullBox('urn', version = 0, flags) {
    string name;
    string location;
}
aligned(8) class DataReferenceBox extends FullBox('dref', version = 0, 0) {
    unsigned int(32) entry_count;
    for (i=1; i <= entry_count; i++) {
    	DataEntryBox(entry_version, entry_flags) data_entry;
    }
}

各字段的含義如下:

  • entry_count:條目的數量,即DataEntryBox的數量。
  • entry_flags:一個24bits表示的整數,如果值爲0x000001意味着Media data 在當前文件中,並且Movie Box包含了數據的引用。
  • data_entry :是一個URL或者URN類型的條目,Name是URN,那麼URN條目是必需的。 Location是一個URL,那麼URL條目是必需的,在URN條目中是可選的,它提供了一個位置來查找具有給定名稱的資源。 他們都是使用UTF-8字符的以null結尾的字符串。
    如果設置了自包含標誌,則使用URL表單並且不存在字符串值; 該框終止於entry-flags字段。 URL類型應該是提供文件的服務(例如,類型爲file,http,ftp等的URL),並且理想情況下哪些服務也允許隨機訪問。 相對URL是允許的,並且和包含了指定數據的Movie Box的文件相關。

Sample Table Box : ‘stbl’

Box類型:‘stbl’

容器: Media Information Box (‘minf’)

是否強制:是

數量: 1個

Sample Table Box可以翻譯成樣本表容器,是MP4規範中非常重要的容器。它包含了一個track中所有媒體樣本的所有時間和數據的引用。使用容器中的sample信息,可以定位sample的媒體時間、定位其類型,決定其大小,以及在其它容器中,確定相鄰sample的offset。

如果包含了Sample Table Box的track沒有數據,那麼該Sample Table Box不需要包含任何子Box。

如果Sample Table Box所在的track有數據引用,該Sample Table Box必須包含如下子Box:

  • Sample Description
  • Sample Size
  • Sample To Chunk
  • Chunk Offset

此外,Sample Description Box應包含至少一個條目。Sample Description Box是必需的,因爲它包含數據引用索引字段,該字段指示用於檢索媒體樣本的Data Reference Box 。
如果沒有Sample Description Box,則無法確定媒體樣本的存儲位置。
Sync Sample Box 是可選的。 如果不存在Sync Sample Box,則所有樣本都是同步樣本。

Sample Description Box : ‘stsd’

Box類型:‘stsd’

容器: Sample Table Box (‘stbl’)

是否強制:是

數量: 1個

樣本描述容器:提供了編碼類型和用於編碼初始化的詳細信息。在ISO/IEC 14496-12:2015 標準中,相關的定義如下:

aligned(8) class SampleDescriptionBox (unsigned int(32) handler_type) extends FullBox('stsd', version, 0){
    int i ;
    unsigned int(32) entry_count; // entry 的數量
    for (i = 1 ; i <= entry_count ; i++){
    	SampleEntry(); // 這表示一個SampleEntry派生類的實例
    }
}
aligned(8) abstract class SampleEntry (unsigned int(32) format) extends Box(format){
    const unsigned int(8)[6] reserved = 0;
    unsigned int(16) data_reference_index;
}
class BitRateBox extends Box(‘btrt’){
    unsigned int(32) bufferSizeDB; // bufferSizeDB以字節爲單位給出基本流的解碼緩衝區的大小。
    unsigned int(32) maxBitrate; // 最大比特率
    unsigned int(32) avgBitrate; // 平均比特率
}

可以看到,SampleDescriptionBox中有幾個SampleEntry的子類實例是通過entry_count確定。

  • data_reference_index:是一個整數,包含用於檢索與使用此樣本描述容器的樣本關聯的數據的數據引用的索引。數據引用存儲在Data Reference Boxes中。 索引的範圍從1到數據引用的數量。

SampleEntry是一個抽象類,它的子類比較豐富,如:視頻相關的VisualSampleEntry、音頻相關的AudioSampleEntry 、字幕相關的SubtitleSampleEntry 等。這裏簡單展開解讀一下VisualSampleEntry。它的定義爲:

class VisualSampleEntry(codingname) extends SampleEntry (codingname){
    unsigned int(16) pre_defined = 0;
    const unsigned int(16) reserved = 0;
    unsigned int(32)[3] pre_defined = 0;
    unsigned int(16) width; // sample的寬
    unsigned int(16) height; // sample的高
    template unsigned int(32) horizresolution = 0x00480000; // 72 dpi 水平分辨率
    template unsigned int(32) vertresolution = 0x00480000; // 72 dpi 垂直分辨率
    const unsigned int(32) reserved = 0;
    template unsigned int(16) frame_count = 1; // 每一個sample中包含多少幀數據,默認爲1
    string[32] compressorname; // 一個固定的32字節字段,第一個字節設置爲要顯示的字節數,然後是可顯示數據的字節數,然後填充以完成總共32個字節(包括大小字節)。 該字段可以設置爲0。
    template unsigned int(16) depth = 0x0018;
    int(16) pre_defined = -1;
    // other boxes from derived specifications
    CleanApertureBox clap; // optional
    PixelAspectRatioBox pasp; // optional
}
  • codingname:表示的就是編碼名稱,這個名稱是通過VisualSampleEntry的子類傳遞的,至於具體的子類,在ISO/IEC 14496-12:2015 標準中並沒有定義,而是定義在其它標準文檔中,例如ISO/IEC 14496-15標準中的AVCSampleEntry:

    class AVCSampleEntry() extends VisualSampleEntry ('avc1'){
        AVCConfigurationBox config;
        MPEG4BitRateBox (); // optional,可選
        MPEG4ExtensionDescriptorsBox (); // optional
    }
    

    它組合了其它的一些Box,如’mp4a’這裏就不展開了。

在具體解析stsd Box 時,只需要按照定義和字段大小就可以解析出數據的編碼信息了。

Decoding Time to Sample Box :‘stts’

Box類型:‘stts’

容器: Sample Table Box (‘stbl’)

是否強制:是

數量: 1個

該Box包含了一個解碼時間到sample索引的映射關係表(Table entries)。

entries表中的每個entry給出了具有相同時長的連續sample的數和這些sample的時間間隔值。將這些時間間隔相加在一起,就可以得到一個完整的time與sample之間的映射。將所有的時間間隔相加在一起,就可以得到該track的總時長。

Decoding Time to Sample Box包含解碼時間增量,即每個sample的顯示時間計算公式如下:

DT(n+1)=DT(n)+STTS(n)DT(n + 1) = DT(n) + STTS(n)

其中STTS(n)STTS(n)是sample n的時間間隔,DT(n)DT(n)是sample n的顯示時間。

sample 的entry都是按照解碼的時間排序,所以時間增量DT(n+1)DT(n + 1)都是非負的。Table entries根據每個sample在媒體流中的順序和時長對它們進行描述。如果連續的sample時長相同,會被放在同一個table entry中。

Box定義如下:

aligned(8) class TimeToSampleBox extends FullBox(’stts’, version = 0, 0) {
    unsigned int(32) entry_count; // 映射表中entry實體的數量
    int i;
    for (i=0; i < entry_count; i++) {
        unsigned int(32) sample_count; // 指定時長的樣本數量
        unsigned int(32) sample_delta; // sample樣本的時長
    }
}

在這裏插入圖片描述
如上圖,表示1080.mp4文件的stts Box中有1500個時長爲512的sample。

Sync Sample Box:‘stss’

Box類型:‘stss’

容器: Sample Table Box (‘stbl’)

是否強制:否

數量: 0個或1個

該Box提供流中同步樣本的緊湊標記,標記了關鍵幀,提供隨機訪問點標記。 它包含了一個table, table的每個entry標記了一個sample,該sample是媒體關鍵幀。table按sample編號的嚴格遞增順序排列。如果不存在該Box,則每個sample都是關鍵幀。

定義如下:

aligned(8) class SyncSampleBox extends FullBox(‘stss’, version = 0, 0) {
    unsigned int(32) entry_count; // 表中entry的數量。如果爲0意味着流中沒有關鍵幀,table也爲空
    int i;
    for (i=0; i < entry_count; i++) {
   		unsigned int(32) sample_number; // 流中關鍵幀的編號
    }
}

下圖表示:該流有18個關鍵幀,對應的sample編號爲1、151、211…
在這裏插入圖片描述

Composition Time to Sample Box : 'ctts ’

Box類型:‘ctts’

容器: Sample Table Box (‘stbl’)

是否強制:否

數量: 0個或1個

Composition Time to Sample Box也被稱爲時間合成偏移表,每個音視頻的sample都有自己解碼順序和顯示順序。對每個sample而言,解碼順序和顯示順序往往都不相同。這時,就有了Composition Time to Sample Box。

有一種特殊情況,sample的解碼順序和顯示順序一致。那麼mp4文件中將不會出現Composition Time to Sample Box,Decoding Time to Sample Box :‘stts’ 將即提供解碼順序,也代表了顯示順序,同時可以根據時長計算每個sample開始和結束的時間。

一般而言,顯示順序和和解碼順序通常不一致(涉及到I、P、B幀的解碼順序)。此時Decoding Time to Sample Box提供解碼順序,Composition Time to Sample Box通過差值的形體,可以計算出顯示時間。

Composition Time to Sample Box提供了從解碼時間到顯示時間的映射關係,如下:

CT(n)=DT(n)+CTTS(n)CT_{(n)} = DT_{(n)} + CTTS{(n)}

其中,DT(n)DT_{(n)}是sample n 的解碼時間,通過Decoding Time to Sample Box計算獲得,CTTS(n)CTTS_{(n)}是sampe n在表中的entry,CT(n)CT_{(n)}即爲sample n的顯示時間。

對於完成GOP的映射表示例如下:
在這裏插入圖片描述
對1080.mp4文件,使用MP4 Reader查看’ctts’如下:
在這裏插入圖片描述
定義:

aligned(8) class CompositionOffsetBox extends FullBox(‘ctts’, version, 0) {
    unsigned int(32) entry_count; // entry數
    int i;
    if (version==0) {
        for (i=0; i < entry_count; i++) {
            unsigned int(32) sample_count;
            unsigned int(32) sample_offset; // 不同版本 偏移量的類型不同
        }
    } else if (version == 1) {
        for (i=0; i < entry_count; i++) {
            unsigned int(32) sample_count;
            signed int(32) sample_offset;
        }
    }
}

Sample To Chunk Box :‘stsc’

Box類型:‘stsc’

容器: Sample Table Box (‘stbl’)

是否強制:是

數量: 1個

媒體數據中的sample被分組爲一個個chunk,一個chunk可以包含多個sample。 chunk可以具有不同的大小,並且chunk內的sample可以具有不同的大小。

Sample To Chunk Box中有一個table,該table可用於查找包含樣本的塊,其位置以及關聯的sample信息。

每個entry都給出具有相同特徵的一組chunk的第一個chunk的索引,和這些具有相同特徵的chunk中每個包含幾個sample。

定義:

aligned(8) class SampleToChunkBox extends FullBox(‘stsc’, version = 0, 0) {
    unsigned int(32) entry_count; // 表中 entry的數量
    for (i=1; i <= entry_count; i++) {
        unsigned int(32) first_chunk; 
        unsigned int(32) samples_per_chunk; // 每個chunk中的sample數量
        unsigned int(32) sample_description_index;
    }
}
  • first_chunk:當前chunk組中,第一個chunk的index。該chunk組中,每個chunk都相同的samples‐per‐chunk和 sample‐description‐index 信息。在一個track中,的第一個chunk的index值爲1(該Box的第一個記錄中的first_chunk字段的值爲1,表示第一個sample映射到第一個chunk)。
  • sample_description_index:一個整數,它給出了描述此塊中樣本的樣本條目的索引。 index的範圍從1到Sample Description Box中的樣本條目數。

對1080.mp4文件,使用MP4 Reader查看’stsc’如下:
在這裏插入圖片描述

Sample Size Boxes :‘stsz’ & 'stz2 ’

Box類型:‘stsz’ 、 'stz2 ’

容器: Sample Table Box (‘stbl’)

是否強制:是

數量: 1個

Sample Size Boxes給出了sample的總數,以及一張關於sample大小的表。該表顯示了sample和sample size的映射關係。

Sample Size Boxes有兩個版本:

第一個版本固定大小爲32-bit的字段,用於顯示每個sample的大小。該版本允許track中所有的sample擁有恆定的大小。

第二個版本允許更小的字段,一邊在不同大小事節約空間。第一個版本是最佳兼容性的選擇。

定義:

aligned(8) class SampleSizeBox extends FullBox(‘stsz’, version = 0, 0) {
    unsigned int(32) sample_size; // 固定大小字段
    unsigned int(32) sample_count; // 總的sample數
    if (sample_size==0) { // 如果使用了固定大小的版本,沒必要爲每個sample指定大小了。
        for (i=1; i <= sample_count; i++) {
      	  unsigned int(32) entry_size; // 如果沒有使用固定大小的版本,爲每個sample指定大小。
        }
    }
}

對1080.mp4文件,使用MP4 Reader查看’stsz’如下:
在這裏插入圖片描述

Chunk Offset Box : ‘stco’ & ‘co64’

Box類型:‘stco’ 、 ‘co64’

容器: Sample Table Box (‘stbl’)

是否強制:是

數量: 1個

Chunk Offset Box 包含一個chunk的偏移表,將每個chunk的索引提供給包含文件。 有兩種版本,允許使用32位或64位偏移。 後者在管理非常大的演示文稿時非常有用。 這些變體中的至多一個將出現在樣本表的任何單個實例中。如果Box類型是’stco’ ,則是32位, 'co64’爲64位。

偏移是文件偏移,而不是文件中任何Box(例如Media Data Box)的偏移。 這允許在沒有任何Box結構的文件中引用媒體數據。 它還意味着在構建一個自包含的ISO文件時必須小心,因爲Movie Box的大小會影響媒體數據的塊偏移。

定義:

aligned(8) class ChunkOffsetBox extends FullBox(‘stco’, version = 0, 0) {
    unsigned int(32) entry_count; // 表中entry的數量
    for (i=1; i <= entry_count; i++) {
    	unsigned int(32) chunk_offset;
    }
}
aligned(8) class ChunkLargeOffsetBox extends FullBox(‘co64’, version = 0, 0) {
    unsigned int(32) entry_count;
    for (i=1; i <= entry_count; i++) {
    	unsigned int(64) chunk_offset;
    }
}
  • chunk_offset :是一個32位或64位整數,它表示當前chunk在媒體文件中的起始偏移量。

對1080.mp4文件,使用MP4 Reader查看’stco’如下:
在這裏插入圖片描述

附:MP4文件結構列表

Box類型 必須 描述
ftyp file type and compatibility
pdin progressive download information
moov container for all the metadata
mvhd movie header, overall declarations
trak container for an individual track or stream
tkhd track header, overall information about the track
tref track reference container
edts edit list container
elst an edit list
mdia container for the media information in a track
mdhd media header, overall information about the media
hdlr handler, declares the media (handler) type
minf media information container
vmhd video media header, overall information (video track only)
smhd sound media header, overall information (sound track only)
hmhd hint media header, overall information (hint track only)
nmhd Null media header, overall information (some tracks only)
dinf data information box, container
dref data reference box, declares source(s) of media data in track
stbl sample table box, container for the time/space map
stsd sample descriptions (codec types, initialization etc.)
stts (decoding) time-to-sample
ctts (composition) time to sample
stsc sample-to-chunk, partial data-offsetinformation
stsz sample sizes (framing)
stz2 compact sample sizes (framing)
stco chunk offset, partial data-offset information
co64 64-bit chunk offset
stss sync sample table (random access points)
stsh shadow sync sample table
padb sample padding bits
stdp sample degradation priority
sdtp independent and disposable samples
sbgp sample-to-group
sgpd sample group description
subs sub-sample information
mvex movie extends box
mehd movie extends header box
trex track extends defaults
ipmc IPMP Control Box
moof movie fragment
mfhd movie fragment header
traf track fragment
tfhd track fragment header
trun track fragment run
sdtp independent and disposable samples
sbgp sample-to-group
subs sub-sample information
mfra movie fragment random access
tfra track fragment random access
mfro movie fragment random access offset
mdat media data container
free free space
skip free space
udta user-data
cprt copyright etc.
meta metadata
hdlr handler, declares the metadata (handler) type
dinf data information box, container
dref data reference box, declares source(s) of metadata items
ipmc IPMP Control Box
iloc item location
ipro item protection
sinf protection scheme information box
frma original format box
imif IPMP Information box
schm scheme type box
schi scheme information box
iinf item information
xml XML container
bxml binary XML container
pitm primary item reference
fiin file delivery item information
paen partition entry
fpar file partition
fecr FEC reservoir
segr file delivery session group
gitn group id to name
tsel track selection
meco additional metadata container
mere metabox relation
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章