MP4笔记

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。

  1. fist chunk: 具有相同采样点sample和sample_description_index的chunk中,第一个chunk的索引值,也就是说该chunk索引值一直到下一个索引值之间的所有chunk都具有相同的sample个数,同时这些sample的描述description也一样;
  2. samples per chunk: 上面所有chunk的sample个数
  3. 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文件步骤

  1. 构造Ftyp Box,这是MP4文件的基本标识,基本按照规范构造即可;
  2. 构造Mdat Box,这里面都是音视频媒体数据,将NALU数据封装成一个个Sample,从上到下排列起来即可;
  3. 构造Moov Box,这个Box,先构造除了stbl的其它Box,这样从子Box,一直按照层次构造上来,这些Box的基本信息是明确的,个别信息通过解析SPS、PPS是可以明确知道的,所以上文已经明确了这些Box的字段,所以构造起来并不难;
  4. 构造Moov Box的Stbl部分,这部分要封装:

SPS、PPS的NALU数据

也要构造时间戳PTS和DTS信息

Sample的大小和数量

Chunk的数量和在文件偏移量

Sample和Chunk的映射关系等,

需要仔细处理,一旦构造错误都会播放失败;

  1. 其中Moov到底是放到Mdat Box前面还是后面,需要在封装打包前确定后,因为会牵一发动全身,里面的信息都依赖在具体文件的位置;
  2. 再填充一些你感兴趣的非必要信息Box,至此组装成整个MP4文件即可;

BOX

box avcc

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

reference

# MP4核心Box详解