视频文件格式解析之 3GP与MP4
流行的文件格式背后都有大公司的支持。FLV得益于ADOBE公司推動(dòng)的網(wǎng)絡(luò)視頻分享風(fēng)潮,而AVI則是MICROSOFT首創(chuàng)的RIFF即視頻和音頻交 織在一起同步播放。 3GP/MP4是APPLE提出并得到ISO標(biāo)準(zhǔn)支持作為NOKIA等手機(jī)的默認(rèn)視頻格式。3GP是MP4格式在手機(jī)上的簡(jiǎn)化版。MP4的codec組合 一般是mpeg4 + AAC, 3GP則按版本演進(jìn)分為3gpp r5(h.263/mpeg4 + AMR-NB/AMR WB), 3gpp r6(增加h.264視頻和aacPlus音頻支持)。
有人會(huì)把MP4和MPEG4搞混, 前者是文件容器(container),后者是視頻編碼格式, 容器的作用是把壓縮編碼
后的視頻和音頻數(shù)據(jù)盡可能緊湊的排布,就好像阿甘的巧克力盒子,你并不知道盒子里有什么, 但你可以按照
既定的線索解開(kāi)文件,取出你需要的數(shù)據(jù)。
文件格式一般包括以下三要素:
header: 標(biāo)記文件類(lèi)型,音視頻碼流的基本屬性信息
index:??? 索引表,每個(gè)frame有對(duì)應(yīng)的offset,size,timestamp.
stream: 真正的音視頻流數(shù)據(jù)。
任何文件格式都應(yīng)該有以上3要素。 當(dāng)然AVI視頻沒(méi)有索引也能播放,但不能拖放seek,需要自己重建索引。解
析器(demuxer)根據(jù)frame_id找到其在文件中的offset和size,然后讀取出來(lái)解碼并播放。
2. 文件格式分析
下面來(lái)分析一下3GP/MP4文件格式。APPLE的格式有2個(gè)特點(diǎn),1. 排布緊湊幾乎沒(méi)有冗余數(shù)據(jù)(AVI則有很多junk
數(shù)據(jù)),2.音視頻碼流數(shù)據(jù)可隨意存放而不需按時(shí)間順序排布。
3gp文件由一系列的box(atom)組成。每個(gè)box的結(jié)構(gòu)都是4字節(jié)的size,4字節(jié)的type, 還有一些data數(shù)據(jù)。用
mp4info查看3gp文件的數(shù)據(jù)排布如下圖:
如上圖, ftyp是表示文件的版本信息, mdat存放文字,音視頻等數(shù)據(jù)。你可能要問(wèn),這些音視頻數(shù)據(jù)怎么找
到呢? 是通過(guò)moov box里的子box trak,里面存放著音視頻的屬性描述以及每個(gè)sample的索引。
3. 關(guān)于sample atoms
?? video和audio的碼流屬性(如視頻width/height,codec id, 音頻采樣率聲道數(shù)等)存放在stsd box里; 下面
著重介紹MP4高效壓縮的精華:stts,stss,stsc,stsz,stco五個(gè)box。對(duì)比AVI的索引表是每個(gè)sample都有對(duì)應(yīng)的
id,flag,offset,size,3GP的高效索引方式可以把AVI轉(zhuǎn)碼成同碼率的MP4后,文件size減小成原來(lái)的20-30%!
1. stts atom(time to sample atoms,見(jiàn)quicktime format 文檔圖2-28 標(biāo)準(zhǔn)文檔點(diǎn)擊下載): 存儲(chǔ)了sample
的時(shí)間信息。stts能讓很方便的根據(jù)timestamp找到對(duì)應(yīng)的sample,或者獲取某個(gè)sample對(duì)應(yīng)的timestamp. stts
table記錄著有相同duration的sample的數(shù)量count和時(shí)長(zhǎng)dutation。
2. stss atom(sync sample atom,見(jiàn)文檔圖2-31): 存儲(chǔ)了每個(gè)關(guān)鍵幀的sample id。 stss能讓你很方便的找到
當(dāng)前幀最近的關(guān)鍵幀。
3. stsc atom(sample to chunk atom): sample存放在chunk里為了允許優(yōu)化的數(shù)據(jù)讀取。比如音頻sample size
都很小(amr-nb sample size為32字節(jié)), 每次讀取一個(gè)sample開(kāi)銷(xiāo)太大, 可一次性讀所在chunk里一堆
sample。
4. stsz atom(sample size atom): stsz可以描述每個(gè)sample的size.
5. stco atom(chunk offset atoms): stco描述了每個(gè)chunk在文件中的絕對(duì)偏移位置。該offset可以是32位的
也可以是64位的,后者用來(lái)支持處理超大文件。
4 .使用sample atoms來(lái)處理播放流程
- 查找sample????????
1.確定時(shí)間,相對(duì)于媒體時(shí)間坐標(biāo)系統(tǒng)
2.檢查time-to-sample atom來(lái)確定給定時(shí)間的sample序號(hào)。
3.檢查sample-to-chunk atom來(lái)發(fā)現(xiàn)對(duì)應(yīng)該sample的chunk。
4.從chunk offset atom中提取該trunk的偏移量。
5.利用sample size atom找到sample在trunk內(nèi)的偏移量和sample的大小。
例如,如果要找第1秒的視頻數(shù)據(jù),過(guò)程如下:
1. 第1秒的視頻數(shù)據(jù)相對(duì)于此電影的時(shí)間為600
2. 檢查time-to-sample atom,得出每個(gè)sample的duration是40,從而得出需要尋找第600/40 = 15 + 1 = 16個(gè)sample
3. 檢查sample-to-chunk atom,得到該sample屬于第5個(gè)chunk的第一個(gè)sample,該chunk共有4個(gè)sample
4. 檢查chunk offset atom找到第5個(gè)trunk的偏移量是20472
5. 由于第16個(gè)sample是第5個(gè)trunk的第一個(gè)sample,所以不用檢查sample size atom,trunk的偏移量即是該sample的偏移量20472。如果是這個(gè)trunk的第二個(gè)sample,則從sample size atom中找到該trunk的前一個(gè)sample的大小,然后加上偏移量即可得到實(shí)際位置。
6. 得到位置后,即可取出相應(yīng)數(shù)據(jù)進(jìn)行解碼,播放
- ????? 查找關(guān)鍵幀?????
查找過(guò)程與查找sample的過(guò)程非常類(lèi)似,只是需要利用sync sample atom來(lái)確定key frame的sample序號(hào)
確定給定時(shí)間的sample序號(hào)
檢查sync sample atom來(lái)發(fā)現(xiàn)這個(gè)sample序號(hào)之后的key frame
檢查sample-to-chunk atom來(lái)發(fā)現(xiàn)對(duì)應(yīng)該sample的chunk
從chunk offset atom中提取該trunk的偏移量
利用sample size atom找到sample在trunk內(nèi)的偏移量和sample的大小
5 .3GP/MP4相關(guān)資源
開(kāi)源的3GP/MP4解析器: ffmpeg, GPAC, helix, google opencore等
--------------------------------------------------
MP4文件格式的解析,以及MP4文件的分割算法
mp4應(yīng)該算是一種比較復(fù)雜的媒體格式了,起源于QuickTime。以前研究的時(shí)候就花了一番的功夫,尤其是如何把它完美的融入到視頻點(diǎn)播應(yīng)用中,更是費(fèi)盡了心思,主要問(wèn)題是處理mp4文件龐大的“媒體頭”。當(dāng)然,流媒體點(diǎn)播也可以采用flv格式來(lái)做,flv也可以封裝H.264視頻數(shù)據(jù)的,不過(guò)Adobe卻不推薦這么做,人家說(shuō)畢竟mp4才是H.264最佳的存儲(chǔ)格式嘛。
這幾天整理并重構(gòu)了一下mp4文件的解析程序,融合了分解與合并的程序,以前是c語(yǔ)言寫(xiě)的,應(yīng)用在linux上運(yùn)行的服務(wù)器程序上,現(xiàn)在改成c++,方便我在其他項(xiàng)目中使用它,至于用不用移植一份c#的,暫時(shí)用不到,等有必要了再說(shuō)吧。這篇文章先簡(jiǎn)單介紹一下mp4文件的大體結(jié)構(gòu),以及它的分割算法,之后再寫(xiě)文章介紹如何把mp4完美應(yīng)用在點(diǎn)播項(xiàng)目中。
?
一、MP4格式分析 ? ? ? ? ? ? ? ? ?
MP4(MPEG-4 Part 14)是一種常見(jiàn)的多媒體容器格式,它是在“ISO/IEC 14496-14”標(biāo)準(zhǔn)文件中定義的,屬于MPEG-4的一部分,是“ISO/IEC 14496-12(MPEG-4 Part 12 ISO base media file format)”標(biāo)準(zhǔn)中所定義的媒體格式的一種實(shí)現(xiàn),后者定義了一種通用的媒體文件結(jié)構(gòu)標(biāo)準(zhǔn)。MP4是一種描述較為全面的容器格式,被認(rèn)為可以在其中嵌入任何形式的數(shù)據(jù),各種編碼的視頻、音頻等都不在話下,不過(guò)我們常見(jiàn)的大部分的MP4文件存放的AVC(H.264)或MPEG-4(Part 2)編碼的視頻和AAC編碼的音頻。MP4格式的官方文件后綴名是“.mp4”,還有其他的以mp4為基礎(chǔ)進(jìn)行的擴(kuò)展或者是縮水版本的格式,包括:M4V, ?3GP,F4V等。
mp4是由一個(gè)個(gè)“box”組成的,大box中存放小box,一級(jí)嵌套一級(jí)來(lái)存放媒體信息。box的基本結(jié)構(gòu)是:
??
其中,size指明了整個(gè)box所占用的大小,包括header部分。如果box很大(例如存放具體視頻數(shù)據(jù)的mdat box),超過(guò)了uint32的最大數(shù)值,size就被設(shè)置為1,并用接下來(lái)的8位uint64來(lái)存放大小。
一個(gè)mp4文件有可能包含非常多的box,在很大程度上增加了解析的復(fù)雜性,這個(gè)網(wǎng)頁(yè)上http://mp4ra.org/atoms.html記錄了一些當(dāng)前注冊(cè)過(guò)的box類(lèi)型??吹竭@么多box,如果要全部支持,一個(gè)個(gè)解析,怕是頭都要爆了。還好,大部分mp4文件沒(méi)有那么多的box類(lèi)型,下圖就是一個(gè)簡(jiǎn)化了的,常見(jiàn)的mp4文件結(jié)構(gòu):
??
一般來(lái)說(shuō),解析媒體文件,最關(guān)心的部分是視頻文件的寬高、時(shí)長(zhǎng)、碼率、編碼格式、幀列表、關(guān)鍵幀列表,以及所對(duì)應(yīng)的時(shí)戳和在文件中的位置,這些信息,在mp4中,是以特定的算法分開(kāi)存放在stbl box下屬的幾個(gè)box中的,需要解析stbl下面所有的box,來(lái)還原媒體信息。下表是對(duì)于以上幾個(gè)重要的box存放信息的說(shuō)明:
看吧,要獲取到mp4文件的幀列表,還挺不容易的,需要一層層解析,然后綜合stts stsc stsz stss stco等這幾個(gè)box的信息,才能還原出幀列表,每一幀的時(shí)戳和偏移量。而且,你要照顧可能出現(xiàn)或者可能不出現(xiàn)的那些box。。。可以看的出來(lái),mp4把幀sample進(jìn)行了分組,也就是chunk,需要間接的通過(guò)chunk來(lái)描述幀,這樣做的理由是可以壓縮存儲(chǔ)空間,縮小媒體信息所占用的文件大小。這里面,stsc box的解析相對(duì)來(lái)說(shuō)比較復(fù)雜,它用了一種巧妙的方式來(lái)說(shuō)明sample和chunk的映射關(guān)系,特別介紹一下。
這是stsc box的結(jié)構(gòu),前幾項(xiàng)的意義就不解釋了,可以看到stsc box里每個(gè)entry結(jié)構(gòu)體都存有三項(xiàng)數(shù)據(jù),它們的意思是:“從first_chunk這個(gè)chunk序號(hào)開(kāi)始,每個(gè)chunk都有samples_per_chunk個(gè)數(shù)的sample,而且每個(gè)sample都可以通過(guò)sample_description_index這個(gè)索引,在stsd box中找到描述信息”。也就是說(shuō),每個(gè)entry結(jié)構(gòu)體描述的是一組chunk,它們有相同的特點(diǎn),那就是每個(gè)chunk包含samples_per_chunk個(gè)sample,好,那你要問(wèn),這組相同特點(diǎn)的chunk有多少個(gè)?請(qǐng)通過(guò)下一個(gè)entry結(jié)構(gòu)體來(lái)推算,用下一個(gè)entry的first_chunk減去本次的first_chunk,就得到了這組chunk的個(gè)數(shù)。最后一個(gè)entry結(jié)構(gòu)體則表明從該first_chunk到最后一個(gè)chunk,每個(gè)chunk都有sampls_per_chunk個(gè)sample。很拗口吧,不過(guò),就是這個(gè)意思:)。由于這種算法無(wú)法得知文件所有chunk的個(gè)數(shù),所以你必須借助于stco或co64。直接上代碼可能會(huì)清楚些:
1. 首先直接分析entry
2. 然后,通過(guò)stco或co64獲知chunk總個(gè)數(shù)之后,開(kāi)始還原映射表
讀出stsc之后,就可以綜合stbl下的所有box,推算出視頻和音頻幀列表,時(shí)戳和偏移量等數(shù)據(jù)。下面截圖展示獲取到的關(guān)鍵幀列表:
? ? ?
有了關(guān)鍵幀列表之后,就可以繼續(xù)我們一下個(gè)題目,就是mp4文件的分割。實(shí)現(xiàn)mp4的分割,是把mp4應(yīng)用到點(diǎn)播系統(tǒng)中最關(guān)鍵的技術(shù)環(huán)節(jié),做不到這個(gè),就無(wú)法實(shí)現(xiàn)點(diǎn)播播放mp4影片的“拖動(dòng)”。
??
二、MP4文件的分割算法
所謂“分割”,就是把大文件切成小文件,要實(shí)現(xiàn)mp4的分割,
- 首先,需要獲取到關(guān)鍵幀列表
- 然后,選擇要分割的時(shí)間段(比如從關(guān)鍵幀開(kāi)始)
- 接著,重新生成moov box(注意所有相關(guān)的box 以及 box size都需要改變)
- 最后,拷貝對(duì)應(yīng)的數(shù)據(jù),生成新文件
第一點(diǎn),上面已經(jīng)介紹了,第二點(diǎn),只需要遍歷關(guān)鍵幀列表,就能找到離你想要分割的時(shí)間段最接近的關(guān)鍵幀,第四點(diǎn)就是“copy-paste”的工作,關(guān)鍵在于第三點(diǎn)。因?yàn)檫@一步涉及到stbl下的所有box,必須重新生成entrys,同樣的,其他的box都還好,只需要保留關(guān)鍵幀所對(duì)應(yīng)的sample和chunk,其余的刪掉即可,只是stsc box的比較麻煩,說(shuō)起來(lái)比較啰嗦,還是直接看代碼吧:
修改完box之后,需要重新生成moov box,由于moov box的大小以及時(shí)長(zhǎng)等信息都發(fā)生了改變,所以需要box的大小做相應(yīng)的修改,這點(diǎn)千萬(wàn)不能忘記,否則播放器會(huì)解析錯(cuò)誤。重新生成box之后,還要計(jì)算一下分割后的數(shù)據(jù)的長(zhǎng)度,由于數(shù)據(jù)長(zhǎng)度也發(fā)生了改變,所以修改mdat box的大小的同時(shí),要同時(shí)修改stbl下所有box的chunk offset,切記!
以下是整個(gè)的邏輯過(guò)程:
好了,所有這些都實(shí)現(xiàn)之后,就具備了做mp4點(diǎn)播系統(tǒng)的條件了。不過(guò),要做mp4點(diǎn)播,還有一些其他的問(wèn)題需要解決,我將在下一篇文章中介紹。
總結(jié)
以上是生活随笔為你收集整理的视频文件格式解析之 3GP与MP4的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: MySQL高级--个人笔记
- 下一篇: 时钟编程c语言,用c语言怎么实现时钟程序