Asterisk播放mp4(5)——MP4文件解析

Asterisk 現(xiàn)有版本不支持播放視頻文件(支持視頻通話)锰悼,無法滿足發(fā)送視頻通知、視頻 IVR 等場景。本系列文章砚偶,通過學(xué)習(xí)音視頻的相關(guān)知識和工具,嘗試實現(xiàn)一個通過 Asterisk 播放 mp4 視頻文件的應(yīng)用洒闸。

本文關(guān)注在MP4文件中染坯,h264aac的媒體數(shù)據(jù)是如何存放的,又如何進行訪問丘逸?為后續(xù)解析文件后单鹿,通過RTP進行發(fā)送進行準(zhǔn)備。

MP4文件格式

MP4文件封裝格式深纲,對應(yīng)的標(biāo)準(zhǔn)為ISO/IEC 14496-12仲锄,即:信息技術(shù)視聽對象編碼的第12部分:ISO 基本媒體文件格式(Information technology Coding of audio-visual objects Part 12: ISO base media file format)。MP4文件可以嵌入任何形式的數(shù)據(jù)湃鹊,不過通常存放的是AVC(H.264)編碼的視頻和AAC/MPEG-4(Part 2)編碼的音頻儒喊。

MP4文件由許多box組成,box可以嵌套币呵。box分為headerdata兩部分怀愧。header包括size(4字節(jié)),type(4字節(jié))和largesize(8字節(jié)余赢,可選)芯义。其中,size指明了整個box的大小妻柒,包括header部分扛拨。如果box很大(例如存放具體視頻數(shù)據(jù)的mdat box),超過了uint32的最大數(shù)值举塔,size就被設(shè)置為1绑警,并用接下來的8位uint64來存放大小求泰。box中的字節(jié)序為網(wǎng)絡(luò)字節(jié)序,也就是大端字節(jié)序(Big-Endian)计盒,就是一個32位的4字節(jié)整數(shù)存儲方式為高位字節(jié)在內(nèi)存的低端拜秧。

下面看看幾個主要的box

box類型 層級 名稱 說明
ftyp 1 File Type Box 有且只有1個章郁,只能被包含在文件層,而不能被其他 box 包含志衍。該 box 應(yīng)該被放在文件的最開始暖庄,指示該 MP4 文件應(yīng)用的相關(guān)信息。
moov 1 Movie Box 有且只有1個楼肪,只能被包含在文件層培廓。moov是一個container box,包含若干子box春叫,例如:mvhd肩钠,trak等,子box中存放媒體的元數(shù)據(jù)(metadata)信息暂殖。
mvhd 2 Movie Header Box 描述了媒體一些基本信息价匠,例如:timescale,duration等呛每。
trak 2 Track Box trak也是一個container box踩窖,其子box包含了該track的媒體數(shù)據(jù)引用和描述(hint track除外)。一個MP4文件中的媒體可以包含1個或多個track晨横,它們之間彼此獨立洋腮,有自己的時間和空間信息。trak至少包含tkhd和mdia這兩個box手形,此外還有很多可選的box啥供。其中tkhdtrack header boxmdiamedia box库糠,該box是一個包含一些track媒體數(shù)據(jù)信息box的container box伙狐。
mdat 1 Media Data 實際媒體數(shù)據(jù),最終解碼播放的音視頻數(shù)據(jù)都在這里面曼玩。對于h264aac編碼的媒體來說鳞骤,其視頻mdat中內(nèi)容是nal,對于音頻來說黍判,其內(nèi)容為aac的一幀豫尽。mdat中的幀依次存放,每個幀的位置顷帖、時間美旧、長度都由moov中的信息指定渤滞。
mp4 box

trak是mp4中最復(fù)雜的部分,包含了讀取媒體數(shù)據(jù)所需的各種信息榴嗅。要理解trak下的box首先要掌握幾個基本概念妄呕,包括:track,sample嗽测,trunk绪励。

  • track:表示sample的集合,對于媒體數(shù)據(jù)來說唠粥,track表示一個視頻或音頻序列疏魏。

  • sample:video sample即為一幀視頻,或一組連續(xù)視頻幀晤愧,audio sample即為一段連續(xù)的壓縮音頻大莫。

  • chunk:一個track中的幾個sample組成的單元。

trak下有很多box官份,最重要也是最復(fù)雜的是trak/mdia/minf/stbl只厘,它下面又包含了多個boxsample table指明sampe時序和存儲地址的表舅巷。利用這個表羔味,可以解析sample的時序、類型钠右、大小以及在文件中的位置介评。下面對這些box做個簡單的說明:

