简介
MP4视频文件封装格式是基于QuickTime容器格式定义的,因此参考QuickTime的格式定义对理解MP4文件格式很有帮助。MP4文件格式是一个十分开放的容器,几乎可以用来描述所有的媒体结构,MP4文件中的媒体描述与媒体数据是分开的,并且媒体数据的组织也很自由,不一定要按照时间顺序排列,甚至媒体数据可以直接引用其他文件。同时,MP4也支持流媒体。MP4目前被广泛用于封装h.264视频和AAC音频,是高清视频的代表。
格式概述
MP4文件中的所有数据都装在box(QuickTime中为atom)中,也就是说MP4文件由若干个box组成,每个box有类型和长度,可以将box理解为一个数据对象块。box中可以包含另一个box,这种box称为container box。一个MP4文件首先会有且只有一个“ftyp”类型的box,作为MP4格式的标志并包含关于文件的一些信息;之后会有且只有一个“moov”类型的box(Movie Box),它是一种container box,子box包含了媒体的metadata信息;MP4文件的媒体数据包含在“mdat”类型的box(Midia Data Box)中,该类型的box也是container box,可以有多个,也可以没有(当媒体数据全部引用其他文件时),媒体数据的结构由metadata进行描述。
Box
首先需要说明的是,box中的字节序为网络字节序,也就是大端字节序(Big-Endian),简单的说,就是一个32位的4字节整数存储方式为高位字节在内存的低端。Box由header和body组成,其中header统一指明box的大小和类型,body根据类型有不同的意义和格式。
标准的box开头的4个字节(32位)为box size,该大小包括box header和box body整个box的大小,这样我们就可以在文件中定位各个box。如果size为1,则表示这个box的大小为large size,真正的size值要在largesize域上得到。(实际上只有“mdat”类型的box才有可能用到large size。)如果size为0,表示该box为文件的最后一个box,文件结尾即为该box结尾。(同样只存在于“mdat”类型的box中。)
size后面紧跟的32位为box type,一般是4个字符,如“ftyp”、“moov”等,这些box type都是已经预定义好的,分别表示固定的意义。如果是“uuid”,表示该box为用户扩展类型。如果box type是未定义的,应该将其忽略。
Base Box{
BoxHead{
box_size 4byte;
box_type 4byte;
};
BoxBody
};
接下来我们看看真正的Box
ftyp box(file type box)
该box有且只有1个,并且只能被包含在文件层,而不能被其他box包含。该box应该被放在文件的最开始,指示该MP4文件应用的相关信息。
"ftyp" body依次包括1个32位的major brand(4个字符),1个32位的minor version(整数)和1个以32位(4个字符)为单位元素的数组compatible brands。这些都是用来指示文件应用级别的信息。该box的字节实例如下:
struct mov_ftyp_t
{
uint32_t major_brand;
uint32_t minor_version;
uint32_t compatible_brands[N_BRAND];
size_t brands_count;
};
moov box(movie box)
该box包含了文件媒体的metadata信息,moov是一个container box,具体内容信息由子box诠释。同File Type Box一样,该box有且只有一个,且只被包含在文件层。一般情况下,moov会紧随ftyp出现。
一般情况下(限于篇幅,本文只讲解常见的MP4文件结构),moov中会包含1个mvhd和若干个trak。其中mvhd为header box,一般作为moov的第一个子box出现(对于其他container box来说,header box都应作为首个子box出现)。trak包含了一个track的相关信息,是一个container box。下图为部分moov的字节实例,其中红色部分为box header,绿色为mvhd,黄色为一部分trak。
mvhd(movie header box)
字段 | 字节数 | 说明 |
---|---|---|
box size | 4 | box 的大小 |
box type | 4 | box 的类型 |
version | 1 | box 的版本,0或则1,一般为0。一下的字节数均按照version=0设置 |
flag | 3 | |
creation time | 4 | 创建时间,相对于UTC时间(1904-01-01零点的秒数) |
modification time | 4 | 修改时间 |
time scale | 4 | 文件媒体在1秒内的时间刻度,即把1秒划分成多少个小的时间片) |
duration | 4 | 该track的时间长度,用duration和time sacle值可以计算出track的时长; 比如audio track的time scale = 8000,duration=560128,则时长为70.016; video track的time scale=600,duration=42000,时长为70。 |
rate | 4 | 推荐播放速率,高16位和低16位分别为小数点整数部分和小数部分,即[16.16]。 如1.0会表示成0x00010000,表示正常向前播放。 |
volume | 2 | 与rate类似,[8.8] 格式,1.0(0x0100)表示最大音量 |
reserved | 10 | 保留位 |
matrix | 36 | 视频变换矩阵 |
pre-defined | 24 | |
next track id | 4 | 下一个track的id号 |
mvhd的字节实例如下图,各字段已经用颜色区分开:
数据结构的定义
struct mov_mvhd_t
{
// FullBox
uint32_t version : 8;
uint32_t flags : 24;
uint32_t timescale; // time-scale for the entire presentation, the number of time units that pass in one second
uint64_t duration; // default UINT64_MAX(by timescale)
uint64_t creation_time; // seconds sine midnight, Jan. 1, 1904, UTC
uint64_t modification_time; // seconds sine midnight, Jan. 1, 1904, UTC
uint32_t rate;
uint16_t volume; // fixed point 8.8 number, 1.0 (0x0100) is full volume
//uint16_t reserved;
//uint32_t reserved2[2];
int32_t matrix[9]; // u,v,w
//int32_t pre_defined[6];
uint32_t next_track_ID;
};
trak(track box)
trak也是一个container box,其子box包含了该track的媒体数据引用和描述(hint track除外)。一个MP4文件中的媒体可以包含多个track,且至少有一个track,这些track之间彼此独立,有自己的时间和空间信息。trak必须包含一个tkhd和一个mdia,此外还有很多可选的box(略)。其中tkhd为track header box,mdia为media box,该box是一个包含一些track媒体数据信息box的container box。
trak的部分字节实例如下图,其中黄色为trak box的头,绿色为tkhd,蓝色为edts(一个可选box),红色为一部分mdia。
tkhd(track header box)
tkhd结构如下表。
字段 | 字节数 | 意义 |
---|---|---|
box size | 4 | box大小 |
box type | 4 | box类型 |
version | 1 | box版本,0或1,一般为0。(以下字节数均按version=0) |
flags | 3 | 按位或操作结果值,预定义如下: 0x000001 track_enabled,否则该track不被播放; 0x000002 track_in_movie,表示该track在播放中被引用; 0x000004 track_in_preview,表示该track在预览时被引用。 一般该值为7,如果一个媒体所有track均未设置track_in_movie和track_in_preview, 将被理解为所有track均设置了这两项;对于hint track,该值为0 |
creation time | 4 | 创建时间(相对于UTC时间1904-01-01零点的秒数) |
modification time | 4 | 修改时间 |
track id | 4 | id号,不能重复且不能为0 |
reserved | 4 | 保留位 |
duration | 4 | track的时间长度 |
reserved | 8 | 保留位 |
layer | 2 | 视频层,默认为0,值小的在上层 |
alternate group | 2 | track分组信息,默认为0表示该track未与其他track有群组关系 |
volume | 2 | [8.8] 格式,如果为音频track,1.0(0x0100)表示最大音量;否则为0 |
reserved | 2 | 保留位 |
matrix | 36 | 视频变换矩阵 |
width | 4 | 宽 |
height | 4 | 高 |
mdia(Media Box)
mdia也是个container box,其子box的结构和种类还是比较复杂的。先来看一个mdia的实例结构树图。
mdhd(media header box)
结构如下表:
字段 | 字节数 | 意义 |
---|---|---|
box size | 4 | box大小 |
box type | 4 | box类型 |
version | 1 | box版本,0或1,一般为0。(以下字节数均按version=0) |
flags | 3 | |
creation time | 4 | 创建时间(相对于UTC时间1904-01-01零点的秒数) |
modification time | 4 | 修改时间 |
time scale | 4 | 文件媒体在1秒内的时间刻度,即把1秒划分成多少个小的时间片) |
duration | 4 | 该track的时间长度,用duration和time sacle值可以计算出track的时长; 比如audio track的time scale = 8000,duration=560128,则时长为70.016; video track的time scale=600,duration=42000,时长为70。 |
language | 2 | 媒体语言码。最高位为0,后面15位为3个字符(见ISO 639-2/T标准中定义) |
pre-defined | 2 |
字段 | 字节数 | 意义 |
---|---|---|
box size | 4 | box大小 |
box type | 4 | box类型 |
version | 1 | box版本,0或1,一般为0。(以下字节数均按version=0) |
flags | 3 | |
pre-defined | 4 | |
handler type | 4 | 在media box中,该值为4个字符: vide— video track soun— audio track hint— hint track |
reserved | 12 | |
name | 不定 | track type name,以‘0’结尾的字符串 |
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。