回 帖 发 新 帖 刷新版面

主题:[原创]MP4文件数据结构以及提取部分信息的代码

MP4文件数据结构以及提取部分信息的代码

一、名词解释
    ①track:音轨,它是样本的集合,是影像中可以独立操作的媒体单位。对于媒体数据来说,音轨
表示一个视频或音频序列,例如一个声道就是一个音轨。
    ②hint track:提示音轨,这个特殊的音轨并不包含媒体数据,而是包含了一些将其他数据音轨打
包成流媒体的指示信息。如果文件只是本地播放,可以忽略提示音轨,因为它们只与流媒体有关系。本
文不讨论提示音轨的内容,只关注包含媒体数据的本地MP4 文件。
    ③sample:样本,对于媒体音轨来说,视频样本即为一帧视频,或一组连续视频帧,音频样本即为
一段连续的压缩音频。对于提示音轨来说,样本定义一个或多个流媒体包的格式。
    ④sample table:样本表。指明样本时序和物理布局的表格。
    ⑤chunk:块。一个音轨中的几个连续样本组成的单元。换句话说,几个连续样本组成一个块,几个
块组成一个音轨。样本存放在块里是为了优化数据读取。比如音频样本大小都很小(约为32字节),每
次读取一个样本开销太大,可一次性读入所在块里的全部样本。
    ⑥ticks:瞬时,是MP4文件媒体的最小时间单元。


二、概述
    MP4 文件格式中,所有的内容存在一个称为movie的容器中。一个movie可以由多个音轨组成。每个
音轨就是一个随时间变化的媒体序列。例如视频帧序列。音轨里的每个时间单位是一个样本,它可以是
一帧视频,或者音频。样本按照时间顺序排列。注意,一帧音频可以分解成多个音频样本,所以音频一
般用样本作为单位,而不用帧。
    mp4 文件的媒体数据可以直接引用其他文件,这样,一部电影就可以由一个媒体数据库中的多个不
同文件组成(这些被引用的文件不一定是MP4 格式),而不用把它们全部拷贝到一个文件中。数据引用
允许在第二个媒体文件中找到媒体的位置。
    MP4 文件格式的定义里,用样本这个单词表示一个时间帧或者数据单元。每个音轨会有一个或者多
个样本描述。音轨里面的每个样本通过引用关联到一个样本描述。这个样本描述定义了怎样解码这个样
本,例如使用压缩算法。
    许多文件格式将媒体数据分成帧,头部或者其他数据紧紧跟随每一帧视频。而MP4 文件格式不是这
样,它的文件中的媒体描述与媒体数据是分开的,物理格式没有限定媒体本身的格式,文件的物理格式
和媒体数据的排列都不受媒体的时间顺序的限制,视频帧不需要在文件里按时间顺序排列,这就意味着
有一些文件结构来描述媒体的排列和对应的时间信息。
    MP4 文件由许多包(box)组成。包可以嵌套,嵌套的包称为集装包(container box)。
由于嵌套的出现,又形成了层,最顶级的层为文件层。
    包有很多类型(但并不都是必需的),MP4 文件格式定义了这些这些包的格式。类型名称由4个小
写的Ascii字符组成。包类型是预先定义好的,有固定的意义。MP4 文件的常用包类型见表1。
    包定义了如何在样本表中找到媒体数据的排列,这包括数据引用、样本大小表、样本块表和块偏移
量表。为了节约空间,这些表都很紧凑。根据这些表就可以找到音轨中每个样本在文件中的位置和大小。
有很多种类的音轨,其中有三个最重要:视频音轨包含了视频样本;音频音轨包含了音频样本;提
示音轨稍有不同,它描述了一个流媒体服务器如何把文件中的媒体数据组成符合流媒体协议的数据包。
如果文件只是本地播放,可以忽略提示音轨,它们只与流媒体有关系。
    一个音轨的连续几个样本组成的单元就被称为块。每个块在文件中有一个偏移量,这个偏移量是从
文件开头算起的,在这个块内,样本是连续存储的。这样,如果一个块包含两个样本,第二个样本的位
置就是块的偏移量加上第一个样本的大小。样本块表说明了样本序号和块序号的映射关系。注意块之间
可能会有死区,没有任何媒体数据引用到这部分区域,但是块内部不会有这样的死区。这样,如果在节
目编辑时,不需要一些媒体数据,就可以简单的留在那里,而不用引用,这样就不用删除它们了。类似
的,如果媒体存放在第二个文件中,但是格式不同于MP4 文件格式,这个陌生文件的头部或者其他文件
格式都可以简单忽略掉。
    每个音轨都有一个时间刻度,它定义了每秒钟有多少个瞬时。一般来说,对于音频音轨,这就是音
频的采样率。
    音轨的时间结构受一个剪辑列表影响,有两个用途:全部电影中的一个音轨的一部分时间片断变化
(有可能是重复使用);空白时间的插入,也就是空剪辑。特别注意的是如果一个音轨不是从节目开头
部分开始,剪辑列表的第一个剪辑就一定是空剪辑。
    每个样本都有规定的持续时间。每个音轨的全部持续时间,也就是它的时间戳(time-stamp)就是以
前的样本的持续时间之和。
    如果多个音频音轨包含在同一个文件中,它们有可能被混合在一起进行播放,并且由一个总音轨
