媒體文件格式分析之FMP4

媒體文件格式分析之FMP4

MP4 中最基本的單元就是Box,它內(nèi)部是通過一個(gè)一個(gè)獨(dú)立的Box拼接而成的罢绽。所以,這里,我們先從 Box 的講解開始,每個(gè) Box 是由 Header 和 Data 組成的寓调,F(xiàn)ullBox 是 Box 的擴(kuò)展,Box 結(jié)構(gòu)的基礎(chǔ)上在 Header 中增加 8bits version 和 24bits flags

1. 名詞解釋

2. 最小單元Box

2.1 常見的mp4文件結(jié)構(gòu)(簡(jiǎn)化版)

normal_box_file.jpg

3. Mp4文件整體結(jié)構(gòu)

這里锄码,我們按照 MP4 box 的劃分來進(jìn)行相關(guān)的闡述夺英。先看一張 MP4 給出的結(jié)構(gòu)圖:

box_structure.png

一般來說,解析媒體文件滋捶,最關(guān)心的部分是視頻文件的寬高痛悯、時(shí)長(zhǎng)、碼率重窟、編碼格式载萌、幀列表、關(guān)鍵幀列表巡扇,以及所對(duì)應(yīng)的時(shí)戳和在文件中的位置扭仁,這些信息,在mp4中厅翔,是以特定的算法分開存放在stbl box下屬的幾個(gè)box中的乖坠,需要解析stbl下面所有的box,來還原媒體信息刀闷。下表是對(duì)于以上幾個(gè)重要的box存放信息的說明

majorbox.jpg

3.1 File Type Box (ftyp)

通常放在MP4文件的開頭瓤帚,告訴解碼器基本的解碼版本和兼容格式描姚。

  • 基本格式如下:
aligned(8) class FileTypeBox
   extends Box(‘ftyp’) {
   unsigned int(32)  major_brand;
   unsigned int(32)  minor_version;
   unsigned int(32) compatible_brands[];
}
  • 字段說明:
字段 長(zhǎng)度 說明 默認(rèn)值
major_brand 4 推薦兼容性的版本 iso6
minor_version 4 最低兼容性的版本 1
compatible_brands 列表值 所有的兼容性的版本 'iso6' 'isom' 'dash'
  • Nginx模塊實(shí)現(xiàn)
ngx_int_t
ngx_rtmp_mp4_write_ftyp(ngx_buf_t *b)
{
    u_char  *pos;

    pos = ngx_rtmp_mp4_start_box(b, "ftyp");

    /* major brand */
    ngx_rtmp_mp4_box(b, "iso6");

    /* minor version */
    ngx_rtmp_mp4_field_32(b, 1);

    /* compatible brands */
    ngx_rtmp_mp4_box(b, "isom");
    ngx_rtmp_mp4_box(b, "iso6");
    ngx_rtmp_mp4_box(b, "dash");

    ngx_rtmp_mp4_update_box_size(b, pos);

    return NGX_OK;
}

3.2 Movie Box (moov)

作為容器盒子,存放相關(guān)的trak及meta信息.

  • 基本格式如下:
aligned(8) class MovieExtendsBox extends Box(‘mvex’){ }

3.2.1 Movie Header Box (mvhd)

mvhd 是 moov 下的第一個(gè) box戈次,用來描述 media 的相關(guān)信息:

  • 基本格式如下:
aligned(8) class MovieHeaderBox extends FullBox(‘mvhd’, 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;
    }
    
    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;
}
  • 字段說明:
字段 長(zhǎng)度 說明 默認(rèn)值
version 4 版本 0 or 1s
creation_time 4 創(chuàng)建的UTC時(shí)間轩勘。從1904年開始算起, 用秒來表示
modification_time 4 最后一次修改時(shí)間
timescale 4 文件媒體在1秒時(shí)間內(nèi)的刻度值,可以理解為1秒長(zhǎng)度的時(shí)間單元數(shù)
duration 4 該track的時(shí)間長(zhǎng)度怯邪,用duration和time scale值可以計(jì)算track時(shí)長(zhǎng)s 實(shí)際時(shí)間為:duration/timescale = xx 秒
rate 4 推薦播放速率 0x00010000
volume 2 音量大小 0x0100 為最大值
reserved 10 保留字段 0
matrixs 4 * 9 視頻變換矩陣 {0x00010000,0,0,0,0x0001s0000,0,0,0,0x40000000}
next_track_ID 4 下一個(gè)track使用的id號(hào)
  • Nginx模塊實(shí)現(xiàn)