box類型 名稱 說明
stsd Sample Description Box 包含h264編碼的spspps∨澜ⅲ可以有一個到多個sample description们陆。
stsc Sample To Chunk Box 指定了chunksample的對應(yīng)關(guān)系。從first_chunk這個chunk序號開始情屹,每個chunk都有samples_per_chunksample坪仇,每個sample都可以通過sample_description_index這個索引,在stsd中找到描述信息垃你。
stsz Sample Size Box 指定了每個sample的大小椅文。
stco Sample Size Box 指定了每個chunk的在整個文件中的起始地址。
stss Sync Sample Box 關(guān)鍵幀惜颇。
stts DecodingTime to Sample 用于計算sampledts皆刺,其中sample_counts定義連續(xù)多少個sample的dts具有相同的差值,sample_deltadts的差值凌摄。
ctts Composition Time to Sample 每個sample的構(gòu)成時間(Composition Time)和解碼時間(DT)之間的差值羡蛾。如果不存在ctts,則代表該流不存在B幀锨亏,那么CT就直接等于DT痴怨。
幀順序及時間

上圖是ISO/IEC 14496-12規(guī)范中給出的示例忙干。第2行代表了視頻幀的存儲序列,幀后面的編號代表了顯示順序浪藻。視頻流編碼時捐迫,如果支持B幀,P幀會先于B幀編碼爱葵,因此幀編碼順序(存儲順序)和幀播放順序不一致施戴。通過這個圖我們就更容理解上面兩個和時間相關(guān)的box的含義。stts定義的是表格中的第3行萌丈,DT暇韧,用于計算出每個sampledtsctts對應(yīng)的是表格中的第6行浓瞪,Composition offset,用于計算出每個samplepts(Compostion Time)

DTS(Decode Time Stamp):標(biāo)識讀入內(nèi)存中的視頻幀什么時候開始送入解碼器中進行解碼巧婶。PTS(Presentation Time Stamp):用于度量解碼后的視頻幀什么時候被顯示出來 乾颁。這兩個值對應(yīng)的并不是秒,毫秒這些時間單位艺栈,而是時間刻度英岭,它們的值除以mdhd中的timescale(每秒鐘有多少個時間刻度)轉(zhuǎn)換為時間。

制作樣本

為了控制篇幅我們忽略音頻流湿右,只分析視頻流诅妹。

ffmpeg -t 10 -lavfi sine -t 10 -lavfi color=red sine-red-10s.mp4

FFmpeg命令行輸出 sine-red-10s.mp4
vi %!xxd sine-red-10s.mp4

mdat中存放的就是媒體數(shù)據(jù),視頻就是h264NALU毅人,我們可以將mp4中的數(shù)據(jù)和h264裸流中的數(shù)據(jù)進行對比吭狡。

ffmpeg -t 10 -lavfi color=red red-default.h264

我們直接生成h264的裸流,其中I/P/B幀的數(shù)據(jù)和生成mp4文件中的h264流的數(shù)量是一致的丈莺。

FFmpeg命令行輸出 red.h264

通過ffmpeg生成mp4文件時有很多參數(shù)可以指定划煮,faststart是比較常用的一個,其作用是將moov挪到mdat前面缔俄,這樣就可以實現(xiàn)邊下載邊播放弛秋。

ffmpeg -t 10 -lavfi sine -t 10 -lavfi color=red -movflags faststart sine-red-10s-faststart.mp4

FFmpeg輸出 sine-red-10s-faststart.mp4
sine-red-10s-faststart.mp4

mp4文件的結(jié)構(gòu)太復(fù)雜了,直接看二進制數(shù)據(jù)很費勁俐载,下面我們通過一個在線工具解析mp4數(shù)據(jù)蟹略。

ftyp
video - mdhd

后面計算時序時要用到timescaleduration這兩個參數(shù),duration / timescale = 10秒遏佣。

video - stsd

stsd/avc1/avcC中可以獲得h264spspps挖炬。另外,需要特別注意lengthSizeMinusOne這個參數(shù)状婶,其含義是用幾個字節(jié)表示nalu的長度茅茂,實際的長度是值加1捏萍,這里就是3+1=4h264裸流中空闲,分割nalu通常采用的是Annex B這種用起始碼的方式(用3字節(jié)或4字節(jié)的起始碼)令杈,但是在MP4中使用的是AVCC方式(填加字節(jié)指定nalu的大小)碴倾。

video - stsz

stsc中指明track共有250個采樣逗噩,以及每個采樣的大小。這里需要注意兩點:1跌榔、采樣的大小是NALU的實際大小加4异雁,因為前面有4字節(jié)記錄用來記錄尺寸;2僧须、采樣不一定是一個NALU纲刀,實際上第一個采樣(759)就包括了SEIIDR兩個NALU

video - stsc

stsc中定義了chunksample的對應(yīng)關(guān)系担平,以及sample的描述信息(stsd)示绊。這里第一個chunk包含了兩個sample,后面每個chunk包含一個sample暂论。

video -stco