(volume)和左右声道平衡(balance)控制。类似的,视频音轨也可以根据各自的层次序列号(从后
向前)和合成模式进行混合。另外,每个音轨可以用一个矩阵(matrix)进行变换,也可以全部电影用
一个矩阵进行变换。这样既可以进行简单操作(例如放大图像,校正90度旋转),也可以做更复杂的操
作(例如剪裁、任意旋转)。这个混合方法只是非常简单,是一个缺省的方法。
    MP4 还支持流媒体。
    MP4 文件中有关长度和大小的数据,其字节序为高位在前的存储方式。
    mp4文件与3gp文件的异同:3GP和MP4都是文件格式容器,都符合ISO BASEMEDIA FORMAT,文件里的
包类型和字段值只存在着略微的差别。它们最大的不同在于:默认使用的视/音频编码不同。3GP默认是
H263,AMR-NB/WB;MP4默认是H264/MPEG4,AAC/MP3等。


表1 MP4的包类型(星号线前是文件层的包,星号线后是子包)
-------------------------------------------------------------------------------------
名称 全称               描述
-------------------------------------------------------------------------------------
ftyp file type box          文件类型包,结构见表3
free Free Space Box          自由空间,可忽略
mdat media Data box          媒体数据包(集装包),结构见表21
meco metadata container box      附加元数据集合包
mfra movie fragment random box    影像片断随机访问包
moof movie fragment box        影像片断描述信息,流文件中才有
moov movie box            影像包(集装包),结构见表4
pdin progressive download information 累进下载信息
skip                  自由空间,可忽略
uuid                  用户扩展类型
        ********************************
clip track clipping box        音轨剪裁包
co64                  类同stco
ctts composition time to sample box  样本构成时间包
dinf data information box       数据信息包(集装包)
dref data reference box        数据引用包,又称数据定位基准包,结构见表12
edts edit box             剪辑包,结构见表19
elst edit list box          剪辑列表包,结构见表20
esds                  mp4a的子包
hdlr handler reference box      操作引用包,结构见表8
hmhd hint media header box      minf的提示媒体头部包
ilst                  meta的子包
imap track input map box       音轨输入映射包
load track load settings box     音轨装载设置包
matt track matte box         音轨框边包
mdia media box            媒体包(集装包)
mdhd media header box         mdia的头部包,结构见表7
meca metadata container box      附加元数据集合
meta metadata box           元数据
mfra mfra box             媒体索引,可查询直接定位所需时间点的媒体数据
minf media information box      媒体信息包(集装包),结构见表9
mp4a                  stsd的子包
mvhd movie header box         moov的头部包,结构见表5
nmhd null media header box      minf的非媒体头部包
smim sound media information box   音频媒体信息包
smhd sound media header box      minf的音频媒体头部包,结构见表11
stbl sample table box         样本表(集装包)
stco chunk offset box         块偏移量包,结构见表18
stsc sample to chunk box       样本块包,结构见表16
stsd sample description box      样本描述包,stbl的子包,结构见表13
stss sync sample box         同步样本包,结构见表15
stsz sample size box         样本大小包,结构见表17
stts time to sample box        样本时间包,结构见表14
stz2                  类同stsz
tkhd track header box         trak的头部包,结构见表6
trak track box            音轨包(集装包)
tref track reference box       音轨引用包(音轨包的子包)
vmim video media information box   视频媒体信息包
udta user data box          用户数据包
vmhd video media header box      minf的视频媒体头部包,结构见表10
-------------------------------------------------------------------------------------
说明:
    ①一个MP4文件必有且只有一个“ftyp”类型的包
    ②一个MP4文件必有且只有一个“moov”类型的包
    ③mdat包含着 MP4文件的媒体压缩数据,媒体数据的属性数据由metadata进行描述。当 MP4文件的
媒体数据不是全部引用其他文件时,此包是必有包,还可以有多个。当媒体数据全部引用其他文件时,
就不需要这种包了。
    ④moof类型包是流文件中的必有包,但本地MP4文件不需要。
    ⑤tref(音轨引用子包)定义音轨之间的关系。例如:一个MP4文件中有三条视频音轨,ID分别是2
、3、4,还有三条音频音轨,ID分别是6、7、8,在播放音轨2视频时要采用哪条音频与其配套播放呢?
假设配套的是音轨6,这时就需要在音轨2与音轨6的tref中指定一下,将2与6两条音轨绑定起来。但一
般本地mp4文件中只有2个音轨,一个视频的一个音频的,所以就不需要tref包。


三、包的数据结构
    包由包头(header)和包体(body)组成,其中包头指明包的大小和类型,包体根据包类型有不同
的意义和格式,它的结构见表2a。
    集装包也由包头和包体组成,其包体由若干子包组成。第一个子包称作头部包,头部包不能是集装
包,其它子包可以是集装包。头部包的结构见表2b。

表2a 文件层的包结构
---------------------------------------------
名称 数据类型 字节数 描述
---------------------------------------------
size  UINT32  4  包头和包体的总大小
type  字符型  4  包类型,Ascii小写字符
data         包体,数据
---------------------------------------------
说明:
    ①前2项合称包头,第3项为包体。


表2b 头部包的结构
--------------------------------------
名称  字节数 描述
--------------------------------------
box size  4  包大小,包括所有项
box type  4  包类型,Ascii小写字符
version  1  包版本
flags   3  标记
data      数据
--------------------------------------
说明:
    ①前4项合称包头,后1项称包体。


四、ftyp包(文件类型包)
    该包在文件的最前面,包含着该MP4文件版本、兼容协议等信息,是MP4文件格式的标志。
文件类型包的结构见表3。

