多媒体文件格式之MP4

[时间:2016-06] [状态:Open]

学习多媒体容器格式的目的

主要是为了回答以下问题:

  1. 该容器中数据是如何组织的?
  2. 该容器包含哪些编码格式的数据?这些数据是如何存储的?
  3. 该容器包含哪些元数据信息?包含哪些节目信息?
  4. 对于支持多节目的容器格式,如何找到对应的音频流、视频流、字幕流?
  5. 如何确定该容器的节目播放时长?
  6. 如何从该容器中提取音频、视频、字幕数据,并交给解码器解码,有时间戳否?
  7. 该容器是否支持seek?有哪些辅助信息?
  8. 是否支持直接流化?
  9. 哪里可以找到该容器格式最标准的文档资料?
  10. 有哪些可用的工具,方便分析容器格式异常或者错误?

1. MP4文件内部结构

MP4文件是有多个box嵌套构成的,所有数据都必须保存在box中,而且必须包含一个File Type box。

box的定义

其基本存储结构box(或者atom),其定义如下:

==========
BoxHeader
----------
BoxData
==========

其中BoxHeader定义如下:

Field name Type Size(bits)
box size uint32 32
box type uint32 32
largesize uint64 0/64
usertype uint8[16] 0/128

其中box size为1时,表示largesize域存在,size为0时,表示该box持续到文件结尾;box长度是64位无符号整数。当box type是"uuid"时,usertype域存在,表示自定义的box。
在解析时,可以忽略所有无法识别的box。
还有一种FullBox,作为Box的扩展,仅在header中添加了以下两个字段:

Field name Type Size(bits)
boxHeader - -
version uint8 8
flag uint24 24

在解析时可以忽略所有无法识别的version。

MP4顶部视图

MP4文件的整体结构如下:

|表1 MP4 file structure|
|---|--|--|
|ftyp| -|file type and compatbility|
|pdin|-|progressive download info|
|moov|-|container for all the metadata|
|-|mvhd|movie header, overall declarations|
|-|meta| metadata|
|-|trak| container for an individual track or stream|
|-|mvex|movie extends box|
|moof|-|movie fragement|
|-|mfhd|movie fragement header|
|-|meta| metadata|
|-|traf| track fragement|
|mfra|-|movie fragement random access|
|-|tfra|track fragment random access|
|-|mfro|movie fragment random access offset|
|mdat|-|movie data container|
|free|-|free space|
|skip|-|free space|
|-|udta|user-data|
|meta|-|metadata|
|-|hdlr|handler, declares the metadata(handler) type|
|-|dinf|data infomation box, container|
|-|iloc|item location|
|-|ipro| item protection|
|-|iinf|item inforamtion|
|-|xml|XML container|
|-|bxml| binary XML container|
|-|pitm|primary item reference|
|-|fiin|file delivery item information|
|-|idat|item data|
|-|iref|item reference|
|meco|-|additional metadata container|
|-|mere|metabox relation|
|styp|-|segment type|
|sidx|-|segment index|
|ssix|-|subsegment index|
|prft|-|producer reference time|

Box是可以相互嵌套的。上面表格中加黑的box类型是比较常见的,需要重点关注下。这个表中也仅给出了box的第二层嵌套关系。更详细的建议参考标准文档的6.2节。
从表1中可以看出movie数据是存储在mdat box中,但是如何解析这个box需要参考moov box。
接下来的部分也主要是与moov box解析有关。

2. Movie Structure('moov' box)

Movie Box在mp4文件中有且仅有一个。

Movie Header Box

Movie Header Box包含在Movie Structure Box中,通常包含媒体无关的信息,比如说播放时长、创建时间等。它是FullBox("mvhd")
其结构定义如下:

Field name Type Size(bits)
FullBoxHeader - -
creation time uint32/uint64 32/64
modify time uint32/uint64 32/64
timescale uint32 32
duration uint32/uint64 32/64
rate uint32 32
volume uint16 16
reserved uint8 80
matrix uint32[9] 9*32
pre_defined uint32[6] 6*32
next_track_ID uint32 32

