MP4のデータ構造

## mp4の構成要素

MP4ファイルはBoxとよばれる要素の木構造で構成されている。このBoxはMP4を構成する要素の中で最小単位であり、Atomと呼ばれる。子をもつBoxはContainer boxとも呼ばれる。ちなみにもともとQTFFの方でAtomと呼ばれていて、QTFFを元にMP4が作られたのでそのまま名残でMP4でもAtomと呼ばれているようです。

mp4のBoxは必ずftypeと呼ばれるものから始まり、それ以外のBoxの並び順は、VODで配信する場合はどのような並び順でもOK。だがLODで配信する場合は最初にメタデータを読み込んでから実際のデータを処理する必要があるので、先にmoovという、メタデータが記録されたBox(後述)をロードする必要がある。

## Boxの基本構造

- HeaderとData部分で構成される。
- 先頭のオクテット(8Byte)がボックスを識別するためのHeaderになっている。
  - オクテットの中でも、最初の４ByteがBoxSize、最後の4ByteがそのType(BoxType)になる。
  - このBoxTypeの部分に、`ftype`, `pdin`, `moov`などのBox固有のIDがASCII文字列で入る。
- Data部については、HeaderのBoxSizeにBox全体のサイズが入っているのでHeaderの終わりからBoxSizeて定義されている位置までがBoxDataになる。
  - Headerのサイズは8Byteなので`BoxSize - 8Byte = DataSize`となる。

ISO/IECでのBox構造定義

```
aligned(8) class Box (unsigned int(32) box type, 
                      optional unsigned int(8)[16] extended_type) {
    unsigned int(32) size;
    unsigned int(32) type = boxtype;
    if (size == 1) {
        unsigned int(64) largesize;
    } else if (size == 0) {
        // box extends to end of file
    }
    if (boxtype == 'uuid') {
        unsigned int(8)[16] usertype = extended_type;
    }
}
```

以下にmp4のBox一覧を列挙してみる。rootのBoxについてはこれで全部ですが、子要素のBoxは以下に記載しているもの以外にもたくさんあります。ちなみに、特にmoov内のstblがキモになってくる。

```
sample.mp4
  ├ ftyp
  ├ pdin
  ├ moov
  │   ├ mvhd
  │   ├ trak(movie)
  │   │   ├ tkhd
  │   │   ├ tref
  │   │   ├ edts
  │   │   |  └ elst
  │   │   └ mdia 
  │   │      ├ mdhd
  │   │      └ minf(Media Information Box)
  │   │         └ stbl
  │   │            └ stco
  │   ├ trak(audio)
  │   │   └ ...trak(movie)のchildrenと一緒
  │   ├ trak(hint)
  │   ├ mvex(extended box)
  │   └ ipmc(hint)
  ├ moof
  │   ├ mfhd
  │   └ traf
  ├ mfra
  ├ mdat
  ├ free(free space)
  ├ skip(free space)
  │   └ udta(user data)
  └ meta
```

以下にファイルのrootに配置されるボックスについて書いてみる。

### ftype(File type)

ファイルがどのtypeに準拠しているかを表す。Boxの並び順としては一番最初に配置されている必要がある。

構造

```
aligned(8) class FileTypeBox
 extends Box(‘ftyp’) {
 unsigned int(32) major_brand;
 unsigned int(32) minor_version;
 unsigned int(32) compatible_brands[]; // to end of the box
} 
```

ftype一覧: http://www.ftyps.com/

`minor_version`は`major_brand`のマイナーバージョンを定義するみたいですが、ほぼ活用されないようなので全部0で埋めても問題ないケースが多いようです。
`compatible_brands`は互換性がある`major_brand`を列挙できるみたいですが、こちらも必須ではないようで、空白でもいけるようです。

### moov

moovボックスの中には動画のメタデータが定義されていて、その配下にtrak、mvhdボックスなどのボックスが入れ子になっている。
動画・音声のメディアデータをそれぞれ1trakとし、「movieのtrak」「audioのtrak」というように複数のtrakが同じ階層に配置される。
DRMを扱う場合は、複合の際に使うPSSHなどといったデータもこのボックスに格納される。

trakでは、動画・音声データがどのように配置されているかを記録していて、再生する際はこのtrakの情報を元にメディアデータをシークする。そのため、LODではmoovボックスが最初に読み込まれる必要がある。

そしてtrak配下のmdhdではトラックのメタデータや再生時間などを定義している。

## mdat(Media data box)

メディアデータを格納するBoxで、動画・音声両方を格納できる。
mdatをデコードするには、moov -> trak -> mdia -> minf -> stbl配下のメタデータをパースする必要がある。このstbleを読み解くために、他の諸々のBox定義も理解しないといけなくてなかなか難しいらしい。

## ユーザー定義Box

記事上部に記載したBox構造を見てみると、Boxではオプショナルで`extended_type`というものが定義できる。

ユーザー定義のBoxを使うときはBoxTypeには`uuid`を指定し、extended_typeではユーザが任意に作成した16Byteのuuidを格納する。するとBoxDataでは自由なデータを指定することができ、ユーザー定義Boxとして使うことができる。

## Full Box

FullBoxの定義

```
aligned(8) class FullBox(unsigned int(32) boxtype, unsigned int(8) v, bit(24) f)
 extends Box(boxtype) {
 unsigned int(8) version = v;
 bit(24) flags = f;
} 
```

FullBoxとは、Boxを拡張してversionとflagフィールドをヘッダーに持てるようにしたもの。実際に扱われるのはFull Boxが多かったりする。

## 参考文献

- ISO/IEC
14496-12 - https://standards.iso.org/ittf/PubliclyAvailableStandards/c041828_ISO_IEC_14496-12_2005%28E%29.zip
- unoh.github.com by unoh - https://unoh.github.io/2007/09/12/mp43gpp3gpp2.html