表3 ftyp包的结构
------------------------------------------------------
名称       数据类型 字节数 说明
------------------------------------------------------
size        UINT32  4   包大小
type        字符型  4   Ascii字符“ftyp”
major brand    字符   4   主版本
minor version   UINT32  4   次版本
compatible brands 数组   不定
------------------------------------------------------
说明:
    ①前2项是包头,后3项是包体。
    ②compatible brands是字符型数组,以4字符为单位元素,描述兼容协议。


五、moov包(影像包)
    影像包是一个集装包,要么位于文件的前部(紧跟在ftyp包之后),要么位于文件的末尾,它定义
了文件媒体的属性数据,其包体包含了头部包mvhd和其他子包,如音轨包trak、剪裁包clip、颜色表包
ctab、用户数据包udta(user data Box)。其中音轨包是必有包,一般至少有2个,一个视频的,一
个音频的。
    下面分别解析。

1.影像包的结构
    影像包的包结构见表4a,子包树形结构见表4b,。

表4a moov的结构
----------------------------------------
名称  字节数  描述
-------------------------------------------
size   4   包大小
type   4   Ascii字符“moov”
mvhd   108   头部包,必有
trak       音轨包,必有且可有多个
clip       剪裁子包,可选
ctab       颜色表包,可选
udta       用户数据包,可选
-------------------------------------------
说明:
    ①前2项是包头,后面都是包体。


表4b moov的子包树形结构(只列出了一个音轨)
---------------------------------------------------------------------
名称         描述
---------------------------------------------------------------------
moov           影像包(集装包)。以下的集装包不列出包头
..mvhd        moov的头部包,必有。结构见表5
..trak        音轨包(集装包),必有。一般有2个,视/音频各一个
....tkhd       trak的头部包,必有。结构见表6
....edts       剪辑包,可选,结构见表19
......elst      剪辑列表包,可选
....mdia       媒体包(集装包),必有
......mdhd      mdia的头部包,必有,结构见表7
......hdlr      操作引用包,必有,结构见表8
......minf      媒体信息包(集装包),必有,结构见表9
........smhd     minf的音频音轨头部包,结构见表11
........vmhd     minf的视频音轨头部包,结构见表10
........dinf     数据信息包(集装包),必有
..........dref    dinf的头部包,数据引用包,必有,结构见表12
..........stbl    样本表(集装包),必有
............stsd   stbl的子包,必有,结构见表13
..............mp4a  可选
................esds 可选
............stts   样本时间包,结构见表14
............stss   同步样本包,可选,结构见表15
............stsc   样本块包,结构见表16
............stsz   样本大小包,结构见表17
............stco   块偏移量包,结构见表18
..udta        用户数据包
....meta       元数据
......hdlr      操作引用包
......ilst
........data
---------------------------------------------------------------------
说明:
    ①在同一个音轨中,smhd包与vmhd包只能有其中一个,不能并存。


2.mvhd(影像包的头部包)
    mvhd定义了整部电影的时间刻度,记录了创建时间、修改时间、持续时间以及渲染特性等信息。

表5 mvhd的结构
-------------------------------------------------------------------------------
名称        字节数  描述
-------------------------------------------------------------------------------
box size       4  包大小,共108(&H6C)字节
box type       4  包类型,Ascii字符“mvhd”
version        1  版本,一般为0
flags         3  标记,一般为0
creation time     4  创建时间(相对于UTC时间1904-01-01零时的秒数)
modification time   4  修改时间(同上)
time scale      4  时间刻度,设置文件媒体每秒=多少个瞬时
duration       4  持续时间,设置文件播放时间共有多少个瞬时
rate         4  播放速率
volume        2  音量
reserved       10  保留字段
matrix        36  视频变换矩阵,定义了此影像中两个坐标空间的映射关系
pre-defined     24  预定义6项如下:
预览时间      4  预览此影像的开始时间
预览持续时间    4  预览的瞬时数
Poster time     4  播放影像海报的时间
Selection timet   4  集锦开始时间
Selection duration 4  集锦持续时间
当前时间      4  当前时间
next track id     4  下一条音轨的ID号
-------------------------------------------------------------------------------
说明:
    ①对于创建时间和修改时间来说,4字节的时间值最大为0xFFFFFFFF,从1904年1月1日0点至今的秒
数(每年按365天算,不考虑闰年),通过计算最多支持到2040年。如果这两个参数是必要的参数,那
么到2040年后,也许所有的MP4文件一夜之间就无法播放了。
    ②用duration和time scale可以计算音轨时长:音轨时长(秒)=duration÷time scale
例如:音频音轨的time scale = 8000, duration = 560128,时长=560128÷ 8000=70.016秒
视频音轨的time scale = 600, duration = 42000,时长=42000÷600=70秒
    ③rate是[16.16] 格式,高16位和低16位分别为小数的整数部分和小数部分,1.0表示正常向前播放
    ④volume是[8.8] 格式。如果是音频音轨,1.0表示最大音量;如果是视频音轨,该项值=0
    ⑤next track id指向的音轨其实是不存在的,此ID号是在moov包中最大的音轨ID号再加上1。我们
也可以由此ID号减1从而得到音轨的数目(音轨ID一般从1开始连续递增)。


3.trak(影像包的音轨子包)
    一个音轨包就是一条音轨,其中包含了该音轨的媒体数据引用和描述(注意:不包含具体的媒体压
缩数据),各音轨之间彼此独立,各有自己的时间和空间信息。
    一个MP4文件中至少有一个音轨包,可以有多个。例如,电影《让子弹飞》的正版DVD,就有以下音
