以下内容源于朱有鹏嵌入式课程的学习与整理,如有侵权请告知删除。
参考内容
(1)mp4文件格式解析 - nigaopeng - 博客园(推荐)
(2)你真的懂 MP4 格式吗?
(3)mp4文件格式解析 - 简书
(4)你可能搞错了,MP4和H.264可不是一个东西_编码
(5)H264和MPEG4编码哪一种画质更好,文件大小有区别吗?
(6)FlexHex分析MP4格式的文件_caiBird_2021的博客-CSDN博客_flexhex
(7)MP4视频格式解析_linux_dafei的博客-CSDN博客_视频解析文件(推荐)
一、视频文件的概述
视频文件,记录着视频帧压缩编码后的数据,并且能够被播放器解码播放。
这里补充说明H.264(负责压缩编码)和MP4(负责打包与封装)的关系。H.264是视频图像压缩的标准或者说方法,负责将摄像机获取的原始视频帧数据进行压缩编码,形成H.264的码流。而MP4负责将H.264码流进行打包与封装。
就好比从果园里摘取水果(摄像机获取原始视频帧数据);去除腐败的水果(H.264对原始视频帧数据进行压缩编码,即去掉一些冗余的信息);然后将处理后的水果进行露天喊卖(保存为H.264格式的裸流文件),或者用纸皮箱、木箱、铁箱装起来然后再卖(不同箱子对应着不同的文件封装格式,MP4这种文件封装格式对应的箱子很牢靠,所以大部分果商使用这种箱子装水果)。另外MP4这个文件封装格式对应的箱子不仅可以装水果(比如H.264码流),也可以装蔬菜(其他压缩编码方式的码流)。
在数字图像技术中,编码出来的信息(比如使用H.264编码出来的码流),是一大堆分散的编码数据,因为我们习惯于文件操作,我们需要整理这一堆编码数据,将它们打包在一个个包裹中,然后组织形成一个文件,以便成块地进行存储或其它文件操作。这个打包的过程就是封装。封装时除了要装进视频编码,还要装进音频编码,有的封装还可以装进字幕。我们常说的MP4、MOV、AVI就是指封装文件格式。封装是有规则的,不是说一种封装格式就能够装进任意类型的视音频编码。但实际上,很多封装容器对音频编码和视频编码的组合方式放的很开,如AVI可以使用非压缩AVI,也可以使用H.264+AAC组合等。而我们常说的MP4格式,除了用来封装H.264编码,也能够封装xvid、divx5、3ivx、ffmpeg/ffdshow等编码。
视频文件里包含索引信息、有效信息,有效信息是指视频文件里面真正与视频、音频有关的数据,比如I、P、B帧,而索引信息可以增加容错性。视频文件的性能指标,包括效率与兼容性,其中效率体现在压缩的快慢、占据多少空间等内容,兼容性体现在支持哪些文件格式。MP4这种文件封装格式,凭借其效率与兼容性,成为大部分视频文件的封装格式。
二、MP4文件封装格式的概述
开始的时候,MP4指的是音频(MP3的升级版),即MPEG-2 AAC标准。随后MP4概念被转移到视频上,对应着MPEG-4标准。但我们日常说的MP4,一般是指能播放MPEG-4标准编码格式视频的播放器。
我们这里讨论MP4文件封装格式,对应的标准为 ISO/IEC 14496-12(即MPEG-4标准),即信息技术视听对象编码的第12部分:ISO 基本媒体文件格式(Information technology Coding of audio-visual objects Part 12: ISO base media file format)。
MP4文件封装格式是基于QuickTime容器格式定义的,因此参考QuickTime的格式定义对理解MP4文件格式很有帮助。
MP4文件格式是十分开放的容器,几乎可以用来描述所有的媒体结构。MP4文件中的媒体描述(索引信息?)与媒体数据(有效数据?)是分开的,并且媒体数据的组织也很自由,不一定要按照时间顺序排列,甚至媒体数据可以直接引用其他文件。
MP4也支持流媒体,目前被广泛用于封装H.264视频和AAC音频。
三、MP4文件封装格式的分析
1、分析工具
这里以格式为MP4的小视频1111为例,进行MP4文件封装格式的分析。
(1)winhex软件
可以利用winhex软件打开与修改测试视频。
(2)notepad软件
通过插件菜单选项进入view Hex模式可以编辑数据。比如修改字符编码为moov的数据之后,mp4播放器识别不了。
(3)MP4Info软件
该工具的下载地址为 MP4Info工具_1111。
2、基本概念
(1)MP4文件的结构树
一个典型的MP4的文件结构树如下。
(2)box的概念
MP4文件由许多box组成,所有数据都装在box中。
这些box有不同的类型和长度,可以将box理解为一个数据块,打包和解包时是以box为单位的。
如下图所示,标准的box由header和body组成。header的前4个字节表示该box的大小,紧接着的4个字节表示box的类型,接下来的8个字节表示largesize(如果box的大小超出了4字节所能表示的最大值,则 size=1 且box的大小就储存在largesize中);body 根据类型有不同的意义和格式。 但好像不是所有的box按照这种格式(比如moov类型的box就没有largesize)。
box中可以包含另一个box,这种box(包含其他box的box)被称为container box。
在MP4文件开始处,有且只有一个“ftyp”类型的box,作为MP4格式的标志,并包含关于文件的一些信息;接着有且只有一个“moov”类型的box,它是一种container box,它的子box包含着媒体的metadata信息;“mdat”类型的box包含着媒体数据,该类型的box也是container box,可以有多个这种box,也可以没有(当媒体数据全部引用其他文件时)。媒体数据的结构由metadata描述。
box中的字节序为网络字节序(大端字节序),即高字节存储在内存的低地址中。
(3)track的概念
track表示一些sample的集合,对于媒体数据来说,track表示一个视频或音频序列。hint track 这个特殊的track并不包含媒体数据,而是包含一些将其他数据track打包成流媒体的指示信息。
(4)sample的概念
对于非hint track来说,video sample即为一帧视频或一组连续视频帧,audio sample即为一段连续的压缩音频,它们统称sample。对于hint track,sample定义一个或多个流媒体包的格式。
(5)sample table的概念
指明sampe时序和物理布局的表。
(6)chunk的概念
由一个track的几个sample组成的单元。
3、主要box的简要说明
4、ftyp类型(File Type Box)
(1)整个文件有且只有1个该类型的box,该类型的box不能被其他box包含。
(2)该类型的box被放在文件的最开始处,用来指示文件类型的相关信息。
(3)该类型的box实例分析:
首先使用MP4Info软件打开上面的小视频。ftyp类型的box内容如下,由图中的“00 00 00 18”可知这个ftyp类型的box大小是24字节。
然后,这个ftyp类型的box的各个字段的解释如下表格:
字段 | 占用byte | 描述 |
box-size | 4 | 表示整个box块的长度(包含box-size这4个字节),这里是24个字节。 |
box-type | 4 | 表示box的类型,这里是ftyp。 |
major-brand | 4 | 表示优先选择哪种格式来解析当前文件,这里是mp42格式的ascii码。 |
minor-version | 4 | 表示上述格式的版本号,这里mp42的版本号。 |
compatibled_brands | 8=24-4*4 | 表示本文件兼容哪些协议,这里是mp42与isom。 |
其中major_brand 表示优先选择哪种格式来解析当前的文件,比较常见的格式有isom、mp41、mp42、avc1、qt、iso2等。例如 major_brand 是 A,compatible_brands 是 A1,当解码器同时支持 A、A1 规范时,将优先使用A规范来解码当前媒体文件。
5、moov类型(Movie Box)
(1)整个文件有且只有一个该类型的box,它不能被其他box包含。
(2)该类型的box主要包含文件媒体的metadata信息。
(3)该类型的box是一个container box,包含1个“mvhd”和若干个“trak”。
(4)该类型的box实例分析如下,其中圈出来的是该类型的header信息。从狭义上讲,moov类型的box仅包含header信息(即上图中我们点击moov时显示的信息),广义上囊括它的所有子box。
mvhd类型(Movie Header Box)
(1)“mvhd”是header box,一般作为“moov”类型的box的第一个子box(其他类型的container box也是如此,即header box都作为首个子box)。
(2)该类型的box实例分析如下:
其中每个字段的含义如下:
字段 | 字节数 | 意义 |
box-size | 4 | 表示box的大小(包含box-size这4个字节),这里是108个字节。 |
box-type | 4 | 表示box的类型,这里是mvhd。 |
version | 1 | 表示box的版本,0或1,一般为0。 |
flags | 3 | |
creation time | 4 | 创建时间(相对于UTC时间1904-01-01零点的秒数) |
modification time | 4 | 修改时间 |
time scale | 4 | 时间缩放因子?文件媒体在1秒时间内的刻度值,可以理解为1秒长度的时间单元数? |
duration | 4 | 视频时长,单位ms。 或者说该track的时间长度,用duration和time scale值可以计算track时长,比如audio track的time scale = 8000, duration = 560128,时长为70.016,video track的time scale = 600, duration = 42000,时长为70 |
rate | 4 | 推荐播放速率,高16位和低16位分别为小数点整数部分和小数部分,即[16.16] 格式,为1.0(0x00010000)时表示正常前向播放。 |
volume | 2 | 与rate类似,[8.8] 格式,1.0(0x0100)表示最大音量。 |
reserved | 10 | 保留位 |
matrix | 36 | 视频变换矩阵 |
pre-defined | 24 | |
next track id | 4 | 下一个track使用的ID。 |
track类型(Track Box)
(1)MP4文件至少有一个track,可以包含多个track,这些track之间彼此独立。
(2)trak类型的box 是一个container box,必须包含一个“tkhd”和一个“mdia”。
1)tkhd类型(Track Header Box)
(1)tkhd类型的box的实例如下:
(2)tkhd类型的box的字段含义如下。
字段 | 字节数 | 意义 |
box size | 4 | box大小,这里是0x5C=92。 |
box type | 4 | box类型,这里是tkhd,t\k\h\d对应的ASCII码是74\6B\68\64。 |
version | 1 | box版本,0或1,一般为0。(以下字节数均按version=0) |
flags | 3 | 按位或操作结果值,预定义如下: 0x000001 track_enabled,否则该track不被播放; 0x000002 track_in_movie,表示该track在播放中被引用; 0x000004 track_in_preview,表示该track在预览时被引用。 一般该值为7,如果一个媒体所有track均未设置track_in_movie和track_in_preview,将被理解为所有track均设置了这两项;对于hint track,该值为0 |
creation time | 4 | 创建时间(相对于UTC时间1904-01-01零点的秒数) |
modification time | 4 | 修改时间 |
track id | 4 | ID号,不能重复且不能为0 |
reserved | 4 | 保留位 |
duration | 4 | track的时间长度 |
reserved | 8 | 保留位 |
layer | 2 | 视频层,默认为0,值小的在上层 |
alternate group | 2 | track分组信息,默认为0表示该track未与其他track有群组关系 |
volume | 2 | [8.8] 格式,如果为音频track,1.0(0x0100)表示最大音量;否则为0 |
reserved | 2 | 保留位 |
matrix | 36 | 视频变换矩阵 |
width | 4 | 宽 |
height | 4 | 高,均为 [16.16] 格式值,与sample描述中的实际画面大小比值,用于播放时的展示宽高 |
2)mdia类型(Media Box)
(1)mdia类型的box定义了track媒体类型与sample数据,描述了sample信息。
(2)mdia类型的box是一个container box,包含1个“mdhd”,1个“hdlr”和1个“minf”,其中“mdhd”为media header box,“hdlr”为handler reference box,“minf”为media information box。
A、mdhd类型(Media Header Box)
(1)mdhd类型的box的各字段含义如下:
字段 | 字节数 | 意义 |
box size | 4 | box大小 |
box type | 4 | box类型 |
version | 1 | box版本,0或1,一般为0。(以下字节数均按version=0) |
flags | 3 | |
creation time | 4 | 创建时间(相对于UTC时间1904-01-01零点的秒数) |
modification time | 4 | 修改时间 |
time scale | 4 | 同前表 |
duration | 4 | track的时间长度 |
language | 2 | 媒体语言码。最高位为0,后面15位为3个字符(见ISO 639-2/T标准中定义) |
pre-defined | 2 |
(2)该类型的box的实例分析如下:
B、hdlr类型(Handler Reference Box)
(1)hdlr类型的box解释了媒体的播放过程信息。
(2)“hdlr”结构如下表。
字段 | 字节数 | 意义 |
box size | 4 | box大小,这里是33个字节 |
box type | 4 | box类型 |
version | 1 | box版本,0或1,一般为0。(以下字节数均按version=0) |
flags | 3 | |
pre-defined | 4 | |
handler type | 4 | 在media box中,该值为4个字符: “vide”— video track “soun”— audio track “hint”— hint track |
reserved | 12 | |
name | 不定 | track type name,以‘\0’结尾的字符串 |
(3)hdlr类型的box实例如下:
C、minf类型(Media Information Box)
(1)minf类型的box存储了解释track媒体数据的handler-specific信息,media handler用这些信息将媒体时间映射到媒体数据并进行处理。minf类型的box中的信息格式和内容,与媒体类型以及解释媒体数据的media handler密切相关,其他media handler不知道如何解释这些信息。
(2)minf类型的box是一个container box,其包含1个header box、1个“dinf”和1个“stbl”。其中header box根据track type(即media handler type)可分为“vmhd”“smhd”“hmhd”和“nmhd”;而“dinf”为data information box;“stbl”为sample table box。
C.a.1 vmhd(Video Media Header Box)
字段 | 字节数 | 意义 |
box size | 4 | box大小 |
box type | 4 | box类型 |
version | 1 | box版本,0或1,一般为0。(以下字节数均按version=0) |
flags | 3 | |
graphics mode | 4 | 视频合成模式,为0时拷贝原始图像,否则与opcolor进行合成 |
opcolor | 2×3 | {red,green,blue} |
C.a.2 smhd(Sound Media Header Box)
字段 | 字节数 | 意义 |
box size | 4 | box大小 |
box type | 4 | box类型 |
version | 1 | box版本,0或1,一般为0。(以下字节数均按version=0) |
flags | 3 | |
balance | 2 | 立体声平衡,[8.8] 格式值,一般为0,-1.0表示全部左声道,1.0表示全部右声道 |
reserved | 2 |
C.a.3 hmhd(Hint Media Header Box)
略。
C.a.4 nmhd(Null Media Header Box)
非视音频媒体使用该box,略。
C.b dinf(Data Information Box)
(1)“dinf”解释如何定位媒体信息,是一个container box。“dinf”一般包含一个“dref”,即data reference box;“dref”下会包含若干个“url”或“urn”,这些box组成一个表,用来定位track数据。
(2)track可以被分成若干段,每一段都可以根据“url”或“urn”指向的地址来获取数据,sample描述中会用这些片段的序号将这些片段组成一个完整的track。一般情况下,当数据被完全包含在文件中时,“url”或“urn”中的定位字符串是空的。
(3)“dref”的字节结构如下表。
字段 | 字节数 | 意义 |
box size | 4 | box大小 |
box type | 4 | box类型 |
version | 1 | box版本,0或1,一般为0。(以下字节数均按version=0) |
flags | 3 | |
entry count | 4 | “url”或“urn”表的元素个数 |
“url”或“urn”列表 | 不定 |
(4)“url”或“urn”都是box,“url”的内容为字符串(location string),“urn”的内容为一对字符串(name string and location string)。当“url”或“urn”的box flag为1时,字符串均为空。
(5)下面是一个“dinf”的字节实例图。其中黄色为“dinf”的box header,由红色部分我们知道包含的“url”或“urn”个数为1,红色后面为“url”box的内容。紫色为“url”的box header(根据box type我们知道是个“url”),绿色为box flag,值为1,说明“url”中的字符串为空,表示track数据已包含在文件中。
C.c stbl(Sample Table Box)
(1)“stbl”是MP4文件中最复杂的一个box,首先需要回忆一下sample的概念。sample是媒体数据存储的单位,存储在media的chunk中,chunk和sample的长度均可互不相同,如下图所示。
(2)“stbl”包含了关于track中sample所有时间和位置的信息,以及sample的编解码等信息。利用这个表,可以解释sample的时序、类型、大小以及在各自存储容器中的位置。
(3)“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)等。
(5)其中 “stsd”必不可少,且至少包含一个条目,该box包含了data reference box进行sample数据检索的信息。没有“stsd”就无法计算media sample的存储位置。“stsd”包含了编码的信息,其存储的信息随媒体类型不同而不同。
C.c.1 stsd(Sample Description Box)
(1)box header和version字段后会有一个entry count字段,根据entry的个数,每个entry会有type信息,如“vide”、“sund”等,根据type不同sample description会提供不同的信息,例如对于video track,会有“VisualSampleEntry”类型信息,对于audio track会有“AudioSampleEntry”类型信息。
(2)视频的编码类型、宽高、长度,音频的声道、采样等信息都会出现在这个box中。
C.c.2 stts(Time To Sample Box)
“stts”存储了sample的duration,描述了sample时序的映射方法,我们通过它可以找到任何时间的sample。“stts”可以包含一个压缩的表来映射时间和sample序号,用其他的表来提供每个sample的长度和指针。表中每个条目提供了在同一个时间偏移量里面连续的sample序号,以及samples的偏移量。递增这些偏移量,就可以建立一个完整的time to sample表。
C.c.3 stsz(Sample Size Box)
“stsz” 定义了每个sample的大小,包含了媒体中全部sample的数目和一张给出每个sample大小的表。这个box相对来说体积是比较大的。
C.c.4 stsc(Sample To Chunk Box)
用chunk组织sample可以方便优化数据获取,一个thunk包含一个或多个sample。“stsc”中用一个表描述了sample与chunk的映射关系,查看这张表就可以找到包含指定sample的thunk,从而找到这个sample。
C.c.5 stss(Sync Sample Box)
“stss”确定media中的关键帧。对于压缩媒体数据,关键帧是一系列压缩序列的开始帧,其解压缩时不依赖以前的帧,而后续帧的解压缩将依赖于这个关键帧。“stss”可以非常紧凑的标记媒体内的随机存取点,它包含一个sample序号表,表内的每一项严格按照sample的序号排列,说明了媒体中的哪一个sample是关键帧。如果此表不存在,说明每一个sample都是一个关键帧,是一个随机存取点。
C.c.6 stco(Chunk Offset Box)
“stco”定义了每个thunk在媒体流中的位置。位置有两种可能,32位的和64位的,后者对非常大的电影很有用。在一个表中只会有一种可能,这个位置是在整个文件中的,而不是在任何box中的,这样做就可以直接在文件中找到媒体数据,而不用解释box。需要注意的是一旦前面的box有了任何改变,这张表都要重新建立,因为位置信息已经改变了。
6、free类型(Free Space Box)
“free”中的内容是无关紧要的,可以被删除,且删除后不会对播放产生任何影响。
7、mdat类型(Meida Data Box)
(1)该类型的box用来存储媒体数据(每个帧的真实数据)。MP4的媒体描述(索引信息?)和媒体数据(真实的数据)是分开存放的,获得媒体数据之前必须要解析出每个帧数据所在的位置信息,这个信息位于stbl类型的box中,而真实的数据放在mdat类型的box中。
(2)可以有多个这种类型box,也可以没有(当媒体数据全部为外部文件引用时)。
(3)数据直接跟在“type”字段后面,但具体数据结构的意义需要参考metadata。