MP4
BOX
第一层Ftyp、Moov、Mdat、Free等:
ftyp Box
ftyp是MP4文件的第一个Box,包含了视频文件使用的编码格式、标准等,这个Box作用基本就是MP4这种封装格式的标识,同时在一份MP4文件中只有一个这样的Box。ftyp box通常放在文件的开始,通过对该box解析可以让我们的软件(播放器、demux、解析器)知道应该使用哪种协议对这该文件解析,是后续解读文件基础
Moov Box
Moov Box这个Box也是MP4文件中必须有但是只存在一个的Box,这个Box里面一般存的是媒体文件的元数据,这个Box本身是很简单的,是一种Container Box,里面的数据是子Box,自己更像是一个分界标识。
所谓的媒体元数据主要包含类似SPS PPS的编解码参数信息,还有音视频的时间戳等信息。对于MP4还有一个重要的采样表stbl信息,这里面定义了采样Sample、Chunk、Track的映射关系,是MP4能够进行随机拖动和播放的关键,也是需要好好理解的部分,对于实现一些音视频特殊操作很有帮助。
Mdat Box
Mdat Box这个Box是存储音视频数据的Box,要从这个Box解封装出真实的媒体数据。当然这个Box一般都会存在,但是不是必须的。
在前面的文章《音视频压缩:H264码流层次结构和NALU详解》中已经讲解了H264的基本结构是由一系列的NALU组成。原始的NALU单元组成:
Start code + NALU header + NALU payload
但是在MP4格式文件中,H264 slice并不是以00 00 00 01 Start Code来进行分割,而是存储在Mdat Box的Data中。
Mdat Box的格式:
Box header + Box Data
Box length + Box Type + NALU length + NALU header + Nalu Data……. NALU length + NALU header + Nalu Data
Free Box
Free Box中的内容是无关紧要的,可以被忽略即该box被删除后,不会对播放产生任何影响。这种类型的Box也不是必须的,可有可无,类似的Box还有Sikp Box.虽然在解析是可以忽略,但是需要注意该Box的删除对其它Box的偏移量影响,特别是当Moov Box放到Mdat Box后面的情况。
MOOV
Mvhd Box
这个Box也是全文件唯一的一个Box,一般处于Moov Box的第一个子Box,这个Box对整个媒体文件所包含的媒体数据(包含Video track和Audio Track等)进行全面的描述。其中包含了媒体的创建和修改时间,默认音量、色域、时长等信息。
Trak Box
Trak Box定义了媒体文件中媒体中一个Track的信息,视频有Video Track,音频有Audio Track,媒体文件中可以有多个Track,每个Track具有自己独立的时间和空间的信息,可以进行独立操作。
每个Track Box都需要有一个Tkhd Box和Mdia Box,其它的Box都是可选择的
Trak
Tkhd Box
该Box描述了该Track的媒体整体信息包括时长、图像的宽度和高度等,实际比较重要
Mdia Box
这个Box也是Container Box,里面包含子Box,一般必须有Mdhd Box、Hdlr Box、Minf Box。基本就是当前Track媒体头信息和媒体句柄以及媒体信息。
Box自身非常简单,就是一个标识而已,最复杂的还是里面包含的子Box.
Mdia
Mdhd Box
这个Box是Full Box,意味着Box Header有Version和Flag字段,该Box里面主要定义了该Track的媒体头信息,其中我们最关心的两个字段是Time scale和Duration,分别表示了该Track的时间戳和时长信息,这个时间戳信息也是PTS和DTS的单位。
Hdlr Box
这个Box是Full Box,意味着Box Header有Version和Flag字段,该Box解释了媒体的播放过程信息,用来设置不同Track的处理方式,标识了该Track的类型。
Minf Box
这个Box是我认为Moov Box里面最重要最复杂的Box,内部还有子Box,我们还是从上到下从外到内的分析各个Box。该Box建立了时间到真实音视频Sample的映射关系,对于音视频数据操作时很有帮助的。
同时该Box是Container Box,下面一般含有三大必须的子Box:
媒体信息头Box: Vmhd Box或者Smhd Box;
数据信息Box:Dinf Box
采样表Box:Stbl Box
Minf
Vmhd Box
Dinf Box
Stbl Box
怎样把媒体数据的Sample和时间进行映射的,看下Sample-Trunk-Track的三者关系。
我们知道Sample是媒体数据的存储单元,其中存储在Media的chunk中,在分析Mdat Box的H264 NALU打包时已经体现出来了
其中每个Sample的时间和位置、编解码信息、和chunk关系等都是由Stbl Box来描述的,该Box又称为采样参数列表即Sample Table。
Stbl Box包含了Track中media媒体的所有时间和索引,利用这个容器的Sample信息,就可以定位Sample的媒体时间、类型、大小以及和其相邻的Sample。同时该Box是必须在Trak Box中存在的。
其一般要包含下列子Box:
采样描述容器: Sample Description即Stsd Box
采样时间容器: Time To Sample 即Stts Box
采样同步容器: Sync Sample即Stss
Chunk采样容器: Sample To Chunk即Stsc
采样大小容器: Sample Size即Stsz
Chunk偏移容器:Chunk Offest即Stco
Stsd Box
该Box存储了编码类型和初始化解码器需要的信息,与特定的Track Type有关,根于不同的Track使用不一样的编码标准。
box header和version字段后会有一个entry count字段,根据entry的个数,每个entry会有type信息,如“vide”、“sund”等,根据type不同sample description会提供不同的信息,例如对于video track,会有“VisualSampleEntry”类型信息,对于audio track会有“AudioSampleEntry”类型信息。视频的编码类型、宽高、长度,音频的声道、采样等信息都会出现在这个box中。
对于Video Track里面而言,H264的SPS PPS就存在该Box里面,对于解码非常重要。
Stsd/Avc1 Box:
当为Video Track,所以VisualSampleEntry为Avc1 Box,内部含有SPS PPS 等音视频解码信息。
Stsd/Avc1/AVCC Box
该Box则包含了真实的SPS PPS等信息,包含着音视频编解码参数:
音频的STSD的Box Data主要由mp4a和esds Box嵌套组成,里面包含了通道个数,采样率、音频AAC编码级别等信息
Stsd/mp4a Box:
Stsd/mp4a/Esds Box
里面主要是将音频的编码信息和音频码率信息放到该Box里面,所以解码音频时非常关键。
Stts Box
这个Box是sample number和解码时间DTS之间的映射表,通过这个表格,我们可以找到任何时间的sample。Stts Box这个表格有两项值,其中一项是连续的样点数目即sample count和样点相对时间差值即sample delta即表格中每个条目提供了在同一个时间偏移量里面连续的sample序号以及sample偏移量。当然这里的相对时间差单位是由该Track的Mdhd Box描述的时间单位
Ctts Box
该Box保存了每个sample的composition time和decode time之间的差值,这里通过Composition Time就可以计算出Sample的PTS。
不存在B帧情况下PTS是等于DTS的,则不含B帧的视频文件是没有Ctts Box的,同样音频也没有Ctts Box。
Stss Box
I帧是播放的起始位置,只有编码器拿到第一个I帧才能渲染出第一幅画面。所以后续的一些特殊随机操作,高标清切换时都需要找I帧,只有随机找到I帧才能完成这些特殊操作。
其中该Box就是存储了那些Sample是I关键帧,很显然音频Track也是不存在这个Box的。
Stsc Box
MP4中存在Track-Trunk-Sample概念,讲到现在Track和Sample已经都讲到了,但是还没有讲解Trunk和Sample的映射关系,这个Box就是说明那些Sample可以划分为一个Trunk。
媒体数据被分为若干个chunk, chunk可以有不同的大小,同一个chunk中的样点sample也允许有不同的大小;通过本表可以定位一个样点的chunk位置,同时该Box里面的Box Data里面有三个字段,分别是first chunk、sample per chunk、sample description index。
- fist chunk: 具有相同采样点sample和sample_description_index的chunk中,第一个chunk的索引值,也就是说该chunk索引值一直到下一个索引值之间的所有chunk都具有相同的sample个数,同时这些sample的描述description也一样;
- samples per chunk: 上面所有chunk的sample个数
- sample description index: 描述采样点的采样描述项的索引值,范围为1到样本描述表中的表项数目;
这 3 个字段实际上决定了一个 MP4 中有多少个 chunks,每个 chunks 有多少个 samples。
Stsz Box
前面分析了sample的PTS、DTS等,也分析了chunk里面sample的信息,但是没有分析sample的大小,这是我们在文件读取和解析Sample的关键。这里给出每个Sample的Size即包含的字节数。
包含了媒体中全部sample的数目和一张给出每个sample大小的表。这个box相对来说体积是比较大的。
Stco Box
该Box存储了Chunk Offset,表示了每个Chunk在文件中的位置,这样我们就能找到了chunk在文件的偏移量,然后根据其它表的关联关系就可以读取每个Sample的大小。
H.264数据打包MP4文件步骤
- 构造Ftyp Box,这是MP4文件的基本标识,基本按照规范构造即可;
- 构造Mdat Box,这里面都是音视频媒体数据,将NALU数据封装成一个个Sample,从上到下排列起来即可;
- 构造Moov Box,这个Box,先构造除了stbl的其它Box,这样从子Box,一直按照层次构造上来,这些Box的基本信息是明确的,个别信息通过解析SPS、PPS是可以明确知道的,所以上文已经明确了这些Box的字段,所以构造起来并不难;
- 构造Moov Box的Stbl部分,这部分要封装:
SPS、PPS的NALU数据
也要构造时间戳PTS和DTS信息
Sample的大小和数量
Chunk的数量和在文件偏移量
Sample和Chunk的映射关系等,
需要仔细处理,一旦构造错误都会播放失败;
- 其中Moov到底是放到Mdat Box前面还是后面,需要在封装打包前确定后,因为会牵一发动全身,里面的信息都依赖在具体文件的位置;
- 再填充一些你感兴趣的非必要信息Box,至此组装成整个MP4文件即可;
avcC | 61 76 63 43 |
---|---|
版本号 | 1 |
AVCProfileIndication | 64 |
profile_compatibility | 0 |
AVCLevelIndication | 29 |
reserved(6bit)+NALU长度(2bit) | ff |
reserver(3bit)+sps个数(5bit) | E1 |
sps长度 | 00 1D |
sps内容 | 27 64 00 29 AC 13 16 C0 78 02 27 E5 C0 5A 80 80 80 98 18 00 2E E0 00 0B B8 2F 7B E0 A0 |
pps个数 | 01 |
pps长度 | 00 04 |
pps内容 | 28 EE 1F 2C |