说明:MP4v2版本号为mp4v2-2.0.0;不同版本创建的mp4info结构略有差异;
创建mp4文件
接口有两个:
(1) MP4FileHandle MP4Create(
const char* fileName, //输入的想要创建的mp4文件名;
uint32_t flags DEFAULT(0) );//位掩码,允许用户为数据或时间原子设置64位值.有效位可以是以下任意组合:
//MP4_CREATE_64BIT_DATA(0x01) 与 MP4_CREATE_64BIT_TIME(0x02) 默认为0,两者皆没有选择;
/*源码
{
return MP4CreateEx(fileName, flags); 实际上调用了MP4CreateEx;
}*/
(2) MP4FileHandle MP4CreateEx(
const char* fileName, //输入的想要创建的mp4文件名;
uint32_t flags DEFAULT(0),//位掩码,允许用户为数据或时间原子设置64位值; 默认0;
int add_ftyp DEFAULT(1),//如果为true,则自动创建<b>ftyp</b>原子。 默认1;
int add_iods DEFAULT(1),//如果为true,则自动创建<b>iods</b>原子。 默认1;
char* majorBrand DEFAULT(0),//<b>ftyp</b>主要标识,默认0;
uint32_t minorVersion DEFAULT(0),//为主要标识的次要版本提供信息整数。 默认0;
char** compatibleBrands DEFAULT(0),//<b>ftyp</b>兼容标识列表。默认0;
uint32_t compatibleBrandsCount DEFAULT(0) );//兼容标识数量,默认0;
总结:
实际调用时,通过:
MP4FileHandle hMp4file = MP4Create(pFileName, MP4_CREATE_64BIT_DATA);
if (hMp4file == MP4_INVALID_FILE_HANDLE){...}
或
MP4FileHandle hMp4file = MP4CreateEx(pFileName, MP4_CREATE_64BIT_DATA, 1, 1, 0, 0, 0, 0);
if (hMp4file == MP4_INVALID_FILE_HANDLE){...}
来创建mp4文件;
mp4info 与 WinHex工具分析
1. ftyp box
简介: 有且只有一个,在mp4文件最开始的地方;
1.1 MP4CreateEx(pFileName, MP4_CREATE_64BIT_DATA, 1, 1, “wu”, 100, 0, 0);调用后;
通过二进制分析:
其中:
00 00 00 10 为该box的长度;总共占位4字节;
66 74 79 70为固定标识ftyp;总共占位4字节;
77 75 00 00为MP4CreateEx中majorBrand主标识;明显这里填入的是"wu"; 总共占位4字节;
00 00 00 64为MP4CreateEx中minorVersion整数值; 这里写入的是100; 总共占位4字节;
参数 compatibleBrands和compatibleBrandsCount 传入若compatibleBrandsCount 大于1,将会产生段错误;原因未知;使用默认就好;
1.2 MP4CreateEx(pFileName, MP4_CREATE_64BIT_DATA, 1, 1, 0, 0, 0, 0); 默认参数创建后;
其中:
00 00 00 18 为该box的长度;
...
6D 70 34 32 69 73 6F 6D:为mp42isom;兼容标识;占位8bit;
兼容标识为mp42isom的源码,可能各个版本标识不太一样;
void MP4FtypAtom::Generate()
{
MP4Atom::Generate();
majorBrand.SetValue( "mp42" );
minorVersion.SetValue( 0 );
compatibleBrands.SetCount( 2 );
compatibleBrands.SetValue( "mp42", 0 );
compatibleBrands.SetValue( "isom", 1 );
}
2. free box
简介: "free"中的内容是无关紧要的, 可以被忽略;该box被删除后,不会对播放产生任何影响;
从mp4info部分看出,free box有两个,另外一个在最后;数据一模一样;
其中:
00 00 00 88 为该free box的长度;0x88 -> 十进制为136字节;
66 72 65 65 为该free box的固定标识 "free";
3. (截图仅仅开始部分值) mdat box
简介: 该box包含于文件层,可以有多个,当媒体数据全部为外部文件引用时也可以没有;用来存储媒体数据;数据直接跟在 box type字段后面;
具体的意义参考metadata(主要在sample table中);
4. Movie Box(moov)
简介: 该box包含了文件媒体的metadata信息,"moov"是一个container box,具体内容信息由子box诠释;同 ftyp box 一样;该box有且只有一个;
且被包含在文件层;一般情况下,"moov"会仅随着"ftyp"出现;
一般情况下:“moov"中会包含一个"mvhd"和若干个"trak”;其中"mvhd"为header box,作为"moov"的第一个子box出现;"trak"包含了一个
tack的相关信息,是一个container box;
其中:
00 00 1E B8 为moov的长度;
6D 6F 6F 76为"moov"标识;
4.1 mvhd
简介:Movie Header Box; 对整个文件所包含的媒体数据作全面的描述;包含了媒体的创建与修改时间刻度,默认音量,色域时长等信息;
mvhd用结构体表示如下;
typedef struct
{
int box_size; //box大小;4字节;
int box_type; //box类型;4字节;
char version; //box版本,0或1;一般为0; 1字节;
char flags[3];//标志,3字节;
int creation_time;//创建时间;相对于UTC时间1904-01-01零点的秒数;4字节;
int modification_time;//修改时间; 4字节;
int time_scale;//文件媒体在1秒时间内的刻度值,可以理解为1秒长度的时间单元数;4字节;
int duration;//该track的时间长度,用duration和time scale值可以计算track时长, 4字节;
//比如audio track的time scale = 8000,duration = 560128,时长为70.016,video track的time scale=600,duration=42000,时长为70;
int rate;// 推荐播放速率,高16位和低16位分别为小数点整数部分和小数部分,即[16.16] 格式,该值为1.0(0x00010000)表示正常前向播放;4字节;
short volume;//与rate类似,[8.8] 格式,1.0(0x0100)表示最大音量;
char reserved[10];//保留
char matrix[36];//视频变换矩阵;
char pre_defined[24];
int next_track_id;//下一个track使用的id号;4字节;
}mvhd;
mp4info如下如:
其中:
00 00 00 6C 为mvhd的长度;对应box_size;
6D 76 68 64为"mvhd"标识; 对应box_type;
00 00 00 00为版本和标记;对应version(1byte)+flags(3byte);
7C 27 D9 0D为创建时间,对应creation_time;
7C 27 D9 3C为修改时间,对应modification_time;
00 01 5F 90为time_scale;
00 3F 75 00为duration;公式:duration / timescale = 可播放时长(s);换算下来等于46s;和实际播放一样;
00 01 00 00为rate; 值为1.0,正常速率播放;
01 00 为volume;值为1.0,最大音量;
...
00 00 00 03 为next_track_id;
对应部分源码在 src\atom_mvhd.cpp中;
4.2 iods
可以在MP4CreateEx的参数4控制是否创建; 可省,具体作用暂不知;
00 00 00 18 表示该box长度;
69 6F 64 73 表示"iods"标识;
4.3 trak
简介:trak box它属于moov的子box;是一个container box;其子box包含了该track的媒体数据引用和描述(hint track除外);
一个mp4文件中的媒体可以包含多个track,且至少由一个track,这些track间彼此独立,有自己的时间和空间信息;“trak"必须
包含一个"tkhd"和一个"media”,
4.3.1 tkhd
简介: 它是trak box的第一个子box; 全名(Track Header Box);
源码位置:src\atom_tkhd.cpp中;
tkhd用结构体表示如下;
typedef struct
{
int box_size;//box大小;4字节;
int box_type;//box类型;4字节;
char version;//box版本,0或1,一般为0; 1字节;
char flags[3];//按位或操作结果值; 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;
*/
int creation_time;//创建时间; 4字节;
int modification_time;//修改时间;4字节;
int track_id;//id号,不能重复且不能为0;4字节;
char reserved[4];//保留位;4字节;
int duration;//track的时间长度;4字节;
char reserved1[8];//保留位;8字节;
short layer;//视频层,默认0;值小的在上面;2字节;
short alternate_group;//track分组信息;默认为0表示该track未与其他track有群组关系;2字节;
short volume;//[8.8] 格式,如果为音频track,1.0(0x0100)表示最大音量;否则为0;2字节;
char reserved2[2];//保留位;2字节;
char matrix[36];//视频变换矩阵;
int width;//宽;4字节;
int height;//高;均为 [16.16]格式值,与sample描述中的实际画面大小比值,用于播放时的展示宽高;4字节;
}tkhd;
mp4info如下如:
其中:
00 00 00 5C表示该tkhd长度;
74 6B 68 64表示"tkhd"标识;
00 00 00 01表示version(0x00)+flags(0x000001)使能;可以播放该track;
7C 27 D9 0D:创建时间;对应creation_time;
7C 27 D9 3C:修改时间modification_time;
00 00 00 02:track id;
00 00 00 00:保留
00 3F 75 00:track的时间长度;对应duration;
00 00 00 00 00 00 00 00 :保留;
00 00 :layer 视频层;
00 00:track分组信息;
01 00:volume对应值未1.0;最大音量;
00 00 :保留
后面36字节:视频变换矩阵; 与源码中的值一模一样;
03 20 00 00:宽;800;
02 58 00 00:高;600;
源码:
static uint8_t matrix[36] = {
0x00, 0x01, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0x00, 0x01, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0x40, 0x00, 0x00, 0x00,
};
((MP4BytesProperty*)m_pProperties[12])->SetValue(matrix, sizeof(matrix));
4.3.2 mdia
简介:“Media Box”;是一个 container box;子box结构和种类比较复杂;
总体来说,"mdia"定义了track媒体类型以及sample数据;描述sample信息;一般"mdia"下列内容:
=>"mdhd"为media header box;
=>"hdlr"为handler reference box;解释了媒体播放的播放过程信息;该box也可以被包含在meta box中;
=>"minf"为media information box;存储了解释track媒体数据的handler-specific信息,media handler用这些信息将媒体时间映射到媒体
数据并进行处理;"minf"中的信息格式信息和内容与媒体类型以及解释媒体数据的media handler密切相关;其他media handler不知道
如何解释这些信息;是一个container box;其实际内容由子box说明;
4.3.2.1 mdhd
mdhd对应结构内容
typdef struct
{
int box_size;//box大小;4字节;
int box_type;//box类型;4字节;
char version;//box版本,0或1,一般为0; 1字节;
char flags[3];
int creation_time;//创建时间; 4字节;
int modification_time;//修改时间;4字节;
int time_scale;//文件媒体在1秒时间内的刻度值,可以理解为1秒长度的时间单元数;4字节;
int duration;//该track的时间长度;
short language;//媒体语言码;最高位为0,后面15位为3个字符(见ISO 639-2/T标准中定义)
short pre_defined;
}mdhd;
mp4info如下如:
其中:
00 00 00 20 :box大小
6D 64 68 64 :"mdhd"标识;
00 00 00 00 :version+flags
7C 27 D9 0D :创建时间
7C 27 D9 3C :修改时间;
00 01 5F 90 :time_scale值
00 3F 39 F0:duration值
55 C4:媒体语言码
00 00:pre_defined
4.3.2.2 hdlr
hdlr对应结构内容
typdef struct
{
int box_size;//box大小;4字节;
int box_type;//box类型;4字节;
char version;//box版本,0或1,一般为0; 1字节;
char flags[3];
int pre_defined;
int handler_type;//在media box中,该值为4个字符;
/*vide -> video track
soun -> audio track
hint -> hint track
*/
char reserved[12];
char *name;//长度不定,track type name;以'\0'结尾的字符串;
}mdlr;
mp4info如下如:
其中:
00 00 00 21 :mdlr box长度
68 64 6C 72 :"mdlr"标识;
00 00 00 00 :version+flags
00 00 00 00 : pre_defined
76 69 64 65 :vide;可知为视频track;
...
4.3.2.3 minf
简介:"minf"包含如下:
源码: src/mp4file.cpp/AddH264VideoTrack
4.3.2.3.1 header box;
根据上面的track type对应;
/* 源码
#define MP4_OD_TRACK_TYPE "odsm" /**< Constant: OD track. */
#define MP4_SCENE_TRACK_TYPE "sdsm" /**< Constant: scene track. */
#define MP4_AUDIO_TRACK_TYPE "soun" /**< Constant: audio track. */
#define MP4_VIDEO_TRACK_TYPE "vide" /**< Constant: video track. */
#define MP4_HINT_TRACK_TYPE "hint" /**< Constant: hint track. */
#define MP4_CNTL_TRACK_TYPE "cntl" /**< Constant: control track. */
#define MP4_TEXT_TRACK_TYPE "text" /**< Constant: text track. */
#define MP4_SUBTITLE_TRACK_TYPE "sbtl" /**< Constant: subtitle track. */
#define MP4_SUBPIC_TRACK_TYPE "subp" /**< Constant: subpic track. */
*/
struct xxx
{
int box_size;//box大小;4字节;
int box_type;//box类型;4字节;
char version;//box版本,0或1,一般为0; 1字节;
char flags[3];
#if vmhd
int graphics_mode;//视频合成模式;为0时拷贝原始图像;否则与opcolor进行合成;
short[3];//{red,green,blue};
#else if smhd
float balance;//立体声平衡,[8.8] 格式值,一般为0,-1.0表示全部左声道,1.0表示全部右声道
char reserved[2];
#else
...
#endif
};
其中:
00 00 00 14 :该box长度;
76 6D 68 64 :"vmhd",可知为视频;
00 00 00 01:version+flags
00 00 00 00 : graphics_mode 为0;
00 00 00 00:
4.3.2.3.2 dinf:data information box;
简介:解释如何定位媒体信息;是一个container box;一般包含一个 dref;即data reference box;
dref下回包含若干 url或 urn;这些box组成一个表;用来定位track数据;
简单的说:track可以被分成若干段,每一段都可以根据url或urn指向的地址来获取数据;sample描述中会用这些片段的序号将这些组成
一个完整的track;一般情况下,当数据被完全包含在文件中时;url和urn中的定位字符串为空的;url或urn都是box;url的内容为字符
串(location string); urn的内容为一对字符串(name string and location string);当url或urn的box flag为时,字符串均为空;
typedef struct
{
int box_size;//box大小;4字节;
int box_type;//box类型;4字节;
char version;//box版本,0或1,一般为0; 1字节;
char flags[3];
int entry_count;//“url”或“urn”表的元素个数
char *url_urn_table;//“url”或“urn”表
}dinf;
其中:
00 00 00 24:dinf长度
64 69 6E 66 :”dinf“字符串标识
00 00 00 1C :dref长度
64 72 65 66 :"dref"字符串标识;
00 00 00 00 :version+flags
00 00 00 01 :url/urn元素个数;
00 00 00 0C :url/urn元素表;
4.3.2.3.3 stbl (sample table box)
简介:它是minf box的子box;"stbl"几乎是普通mp4文件中最复杂的一个box了;首先需要会议一下sample的概率;
sample是媒体数据存储的单位;存储在media的chunk中;chunk和sample的长度均互不相同;
stbl包含了关于track中sample所有时间和位置的信息;以及sample的编解码等信息;
利用这个表,可以解释sample的时序,类型,大小以及在各自存储容器中的位置;stbl是一个container box,其子box包括:
(a) stsd: sample description box;
=> 属于stbl box的子box;stsd必不可少;且至少包含一个条目;该box包含了data reference box进行sample数据检索的信息;
=> 没有stsd就无法计算media sample的存储位置;sdsd包含了编码的信息,其存储的信息随媒体类型不同而不同;box header
和version字段后有一个entry count字段;根据entry的个数,每个entry会有信息,如vide,sund等;根据type不同,sample destription
会提供不同的信息,如video track,会有visualSampleEntry类型信息,对于audio track会有AudioSampleEntry类型信息;
=> 视频的编码类型,宽高,长度,音频的声道,采样等信息都会出现在这个box中;
(b) stts:time to sample box;
=> 属于stbl box的子box;stts存储了sample的duration,描述了sample时序的映射方法;我们通过它可以找到任何时间的sample;stts可以包含
一个压缩的表来映射时间和sample序号;用其他的表来提供每个sample的长度和指针;表中每个条目提供了在同一个时间偏移里面连续的
sample序号,以及samples的偏移量;递增这些偏移量,就可以建立一个完整的time to sample表;
(c ) stsz或stz2: sample size box;
=> 属于stbl box的子box; stsz定义了每个sample 的大小;包含了媒体中全部的sample的数目和一张给出每个sample大小的表;这个box相对
来说是体积比较大的;
(d) stsc:sample to chunk box
=> 属于stbl box的子box;用chunk组织的sample可以方便优化数据获取,一个trunk包含一个或多个sample;stsc中用一个表来描述sample
和chunk的映射关系,查看这张表就可以找到指定sample的thunk,从而找到这个sample;
(e) stco或co64:chunk offset box;
=> 属于stbl box的子box;stco”定义了每个thunk在媒体流中的位置。位置有两种可能,32位的和64位的,后者对非常 大的电影很有用。
在一个表中只会有一种可能,这个位置是在整个文件中的,而不是在任何box中的,这样做就可以直接在文件中找到媒体数据,
而不用解释 box。需要注意的是一旦前面的box有了任何改变,这张表都要重新建立,因为位置信息已经改变了。
(f) ctts:composion time to sample box;
=> 属于stbl box的子box;
(g) stss:sync sample box;
=> 属于stbl box的子box;它是stbl box的子box。stss”确定media中的关键帧。对于压缩媒体数据,关键帧是一系列压缩序列的开始帧,
其解压缩 时不依赖以前的帧,而后续帧的解压缩将依赖于这个关键帧。“stss”可以非常紧凑的标记媒体内的随机存取点,它包含一个
sample序号表,表内的每一 项严格按照sample的序号排列,说明了媒体中的哪一个sample是关键帧。如果此表不存在,说明每一个
sample都是一个关键帧,是一个随机存取点。
参考博客:
本文绝大部分参考自下面博客,仅做学习笔录;
https://www.cnblogs.com/ranson7zop/p/7889272.html
https://blog.csdn.net/lh2016rocky/article/details/52691768