mp4是我们最熟悉的一种视频封装格式,也是跨平台中通用型最好的一种视频封装格式。我们平时看的视频大部分都是mp4格式的,具有较强的可编辑性,支持以较小的代价进行原本较为复杂的操作。此外,mp4具有较强的兼容性,支持多种不同的音视频编码格式的组合,如 H.264+ MP3、H.264+AAC等。下面我们就来看一看熟悉的mp4文件内部到底是什么样子的。我们先来看一下整体的文件格式,下面这张图是根据mp4Info查看的mp4问的文件结构:
0x01mp4的封装格式
通常,一个MP4格式文件是有一个个嵌套形式的“Box结构”构成的。Box结构为一种由头结构(Box Header)和负载数据(Box Data)组成的能容纳特性信息的数据结构。某种类型的Box结构可以在其内部包含若干其他类型的Box结构,形成嵌套的多层Box结构,以此存储复杂的数据结构。
MP4文件中定义的Box结构可以分为两种,Box和FullBox。
FullBox是Box的扩展,在header中增加了8位的version和24位的flags标志,可以保存更全面的信息。Header包含了整个Box的长度的大小和类型,当size等于0时,代表这个Box是稳健的最后一个Box。当size等于1时,说明Box长度需要更多的位来描述,后面会定义一个64位的largesize来描述Box的长度。当Type位uuid时,说明这个box中的数据是用户自定义的扩展类型。
0X02 Box类型
MP4协议定义的Box类型超过70多种,它们都定义在标准文档ISO/IEC 14496 part12中
常见的Box类型如下图所示
1.ftyp
ftyp box代表媒体文件的类型、版本号、及兼容的协议类型.文件结构如下:
该结构的4 byte 00 00 00 20 表示当前结构的大小为0x20(32 byte).随后的4 byte 66 74 79 70 以ASC码形式表示当前的结构类型未ftyp。之后的数据为内容。marjorBrand 位isom,minor_version 为512byte,兼容其他格式为 isom、iso2、avc1、mp41.
2.moov
moov box表示音视频文件的媒体信息头结构,包换了音频文件和视频文件的总体描述信息等。moov是一个复合结构,做为其他结构的父容器,内部包含众多个box的总要结构。
moov可以放到文件的头部或尾部,位于尾部的moov更适合视频文件的编码与编辑,它可以在编码完成之后直接将参数写入媒体的信息头结构中,并写入输出文件,不需要在更新视频编码数据的偏移量,实现简单且效率更高。而在在线播放的应用场景中,moov在头部位置时,不需要加载全部文件,只需加载完成moov的索引数据,根据索引数据就可以获取到mdat的数据,直接解码和播放,更加的高效。负责需要下载完成完整的mp4文件才能编码和播放。moov中包含的子box内容:
一、mvhd (movie header)视频头结构,保存文件的全局信息:
create_time | 文件创建时间 |
---|---|
modification_time | 文件修改时间 |
timescale | 文件的时间刻度 |
duration | 媒体的整体时长 |
rate | 播放速度 |
volume | 播放音量 |
matrix | 视频变换矩阵 |
next_track_id | 新添加数据流时所使用的track_ID |
二、trak 表示视频中包含的轨道:
一般包换音频轨道、视频轨道、字幕轨道等。trak也是容器类的box,包含很多子容器box。
trak包含的子box:
2.1 tkhd (track header)音频轨或者视频轨的头结构,表示当前流的总体信息:
version | 版本 0或者1,一般为0 |
---|---|
flag | 按位或操作结果值,预定义如下: 0x000001 track_enabled track生效0x000002 track_in_movie track被用在movie0x000004 track_in_preview 被用在movie预览中0x000008 track被用在Movie的poster中 |
trackId | 轨道id |
duration | 时长 |
layer | 视频层,默认是0,值小的在最上层 |
altermateGroup | track分组信息,默认是0表示该track未与其他track有群组关系 |
volume | 音量 |
matrix | 矩阵结构,该矩阵定义了track中两个坐标空间的映射关系 |
width | 播放显示的尺寸宽度 |
height | 播放显示的尺寸高度 |
2.2 edts 容器定义了媒体文件中一个tack的一部分媒体,所有的edts数据都在一个表里,包括每一部分的时间偏移量和长度,如果没有该表,那么这个track就会立即开始播放。
2.3 mdia容器 主要的媒体配置信息存放在mdia容器中,他必须包含以下子容器 2.3.1 mdhd(media header atom) 媒体头
version | 版本 |
---|---|
flag | 默认为0 |
creationTime | Movie atom的起始时间。基准时间是 1904-1-1 0:00 AM |
modificationTime | Movie atom的修订时间。基准时间是1904-1-1 0:00 AM |
timescale | 时间计算单位 |
duration | 这个媒体track的时长 |
lanugage | 媒体的语言码 |
quality | 媒体的回放质量 |
2.3.2 hdlr (Handler Reference)句柄参考
version | 版本 |
---|---|
flag | 标志 默认是0 |
componentType | handler的类型。两种类型 'mhlr' media handlers 'dhlr' data handlers |
componentSubType | 如果componentType 是 'mhlr', subType = vide 代表video, subType = soun 代表 sound数据; 如果componentType 是'dhlr'则定义为数据引用类型 |
componmentName | componment的名字 |
2.3.3 minf (Media Infomation)媒体信息,保存了当前mdia结构的主要特征信息。
在video Track中包换 vmhd子容器
version | 版本 |
---|---|
flag | 固定为0x000001 |
graphicsMode | 图形模式 |
opcolorRed、opcolorGreen、opcolorBule | 颜色值 |
在Audio Track中包含smhd子容器
version | 版本 |
---|---|
flag | 固定为0 |
blanace | 音频的均衡是用来控制计算机的两个扬声器的声音混合效果,一般是0 |
reserved | 保留字段 |
2.3.3.2 dinf容器
用于描述数据信息的容器格式,其定义了音视频数据信息。
version | 版本 |
---|---|
flag | 固定为0 |
count | 条目数量 |
entry | data Refrece信息 |
type | 类型 url/alis/rsrc |
version | 版本 |
flag | 标志 |
data | data reference信息 |
2.3.3.3 stbl容器
非常重要的结构之一,保存了音视频吗流的头信息,时间戳和码流分片在mp4文件的位置。
stsb(sample description atom) 采样描述容器 保存了mp4文件中音视频流数据的编码类型等解码所需要的全部初始化信息
stts(time to sample atom) 采样时间容器可以获取到视频流的总帧数,每一帧的dts和整体时长
size | timeToSampleBox中的数据组数 |
---|---|
sampleCount | 当前组所包含的共享的dts差值的样本个数 |
sampleDelta | 相邻两样本之间dts的差值 |
stss(sync sample atom) 采样同步容器可以获取到关键帧的树木和每个关键帧的序号
size | 关键帧的个数 |
---|---|
sampleDelta | 每个关键帧所在样本的序号 |
stsc(sample to thunk atom)chunk 采样容器可以计算出每个视频码流的样本与chunk的对应关系,并通过chunk在文件的位置以及chunk中每个样本的大小,确定每个码流样本在文件中的位置和大小
size | stsc中元素的个数,当前流中chunk的组数 |
---|---|
first_chunk | 当前chunk组的气势chunk号 |
samples_per_chunk | 当前chunk组中的每个chunk包含的码流样本个数 |
sampleDespriptionIndex | 当前chunk组中的每个样本描述信息索引 |
stsz(sample size atom)采样大小容器可以获取每个视频码流样本的大小以及整个视频流的总大小
sample_size | 当前音视频码流样本的默认包大小 |
---|---|
sample_count | 当前音视频码流样本的总个数 |
sample_size_table | 每个码流样本的大小 |
stco(chunk offset atom)chunk偏移容器获取视频码流中的chunk的数目和在文件中的位置
size | 当前音视频的chunk的总个数 |
---|---|
chunkOffset | 每个chunk相对于媒体文件起始位置的二进制偏移量 |
3.mdat
mdate用于媒体数据结构保存的二进制的音频流和视频流数据。一个媒体文件可以能包含0个或多个媒体数据结构,分别对应多路音频流和视频流。每路的音频流或视频流的数据根据moov中的索引就可以找到。
0x03 总结
以上就是mp4文件的结构以及每个box的详细解释,通过解析,我们可以了解到moov是整个mp4文件的索引,如果将moov放到后面,我们就需要加载完整的mp4文件才能播放,这对于点播来说是不可接受的,所以点播一般会把moov放到前面。
试想一下我们编辑一个mp4文件,增加一个视频片段,如果moov前置的话,就需要修改moov中索引的偏移量和mdat的偏移量,如果后置则改动就相对较小。