轨:①有一条视频音轨用于电影画面;②至少有两条音频音轨分别提供了普通话与四川话版,实际上为
了营造更加逼真的现场效果配合多声道家庭影院,该影片还独有一条音效音轨;③多条字幕音轨:简体
中文,繁体中文,英文……。从中我们可以理解为什么音轨包可以有多个,并且每个音轨都是独立的,
需要各自描述互不干涉。
    音轨包也是集装包,本身没有特别的字段,需要包体中的子包来进一步说明有效的内容。它的包体
由一个头部包tkhd(track header box)和一个媒体包mdia组成,此外还可以有很多可选的子包。可选
子包有:
    ①clip(音轨剪裁包)
    ②matt(音轨框边包)
    ③edts(剪辑包)
    ④tref(音轨引用包)
    ⑤load(音轨载入设置包)
    ⑥imap(音轨输入映射包)
    音轨包的包头就不做解析了,下面只解析包体中的头部包tkhd和媒体子包mdia。

㈠tkhd(音轨包的头部包)
    tkhd定义了一个音轨的特性,例如时间,空间和音量信息。

表6 tkhd的结构
----------------------------------------------------------------------------------------
字段       字节数  描述
----------------------------------------------------------------------------------------
box size      4   包大小,共92(&H5C)字节
box type      4   包类型,Ascii字符“tkhd”
version      1   版本,有0或1两个版本,一般为0
flags       3   标记,按位进行“或”操作的结果值,其值有预定的意义
creation time   4   创建时间(同表5),此字段在版本1有8字节
modification time 4   修改时间(同表5),此字段在版本1有8字节
track id      4   本音轨ID(各音轨的ID不能相同且>0)
reserved      4   保留字段
duration      4   音轨持续时间(有多少瞬时),此字段在版本1有8字节
reserved      8   保留字段
layer       2   视频层,值小的在上层,因视频通常只有一层,所以默认为0
alternate group  2   音轨分组信息,默认为0(表示该音轨与其他音轨无群组关系)
volume       2   音量,音频音轨才有值,视频音轨=0
reserved      2   保留字段
matrix      36   视频变换矩阵,定义了此音轨中两个坐标空间的映射关系
width       2   画面宽,视频音轨才有值,音频音轨=0
reserved      2   保留字段
height       2   画面高,视频音轨才有值,音频音轨=0
reserved      2   保留字段
--------------------------------------------------------------------------------------
说明:
    ①flags的预定义结果值如下:
=0 该音轨为提示音轨
=1 需激活,否则该音轨不被播放
=2 该音轨在播放中被引用
=4 该音轨在预览时被引用
=8 如果一个媒体所有音轨的该值均≠2或≠4,将被理解为所有音轨均设置了这两项
    ②volume是[8.8] 格式。如果是音频音轨,1.0表示最大音量;视频音轨=0
    ③width和height,均为[16.16] 格式。

㈡音轨包的mdia子包(媒体包)
    mdia也是一个集装包,其子包的结构和种类比较复杂,它定义了音轨的媒体类型以及样本数据,描
述样本数据的媒体操作成员、媒体时间刻度、音轨持续时间、媒体和音轨详情信息(例如音量和图形模
式)。它也可以包含一个引用,指明媒体数据存储在另一个文件中。也可以包含一个样本表子包,指明
样本描述、持续时间、每个媒体样本的数据引用的偏移量字节。媒体包的包体包含1个头部包mdhd、1
个操作引用包(hdlr)和1个媒体信息包(minf),它们的数据结构分别见表7、表8、表9。有的包体
还包含1个用户数据包udta。
    mdia的包头就不解析了,下面只解析它的包体。

表7 mdhd的结构
---------------------------------------------------------------------------------------
字段       字节数 描述
---------------------------------------------------------------------------------------
box size      4  包大小,共32(&H20)字节
box type      4  包类型,Ascii字符“mdhd”
version       1  版本,一般为0
flags        3  标记
creation time    4  创建时间(同表5)
modification time  4  修改时间(同表5)
time scale     4  时间刻度,设置该音轨每秒=多少个瞬时
duration      4  持续时间,设置该音轨共有多少个瞬时
language      2  媒体语言码
pre-defined     2  预定义(回放质量)
-----------------------------------------------------------------------------------------
说明:
    ①如果是音频音轨,本包中的time scale也作为音频的采样频率。
    ②language共16位,最高位=0,后面15位表示3个字母,例如汉语是“chi”,日语是“jpn”(见
《ISO 639-2/T标准》中的定义)。


表8 hdlr的结构
---------------------------------------------
字段    字节数 描述
---------------------------------------------
box size   4  包大小,长度不定
box type   4  包类型,Ascii字符“hdlr”
version    1  版本,0或1,一般为0
flags     3  标记,这里为0
pre-defined  4  预定义成员类型
handler type 4  操作类型
reserved   12  保留字段
name    不定  生成此媒体的程序名称
---------------------------------------------
说明:
    ①hdlr包解释了媒体的播放过程信息,一个媒体包内的操作子包解释了媒体流的播放过程,例如,
一个视频操作处理一个视频音轨。它也可能被包含在meta中。
    ②预定义成员类型当前只有两种类型:mhlr-媒体操作;dhlr-数据操作。如果此项值=0,则默认为
mhlr。
    ③操作类型因预定义成员类型的不同而不同。如果成员类型是mhlr,那么操作类型有:vide=视频
