MP4可以说是当前最流行的视频格式,要播放一个MP4文件需要首先将其结构给解析出来。MP4的结构往简单了说就是类似于俄罗斯套娃一样的很多box套box,往复杂了说就是很多种类的box,而且还需要做一些解析和计算的操作,下面就按照其结构来分析一下MP4文件里的主要的box.左侧的目录可以清晰地展示出各种box之间的关系。需要注意的是在ISO标准中box的种类非常多,这里只是列举分析了一些比较重要的box.
Mp4Box
首先我们需要先了解一下box的结构。在Mp4中所有的box都包含了一个BoxHeader和BoxData.其中BoxHeader包含了box的类型和整个box的长度,BoxData里面包含了子box或者各种数据。基于这种结构的考虑,我就可以设计出所有box的父类,还需要注意的是Media Data Box的长度有可能超出32位int的范围,在这种情况下,size的大小就被设置为1,然后使用接下来的64位来存储其长度。如果box的type为”uuid”的话,那接下来的16byte就用来存储uuid.
在上面我们定义了父类Mp4box,一般情况下box头部的长度都是8byte, 但是还有一种box在头部还有1byte的version和3byte的flags。所以我们需要创建一个Fullbox父类,让所有这种类型的box来继承它。
ftyp
代表了File type box. 一般在文件的开头处(只有固定大小的文件签名可以在其前面),主要包含了该文件brand等,其定义方式如下:
moov
代表了Movie box,这个box包含了一个mvhd box 和多个trak box(如video,audio等),一般在文件的开头处仅次于ftyp,但是也有放在文件末尾的。
代表了Movie Header box。 包含了整个媒体问题的信息。
creationTime: 一个int型的数据代表了文件的创建时间(从1904年1月1日凌晨开始的秒数)
modificationTime:修改时间,定义同上
timescale:1秒内包含的时间单位,和下面的duration结合可以得到媒体的时长。
duration:媒体的时长,以时长最长的track为准
rate:播放的速度,1.0为正常速度
volume:播放的音量
matrix:视频的转换矩阵
nextTrackId:下一个track的id
代表了 Track box。包含了一条track。通常情况下一个视频会包含video和audio两条track,还有一条hint track是为streaming准备的。
一个trak box内包含了tkdh和mdia两种box。
代表了Track Header Box。每个trck box会包含一个tkhd box来存储这条track的信息。
creationTime: 这条track的创建时间(同mvhd)
modificationTime: 这条track的更改时间(同nvhd)
trackId: 当前track的id,不能为0
duration: 当前track的时长
layer: 播放时video track的前后顺序,数字越小的越在上层。
alternateGroup: 对track进行分组,同一个组内同时只能播放一个track
volume: 音量大小,对于video track 会是0
matrix:video的转换矩阵
width/height 视频的宽度和长度,以像素为单位
代表了Media Box, 用来包含当前track的信息。mdia baox主要有三个子box,分别是hdlr、mdhd和minf,我们会在接下来分析这几个子box。
其中componentName并不是mdia box需要解析的内容,在这里我们用来存储当前track的类型,如是vedio还是audio。
mdhd
代表了Media Header Box。包含了一些当前track的信息,如creationTime等,在上文已经提过了,这里将不再赘述。
language 当前媒体的语言代码
hdlr
代表了Handler Refrence Box。包含了当前track类型的信息,如这条track是video、sound还是hint。
minf
代表了Media Information Box。 内部主要包含了一个stbl box。
stbl
代表了Sample Table Box。 这个box包含了当前track中所有Samples的时间和数据索引,所以根据这些信息就可以定位某个时间点的Sample及其大小等信息。
这个box包含了很多子box,将各个子box的信息结合起来就得得到Samples的详细信息了。具体怎么计算将在最后做一下分析。
stts
代表了Decoding Time to Sample Box。这个box包含了一个表,从这个表里可以根据解码时间来定位sample的序号。
sampleCount: 一个时间段内连续的Sample个数
sampleDelta:一个时间段内sample的delta。
ctts
代表了Sample Table Box。包含了decoding time 和composition time之间的偏移量。
sampleCount: 特定偏移量内连续的Sample个数
sampleDelta: CT和DT之间的偏移量,如CT(n)=DT(n)+CTTS(n)
stsd
代表了Sample Description Box,里面包含了一些子box,用来存储编码的信息。根据当前track的类型来决定子box的类型。
####### VisualSampleEntry
//todo