前言:做完了手機(jī)全能播放器的項(xiàng)目, 又要告別幾個(gè)月來(lái)并肩作戰(zhàn),即將去北京發(fā)展的Manager zhu。準(zhǔn)備把做過(guò)的3GP/FLV/AVI格式整理一遍, 算是對(duì)幾個(gè)月辛苦成果的總結(jié), 也為后來(lái)者提供一些參考。
1. 概述
流行的文件格式背后都有大公司的支持。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. sttstable記錄著有相同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)資源
quicktime file format specification: 最權(quán)威的格式文檔 點(diǎn)擊下載
開(kāi)源的3GP/MP4解析器: ffmpeg, GPAC, helix, google opencore等