ffmpeg源码分析及mp4文件解析
一.mp4文件的组织
1. mp4文件的box(ffmpeg中叫atom)
mp4是由一系列的box组成的,每个box的header是8个字节(4字节的长度,4字节的type)
第一个box比较特殊,其type类型为ftyp,还包含一个sub-type
0000000: 0000 0020 6674 7970 6973 6f6d 0000 0200 ... ftypisom....
0000010: 6973 6f6d 6973 6f32 6176 6331 6d70 3431 isomiso2avc1mp41
0000020: 0000 0008 6672 6565 0609 6f8e 6d64 6174 ....free..o.mdat
0000030: 0000 028c 0605 ffff 88dc 45e9 bde6 d948 ..........E....H
0000040: b796 2cd8 20d9 23ee ef78 3236 3420 2d20 ..,. .#..x264 -
0000050: 636f 7265 2031 3030 202d 2048 2e32 3634 core 100 - H.264
0000060: 2f4d 5045 472d 3420 4156 4320 636f 6465 /MPEG-4 AVC code
0000 0020 6674 7970 --> 第1个box的长度为0x20, type=ftyp
6973 6f6d -->其sub-type=isom
0000 0008 6672 6565 --> 第2个box的长度为0x08, type=free
0609 6f8e 6d64 6174 --> 第3个box的长度为0x06096F8E, type=mdat
由此可以看出第4个box:
0x06096F8E+0x08+0x20=0x06096FB6处是第4个box
000c ca81 6d6f 6f76 --> 第4个box的长度是0x0cca81, type=moov
1.2 计算文件的大小
所以整个文件的大小为 0x20+0x08+0x0x06096F8E+0x0cca81=0x6163A37=102119991
aaa@qq.com:/work/ffmpeg/ffmpeg-3.0.1$ ls -l ../san.mp4
-rw-rw-r-- 1 cong cong 102119991 Sep 10 2015 ../san.mp4
1.3 关于box-type:
box-type可以是如下一个:
"ftyp", "mdat", "moov", "pnot", "udta", "uuid", "moof", "free", "skip", "jP2 ", "wide", "load", "ctab", "imap", "matt", "kmat", "clip", "crgn", "sync", "chap", "tmcd", "scpt", "ssrc", "PICT".
sub-type可以取如下一个:
sub-type which must be one of values: "avc1", "iso2", "isom", "mmp4", "mp41", "mp42", "mp71", "msnv", "ndas", "ndsc", "ndsh", "ndsm", "ndsp", "ndss", "ndxc","ndxh", "ndxm", "ndxp", "ndxs".
1.4总结
一个mov文件就是由ftyp free mdat moov这四个部分组成
ftyp --> 格式
free --> 不关心
mdat --> 音视频数据
moov --> 包含一系列次级box:一个mvhd及多个trak
1.5 如下图所示:
清楚了
二. BOX的具体解析
2.1FileTypeBox--> ftype解析
0000000: 0000 0020 6674 7970 6973 6f6d 0000 0200 ... ftypisom....
0000010: 6973 6f6d 6973 6f32 6176 6331 6d70 3431 isomiso2avc1mp41
0000 0020 6674 7970 --> 第1个box的长度为0x20, type=ftyp
6973 6f6d --> major_brand: isom
0000 0200 --> minor_verion: isom的版本号
6973 6f6d 6973 6f32 6176 6331 6d70 3431--> 兼容isom iso2 avc1 mp41这四个协议
ISO14496-12 的 4.3.2 Syntax
aligned(8) class FileTypeBox
extends Box(‘ftyp’) {
unsigned int(32) major_brand;
unsigned int(32) minor_version;
unsigned int(32) compatible_brands[]; // to end of the box
}
没有ftyp后面就不知道用什么去解析这个媒体文件
2.2 Free Space Box -->free解析
没啥作用
ISO14496-12 的8.24.2 Syntax
aligned(8) class FreeSpaceBox extends Box(free_type) {
unsigned int(8) data[];
}
2.3 Media Data Box -->mdat解析
这个box里面全部都是数据
ISO14496-12 的8.2.2 Syntax
aligned(8) class MediaDataBox extends Box(‘mdat’) {
bit(8) data[];
}
2.4 Movie Box -->moov解析 (很复杂)
6096fb0: 9002 1900 2380 000c ca81 6d6f 6f76 0000 ....#.....moov..
6096fc0: 006c 6d76 6864 0000 0000 7c25 b080 7c25 .lmvhd....|%..|%
6096fd0: b080 0000 03e8 0014 6995 0001 0000 0100 ........i.......
6096fe0: 0000 0000 0000 0000 0000 0001 0000 0000 ................
6096ff0: 0000 0000 0000 0000 0000 0001 0000 0000 ................
6097000: 0000 0000 0000 0000 0000 4000 0000 0000 aaa@qq.com
6097010: 0000 0000 0000 0000 0000 0000 0000 0000 ................
6097020: 0000 0000 0000 0000 0003 0005 bf9d 7472 ..............tr
6097030: 616b 0000 005c 746b 6864 0000 000f 7c25 ak...\tkhd....|%
6097040: b080 7c25 b080 0000 0001 0000 0000 0014 ..|%............
6097050: 6595 0000 0000 0000 0000 0000 0000 0000 e...............
6097060: 0000 0001 0000 0000 0000 0000 0000 0000 ................
6097070: 0000 0001 0000 0000 0000 0000 0000 0000 ................
6097080: 0000 4000 0000 01d6 0000 0160 0000 0000 aaa@qq.com`....
6097090: 0024 6564 7473 0000 001c 656c 7374 0000 .$edts....elst..
60970a0: 0000 0000 0001 0014 6595 0000 03e9 0001 ........e.......
60970b0: 0000 0005 bf15 6d64 6961 0000 0020 6d64 ......mdia... md
000c ca81 6d6f 6f76 --> moov的长度是0x0cca81, type=moov
0000 006c 6d76 6864 --> mvhd的长度是0x6c ,type=mvhd
0000 0000 --> version=0x0
7c25 b080 7c25 b080 --> create_time=modify_time=0x7c25b080
0000 03e8 --> timescale=0x3e8=1000
0014 6995 --> duration=0x146995(单位是time_units)
0001 0000 --> rate=0x00010000
0100 --> volume=0x0100
0005 bf9d 7472 616b --> track的长度是0x5bf9d,type=trak
0000 005c 746b 6864 --> tkhd的长度是0x5c, type=tkhd
0000 -->version
000F --> flag
7c25 b080 7c25 b080 -->create_time=modify_time=0x7c25b080
0000 0001 --> trackID=1
0000 0000 --> reserve
0014 6595 --> duration=0x146595
0000 0000 --> reserved
0000 0000 --> reserved
0000 0000 --> layer+group
0000 0000 --> volum+resever
0001 0000 0000 0000 0000 0000 matrix
0000 0000 0001 0000 0000 0000
0000 0000 0000 0000 4000 0000
01d6 0000 0160 0000 --> width=0x1d6 height=0x160(这儿都需要向右移16位)
0000 0024 6564 7473 -->edts的长度是0x24,type=edts
注意:
a.媒体文件在播放过程中用的时间单位,是由timescale计算出来的
一个time units=1s/timescale=1ms,这儿1 time_unts=1ms
b.通过duration可计算媒体的播放时间 0x146995*1ms=1337749ms=1337.749s,对上了
附1.mvhd
ISO14496-12 的8.3.2 Syntax
aligned(8) class MovieHeaderBox extends FullBox(‘mvhd’, version, 0) {
if (version==1) {
unsigned int(64) creation_time;
unsigned int(64) modification_time;
unsigned int(32) timescale;
unsigned int(64) duration;
} else { // version==0
unsigned int(32) creation_time;
unsigned int(32) modification_time;
unsigned int(32) timescale;
unsigned int(32) duration;
}
template int(32) rate = 0x00010000; // typically 1.0
template int(16) volume = 0x0100; // typically, full volume
const bit(16) reserved = 0;
const unsigned int(32)[2] reserved = 0;
template int(32)[9] matrix =
{ 0x00010000,0,0,0,0x00010000,0,0,0,0x40000000 };
// Unity matrix
bit(32)[6] pre_defined = 0;
unsigned int(32) next_track_ID;
}
附2.trak
8.5.2 Syntax aligned(8) class TrackHeaderBox
extends FullBox(‘tkhd’, version, flags){
if (version==1) {
unsigned int(64) creation_time;
unsigned int(64) modification_time;
unsigned int(32) track_ID;
const unsigned int(32) reserved = 0;
unsigned int(64) duration;
} else { // version==0
unsigned int(32) creation_time;
unsigned int(32) modification_time;
unsigned int(32) track_ID;
const unsigned int(32) reserved = 0;
unsigned int(32) duration;
}
const unsigned int(32)[2] reserved = 0;
template int(16) layer = 0;
template int(16) alternate_group = 0;
template int(16) volume = {if track_is_audio 0x0100 else 0};
const unsigned int(16) reserved = 0;
template int(32)[9] matrix=
{ 0x00010000,0,0,0,0x00010000,0,0,0,0x40000000 };
// unity matrix
unsigned int(32) width;
unsigned int(32) height;
}
三.ffmpeg中对mp4的处理
3.1 对mp4文件的probe --> 在libavformat/mov.c中
有两个宏需要关注一下:
#define MKTAG(a,b,c,d) ((a) | ((b) << 8) | ((c) << 16) | ((unsigned)(d) << 24))
# define AV_RL32(x) \
(((uint32_t)((const uint8_t*)(x))[3] << 24) | \
(((const uint8_t*)(x))[2] << 16) | \
(((const uint8_t*)(x))[1] << 8) | \
((const uint8_t*)(x))[0])
这两个宏都是把4个char组成一个int
3.2 mov_probe
static int mov_probe(AVProbeData *p)
{
int64_t offset;
uint32_t tag;
int score = 0;
int moov_offset = -1;
dbmsg();
/* check file header */
offset = 0;
for (;;) {
tag = AV_RL32(p->buf + offset + 4); //将p->buf+4即‘f’ ‘t’ 'y' 'p'组成一个int
switch(tag) { //判断这个int是不是ftyp
case MKTAG('f','t','y','p'):
score = AVPROBE_SCORE_MAX; //如果是的话score=100,说明就是mov格式的文件
break;
}
}
return score;
}
精简一下mov_probe,其实就是判断第一个box是不是ftyp,若是则就是mov格式的了。
3.3.1 对ftype的读取
static int mov_read_ftyp(MOVContext *c, AVIOContext *pb, MOVAtom atom)
{
//读4个字节的major_brand,并存到dict中
ffio_read_size(pb, type, 4);
av_dict_set(&c->fc->metadata, "major_brand", type, 0);
//读4个字节的minor_ver,并存到dict中
minor_ver = avio_rb32(pb);
av_dict_set_int(&c->fc->metadata, "minor_version", minor_ver, 0);
//读剩余的字节,即comp_brands_str,并存到dict中
comp_brand_size = atom.size - 8; //atom.size己经是去除8字节头,余下的size
ffio_read_size(pb, comp_brands_str, comp_brand_size);
comp_brands_str[comp_brand_size] = 0;
av_dict_set(&c->fc->metadata, "compatible_brands", comp_brands_str, 0);
return 0;
}
3.3.2 对free的读取
static int mov_read_free(MOVContext *c, AVIOContext *pb, MOVAtom atom)
{
//没什么作用,只是读取出来,把文件指针指向下一下box而己
avio_read(pb, content, FFMIN(sizeof(content), atom.size));
return 0;
}
3.3.3对mdat的读取
static int mov_read_mdat(MOVContext *c, AVIOContext *pb, MOVAtom atom)
{
//mdat更简单,只把标志设置了一下
c->found_mdat=1;
return 0; /* now go for moov */
}
3.3.4对moov的读取
三.附录: ISO/IEC 14496 MPEG的协议标准
转自: http://blog.csdn.net/yu_yuan_1314/article/details/9406587
- ISO/IEC 14496是MPEG专家组制定的MPEG-4标准于1998年10月公布第1版,1999年1月成为国际标准,1999年12月公布了第2版,2000年初成为国际标准。
- 全文分为27个部分:
- (1)ISO/IEC 14496-1系统部分,描述视频和音频数据流的控制、同步以及混合方式(即混流 Multiplexing,简写为MUX)。
- (2)ISO/IEC 14496-2视频部分,定义了一个对各种视觉信息(包括自然视频、静止纹理、计算机合成图形等等)的编解码器。(例如XviD编码就属于MPEG-4 Part 2)。
- (3)ISO/IEC 14496-3音频部分,定义了一个对各种音频信号进行编码的编解码器的集合。包括高级音频编码(Advanced Audio Coding,缩写为AAC)的若干变形和其他一些音频/语音编码工具。
- (4)ISO/IEC 14496-4一致性部分,定义了比特流和设备的一致性条件,用来测试MPEG-4的实现。
- (5)ISO/IEC 14496-5参考软件,提供了用于演示功能和说明本标准其他部分功能的软件。
- (6)ISO/IEC 14496-6多媒体传送整体框架DMIF,这是MPEG-4应用层与传输网络的接口,定义了通信协议,使MPEG-4系统的数据流能进入各种传输网络。还包含一个存储格式MP4,用于存储编码的场景。
- (7) ISO/IEC 14496-7优化的参考软件,提供了对实现进行优化的例子(这里的实现指的是第五部分)。
- (8)ISO/IEC 14496-8在IP网络上传输,定义了在IP网络上传输MPEG-4内容的方式。
- (9)ISO/IEC 14496-9参考硬件描述,提供了用于演示怎样在硬件上实现本标准其他部分功能的硬件设计方案
- (10)ISO/IEC 14496-10高级视频编码AVC,定义了一个视频编解码器(codec)。AVC和XviD都属于MPEG-4编码,但由于AVC属于MPEG-4 Part 10,在技术特性上比属于MPEG-4 Part2的XviD要先进。另外,它和ITU-T H.264标准是一致的,故又称为H.264。
- (11)ISO/IEC 14496-11场景描述和应用引擎。
- (12)ISO/IEC 14496-12ISO媒体文件格式,定义了一个存储媒体内容的文件格式。
- (13)ISO/IEC 14496-13知识产权管理和保护(IPMP:Intellectual Property Management and Protection)扩展。
- (14)ISO/IEC 14496-14MP4文件格式,定义了基于第十二部分的用于存储MPEG-4内容的容器文件格式。
- (15)ISO/IEC 14496-15AVC文件格式,定义了基于第十二部分的用于存储第十部分的视频内容的文件格式。
- (16)ISO/IEC 14496-16动画框架扩展AFX(Animation Framework eXtension)。
- (17)ISO/IEC 14496-17同步文本字幕格式。
- (18)ISO/IEC 14496-18字体压缩和流式传输(针对公开字体格式)。
- (19)ISO/IEC 14496-19合成材质流(Synthesized Texture Stream)。
- (20)ISO/IEC 14496-20简单场景表示(LASeR for Lightweight Scene Representation)。
- (21)ISO/IEC 14496-21用于描绘(Rendering)的MPEG-J拓展。
- (22)ISO/IEC 14496-22开放字体格式(Open Font Format)。
- (23)ISO/IEC 14496-2符号化音乐表示(Symbolic Music Representation)。
- (24)ISO/IEC 14496-24音频与系统交互作用(Audio and systems interaction)。
- (25)ISO/IEC 14496-253D图形压缩模型(3D Graphics Compression Model)。
- (26)ISO/IEC 14496-26音频一致性检查:定义了测试音频数据与ISO/IEC 14496-3是否一致的方法(Audio conformance)。
- (27)ISO/IEC 14496-273D图形一致性检查:定义了测试3D图形数据与ISO/IEC 14496-11:2005, ISO/IEC 14496-16:2006, ISO/IEC 14496-21:2006, 和 ISO/IEC 14496-25:2009是否一致的方法(3D Graphics conformance)。
推荐阅读
-
jQuery加载及解析XML文件的方法实例分析
-
IE6不能正常解析CSS文件问题的解决方法及原因分析
-
.NET Core实战项目之CMS 第三章 入门篇-源码解析配置文件及依赖注入
-
Laravel框架源码解析之入口文件原理分析
-
基于FFmpeg源码分析TS数据格式的解析
-
Mapreduce源码分析(二):MapTask及LineRecordReader读取文件的工作机制,源码详解
-
ffmpeg开发之旅(3):AAC编码格式分析与MP4文件封装(MediaCodec+MediaMuxer)
-
springMVC源码分析--@SessionAttribute用法及原理解析SessionAttributesHandler和SessionAttributeStore
-
Android 音视频深入 十五 FFmpeg 推流mp4文件(附源码下载)
-
Jquery源码解析及案例分析