音轨;soun=音频音轨;hint=提示音轨。如果成员类型是dhlr,这个字段定义了数据引用的类型,例
如:“alis”是文件的别名。
    ④name是0结尾的utf-8字符串,如果是空串,那就只有一个0,所以至少有1字节。


表9 minf的结构
-----------------------------
名称    描述
-----------------------------
尺寸   包大小
类型   Ascii字符“minf”
头部包  有4种类型
dinf包  数据信息包
stbl包  样本表包
-----------------------------
说明:
    ①minf也是一个集装包,它存储了解释音轨媒体数据的操作特性信息,这些信息是与媒体定义的数
据类型特别对应的,而且媒体信息子包的格式和内容也是与解释此媒体数据流的媒体操作程序密切相关
的,媒体操作程序用这些信息将媒体时间映射到媒体数据,并进行处理。
    ②头部包根据音轨类型分为4种:vmhd包(视频媒体头包,见表10)、smhd包(音频媒体头包,见
表11)、hmhd包(提示媒体头包)和nmhd包(非媒体头包)。例如:如果头部包是vmhd类型,那么后面
的dinf包和stbl包就都是关于视频的信息。反过来,我们也可以根据这个头部包来判断一个音轨是什么
类型:如果是vmdh,就是视频音轨,smhd就是音频音轨,等等。
    ③dinf包解释如何定位媒体信息,它是集成包,但包体中没有头部包,只有2个子包dref(数据定
位基准包)和stbl(样本表包)。dref下会包含若干个url包或urn包,这些包组成一个表,用来定位音
轨数据。简单地说,音轨可以被分成若干块,每一块都可以根据url或urn指向的地址来获取数据,而在
样本描述包(stsd)中会用这些块的序号将这些片段组成一个完整的音轨。一般情况下,当数据被完全
包含在文件中时(本地MP4 文件),url或urn中的定位字符串是空的。dref包的结构见表12,stsd包的
结构见表13。stbl包很复杂也很重要,参见下文“六、stbl包(样本表包)”。


表10 vmhd的结构
-----------------------------------------------
名称     字节数  意义
-----------------------------------------------
box size    4  包大小,共20(&H14)字节
box type    4  包类型,“vmhd”字符
version     1  版本,0或1,一般为0
flags      3  标记,这里总是=1
graphics mode  2   视频合成模式
opcolor     6  操作色(透明色)
-----------------------------------------------
说明:
    ①视频合成模式,默认值为0拷贝原始图像也就是直接覆盖,否则与操作色进行合成。
    ②操作色按红、绿、蓝顺序排列,每色占用2字节。

 
表11 smhd的结构 
---------------------------------------------
名称  字节数  意义
---------------------------------------------
box size  4  包大小,共16(&H10)字节
box type  4  包类型,“smhd”字符
version   1  版本,0或1,一般为0
flags    3  标记
balance   2  立体声平衡
reserved  2  保留的
---------------------------------------------
说明:
    ①balance是[8.8]格式值,0表示左右声道音量相同,-1.0表示全部左声道,1.0表示全部右声道。


表12 dref的结构 
------------------------------------------------------
名称    字节数  意义
------------------------------------------------------
box size    4  包大小
box type    4  包类型,“dref”字符
version     1  版本,0或1,一般为0
flags     3  标记
entry count  4  条目数目,即数据引用表的元素数目
数据引用表     每个条目都是包结构:
尺寸     4  包大小
类型     4  引用类型:url或urn
版本     1  这个数据引用的版本
标志     3  如果为1,表示自我引用
数据    不定  数据引用信息(字符串)
------------------------------------------------------
说明:
    ①url或urn都是包,url包的数据为位置字符串,urn的数据为两个字符串(名称串和位置串)。当
url或urn的标志=1时,没有数据。
    ②引用类型有3种:
alis:别名。一个别名包含文件信息,例如全路径名。
rsrc:别名。别名末尾是文件使用的资源类型(32位整数)和ID(16位带符号的整数)
url: 一个utf-8字符串,表示一个URL。字符串后可以有其他的数据。


六、stbl(样本表包)
    stbl包是dinf包的子包,但它本身也是集成包,它的子包中包含了音轨中样本的所有时间和位置的
信息,以及样本的编解码等信息。利用这些表,可以解释样本的时序、类型、大小以及在各自存储容器
中的位置。例如,视频数据是否需要解压缩,解压缩算法是什么?其子包有stsd,stts、stss、stsc、
stsz、stco等(有的可能还有ctts子包),这6个子包非常重要,是 MP4文件结构的精华,这些子包中
的表有着相同的样本数目。stbl包的包头就不解析了,下面分别解析6个重要子包。

1.stsd(样本描述包)
    stsd,至少包含一个条目,该包包含了数据定位基准包进行样本数据检索的信息。没有stsd就无法
计算媒体样本的存储位置。stsd包含了编码的信息,其存储的信息随媒体类型不同而不同。stsd包的结
构见表13。

表13 stsd的结构
--------------------------------------------------------
名称     字节数 描述
--------------------------------------------------------
box size    4  包大小
box type    4  包类型,Ascii字符“stsd”
version     1  版本
flags      3  标记
entry count   4  下表中的条目数
entry表       表结构如下:
尺寸     4  这个样本描述的字节数
数据格式   4  存储数据的格式。
保留     6
数据引用索引 2  可检索与当前样本描述关联的数据
--------------------------------------------------------
说明:
    ①这是视频stsd包的结构。如果是音频stsd包,紧接entry表数据格式字段后面的是mp4a子包,mp4a
