在我之前的一篇文章(什么是视频封装格式和编码格式)中有整理了一下常见的视频封装格式。在上一篇文章(详解视频封装格式之FLV)中重点剖析了FLV格式。在这篇文章中,我们重点剖析一下MP4这种视频封装格式的具体情况。
MP4 封装相比 FLV 更常见,但是也更复杂一些。其实它们的基本的思想还是一样的,就是用一个规定的格式组织存放音视频数据和一些基础信息。跟 FLV 由一个个 Tag 组成有点类似,MP4 由一个个 box 组成,每一个 box 存放了不同的数据,而且 box 里面还可以嵌套着 box。
MP4 最外层的 box 主要有三个,分别是 File Type box(ftyp box)、Movie box(moov box)和 Media Data box(mdat box)。其中最重要、最复杂的就是 moov box 了,它里面存放了音视频的基本信息和每一个音视频数据的具体位置。
另外,在 MP4 文件中,视频的一帧和音频的一段编码数据称为一个 sample。连续的几个 sample 称之为 chunk,而视频的所有 sample 称为一个视频 track,同样音频的所有 sample 也称为一个音频 track。
因此一般 MP4 文件是由音频 track 和视频 track 组成,而 track 由 sample 组成,其中若干个 sample 组成一个 chunk。
上面所说,mp4由一个个box组成。MP4的box有很多,借用网上摘取mp4文档中的box类型表格如下:
每一个 box 都是由 Box Header 和 Box Data 组成。Box Header 的结构如下图所示:
根据 Box Header 中的 type 我们将 box 分为不同类型的 box,每一种不同的 box 对应的 Box Data 都是不一样。Box Data 里面又可以嵌套 box。MP4 的总体 box 分布图如下图所示:
MP4文件由若干个box组成:
box由header和body组成,header指明了box的size和type;
size包含了box的header和body整个大小;如果size为1,表示box的长度需要用更多的bits位来描述,可以通过一个64bits位的largesize来描述box的长度,如果size为0,表示该box为文件的最后一个box;
type,通常使用4个ASCII码的字符如"ftyp"、"moov"等表示,这些box type是已经预定义好的,表示固定的含义,如果是"uuid",表示该box为用户自定义拓展的类型,如果box type是未定义的,应将其忽略;
box中可以包含box,这种box叫做container box;
box分为两种,Box和Fullbox,FullBox是Box的拓展,header中增加了8位的version和24位的flags字段。
mp4的box很多,不过我们也不需要全部了解,只需要掌握其中比较重要的几个box即可。
首先,ftyp box 放在 MP4 文件的开始,用来表示文件类型,该 box 的 Box Data 包含了 4 字节的主版本(major brand)、4 字节的版本号(minor version)和若干个 4 字节数组组成的兼容版本(compatible_brands)。
ftyp简单的说就是为了标识它的developer是谁,兼容哪些标准等,如“mp42”表示它的major brand是MP4 v2,而“mp42”和“mp41”则表示它的compatible brands是MP4 v2和MP4 v1。
major_brand:推荐兼容性的版本;
minor_version:最低兼容性的版本;
compatible_brands[]:所有的兼容性的版本。
mdat box 是 MP4 的音视频数据存放的地方。mdat box 基本由头部和数据两部分组成,box type 是 “mdat” 的 ASCII 码值。对于 H264 来说,是一个个 NALU。这里的 NLAU 不再包含 SPS 和 PPS,这些数据已经放到 moov box 里面了,此处 NALU 类型是图像数据或者 SEI 数据。
另一个 box 就是最重要的 moov box,用来存放 Metadata 信息。这个 box 可以放在 ftyp 的后面也可以放置在文件的最后面。moov box 里面会一层层嵌套很多层 box。总体嵌套逻辑就是 movie 里面是 track,track 里面是 sample,多个 sample 又组成了一个个 chunk。
moov box 首先有一个 mvhd box(movie header box)主要存放文件的基本信息,比如说 MP4 文件的创建时间、时间单位、总时长等信息。其中的time scale和 duration对文件的播放有着重要作用。
version:box的版本,0或者1,一般为0;
creation time:创建时间(相对于UTC时间1904-01-01零点的秒数);
modification time:修改时间;
timescale:文件媒体在1秒时间内的刻度,可理解为1s长度的时间单元数;
duration:该track的时间长度;
rate:推荐播放速率,高16位和低16位分别为小数点整数部分和小数部分,[16.16]格式,该值为1.0(0x00010000)表示正常向前播放;
volume:推荐播放音量,[8.8]格式,1.0(0x0100)表示最大音量。
martix:视频变换矩阵
newxt track id:下一个track使用的id
moov box 中的另外一个重要的 box 就是 trak box,这个 box 音频和视频各有一个。具体是音频 trak 还是视频 trak,会在 trak box 中的 mdia box 里面的 hdlr box 中表示出来。
trak box 内部有一个 tkhd box(track header box)主要是表示 track 的一些基本信息,比如说视频的宽高信息和音频的音量信息等。
tkhd里有:
version:box版本,0或者1,一般为0;
flags:24-bit整数,按位或操作结果值;
track id:track id号,不能重复且不能为0;
duration:track的时间长度;
volume:[8.8]格式,如果为音频track,1.0(0x0100)表示最大音量,否则为0;
width:宽度,[16.16]格式;
height:高度,[16.16]格式,不必与sample的像素尺寸一致,用于播放时显示的宽高。
trak box 还有一个 mdia box,它是媒体信息 box。它包含了 3 个子 box,一个是 mdhd box,一个是刚才提到的 hdlr box,一个是最重要的 minf box,这个 box 里面包含了 sample 的很多信息,这些信息是找到并正确使用音频和视频数据的关键。
mdia包含:
一个Media Header Atom,即mdhd;
一个Handler Reference,即hdlr;
一个media information,即minf,解码的关键。
mdhd box 里面最重要的一个值就是时间单位 time scale,这个时间单位是 sample 的时间戳的单位,控制播放速度和音视频同步都需要使用到这个值。
mdhd和tkhd内容上大致一致,不过tkhd通常是指定的track设定的相关属性和内容,而mdhd是针对独立的media来设置的,字段包含:
version:box的版本,0或者1,一般为0;
timescale:比mvhd中的timescale精度更高;
duration:track的时间长度;
language:媒体语言码,最高位为0。
hdlr box 主要包含了 track 的类型信息,表明是音频还是视频 track。hdlr解释了媒体的播放过程信息,可获取track类型信息,主要是有字段handler_type(uint32_t)区分,具体含义如下:
handler type:该值为4个字符,会有以下取值:
vide:视频;
soun:音频;
hint:这个特殊的track并不包含媒体数据,而是包含了一些将其他数据track打包成流媒体的指示信息。
重要的容器box,存储了解释track媒体数据的handler-specific信息,media handler用这些信息将媒体时间映射到媒体数据并行处理,minf是一个container box,其实际内容由子box说明。
一般情况下,minf包含了一个header box,一个dinf和一个stbl,其中header box的数据类型有vmhd(视频轨)、smhd(音轨)、hmhd(hint track)、nmhd(null track),dinf为data information box,stbl为sample table box。
minf box 里面包含了一个 stbl box(sample table box),里面存放着可以计算得到每一个 chunk 的偏移地址、每一个 sample 在文件中的地址信息和大小、每一个 sample 的时间戳和每一个视频 IDR 帧的地址信息。stbl是MP4文件中最复杂的一个box了,也是解开MP4文件格式的主干,是一个container box。下面我们来详细介绍一下这些 box。
其中,stts box 中放置的是每一个 sample 的时长,这个值是 DTS。
ctts box 放置着 CTS,也就是每一个 sample 的 PTS 和 DTS 的差值。
stss box 中放置的是哪些 sample 是关键帧。
stsc box 中放置的是 sample 到 chunk 的映射表,也就是哪些 sample 属于哪个 chunk。
stco box 或 co64 box 中放置着每个 chunk 在文件中的偏移地址。
stsz box 中放置着每一个 sample 的大小。
跟 sample 相关的 box 就是以上这些。
mp4box.js:一个在线解析mp4的工具。
bento4:包含mp4dump、mp4edit、mp4encrypt等工具。
MP4Box:类似于bento4,包含很全面的工具。
mp4info.exe: windows平台图形界面展示mp4基本信息的工具。
我们使用mp4box.js,可以看到MP4文件由许多box组成,每个box包含不同的信息,以树形的方式组织,主要的box如下:
通过上表,我们可以看到有4个树节点:
ftyp:文件类型;
moov box:媒体的metadata的描述和信息;
mdat:具体的媒体数据;
free:无关紧要的内容。
关于MP4的封装格式,就讲到这里。