传送门:MP4 文档 P16页
这个 Box 根据官方定义发现也挺简单的,就一个 Header 和 Data ,也可以相当于一个分隔符,类似 Moov Box,在 Data 里面就包含了很多子 Box,根据里面的子 Box 信息,我们可以看到这是 Video Track 还是 Audio Track。Trak Box这里自身只是一个分界符,属于 Container Box,所以它只有 Box Header。
名称 | 大小(byte) | 意义 | 说明 |
---|---|---|---|
Box length | 4 | Box 整体的大小 | 包含 Header 和 Data部分 |
Box type | 4 | ”trak”的ASCII码,表明是 trak Box | box 属性值,通常是固定值 |
Box Data | Box length - 8 | 具体数据 | 数据里面包含的是子Box |
用16进制工具查看:
再用 MP4 info查看
发现子 Box 里面有 tkhd box 和 mdia box,这里就直接看下面代码定义部分。
// BaseBox.h
enum BOX_TYPE{
FTYP,
MOOV,
MVHD,
TRAK,
// 添加2个新的Box类型
TKHD,
MDIA,
LODS,
UUID,
MDAT,
ERROR
};
struct BoxHeader{
// ...
// 其他不变
BOX_TYPE GetType() {
if(_h_type[0]=='f'&&_h_type[1]=='t'&&_h_type[2]=='y'&&_h_type[3]=='p') return FTYP;
else if (_h_type[0]=='m'&&_h_type[1]=='o'&&_h_type[2]=='o'&&_h_type[3]=='v') return MOOV;
else if (_h_type[0]=='m'&&_h_type[1]=='v'&&_h_type[2]=='h'&&_h_type[3]=='d') return MVHD;
else if (_h_type[0]=='t'&&_h_type[1]=='r'&&_h_type[2]=='a'&&_h_type[3]=='k') return TRAK;
else if (_h_type[0]=='t'&&_h_type[1]=='k'&&_h_type[2]=='h'&&_h_type[3]=='d') return TKHD;
else if (_h_type[0]=='m'&&_h_type[1]=='d'&&_h_type[2]=='i'&&_h_type[3]=='a') return MDIA;
return ERROR;
}
};
// ...
// 其他 Box 的定义
class TimeTrakBox : public BaseBox{
public:
TimeTrakBox(BoxHeader h);
TimeTrakBox(BoxHeader h, Timebyte * d): BaseBox(h, d){};
void AnalyzeBoxHeader(BoxHeader header, size_t offset) override; // 这里要解析data数据的子box所以要重写方法
};
实现
// TimeTrakBox.cpp
TimeTrakBox::TimeTrakBox(BoxHeader h) : BaseBox(h) {
if (h.GetSize()) {
data = new Timebyte[h.GetSize()];
}
}
void TimeTrakBox::AnalyzeBoxHeader(BoxHeader header, size_t offset) {
if (header.GetType() == TKHD) {
printf("===========================\n");
header.to_string();
}
if (header.GetType() == MDIA) {
printf("===========================\n");
header.to_string();
}
}
Trak Box 我们定义好了,这里我们回到 Moov Box 去修改一下它的解析 Data 的代码
// TimeMoovBox.cpp
// ...
// 其他不变
void TimeMoovBox::AnalyzeBoxHeader(BoxHeader header, size_t offset) {
if (header.GetType() == MVHD) {
TimeMvhdBox* timeMvhdBox = new TimeMvhdBox(header, data + offset + 8);
timeMvhdBox->PrintDataInfo();
PushBox(timeMvhdBox);
}
if (header.GetType() == TRAK) {
printf("===========================\n");
header.to_string();
TimeTrakBox* timeTrakBox = new TimeTrakBox(header, data + offset + 8);
timeTrakBox->Analyze();
PushBox(timeTrakBox);
}
}
最后把我们运行测试的代码再简单修改一下
void TimeMP4::LodingBox() {
if(!file) return;
while (!feof(file)) {
BoxHeader header;
unsigned int len;
fread(header._h_size, 1, 4, file);
fread(header._h_type, 1, 4, file);
if(header.GetSize() == 1) {
len = 16;
}else if(header.GetSize() == 0) {
break;
}
len = 8;
if(header.GetType() == FTYP) {
ftyBox = new TimeFTYBox(header);
fread(ftyBox->GetData(),1,header.GetSize()-len, file);
}}else if(header.GetType() == MOOV) {
moovBox = new TimeMoovBox(header);
fread(moovBox->GetData(),1,header.GetSize()-len, file);
}else {
if(header.GetSize() >> 31) {
#ifdef _WINDOWS
_fseeki64(file, header.GetSize()-len, 1);
#endif
#ifdef __APPLE__
fread(nullptr, 1, header.GetSize()-len, file);
#endif
}else {
fseek(file, header.GetSize()-len, 1);
}
}
}
}
void TimeMP4::test() {
if(ftyBox) {
ftyBox->PrintDataInfo();
}
if(moovBox) {
moovBox->Analyze();
}
}
最后运行测试