对于version为1时,上面表格中选择数据类型为uint64,对于version为0时,选择类型为uint32。
这里解释下,timescale表示单位时间内的精度,即1秒内经过的时间单位计数;举个例子,正常的时间系统里以毫秒为单位,timescale就是1000。
duration中记录的是最长的track的播放长度。rate是16.16的格式,表示优先选择的播放速度,比如ox00010000表示1.0的播放速度。volume是浮点数的8.8的格式,表示优先选择的播放音量,0x0100表示1.0的音量大小。next_track_ID主要用于添加新的track,通常会大约当前文件最大track-ID。

Track Structure('trak' box)

一个mp4文件至少包含一个media trak box,不同的Track box是相互独立的。每个track box都携带独立的时域空域信息,同时包含相关的media box。track box有两种:media track和hint track,前者用于保存media相关信息,后者包含用于流媒体的打包信息。
track box包含的sub-box如下:

|'trak' box|
|---|---|---|
|tkhd|---|track header, overall info about the track|
|tref|---|track reference container|
|trgr|---|track grouping indication|
|edts|---|edit list container|
|---|elst|an edit list|
|meta|---|metadata
|mdia|---|container for the media info in a track|
|---|mdhd|media header,overall info about the media|
|---|hdlr|handler,说明媒体类型|
|---|elng|extended language tag|
|---|minf|media info container|
|---|udat|user-data|

.1 track header box('tkhd')

这里边有一个字段,track_ID,用于唯一的表示当前track。
另一个字段,duration,用于记录当前track的播放长度。

.2 track media box('mdia')

track media box包含用于声明当前track信息的所有对象。以下sub-box需要关注:

  • handler box('hdlr')
    可获取track类型信息,主要是有字段handler_type(uint32_t)区分,具体含义如下:
    • 'vide' Video track
    • 'soun' Audio track
    • 'hint' Hint track

.3 media infomation box ('minf')

先看看media infomation box的构成,如下表:

|minf|
|---|---|---|
|vmhd|---|video media header(video track only)|
|smhd|---|audio media header(audio track only)|
|hmhd|---|hint media header(hint track only)|
|sthd|---|subtitle media header(subtitle track only)|
|nmhd|---|null media header(some tracks only)|
|dinf|---|data info box, container|
|---|dref|data reference box, declare source of media data|
|stbl|---|sample table box, container for time/space map|
|---|stsd|sample descriptions(codec types, initialization etc.)|
|---|stts|decoding time-to-sample|
|---|ctts|composition time-to-sample|
|---|cslg|composition to decode timeline mapping|
|---|stsc|sample-to-chunk, partial data-offset info|
|---|stsz|sample sizes(framing)|
|---|stz2|compact sample sizes(framing)|
|---|stco|chunk offset, partial data-offset info|
|---|co64|64-bit chunk offset|
|---|stss|sync sample table|
|---|stsh|shadow sync sample table|
|---|padb|sample padding bits|
|---|stdp|sample degradation priority|
|---|sdtp|independent and disposable samples|
|---|sbgp|sample-to-group|
|---|sgpd|sample group description|
|---|subs|sub-sample information|
|---|saiz|sample auxiliary information sizes|
|---|saio|sample auxiliary information offsets|

'minf' box中的header box是根据'hdlr' box中媒体类型一致的,只能出现一个。

.4 Sample Tables('stbl')

可以说stbl box是mp4中最复杂,包含媒体信息最多的box。主要包含时间和media samples的数据映射表,使用这部分数据可以按照时间检索sample的位置、类型、大小、实际偏移位置。

  • sample description box ('stsd')
    主要描述当前track有关的编码信息,以及用于初始化解码的附加信息。
  • Time to Sample box('stts' 'ctts')
    比较常见的'stts' box,decoding time to sample,通过这个box可以实现时间到sample number的映射。
  • sync sample box('stss')
    这个box提供了可以用于同步的sample索引号,并严格按照sample number递增顺序排列。如果不存在这个box,表示所有sample都是可以用于同步。对视频而言,sync sample通常指的关键帧。
  • sample size box('stsz' 'stz2')
    这个box记录每个sample的大小。'stsz' box存储格式如下:
Filed name type Size(bits)
FullBox Header --- ---
sample_size uint32 32
sample_count uint32 32
entry_size uint32[] varies

