前言:做完了手機全能播放器的項目, 又要告別幾個月來并肩作戰,即將去北京發展的Manager zhu。準備把做過的3GP/FLV/AVI格式整理一遍, 算是對幾個月辛苦成果的總結, 也為后來者提供一些參考。
1. 概述
流行的文件格式背后都有大公司的支持。FLV得益于ADOBE公司推動的網絡視頻分享風潮,而AVI則是MICROSOFT首創的RIFF即視頻和音頻交織在一起同步播放。 3GP/MP4是APPLE提出并得到ISO標準支持作為NOKIA等手機的默認視頻格式。3GP是MP4格式在手機上的簡化版。MP4的codec組合一般是mpeg4 + AAC, 3GP則按版本演進分為3gpp r5(h.263/mpeg4 + AMR-NB/AMR WB), 3gpp r6(增加h.264視頻和aacPlus音頻支持)。
有人會把MP4和MPEG4搞混, 前者是文件容器(container),后者是視頻編碼格式, 容器的作用是把壓縮編碼后的視頻和音頻數據盡可能緊湊的排布,就好像阿甘的巧克力盒子,你并不知道盒子里有什么, 但你可以按照既定的線索解開文件,取出你需要的數據。
文件格式一般包括以下三要素:
header: 標記文件類型,音視頻碼流的基本屬性信息
index: 索引表,每個frame有對應的offset,size,timestamp.
stream: 真正的音視頻流數據。
任何文件格式都應該有以上3要素。 當然AVI視頻沒有索引也能播放,但不能拖放seek,需要自己重建索引。解析器(demuxer)根據frame_id找到其在文件中的offset和size,然后讀取出來解碼并播放。
2. 文件格式分析
下面來分析一下3GP/MP4文件格式。APPLE的格式有2個特點,1. 排布緊湊幾乎沒有冗余數據(AVI則有很多junk數據),2.音視頻碼流數據可隨意存放而不需按時間順序排布。
3gp文件由一系列的box(atom)組成。每個box的結構都是4字節的size,4字節的type, 還有一些data數據。用mp4info查看3gp文件的數據排布如下圖:

如上圖, ftyp是表示文件的版本信息, mdat存放文字,音視頻等數據。你可能要問,這些音視頻數據怎么找到呢? 是通過moov box里的子box trak,里面存放著音視頻的屬性描述以及每個sample的索引。
3. 關于sample atoms
video和audio的碼流屬性(如視頻width/height,codec id, 音頻采樣率聲道數等)存放在stsd box里; 下面著重介紹MP4高效壓縮的精華:stts,stss,stsc,stsz,stco五個box。對比AVI的索引表是每個sample都有對應的id,flag,offset,size,3GP的高效索引方式可以把AVI轉碼成同碼率的MP4后,文件size減小成原來的20-30%!
1. stts atom(time to sample atoms,見quicktime format 文檔圖2-28 標準文檔點擊下載): 存儲了sample的時間信息。stts能讓很方便的根據timestamp找到對應的sample,或者獲取某個sample對應的timestamp. sttstable記錄著有相同duration的sample的數量count和時長dutation。
2. stss atom(sync sample atom,見文檔圖2-31): 存儲了每個關鍵幀的sample id。 stss能讓你很方便的找到當前幀最近的關鍵幀。
3. stsc atom(sample to chunk atom): sample存放在chunk里為了允許優化的數據讀取。比如音頻sample size都很小(amr-nb sample size為32字節), 每次讀取一個sample開銷太大, 可一次性讀所在chunk里一堆sample。
4. stsz atom(sample size atom): stsz可以描述每個sample的size.
5. stco atom(chunk offset atoms): stco描述了每個chunk在文件中的絕對偏移位置。該offset可以是32位的
也可以是64位的,后者用來支持處理超大文件。
4 .使用sample atoms來處理播放流程
· 查找sample
1.確定時間,相對于媒體時間坐標系統
2.檢查time-to-sample atom來確定給定時間的sample序號。
3.檢查sample-to-chunk atom來發現對應該sample的chunk。
4.從chunk offset atom中提取該trunk的偏移量。
5.利用sample size atom找到sample在trunk內的偏移量和sample的大小。
例如,如果要找第1秒的視頻數據,過程如下:
1. 第1秒的視頻數據相對于此電影的時間為600
2. 檢查time-to-sample atom,得出每個sample的duration是40,從而得出需要尋找第600/40 = 15 + 1 = 16個sample
3. 檢查sample-to-chunk atom,得到該sample屬于第5個chunk的第一個sample,該chunk共有4個sample
4. 檢查chunk offset atom找到第5個trunk的偏移量是20472
5. 由于第16個sample是第5個trunk的第一個sample,所以不用檢查sample size atom,trunk的偏移量即是該sample的偏移量20472。如果是這個trunk的第二個sample,則從sample size atom中找到該trunk的前一個sample的大小,然后加上偏移量即可得到實際位置。
6. 得到位置后,即可取出相應數據進行解碼,播放
· 查找關鍵幀
查找過程與查找sample的過程非常類似,只是需要利用sync sample atom來確定key frame的sample序號
確定給定時間的sample序號
檢查sync sample atom來發現這個sample序號之后的key frame
檢查sample-to-chunk atom來發現對應該sample的chunk
從chunk offset atom中提取該trunk的偏移量
利用sample size atom找到sample在trunk內的偏移量和sample的大小
5 .3GP/MP4相關資源
quicktime file format specification: 最權威的格式文檔 點擊下載
開源的3GP/MP4解析器: ffmpeg, GPAC, helix, google opencore等