(本文基本逻辑:MP4 封装格式概览 → 重要 Box 具体信息介绍 → 实战中对 MP4 Box 信息的使用)
MP4 也称为 MPEG-4 第 14 部分,是继承 MPEG-4 第 12 部分的 ISO 基础媒体文件格式并略作扩展而来,定义于标准 ISO/IEC 14496-14 中,是一种标准的数字多媒体容器格式。
在现在互联网使用的视频中,MP4 是最常见的格式之一,尤其是短视频。如果我们要对短视频的播放体验做优化,了解 MP4 的格式是非常必要的。所以本文我们将介绍一下如下内容:
- MP4 格式概览
- File Type Box(ftyp) 介绍
- Movie Box(moov) 及其重要子 Box 的介绍
- Media Data Box(mdat) 介绍
- 实战解析案例:
- moov 和 MP4 视频的秒开:moov Box 位置对 MP4 秒开的影响。
- MP4 视频的预加载:最少加载多少数据可以渲染出 MP4 视频首帧。
1、MP4 格式概览
MP4 文件的数据都是封装在一个又一个名为 Box 的单元中。一个 MP4 文件由若干个 Box/FullBox 组成,每个 Box 包含了 Header 和 Data。FullBox 是 Box 的扩展,其包含的 Header 增加了 version(8bits) 和 flags(24bits) 部分。Header 部分包含了 size(32bits) 和 type(32bits) 部分。size 用于描述整个 Box 的长度,type 用于描述 Box 的类型。当 size 为 0 时,表示这是文件中最后一个 Box;当 size 为 1 时,表示 Box 长度需要更多 bits 来描述,这时在后面会定义一个 64bits 的 largesize 来描述 Box 的长度。当 type 是 uuid 时,代表 Box 中的数据是用户自定义扩展类型。
Box 的数据格式定义:
aligned(8) class Box (unsigned int(32) boxtype, 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;
}
}
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;
}
下图是对 Box/FullBox 结构的描述:
Box 有不同的类型,有着不同的数据结构,Box 中还可以包含其他 Box。Box 的类型详见下表(其中 *
表示当父 Box 存在时,则必须包含该 Box):
在众多类型的 Box 中,最常见的第一层级 Box 有 3 个,分别是 ftyp
、moov
、mdat
。
下面就着重介绍和分析一下这几个 Box 以及他们包含的子 Box。
2、File Type Box(ftyp) 解析
ftyp,即 File Type Box,包含文件的类型、版本、兼容信息等。在一个 MP4 文件中,该 Box 有且只有一个,并且需要尽可能放在文件最开始的位置,除非有必要的固定长度的文件签名信息 Box 可以放在该 Box 前面,其他非固定长度的 Box 数据都必须放在它后面。
ftyp 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
}
下面是一个 MP4 文件的 ftyp Box 的 16 进制示例数据:
按照上文所述,前 4 个字节 00 00 00 20
表示该 Box 的 size,即 32 字节。接着 4 个字节 66 74 79 70
是该 Box 的 type,即 ftyp
。接下来 4 个字节 69 73 6F 6D
是主 brand,表示该文件所遵循的标准规格,这里是 isom
,即遵循 ISO Base Media File Format。接下来的 4 个字节 00 00 02 00
表示的是这个 Box 格式的版本号。接下来的 16 个字节则是兼容的 compatible brands,即该文件兼容的其他标准规格,这里是 isom
、iso2
、avc1
、mp41
。
虽然这个 Box 是 MP4 文件所必须的,但是通常我们并不太关注这里的信息,所以这里不再多讲。
3、Movie Box(moov) 解析
moov,即 Movie Box,包含文件中所有媒体数据的宏观描述信息。实际的音视频数据都存储在 mdat 中,那么多的数据,我们怎么确定每一帧数据的位置呢,这就需要解析 moov 中的数据来得到实际音视频数据的索引。
moov Box 可以说是 MP4 文件中最重要的 Box,一般播放器的实现都需要读取到 moov 的数据才能开始播放流程。
moov Box 是一个 container box,所以它的数据格式定义比较简单:
aligned(8) class MovieBox extends Box(‘moov’){
}
moov 通常包含 1 个 mvhd 和若干个 trak。
3.1、Movie Header Box(moov/mvhd)
mvhd,Movie Header Box,包含与具体媒体数据无关,但与整体播放相关的信息,比如 timescale、duration 等信息。
mvhd Box 的数据格式定义:
aligned(8) class MovieHeaderBox extends FullBox(‘mvhd’, version, 0) {
if (version==1) {
unsigned int(64) creation_time;
unsigned int(64) modification_time;
unsigned int(32) timescale;
unsigned int(64) duration;
} else { // version==0
unsigned int(32) creation_time;
unsigned int(32) modification_time;
unsigned int(32) timescale;
unsigned int(32) duration;
}
template int(32) rate = 0x00010000; // typically 1.0
template int(16) volume = 0x0100; // typically, full volume
const bit(16) reserved = 0;
const unsigned int(32)[2] reserved = 0;
template int(32)[9] matrix = { 0x00010000,0,0,0,0x00010000,0,0,0,0x40000000 };
// Unity matrix
bit(32)[6] pre_defined = 0;
unsigned int(32) next_track_ID;
}
下面是一些字段的含义:
- version:该 Box 的版本号。
- creation_time:创建时间。
- modification_time:最新修改时