视频封装格式是指视频数据如何存储的,视频编码格式是指原始视频数据如何编码为二进制数据码流。编码后的视频数据最终通过视频封装格式存储为视频文件。在 mp4 中默认写入字节序是 Big-Endian的。
ISO/IEC 14496-12(MPEG-4 Part 12 ISO base media file format)定义了一种通用的数字媒体文件格式标准,其基础是2001年版的Apple QuickTime文件格式。
ISO/IEC 14496-14标准中定义了ISO/IEC 14496-12的一种多媒体容器格式实现,即我们现在熟知的MP4(MPEG-4 Part 14),它属于MPEG-4的一部分。
MP4文件由若干称为box/atom的数据对象组成,每个box的起首为四个字节的数据长度(Big Endian)和四个字节的类型标识,数据长度和类型标志都可以扩展。box可以嵌套,即其数据域可以由若干其它box组成,从而实现结构化的数据。
MP4是一种描述较为全面的容器格式,被认为可以在其中嵌入任何形式的数据,包括各种编码的视频、音频,我们常见的大部分的MP4文件存放的AVC(H.264)或MPEG-4(Part 2)编码的视频和AAC编码的音频。
MP4格式的官方文件后缀名是“.mp4”,还有其他的以mp4为基础进行的扩展或者是缩水版本的格式,包括:M4V, 3GP, F4V等。
说明:QuickTime影片格式是Apple公司开发的一种音频、视频文件格式,用于存储常用数字媒体类型。其扩展名为.mov。
MP4是由box嵌套来存放媒体信息。Box/Atom的基本结构是:[4bytes atom length] [4bytes atom name] [8bytes largesize, if size ==1] [contents of the atom, if any]
SIZE表示整个box/Atom所占用的大小,包括header部分。如果box/Atom很大,超过了uint32的最大数值(例如存放具体视频数据的mdat),size就被设置为1,并用接下来的LARGESIZE来存放数据大小。
TYPE表示这个box/Atom的类型,主要有ftyp、moov、mdat等。LARGESIZE,如果SIZE==1,则使用8 bytes uint64来存储该Atom大小。DATA是实际的数据。MP4文件含有很多box/Atom,主要的box/Atom和嵌套结构如图。
① box由header和body组成,其中header指明box的size和type。size是包含box header的整个box的大小。
② box type,通常是4个ASCII码的字符如“ftyp”、“moov”等,这些box type都是已经预定义好的,表示固定的含义。如果是“uuid”,表示该box为用户自定义扩展类型,如果box type是未定义的,应该将其忽略。
③ 如果header中的size为1,则表示box长度需要更多的bits位来描述,在后面会有一个64bits位的largesize用来描述box的长度。如果size为0,表示该box为文件的最后一个box,文件结尾(同样只存在于“mdat”类型的box中)。
④ box中可以包含box,这种box称为container box。
⑤ box分为两种,Box和Fullbox。FullBox 是 Box 的扩展,Header 中增加了version 和 flags字段。
Track:一些sample的集合,对于媒体数据来说,track表示一个视频或者音频序列。
Sample:video sample即为一帧或者一组连续视频帧,audio sample即为一段连续的音频。
Sample table:指明sample时序和物理布局的表。
Chunk:一个track的几个sample组成的单元。mp4文件中,媒体内容在moov的box中。一个moov包含多个track。每个track就是一个随时间变化的媒体序列,track里的每个时间单位是一个sample,sample按照时间顺序排列。注意,一帧音频可以分解成多个音频sample,所以音频一般用sample作为单位,而不用帧。
MP4文件需要有ftyp、moov、mdat,它们都是顶级box/Atom,不能被其他box/Atom嵌套。ftyp标示了MP4文件,必须出现在第一个。moov保存了视频的基本信息,mdat保存视频和音频数据。这两个Atom顺序不固定。
一个moov在mdat之后的MP4文件的Atom结构:
由于moov中保存了视频数据的索引,对于在线播放的场景,需要moov在mdat之前,才能流式读取视频数据。
部分摄像设备生成的MP4文件中,moov在mdat之前,两者之间可能还存在一个Atom free,即moov-free-mdat。free中为全0,只是用于占位。
一个moov在mdat之前的MP4文件的Atom结构:
Ftyp(file type)是整个文件的第一个box/Atom,通过判断该box/Atom来确定文件的类型。该box/Atom有且只有1个,并且只能被包含在文件层,而不能被其他box/Atom包含嵌套。该Atom应该被放在文件的最开始,指示文件的相关信息。通过对该box/atom解析可以让我们的软件(播放器、解封装、解析器)知道应该使用哪种协议对这该文件解析,是后续解读文件基础。
文件的最开始的四个字节就是“ftyp”box/Atom的大小size,然后是该box/Atom的类型type。“ftyp”的body依次包括1个32位的major brand(4个字符),1个32位的minor version(整数)和1个以32位(4个字符)为单位元素的数组compatible brands。这些都是用来指示文件应用级别的信息, 主要是用来描述该文件的语法属性的,任何播放器在打开MP4 文件的时候,首先在文件头获取搜索该box,如果未能找到,则判定该文件是非正常的MP4文件从而退出播放。以一个MP4文件的“ftyp”box/Atom为例,如下所示:
0000000: 0000 0018 6674 7970 6d70 3432 0000 0000 ....ftypmp42....
0000010: 6d70 3432 6d70 3431 0528 834f 6d64 6174 mp42mp41.(.Omdat
其中,
(1)0x00 00 00 18是“ftyp”box/Atom的大小,为24个字节,这在一般情况下为一个固定值。
(2)0x66 74 79 70是“ftyp”四个字符的ASCII值,也就是该box/Atom的类型。
(3)0x6D 70 34 32是major brand,这里为“mp42”,对于不同的文件,该值可能是不一样的。
(4)0x00 00 00 00是minor version。
(5)0x6D 70 34 32和0x6D 70 34 31是compatible brands,”mp42”和“mp41”
FTYP到底是什么呢?
ftyp就是一个由四个字符组成的码字,用来标识编码类型、兼容性或者媒体文件的用途。它存在于MP4文件和MOV文件中,当然,也存在于3GP文件中。
虽然MP4文件、MOV文件和3GP文件采用了相同的封装标准,但由于是由不同的厂商合成,因此还是存在差别的。即使是同一种媒体文件,比如MP4文件,由不同developers开发的MP4也是存在差别的。ftyp简单的说就是为了标识它的developer是谁,兼容哪些标准等。
比如上面的例子,“mp42”表示它的major brand是MP4 v2 [ISO 14496-14],而“mp42”和“mp41”则表示它的compatible brands是MP4 v2 [ISO 14496-14]和MP4 v1 [ISO 14496-1:ch13]。
free是可选的,如果存在,则通常出现在moov与mdat之间,即moov-free-mdat。free中的数据通常为全0,其作用相当于占位符,在实时拍摄视频,moov数据增多时分配给moov使用。
因为设备录制视频时并不能预先知道视频数据大小,如果moov在mdat之前,随着拍摄mdat的数据会增加,moov数据也会增多,如果没有free预留的空间,则要不停的向后移动mdat数据以腾出moov空间。
MP4文件的数据,除了音视频数据之外,还有大量的元数据,用于记录文件级别的信息和每一帧数据的坐标、长度、时间戳等多媒体信息。其起始顶层box/atom类型为MOOV。描述了视频文件的信息,其包含的一系列次级box/atom中存储着媒体播放所需的元数据(metadata)。
视频包括编码等级、分辨率、色域、码率、帧率、位深、时长等;音频又包括声道、采样率等音频特有属性。
这些元数据对于我们的价值在于:我们的系统(比如PC播放器,高清播放机)可以通过对moov box/atom的解析,自动适配运行在某种模式下去播放影片。在嵌入式领域,由于DSP或ARM的Ram空间有限,经常需要动态加载本次播放所需的解码器(算法程序),通过自适配可以用最廉价的CPU,完成一款支持多码率多格式的全能播放器。
从它可以迅速定位元数据的起始位置。 其组织结构如下
全文唯一存在(即一个文件中只能包含一个mvhd box),对整个文件所包含的媒体数据作全面的全局的描述。包含了媒体的创建与修改时间刻度、默认音量、色域、时长等信息。mvhd中有一个time scale,以1/n秒的形式给出一个总的时间粒度,moov-trak-tkhd中以此时间粒度给出各个track的duration;
trak表示轨道,每一路数据源头表示一路轨道,往往一部视频包含多路轨道,该轨道可以是视频数据,也可以是音频数据,它们之间相互独立,各自有各自的时间和空间信息。moov中通常包含两个trak,一个视频索引,一个音频索引。
4.3.2.1 tkhd,track header
TKHD是每个轨道单独所包含的媒体数据的描述。包含了该轨道媒体的创建与修改时间、时间刻度、默认音量、色域、时长等信息。
4.3.2.2 mdia,track media information container
media box/atoms定义了track的媒体类型和sample数据,例如音频或视频,描述sample数据的media handler component,media timescale and track duration以及media-and-track-specific信息,例如音量和图形模式。它也可以包含一个引用,指明媒体数据存储在另一个文件中。也可以包含一个sample table atoms,指明sample description, duration, and byte offset from the data reference for each media sample。
media atom的类型是'mdia'。它是一个容器atom/box,必须包含一个media header atom ('mdhd'),一个handler reference ('hdlr'),一个媒体信息引用('minf')和用户数据atom('udta')。
4.3.2.2.1 mdhd,media header
Mdhd是有一个以1/n秒的形式给出各个媒体的时间粒度,以及以此时间粒度为单位的duration。
4.3.2.2.2 hdlr,header
HDLR主要记录所处的trak是视频还是音频的类型。也就是vide/soun/hint/meta/auxv,vide表示视频track,soun表示音频track,hint表示hint track,meta表示timed metadata track,auxv表示auxiliary track。
4.3.2.2.3 minf,media information container
minf存储了解释track媒体数据的handler-specific信息,media handler用这些信息将媒体时间映射到媒体数据并进行处理。“minf”中的信息格式和内容与媒体类型以及解释媒体数据的media handler密切相关,其他media handler不知道如何解释这些信息。“minf”是一个container box,其实际内容由子box说明。
“minf”是嵌套box,一般情况下,“minf”包含一个header box,一个“dinf”和一个“stbl”,其中,header box根据track type(即media handler type)分为“vmhd”、“smhd”、“hmhd”和“nmhd”,“dinf”为data information box,“stbl”为sample table box。
4.3.2.2.3.1 vmhd, video media header box
4.3.2.2.3.2 stbl,sample table box
stbl比较重要,其中保存了解码器需要的信息和索引信息,以下Atom都是stbl Atom的孩子。Stbl(Sample table)记录sample和chunk的信息。stbl”包含了关于track中sample所有时间和位置的信息,以及sample的编解码等信息。利用这个表,可以解释sample的时序、类型、大小以及在各自存储容器中的位置。“stbl”是一个container box,其子box包括:sample description box(stsd)、time to sample box(stts)、sample size box(stsz或stz2)、sample to chunk box(stsc)、chunk offset box(stco或co64)、composition time to sample box(ctts)、sync sample box(stss)等。
stsd:sample description box,样本的描述信息。
stts:time to sample box,sample解码时间的压缩表。
ctts:composition time to sample box,sample的CTS与DTS的时间差的压缩表。
stss:sync sample box,针对视频,关键帧的序号。
stsz/stz2:sample size box,每个sample的字节大小。
stsc:sample to chunk box,sample-chunk映射表。
stco/co64:chunk offset box,chunk在文件中的偏移。
sample是媒体数据存储的单位,存储在media的chunk中,chunk和sample的长度均可互不相同,如下图所示。
(1)stsd,sample descriptions
“stsd”必不可少,且至少包含一个条目,该box包含了data reference box进行sample数据检索的信息。没有“stsd”就无法计算media sample的存储位置。“stsd”包含了编码的信息,其存储的信息随媒体类型不同而不同。stsd中保存了解码器需要的媒体描述信息。STSD 用于存储采样率和编码熟悉的信息,包含一个sample description表。根据不同的编码方案和存储数据的文件数目,每个media可以有一个到多个sample description。sample-to-chunk atom/box(stsc)通过这个索引表,找到合适media中每个sample的description。多媒体类型描述信息。是音频中的AAC G711 还是视频中的H264、MPEG4、或者私有的HINT、TEXT。
(2)stss,sync sample table
“stss”确定media中的关键帧。对于压缩媒体数据,关键帧是一系列压缩序列的开始帧,其解压缩时不依赖以前的帧,而后续帧的解压缩将依赖于这个关键帧。“stss”可以非常紧凑的标记媒体内的随机存取点,它包含一个sample序号表,表内的每一项严格按照sample的序号排列,说明了媒体中的哪一个sample是关键帧。如果此表不存在,说明每一个sample都是一个关键帧,是一个随机存取点。
Sync Sample Table的布局
(3)stts,composition time to sample
“stts”存储了sample的duration,描述了sample时序的映射方法,我们通过它可以找到任何时间的sample。“stts”可以包含一个压缩的表来映射时间和sample序号,用其他的表来提供每个sample的长度和指针。表中每个条目提供了在同一个时间偏移量里面连续的sample序号,以及samples的偏移量。递增这些偏移量,就可以建立一个完整的time to sample表。
stts(Time-To-Sample Atoms)给出每个数据帧sample之间的解码时间间隔,单位是moov-trak-tkhd中的时间粒度。 Box/Atom的每个entry给出了具有相同时间间隔的连续帧的个数,这些帧的时间间隔值,结构如图。
Time-To-Sample的table entry布局
如果连续的帧有相同的时长,他们会被放在同一个entry中。如果所有的帧具有相同的时长,那么Atom中就只有一个entry。
stts实例,下图通过3个entries来描述9个帧。需要说明的是,这里的entry和chunk不是对应的。例如,4、5、6帧可以在同一个chunk中,但是,由于它们的时长不同,4帧的时长为3,而5、6帧的时长为1,因此,保存在不同的entry中。
(4)stco/co64, Chunk Offset Atom
stco/co64给出每个数据Chunk在文件中的偏移。Chunk Offset Atom的每个entry给出了每个chunk在文件中的偏移。如果Chunk Offset Atom的类型为stco,则保存的偏移量是32位;如果是co64,则保存的偏移量是64位的。布局如图。
chunk offset table的布局
需要注意的是,该Atom中只给出了每个chunk的偏移量,并没有给出每个sample的偏移量。因此,如果要获得每个sample的偏 移量,还需要用到Sample Size Table和Sample-To-Chunk Table。
(5)stsc, Sample-To-Chunk
stsc给出各个数据Chunk中包含的数据帧。一个chunk可能会包含一个或者几个帧sample。每个chunk会有不同的size,每个chunk中的帧也会有不同的size。即一个trunk包含几个sample的映射表,它也有一个表来映射sample和trunk之间的关系,查看这张表,就可以找到包含指定sample的trunk,从而找到这个sample。
entry中保存了第一个chunk号、每个chunk包含的帧数、帧描述ID。
Sample-To-Chunk Atom的table entry布局
每个entry包含一组chunk,其中每个chunk的帧数相同。而且,这些chunk中的每个帧都必须使用相同的帧描述。
如果chunk中的帧数或者帧描述改变,必须创建一个新的entry。
如果所有的chunk包含的帧数和帧描述相同,那么只有一个entry。
stsc实例,中表示至少有5个chunk,第1、2个chunk分别包含3个帧,帧描述ID是23;第3、4个chunk分别包含1个帧,帧描述ID是23;第5个及以后的chunk,包含1个帧,帧描述ID是24。
对于最后一个entry需要特殊的处理,因为无法判断什么时候结束。
(6)stsz, Sample Size
sample size table的布局
“stsz” 定义了每个sample的大小,包含了媒体中全部sample的数目和一张给出每个sample大小的表。这个box相对来说体积是比较大的。
所有媒体数据统一存放在mdat中,没有同步字,没有分隔符,只能根据索引进行访问。mdat的位置比较灵活,可以位于moov之前,也可以位于moov之后,但必须和stbl中的信息保持一致。另外,在写mp4文件的时候,对于mdat这个Atom,一般是先将Atom size填写0,待数据写完之后,再回过来填入具体大小。
存储媒体流信息,每个媒体流有多个chunk组成,每个chunk有多个sample组成,每个sample对应音视频的一帧数据。
https://blog.csdn.net/uyy203/article/details/79283087
https://www.jianshu.com/p/529c3729f357
https://blog.csdn.net/weixin_43549602/article/details/89327790
https://blog.csdn.net/hejjunlin/article/details/73162841
https://blog.csdn.net/NB_vol_1/article/details/58071879