stco中定義了chunk在文件中的地址面褐。通過stszstscstco就可以在文件中獲得任意一個sample取胎。9792是第一個chunk的偏移量展哭,第一個chunk包含2個采樣,前2個采樣的大小分別為75917闻蛀,可以計算出下一個chunk的偏移量是10568匪傍,它不等于下一個視頻chunk的偏移量10991,通過查看音頻的stco觉痛,可知音頻流的第一個chunk的偏移量是10568析恢,這說明視頻和音頻的chunk是交錯存儲的。

video - stts

stts中記錄了每個sample間相差的時間刻度512秧饮。前面的timescale的值為12800映挂,512/12800=0.04秒,說明每幀之間的解碼時間間隔為0.04秒盗尸。

video - ctts

ctts提供的是composition timedecoding time的差值柑船,它們的和就是composition time

通過解析red.h264文件的slice可以知道每幀的大小和類型泼各,這樣方便我們理解decode time

解析red.h264文件的nalu
1 視頻幀 I P B B B P B B B
2 DT(stts) 0 512 1024 1536 2048 2560 3072 3584 4096
3 Composition offset(ctts) 1024 2560 1024 0 512 2560 1024 0 512
4 CT 1024 3072 2048 1536 2560 5120 4096 3584 4608
5 seq 1 5 3 2 4 9 7 6 8
6 size 65 13 10 10 10 19 12 10 10

上表中的第1行(DT)代表的是文件中視頻幀的存儲順序鞍时,第4行(CT)代表的是視頻幀的播放時間(單位是時間刻度),第5行(seq)代表的是視頻幀的播放順序∧嫖。可以看到存儲順序和播放順序是不一致的及塘,這是因為視頻幀中包含B幀,它是雙向依賴幀锐极,解析是可能要依賴P(或B幀)笙僚,所以雖然B幀的播放順序靠前,但是解碼的時候必須要先解碼P幀灵再,才能解碼B幀肋层。另外,在avcc中一個sample的前4個字節(jié)代表這個包的大小翎迁,因此stsz中記錄的采樣大小比NALU的大小多4栋猖。

通過對比h264裸流和mp4中的視頻數(shù)據(jù),我們可以得到一致的結(jié)果汪榔,就是說mp4中的sttsctts記錄h264的解析結(jié)果蒲拉,方便了數(shù)據(jù)的直接訪問。

參考

QuickTime container 有box類型的定義

MP4文件格式解析

在線MP4解析工具

ISO/IEC 14496-12:2015 下載地址

FFmpeg formats - mov, mp4, ismv

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末痴腌,一起剝皮案震驚了整個濱河市雌团,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌衷掷,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,525評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件柿菩,死亡現(xiàn)場離奇詭異戚嗅,居然都是意外死亡,警方通過查閱死者的電腦和手機枢舶,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,203評論 3 395
  • 文/潘曉璐 我一進店門懦胞,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人凉泄,你說我怎么就攤上這事躏尉。” “怎么了后众?”我有些...
    開封第一講書人閱讀 164,862評論 0 354
  • 文/不壞的土叔 我叫張陵胀糜,是天一觀的道長。 經(jīng)常有香客問我蒂誉,道長教藻,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,728評論 1 294
  • 正文 為了忘掉前任右锨,我火速辦了婚禮括堤,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己悄窃,他們只是感情好讥电,可當(dāng)我...
    茶點故事閱讀 67,743評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著轧抗,像睡著了一般恩敌。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上鸦致,一...
    開封第一講書人閱讀 51,590評論 1 305
  • 那天潮剪,我揣著相機與錄音,去河邊找鬼分唾。 笑死抗碰,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的绽乔。 我是一名探鬼主播弧蝇,決...
    沈念sama閱讀 40,330評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼折砸!你這毒婦竟也來了看疗?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,244評論 0 276
  • 序言:老撾萬榮一對情侶失蹤睦授,失蹤者是張志新(化名)和其女友劉穎两芳,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體去枷,經(jīng)...
    沈念sama閱讀 45,693評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡怖辆,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,885評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了删顶。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片竖螃。...
    茶點故事閱讀 40,001評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖逗余,靈堂內(nèi)的尸體忽然破棺而出特咆,到底是詐尸還是另有隱情,我是刑警寧澤录粱,帶...
    沈念sama閱讀 35,723評論 5 346
  • 正文 年R本政府宣布腻格,位于F島的核電站,受9級特大地震影響啥繁,放射性物質(zhì)發(fā)生泄漏荒叶。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,343評論 3 330
  • 文/蒙蒙 一输虱、第九天 我趴在偏房一處隱蔽的房頂上張望些楣。 院中可真熱鬧,春花似錦、人聲如沸愁茁。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,919評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽鹅很。三九已至嘶居,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間促煮,已是汗流浹背邮屁。 一陣腳步聲響...
    開封第一講書人閱讀 33,042評論 1 270
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留菠齿,地道東北人佑吝。 一個月前我還...
    沈念sama閱讀 48,191評論 3 370
  • 正文 我出身青樓,卻偏偏與公主長得像绳匀,于是被迫代替她去往敵國和親芋忿。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,955評論 2 355