Firefox OS 的 MP4 container 簡介
前言:
MP4 是目前最常見的影音格式之一,在這篇文章中,我們主要在介紹 container 的格式,以及 MP4 在 Firefox OS 中的現況跟常見問題。
MP4 的 container 格式主要是定義在 ISO/IEC 14496-12 [1] 中,從最早期的 Apple Quicktime format,一路延伸到後來的 MP4、3GPP, 以及 3GPP2 等等 [2]。
而 MP4 container 裡面最小的組成單位,稱之為 Box,每種 Box 都封裝不同的 information;以下是一般常見的 MP4 container 簡略:
|- FileTypeBox |- MovieBox | |---- TrackBox (Audio) | | |---- TrackHeaderBox | | |---- MediaBox | | |---- SampleTableBox | | |---- SampleDescriptionBox | | |---- TimeToSampleBox | | | |---- TrackBox (Video) | |---- TrackHeaderBox | |---- MediaBox | |---- SampleTableBox | |---- SampleDescriptionBox | |---- TimeToSampleBox | |- MediaDataBox Audio elementary stream Video elementary stream
FileTypeBox 是描述這個 MP4 所宣稱支援的 brand,例如「MP42」 指的就是這個 MP4 所使用的 Box 都是在 ISO14496-14 規範中。
一般播放影音用的 MP4 通常會有 Audio Track 以及 Video Track 兩種, 而 TrackBox 則是描述這個 Track 的資訊。例如 TrackHeaderBox (Video) 中,會有下面的資料:
CreationTime="3473061925" - Video錄製的時間 ModificationTime="3473061925" - Video修改的時間 TrackID="1" - Video的TrackID Duration="1667" - Video的長度 Width="320.00" - Video 寬度 Height="240.00" - Video 高度
而 MP4 播放器就可以根據這些資訊來決定播放時的大小以及 timeline 長短。
MediaBox 最主要是包含了 SampleTableBox, SampleTableBox 可以說是所有的 Box 中最重要的一個,包含了 codec 的詳細資訊以及整個影片或聲音在這個 MP4 中的結構。
SampleTableBox 主要是包含了兩大 Boxes:
1. SampleDescriptionBox
針對不同的 Codec 會有不同資料,例如 H264 的話會有一個 AVCSampleEntryBox 來描述這個MP4所使用的 H264 特性, profile…等等。 而 AAC 的話,會有一個 MPEGAudioSampleDescriptionBox 來描述所使用的 AAC 資料例如 SampleRate、Bitrate…等等。
2. TimeToSampleBox
這個 Box 主要是用來 random seeking 時所使用,裡面包含的每個 sample 所對應的播出時間;播放器可以根據時間來換算出特定時間需要跳到MP4 中的 sample 位置。以下是從 nexus-4 所錄製出來的 Video TimeToSampleBox 一部分:
最後的 MediaDataBox,則是非常單純的把 Audio 或是 Video 直接寫入在這個 Box 中,不帶任何資訊。播放器應該解碼出哪個位置的 sample,完全依靠 MovieBox 中的資訊來決定;因此,相對於 MPEG1/2 中 所有 sample 都帶有 timestamp 的特性,MP4 的這種特性也有人稱為 nonframing [3]。
在這邊可以舉一個例子,在 Bug 932204中 [4],會出現 A/V 不同步的問題。由於 Video/Audio 所在的的 MediaDataBox 不帶任何 timestamp 相關資料,因此我們就大膽假設可能出現問題的點是在 TimeToSampleBox 中。藉著 MP4Box [5],我們 dump 出在 TimeToSampleBox 的結構如下:
124221737" SampleCount="1"/>
第一個 TimeToSampleEntry 的欄位大到十分不合邏輯,由此推斷出可能是原始變數未歸零的結果。
Firefox OS 內的 MP4 container 格式
在 FireFox OS 中,由於 MediaRecorder API [6] 的特性,在實際錄影時,無法預先知道整個 Video 或是 Audio 的播放長度。因此在 Bug 891704 中,我們實作了另一種格式的 MP4,稱為 fragmented MP4。
以下是 fragmented MP4 的組成 Box 簡介:
|- FileTypeBox |- MovieBox | |---- TrackBox (Audio) | | |---- TrackHeaderBox | | |---- MediaBox | | |---- SampleTableBox | | |---- SampleDescriptionBox | | |---- TimeToSampleBox | |---- TrackBox (Video) | |---- TrackHeaderBox | |---- MediaBox | |---- SampleTableBox | |---- SampleDescriptionBox | |---- TimeToSampleBox | |- MovieFragmentBox (Fragment 0) | |---- MovieFragmentHeaderBox | |---- TrackFragmentBox (Audio) | |---- TrackFragmentBox (Video) |- MediaDataBox | Audio elementary stream | Video elementary stream | |- MovieFragmentBox (Fragment 1) | |---- MovieFragmentHeaderBox | |---- TrackFragmentBox (Audio) | |---- TrackFragmentBox (Video) |- MediaDataBox | Audio elementary stream | Video elementary stream | |- MovieFragmentBox (Fragment 2) | |---- MovieFragmentHeaderBox | |---- TrackFragmentBox (Audio) | |---- TrackFragmentBox (Video) |- MediaDataBox Audio elementary stream Video elementary stream ...
在 MovieBox 的組成上,除了 TimeToSampleBox 的內容是空的之外,基本上和之前介紹的是一樣的 (因為這時還沒完成錄影,無法預先知道長度)。
再來最大的不同就是組成 fragment 的 MovieFragmentBox 了;基本上 fragment 的原理很簡單,就是將本來完整的一個大 table,打散成各個小 table 散佈在檔案中;換句話說,如果目前 fragment 的時間長度是兩秒,那就累積兩秒鐘的資料,並將這兩秒的時間資訊以及影音資料寫入一個 fragment 中;由此類推,每兩秒鐘寫一個 fragment 直到錄影結束。
以下詳細介紹 fragment 的組成 Box。
MovieFragmentBox,主要是包含 MovieFragmentHeaderBox 以及 TrackFragmentBox。
MovieFragmentHeaderBox 則是記錄目前 fragment 的數目。
TrackFragmentBox 則是扮演之前 SampleTableBox 的腳色,不過在 spec。中規範了好幾種形態,這邊介紹其中一種:frame duration 與 Size 的對映,以下是 Video 的範例:
在這邊,每個 video frame 的播放長度約 2999 ~ 3002,而後面的 Size 就是指這張 video frame 的實際大小。由這些資料,就可以算出各個 video frame 播放的時間與解碼時所需找出的檔案位置。
而在 FireFox OS 中,Bug 891704 已經 landed。而相關的 Audio/Video encoder 也在 Bug 879668 中,陸陸續續的即將 landed,在不久的將來,就可以使用 MediaRecorder API 來作 H264/AAC 的錄影了。
常用工具:
1. MP4Box,之前已經有提過,是一套功能強大的工具,除了能解析 MP4 之外,還可以在 fragment 與 nonfragment 之間作轉換,或是將某個 track 個別抽取出來。
2. MP4V2 [7],跟 MP4Box 很相像,可以解析出一個 MP4 的結構,或是抽取出特定的 Track 資料。
[1] http://www.iso.org/iso/home/store/catalogue_ics/catalogue_detail_ics.htm?csnumber=61988
[2] http://en.wikipedia.org/wiki/ISO_base_media_file_format
[4] https://bugzilla.mozilla.org/show_bug.cgi?id=932204#c21
[5] http://es.wikipedia.org/wiki/MP4Box
[6] https://dvcs.w3.org/hg/dap/raw-file/tip/media-stream-capture/MediaRecorder.html
[7] http://code.google.com/p/mp4v2/