static ngx_int_t
ngx_rtmp_mp4_write_mvhd(ngx_buf_t *b)
{
    u_char  *pos;

    pos = ngx_rtmp_mp4_start_box(b, "mvhd");

    /* version */
    ngx_rtmp_mp4_field_32(b, 0);

    /* creation time */
    ngx_rtmp_mp4_field_32(b, 0);

    /* modification time */
    ngx_rtmp_mp4_field_32(b, 0);

    /* timescale */
    ngx_rtmp_mp4_field_32(b, 1000);

    /* duration */
    ngx_rtmp_mp4_field_32(b, 0);

    /* reserved */
    ngx_rtmp_mp4_field_32(b, 0x00010000);
    ngx_rtmp_mp4_field_16(b, 0x0100);
    ngx_rtmp_mp4_field_16(b, 0);
    ngx_rtmp_mp4_field_32(b, 0);
    ngx_rtmp_mp4_field_32(b, 0);

    ngx_rtmp_mp4_write_matrix(b, 1, 0, 0, 1, 0, 0);

    /* reserved */
    ngx_rtmp_mp4_field_32(b, 0);
    ngx_rtmp_mp4_field_32(b, 0);
    ngx_rtmp_mp4_field_32(b, 0);
    ngx_rtmp_mp4_field_32(b, 0);
    ngx_rtmp_mp4_field_32(b, 0);
    ngx_rtmp_mp4_field_32(b, 0);

    /* next track id */
    ngx_rtmp_mp4_field_32(b, 1);

    ngx_rtmp_mp4_update_box_size(b, pos);

    return NGX_OK;
}

3.2.2 Movie Extends Box (mvex)(fMP4專有)

mvex 是 fMP4 的標(biāo)準(zhǔn)盒子绊寻。它的作用是告訴解碼器這是一個(gè)fMP4的文件,具體的 samples 信息內(nèi)容不再放到 trak 里面悬秉,而是在每一個(gè) moof 中澄步。基本格式為:


aligned(8) class MovieExtendsHeaderBox extends FullBox(‘mehd’, version, 0) { if (version==1) {
      unsigned int(64)  fragment_duration;
   } else { // version==0
      unsigned int(32)  fragment_duration;
   }
}

3.2.2.1 Track Extends Box (trex)(fMP4專有)

trex 是 mvex 的子一級(jí) box 用來給 fMP4 的 sample 設(shè)置默認(rèn)值和泌〈甯祝基本內(nèi)容為

aligned(8) class TrackExtendsBox extends FullBox(‘trex’, 0, 0){ 
    unsigned int(32) track_ID;
    unsigned int(32) default_sample_description_index;
    unsigned int(32) default_sample_duration;
    unsigned int(32) default_sample_size;
    unsigned int(32) default_sample_flags 
}

3.2.3 Track Box (trak)

trak box 就是主要存放相關(guān) media stream 的內(nèi)容。

3.2.3.1 Track Header Box (tkhd)

tkhd 是 trak box 的子一級(jí) box 的內(nèi)容武氓。主要是用來描述該特定 trak 的相關(guān)內(nèi)容信息梯皿。其主要內(nèi)容為:

  • 基本格式如下:

aligned(8) 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;
}

  • 字段說明:
字段 長(zhǎng)度 說明 默認(rèn)值
version 4 版本
creation_time 4 創(chuàng)建時(shí)間,非必須 0
modification_time 4 修改時(shí)間县恕,非必須 0
track_ID 4 指明當(dāng)前描述的 track ID 1
reserved 4 保留 0
duration 4 當(dāng)前 track 內(nèi)容持續(xù)的時(shí)間东羹。通常結(jié)合 timescale 進(jìn)行相關(guān)計(jì)算 0
reserved 12 保留字段 0
reserved 2 保留字段 0
alternate_group 2 保留字段 0
volume 2 保留字段 if track_is_audio 0x0100 else 0
reserved 2 保留字段 0
matrix 9 * 4 matrix b, 1, 0, 0, 1, 0, 0 , width , height
3.2.3.2 Media Box (media)

mdia 主要用來包裹相關(guān)的 media 信息。

(1) Media Header Box (mdhd)
  • 基本格式如下:
aligned(8) 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 language code unsigned int(16) pre_defined = 0;
}

  • 字段說明:
字段 長(zhǎng)度 說明 默認(rèn)值
version 4 版本
creation_time 4 創(chuàng)建時(shí)間忠烛,非必須 0
modification_time 4 修改時(shí)間属提,非必須 0
timescale 4 文件媒體在1秒時(shí)間內(nèi)的刻度值,可以理解為1秒長(zhǎng)度的時(shí)間單元數(shù)
duration 4 當(dāng)前 track 內(nèi)容持續(xù)的時(shí)間美尸。通常結(jié)合 timescale 進(jìn)行相關(guān)計(jì)算 0
lanuage 4s 表明當(dāng)前 trak 的語言冤议。因?yàn)樵撟侄慰傞L(zhǎng)為 15bit,通常是和 pad 組合成為 2B 的長(zhǎng)度师坎。 -
(2) Handler Reference Box(hdlr)
  • 基本格式如下:

aligned(8) 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;
}

  • 字段說明:
字段 長(zhǎng)度 說明 默認(rèn)值
version 4 版本
pre_defined 4 版本 0
handler_type 4 是代指具體 trak 的處理類型 0
reserved 4 * 3 reserved 0
data string reserved "VideoHandler" or "SoundHandler"
  • handler_type 類型如下:
    vide : Video track
    soun : Audio track
    hint : Hint track
    meta : Timed Metadata track
    auxv : Auxiliary Video track

3.2.3.3 Media Information Box (minf)

