Firefox OS 的 MP4 container 簡介

作者:
瀏覽:350

前言:

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

[3] http://books.google.com.tw/books?id=ftRvA08WcM4C&pg=PA254&lpg=PA254&dq=MP4+nonframing&source=bl&ots=lXcgAVJnJz&sig=Ente5auFzX0NDO0ZESq0vI7hrE0&hl=zh-TW&sa=X&ei=mD_dUtO1NcnlkgXdnoGoBA&ved=0CDEQ6AEwAA#v=onepage&q=MP4%20nonframing&f=false

[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/