sample_size中表示sample长度,如果是0表示每个sample长度不定,会记录在entry_size中;否则每个sample长度一样,并且entry_size域不存在。
'stz2' box中的entry_size是compact的,长度由特定字段指定。

  • sample to chunk box('stsc')
    'stsc' box中记录了每个chunk中包含多少sample,其结构定义如下:
Filed name type Size(bits)
FullBox Header --- ---
entry_cout uint32 32
chunk_entry uint32[3] varies

chunk_entry包含三个字段:
first_chunk: uint32
samples_per_chunk: uint32
sample_description_index: uint32

每个entry表示从first_chunk开始的每个chunk都包含samples_per_chunk个samples,这些sample都可以用使用sample_description_index信息解码。

通过这个box,可以构建出当前track的chunk结构,及其包含的sample。

  • chunk offset box('stco' 'co64')
    这个box记录了chunk对应的offset,只是包含字段一个是32为('stco'),一个是64位('co64')。
    chunk offset box中记录都是相对文件的偏移量,可以直接通过这些信息读取。

Track Structure小结

由于'mdat' box中的多媒体数据是没有结构的,只能参考moov的trak box解析。反过头来。我们看一下针对单个track中的media信息存储应该是下面的结构:
|chunk #0| chunk#1| ... | chunk #n|
每个chunk的构成是下面的结构:
|sample #0|sample #1| ... | sample #n|
从trak box中的minf中可以看出,每个chunk的长度不定,其所包含的sample数目不同,每个sample的长度也不完全相同。

3. mp4中的节目信息有哪些? 如何获取?

每个'trak' box表示一个media,其类型记录在stsd中,对于视频,其中包括我们最关心的宽高信息、编码器,保存在VisualSampleEntry;对于音频,其中也包括采样率、声道数、编码方式等,这些信息保存在AudioSampleEntry或AudioSampleEntryV1中。

对于单节目的mp4文件,不需要选择流。从标准上来看'tkhd'中有一个字段alternate_group,估计这个是表示选择节目的一个标志。

4. 如何实现seek?

第2部分介绍moov的结构时,里面有很多信息是跟seek相关的,比如time-sample映射。那么为了实现seek到指定时间,在mp4中需要做如下工作:

  1. 使用timescale将目标时间标准化。
  2. 通过time-to-sample box找到指定track的给定时间之前的第一个sample number。
  3. 通过sync sample table查询sample number之前的第一个sync sample。
  4. 通过sample-to-chunk table查找到对应的chunk number。
  5. 通过chunk offset box查找到对应chunk在文件中的起始偏移量。
  6. 最后使用sample-to-chunk box和sample size box的信息计算出该chunk中需要读取的sample数据,即完成seek。

当然标准中还有关于edit list box的使用,这里多数情况下不涉及,所以不做额外介绍。

5. 其他问题

这里解释下上面没有涉及的问题。

该容器包含哪些元数据信息?包含哪些节目信息?

MP4中包含'meta' box,从中可以解析出需要的metadata,具体建议参考标准。

是否支持直接流化?

mp4支持流化,直接通过特定协议及hint track完成。后续会有介绍。

哪里可以找到该容器格式最标准的文档资料?

标准文档的全称是"ISO/IEC 14496-12:ISO base media file format"(c068960_ISO_IEC_14496-12_2015)。
我是从ISO.org的以下地址下载:http://www.iso.org/iso/home/store/catalogue_ics/catalogue_detail_ics.htm?csnumber=61988。

有哪些可用的工具,方便分析容器格式异常或者错误?

比较经典的工具是mp4info或者elecard streameye,但是如果对mp4熟悉了的话,直接二进制查看还是不错的。

总结

本文主要是关于mp4文件解析的介绍,是我第一次深入的了解mp4文件格式,虽然可用的测试文件不是很多,但是足够理解文件结构了。
本文内容主要作为我个人后续分析mp4文件的参考。

参考资料

  1. "ISO/IEC 14496-12:ISO base media file format"(c068960_ISO_IEC_14496-12_2015)。
  2. MP4文件格式解析
  3. http://blog.chinaunix.net/uid-20758197-id-5056943.html
posted @ 2016-07-23 14:04  Tocy  阅读(8769)  评论(1编辑  收藏  举报