子包里面又有一个esds子包,esds子包中的数据与采样率有关。
    ②entry表是样本描述表,它包含了数据引用子包检索媒体样本的目录信息。没有样本描述,就不
可能计算出媒体样本存储的位置。不同的媒体类型存储不同的样本描述,例如视频媒体,样本描述就是
图像的结构。每个媒体可以有一个以上的样本描述。样本块子包通过这个表,找到合适媒体中每个样本
的描述。


2.stts(样本时间包)
    stts存储了有相同持续时间的样本的数量和持续时间,能方便地根据时间戮找到对应的样本,或者
获取某个样本对应的时间戮。stts包的结构见表14。

表14 stts的结构
-------------------------------------------------------
字段     字节数  描述
-------------------------------------------------------
尺寸      4   包大小
类型      4   Ascii字符“stts”
版本      1   这个子包的版本
标志      3   这里为0
条目数目    4   下表中的条目数
样本时间表       表结构如下:
样本数目   4   有相同持续时间的连续样本的数目
样本持续时间 4   每个样本的持续时间
-------------------------------------------------------
说明(以下两点说明是笔者本人的理解,不一定正确,抛砖引玉吧):
    ①如果多个样本有相同的持续时间,可以只用一项描述所有这些样本,样本数目字段说明相同样本
的个数。例如:如果一个视频媒体有1000个样本,有500个的持续时间相同,另外500个的持续时间也相
同(但与前面500个的持续时间不同),那么样本数目字段值=2。如果1000个样本的持续时间都相同,
那么那么样本数目字段值=1。
    ②样本持续时间字段中的“每个样本”指的是①所描述的相同样本,以①为例,如果=2,那么本
字段会有2个持续时间值;如果=1,那么本字段只有1个持续时间值。


3.stss(同步样本包)
    视频音轨才有此包。
    stss存储了每个关键帧的样本ID。对于压缩媒体数据,关键帧是一系列压缩序列的开始帧,它的解
压缩不依赖以前的帧,而后续帧的解压缩要依赖于这个关键帧。stss可以非常紧凑的标记媒体内的随机
存取点,它包含一个样本序号表,表内的每一项严格按照样本的序号排列,说明了媒体中的哪一个样本
是关键帧。同步样本子包是可选的,如果此表不存在,说明所有样本都是关键帧,是一个随机存取点。
stss的结构见表15。

表15 stss的结构
-------------------------------------
字段   字节数 描述
-------------------------------------
尺寸    4  包大小
类型    4  Ascii字符“stss”
版本    1  这个子包的版本
标志    3  这里为0
条目数目  4  下表中的条目数
同步样本表    表结构如下:
样本序号 4  关键帧的样本序号
--------------------------------------
说明:
    ①在一篇文章中看到有关这个包的另外一个解释:此包决定了整个mp4 文件是否可以拖拉, 如果这
个包只有一个条目,则拖拉时cpu将达到100%。


4.stsc(样本块包)
    一个块包含一个或多个样本。块的长度不同,块内的样本的长度也不同。stsc用一个表描述了样本
与块的映射关系,查看这张表就可以找到包含指定样本的块,从而找到这个样本。stsc包的结构见表16。


表16 stsc的结构
------------------------------------------
字段      字节数 描述
------------------------------------------
尺寸        4 包大小
类型        4 Ascii字符“stsc”
版本        1 这个子包的版本
标志        3 这里为0
条目数目      4 下表中的条目数
样本块表        表结构如下:
first_chunk    4 优先块序号
samples_per_chunk 4 当前块内的样本数目
样本描述ID    4 样本描述的序号
------------------------------------------
说明:
    ①样本块表类似于行程编码,第一个优先块减去第二个优先块就是一共有多少个块包含相同的样本
数目,这样通过不断的叠加,就可以得到一共有多少个块,每个块包含多少个样本,以及每个块对应的
描述。


5.stsz(样本大小包)
    stsz定义了每个样本的大小,包含了媒体中全部样本的数目和一张给出每个样本大小的表。这个包
的体积可能比较大。stsz的结构见表17。

表17 stsz的结构
--------------------------------------
字段   字节数  描述
--------------------------------------
尺寸    4   包大小
类型    4   Ascii字符“stsz”
版本    1   这个子包版本
标志    3   这里为0
样本大小  4   所有样本的大小
条目数目  4   下表中的条目数
样本大小表     表结构如下:
大小   4   每个样本的大小
--------------------------------------
说明:
    ①如果所有样本的大小相同,那么样本大小字段就是这个值。否则,这个字段的值=0,那些长度
值保存在样本大小表中。
    ②样本大小表根据样本编号的索引,第一项就是第一个样本,第二项就是第二个样本,由此类推。
    ③样本大小表包含了每个样本的长度,找到样本的序号,就可以找到对应样本的长度。


6.stco(块偏移量包)
    stco定义了每个块在文件中的绝对偏移位置(该偏移量可以是32位的也可以是64位的,后者用来支
持处理超大文件),这样做就可以直接在文件中找到媒体数据,而不用解释包。需要注意的是一旦前面
的包有了任何改变,这张表都要重新建立,因为位置信息已经改变了。stco的结构见表18。

表18 stco的结构
--------------------------------------
字段   字节数  描述
--------------------------------------
尺寸    4   包大小
类型    4   Ascii字符“stco”
版本    1   这个子包的版本
标志    3   这里为0
条目数目  4   下表中的条目数
块偏移量表     表结构如下:
偏移量  4   从文件开始到当前块
--------------------------------------
说明:
    ①块偏移量的单位是字节。
    ②具体的块数据都存放在mdat包中,第一块紧跟在包类型的字串后面。
    ③块偏移量表根据块编号索引,第一项就是第一个块,第二项就是第二个块,由此类推。