minf 是子屬內(nèi)容中求类,重要的容器 box,用來存放當(dāng)前 track 的基本描述信息屹耐。

(1) Video Media Header Box(vmhd)
  • 基本格式如下:
aligned(8) class VideoMediaHeaderBox
extends FullBox(‘vmhd’, version = 0, 1) {
template unsigned int(16) graphicsmode = 0; // copy, see below 
template unsigned int(16)[3] opcolor = {0, 0, 0};
}
(2) Sound Media Header Box(smhd)
  • 基本格式如下:
aligned(8) class SoundMediaHeaderBox
   extends FullBox(‘smhd’, version = 0, 0) {
   template int(16) balance = 0;
   const unsigned int(16)  reserved = 0;
}

(3) Data Information Box(dinf)

dinf 是用來說明在 trak 中尸疆,media 描述信息的位置。其實(shí)本身就是一個(gè)容器惶岭,沒啥內(nèi)容:

  • 基本格式如下:
aligned(8) class SoundMediaHeaderBox
   extends FullBox(‘smhd’, version = 0, 0) {
   template int(16) balance = 0;
   const unsigned int(16)  reserved = 0;
}

(4) Data Reference Box(dref)

dref 是用來設(shè)置當(dāng)前Box描述信息的 data_entry寿弱。

  • 基本格式如下:
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; }
    }

  • 字段說明:
字段 長(zhǎng)度 說明 默認(rèn)值
version 4 版本 0
entry_count 4 入口數(shù) 1
entry_version 4 入口數(shù) 0
entry_flags 3 入口數(shù) 0

3.3 Moof Box

3.4 Sidxs Box

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市按灶,隨后出現(xiàn)的幾起案子症革,更是在濱河造成了極大的恐慌,老刑警劉巖鸯旁,帶你破解...
    沈念sama閱讀 218,858評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件噪矛,死亡現(xiàn)場(chǎng)離奇詭異量蕊,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)艇挨,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,372評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門残炮,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人缩滨,你說我怎么就攤上這事势就。” “怎么了脉漏?”我有些...
    開封第一講書人閱讀 165,282評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵苞冯,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我侧巨,道長(zhǎng)舅锄,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,842評(píng)論 1 295
  • 正文 為了忘掉前任司忱,我火速辦了婚禮皇忿,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘烘贴。我一直安慰自己,他們只是感情好撮胧,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,857評(píng)論 6 392
  • 文/花漫 我一把揭開白布桨踪。 她就那樣靜靜地躺著,像睡著了一般芹啥。 火紅的嫁衣襯著肌膚如雪锻离。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,679評(píng)論 1 305
  • 那天墓怀,我揣著相機(jī)與錄音汽纠,去河邊找鬼。 笑死傀履,一個(gè)胖子當(dāng)著我的面吹牛虱朵,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播钓账,決...
    沈念sama閱讀 40,406評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼碴犬,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了梆暮?” 一聲冷哼從身側(cè)響起服协,我...
    開封第一講書人閱讀 39,311評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎啦粹,沒想到半個(gè)月后偿荷,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體窘游,經(jīng)...
    沈念sama閱讀 45,767評(píng)論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,945評(píng)論 3 336
  • 正文 我和宋清朗相戀三年跳纳,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了忍饰。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,090評(píng)論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡棒旗,死狀恐怖喘批,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情铣揉,我是刑警寧澤饶深,帶...
    沈念sama閱讀 35,785評(píng)論 5 346
  • 正文 年R本政府宣布,位于F島的核電站逛拱,受9級(jí)特大地震影響敌厘,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜朽合,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,420評(píng)論 3 331
  • 文/蒙蒙 一俱两、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧曹步,春花似錦宪彩、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,988評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至筹麸,卻和暖如春活合,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背物赶。 一陣腳步聲響...
    開封第一講書人閱讀 33,101評(píng)論 1 271
  • 我被黑心中介騙來泰國(guó)打工白指, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人酵紫。 一個(gè)月前我還...
    沈念sama閱讀 48,298評(píng)論 3 372
  • 正文 我出身青樓告嘲,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親奖地。 傳聞我的和親對(duì)象是個(gè)殘疾皇子状蜗,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,033評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容

  • 目錄 概述 mp4文件基本信息 封裝格式重要概念 重要box介紹 其他box介紹 實(shí)用技術(shù) 開源軟件 參考 [1]...
    smallest_one閱讀 60,608評(píng)論 5 61
  • 譯者注:這里面的內(nèi)容主要是分析mp4/3gp文件的層級(jí)結(jié)構(gòu),詳細(xì)的介紹了各種不同的box的結(jié)構(gòu)等鹉动,網(wǎng)上有一些參考資...
    HaloMartin閱讀 2,661評(píng)論 0 2
  • 今天上午課比較多轧坎,等我回到辦公室,打開手機(jī)一看泽示,發(fā)現(xiàn)有好幾個(gè)未接來電缸血,其中有幾個(gè)是我們的校長(zhǎng)打過來的蜜氨。(為了不耽誤...
    茌平張曉芬閱讀 473評(píng)論 0 2