MP4的解析流程
常见的MP4结构图
MP4 box的定义
MP4也是一个容器
/*
** MP4容器定义,包含:
** ftyp、moov、mdat
*/
static mp4_atom_handler mp4_atoms[] = {
{ "ftyp", &Mp4Meta::mp4_read_ftyp_atom },
{ "moov", &Mp4Meta::mp4_read_moov_atom },
{ "mdat", &Mp4Meta::mp4_read_mdat_atom },
{ NULL, NULL }
};
MP4的解析步骤
解析步骤如下:
1、读取mp4文件
2、读取box的size字段
3、如果box的size字段的值是1,表示真实的长度需要用64位来表示,需要继续读取
4、读取box的名字,根据名字来调用mp4 box中的函数指针:
(1)mp4_read_ftyp_atom,读取ftyp box
(2)mp4_read_moov_atom,读取moov box
(3)mp4_read_mdat_atom,读取mdat box
代码实现
int
Mp4Meta::parse_root_atoms()
{
int i, ret, rc;
int64_t atom_size, atom_header_size;
char buf[64];
char *atom_header, *atom_name;
memset(buf, 0, sizeof(buf));
for (;;) {
if (meta_avail < (int64_t)sizeof(uint32_t))
return 0;
IOBufferReaderCopy(meta_reader, buf, sizeof(mp4_atom_header64));
// 读取box的size
atom_size = mp4_get_32value(buf);
if (atom_size == 0) {
return 1;
}
atom_header = buf;
if (atom_size < (int64_t)sizeof(mp4_atom_header)) {
// 如果size等于1,表示真实的size需要64位表示,需要继续读取
if (atom_size == 1) {
if (meta_avail < (int64_t)sizeof(mp4_atom_header64)) {
return 0;
}
} else {
return -1;
}
atom_size = mp4_get_64value(atom_header + 8);
atom_header_size = sizeof(mp4_atom_header64);
} else { // regular atom
if (meta_avail < (int64_t)sizeof(mp4_atom_header)) // not enough for atom header
return 0;
atom_header_size = sizeof(mp4_atom_header);
}
// 读取box的名字
atom_name = atom_header + 4;
if (atom_size + this->passed > this->cl) {
return -1;
}
// 调用MP4容器的处理函数
for (i = 0; mp4_atoms[i].name; i++) {
// 根据名字进行调用mp4_read_ftyp_atom、mp4_read_moov_atom、mp4_read_mdat_atom
if (memcmp(atom_name, mp4_atoms[i].name, 4) == 0) {
ret = (this->*mp4_atoms[i].handler)(atom_header_size, atom_size - atom_header_size); // -1: error, 0: unfinished, 1: success
if (ret <= 0) {
return ret;
} else if (meta_complete) { // success
return 1;
}
goto next;
}
}
// nonsignificant atom box
rc = mp4_atom_next(atom_size, true); // 0: unfinished, 1: success
if (rc == 0) {
return rc;
}
next:
continue;
}
return 1;
}