七、moov包里可选的其它包

1.剪辑包(edit box)
    剪辑包定义了创建影像中一个音轨的一部分媒体。所有的剪辑都在一个表里面,包括每一部分的
时间偏移量和长度。如果没有该表,则此音轨会被立即播放。一个空剪辑用来偏移音轨的起始时间。
如果没有剪辑包或剪辑列表子包,则此音轨使用全部媒体。
剪辑包是一个集成包,本身没有特别的字段,需要子包来进一步说明有效的内容。

表19 edts的结构
---------------------------------------
字段   字节数  描述
---------------------------------------
尺寸    4   包大小
类型    4   Ascii字符“Edts”
包内容       子包
-----------------------------------------


2.剪辑列表子包(edit list box)
    剪辑列表子包用来映射影像的时间到此音轨媒体的时间。所有信息在一个表中。

表20 elst的结构
-------------------------------------------
字段    字节数  描述
-------------------------------------------
尺寸      4  包大小
类型      4  Ascii字符“elst”
版本      1  这个包的版本
标志      3  这里为0
条目数目    4  下表中的条目数目
剪辑列表 不定    表结构如下:
音轨持续时间 4  剪辑区域的持续时间
时间     4  剪辑区域的媒体开始时间
速率     4  必须>0
-------------------------------------------
说明:
     ①剪辑列表中的时间值=-1表示是空剪辑。音轨中的最后一个剪辑不能为空。


3.视频媒体信息子包(Video Media Information Box)
    视频媒体信息子包是视频媒体的第一层子包,包含其他的定义视频媒体数据的特性。


4.音频媒体信息子包(Sound Media Information Box)
    音频媒体信息子包是音频媒体的第一层子包,包含其他的定义音频媒体数据的特性。


八、mdat(媒体数据包)
    mdat包存放了音频、视频和其他的数据,通常还会有一些文本信息也放在mdat包中,各种信息的顺
序不固定。mdat的结构见表21。

表21 mdat包结构
----------------------------------------------
名称  字节数 描述
----------------------------------------------
box size 4  包头和包体的总大小
box type 4  包类型,Ascii码字符“mdat”
largesize 8  数据类型为uint64
data      媒体数据
-----------------------------------------------
说明:
    ①如果size>1,就没有largesize项;如果size=1,说明包很大,超过了uint32的最大值,这时
就会有largesize项,包大小就由该项值决定;如果size=0,也没有largesize项,表示该包为文件的
最后一个包,文件结尾即为该包结尾。
    ②媒体数据是以块的形式存在的,样本数据包含在块中。
    ③笔者只在一个mp4 文件中看到了第一个块前面有一段文本字串(这个文件是2017年初很流行的公
鸡唱歌视频),字串前有个4字节的值,估计可能是字串长度(sliece)。


七、实例

1.下面是一个MP4文件的前512个数据:
------------------------------------------------------------------------
0000: 00 00 00 1C 66 74 79 70 6D 70 34 32 00 00 00 00   ....ftypmp42....
0010: 6D 70 34 32 69 73 6F 6D 61 76 63 31 00 00 81 64   mp42isomavc1..乨
0020: 6D 6F 6F 76 00 00 00 6C 6D 76 68 64 00 00 00 00   moov...lmvhd....
0030: CE DA 4F E8 CE DA 4F F3 00 01 5F 90 00 73 66 DB   乌O栉贠..._..sf.
0040: 00 01 00 00 01 00 00 00 00 00 00 00 00 00 00 00   ................
0050: 00 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00   ................
0060: 00 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00   ................
0070: 40 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   @...............
0080: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 03   ................
0090: 00 00 41 F0 74 72 61 6B 00 00 00 5C 74 6B 68 64   ..A餿rak...\tkhd
00A0: 00 00 00 01 CE DA 4F E8 CE DA 4F F3 00 00 00 01   ....乌O栉贠.....
00B0: 00 00 00 00 00 73 43 D0 00 00 00 00 00 00 00 00   .....sC.........
00C0: 00 00 00 00 00 00 00 00 00 01 00 00 00 00 00 00   ................
00D0: 00 00 00 00 00 00 00 00 00 01 00 00 00 00 00 00   ................
00E0: 00 00 00 00 00 00 00 00 40 00 00 00 01 E0 00 00   ........@.......
00F0: 01 10 00 00 00 00 41 8C 6D 64 69 61 00 00 00 20   ......A宮dia... 
------------------------------------------------------------------------

解析:
0000-001B:ftyp包
    0000-0007:包头
        0000-0003:包大小,&H1C 字节
        0004-0007:包类型,字符“ftyp”
    0008-001B:包体
        0008-000F:版本为mp4 2.0
        0010-001B:mp42isomavc1(兼容mp42、isom、avc1三种协议)
001C-817F:moov包(注:00FF以后的内容未列出)
    001C-0023:包头
        001C-001F:包大小,&H8164 字节
        0020-0023:包类型,字符“moov”
    0024-817F:包体
        0024-008F:mvhd包,这是头部包
            0024-002B:包头,包括包大小(&H6C)和包类型(mvhd),以下为包体
            002C-002F:版本和标记
            0030-0033:创建时间(距1904-1-1 0:0:0已有 &HCEDA4FE8 秒,即2013-12-20 19:50:00)
            0034-0037:修改时间(距1904-1-1 0:0:0已有 &HCEDA4FF3 秒,即2013-12-20 19:50:11)
            0038-003B:时间刻度,每秒钟划分为 &H15F90 瞬时
            003C-003F:持续时间,&H7366DB 瞬时,可播放时间=&H7366DB÷&H15F90=84秒
            0040-0043:播放速率=1.0,正常播放
            ……
        0090-427F:trak包,这是集成包(注:00FF以后的内容未列出)
            0090-0097:包头,包括包大小(&H41F0)和包类型(trak),以下为包体
            0098-00F3:tkhd子包,这是头部包
                0098-009F:包头,包括包大小(&H5C)和包类型(tkhd),以下为包体
                00A0-00A3:版本和标记
                00A4-00AB:创建时间和修改时间,同上
                00AC-00AF:本音轨ID=1
                ……
                00EC-00ED:画面宽
                ……
                00F0-00F1:画面高
                ……


2.常用计算
    ①视频帧率=持续时间÷帧的数目
    ②电影的比特率(bps)=整部电影的尺寸÷时间长度
    ③电影长度=持续时间÷时间刻度


八、提取MP4文件部分信息的代码
    提取的信息为:创建时间、修改时间、时间刻度、持续时间、画面宽高。下面是源代码。

Private Sub Command1_Click()
Dim mp4Data(4999) As Byte, tem() As Byte
Dim mp4Name As String
Dim creationTime As String     '创建时间
Dim modificationTime As String '修改时间
Dim timeScale As Long          '时间刻度
Dim duration As Long           '持续时间
Dim mp4Width As Long           '画面宽
Dim mp4Height As Long          '画面高
Dim st1 As String, st2 As String, st3 As String, st4 As String
Dim i As Integer, k As Long, st As String

mp4Name = Text1 '文本框中是全路径文件名
Open mp4Name For Binary As #1
Get #1, , mp4Data
Close #1

tem = StrConv("mvhd", vbFromUnicode)
k = InStrB(mp4Data, tem) '查找mvhd包
If k = 0 Then Exit Sub

For i = 7 To 22
  Select Case i
    Case 7 To 10: st1 = st1 & Right("0" & Hex(mp4Data(k + i)), 2)
    Case 11 To 14: st2 = st2 & Right("0" & Hex(mp4Data(k + i)), 2)
    Case 15 To 18: st3 = st3 & Right("0" & Hex(mp4Data(k + i)), 2)
    Case 19 To 22: st4 = st4 & Right("0" & Hex(mp4Data(k + i)), 2)
  End Select
Next

creationTime = shiftTime(st1)
modificationTime = shiftTime(st2)
timeScale = Val("&H" & st3)
duration = Val("&H" & st4)
st = "创建时间:" & creationTime & vbCrLf & "修改时间:" & modificationTime & vbCrLf & "播放时长:" & Int(duration / timeScale) & " 秒" & vbCrLf

tem = StrConv("tkhd", vbFromUnicode)
k = InStrB(mp4Data, tem) '查找tkhd包
If k = 0 Then Exit Sub

st1 = "&H" & Right("0" & Hex(mp4Data(k + 79)), 2) & Right("0" & Hex(mp4Data(k + 80)), 2)
st2 = "&H" & Right("0" & Hex(mp4Data(k + 83)), 2) & Right("0" & Hex(mp4Data(k + 84)), 2)
mp4Width = Val(st1)
mp4Height = Val(st2)
st = st & "画面宽高:" & mp4Width & "/" & mp4Height

Text2 = st
End Sub


Private Function shiftTime(t1 As String) As String '总秒数转为日期和时间序列
Dim t2#, d&, h&, n#, s&
Dim tem

t2 = BaseChange(t1)
tem = t2 / 60
n = Fix(tem) '分
s = t2 - n * 60 '剩下的秒
h = n \ 60 '时
n = n Mod 60 '剩下的分
d = h \ 24 '日
h = h Mod 24 '剩下的时

shiftTime = DateAdd("d", d, #1/1/1904#) & "  " & h & ":" & n & ":" & s
End Function


Private Function BaseChange(Num As String) As Double '16进制转为10进制
Dim A#, B#
Dim t3 As String, k As Integer, i As Integer, L As Integer

L = Len(Num)
For i = 0 To L - 1
  t3 = Mid(Num, L - i, 1)
  A = Asc(t3) - 48: If A > 9 Then A = A - 7
  B = B + A * 16 ^ i
Next

BaseChange = B
End Function


说明:
    ①因为Val函数能转换的最大16进制数据为&H7FFFFFFF(长整形),所以要自编BaseChange函数。
    ②shiftTime函数中,求剩下的秒数为什么不用整除号“\”和Mod取模呢?原因同①。


回复列表 (共6个回复)

沙发

秋水兄还是一如既往的人专注于数据文件研究啊

板凳

点赞。这个都可以写一个库了。对啊,我可以考虑写一个库。

3 楼

秋水老师一般是怎么研究的呢?如果是参考国外的标准规范,那么有没有可以参考的规范的URL?

谢谢老师!

4 楼

我执行有问题,无法解析我这里的MP4文件。难道老师那里有可以被解析的?发来看看。

5 楼

我都是参考的国内资料,我一般要下载七、八个有关的资料,反复对照本机的文件研究。英文资料我没那个本事看懂。HEX编辑器是必需的。

6 楼

本文已作了大幅修改,所以重新编辑了

我来回复

您尚未登录,请登录后再回复。点此登录或注册