传送门:MP4 文档 P18页
tkhd Box 里面包含了当前的 Track 的媒体整体信息,包括时长、图像的宽度和高度等,同时该 Box 是 Full Box。
名称 | 大小(byte) | 意义 | 说明 |
---|---|---|---|
Box length | 4 | Box 整体的大小 | 包含 Header 和 Data部分 |
Box type | 4 | ”trak”的ASCII码,表明是 trak Box | box 属性值,通常是固定值 |
version | 1 | box版本,0或1 | 一般为0 |
flags | 3 | ||
creation time | 4 | 当前Track创建时间 | 1904-01-01零点开始 |
modification time | 4 | 当前Track修改时间 | 1904-01-01零点开始 |
track ID | 4 | 该Track的id | |
reserve | 4 | 保留位4字节 | |
duration | 4 | 该 Track 的时长,需要和时间戳进行一起计算 | |
reserver | 8 | 保留位8字节 | |
layer | 2 | 视频层,值小的在上层 | |
alternate group | 2 | track分组信息,表示该track和其它track没有建立群组关系 | 一般默认为0 |
volume | 2 | 播放此track的音量 | 1.0为正常音量 |
reserver | 2 | 保留位2字节 | |
matrix | 36 | 视频变换矩阵 | |
width | 4 | 则表示图像的宽度 | video track |
height | 4 | 则表示图像的高度 | video track |
用16进制工具查看,后面标记的 tkhd box 的内容,发现是紧接在 trak box 后面,如图:
名称 | 实际值(16进制) | 具体值(10进制 / ASCII) | 字段位置 |
---|---|---|---|
Box length | 00 00 00 5C | 92 | Header |
Box type | 74 6B 68 64 | "tkhd" | Header |
version | 00 | 0 | Header |
flags | 00 00 01 | 1 | Header |
creation time | DA 25 22 45 | 3659866693 | Data |
modification time | DA 25 22 45 | 3659866693 | Data |
track ID | 00 00 00 01 | 1 | Data |
reserve | 00 00 00 00 | Data | |
duration | 00 1D 33 A1 | 1913761 | Data |
reserver | 00 ... | Data | |
layer | 00 00 | Data | |
alternate group | 00 00 | Data | |
volume | 00 00 | video track 0 | Data |
reserver | 00 00 | Data | |
matrix | ... | Data | |
width | 00 07 80 00 | 1920 | Data |
height | 00 04 38 00 | 1080 | Data |
打开 MP4 Explorer 验证:
符合上面我们得出的数据,下面还有一个 trak box 其中还包含了一个 tkhd box,这个是音频的 trak,这里就不过多分析了,具体分析方法和上面如出一辙,大家可以尝试自己去分析查看对应的字段值。
// BaseBox.h
// ...
// 其他 Box 的定义
class TimeTkhdBox : public BaseBox {
public:
Timebyte version = 0;
Timebyte flags = 0;
unsigned int creation_time = 0; // 4 创建时间(相对于UTC时间1904-01-01零点的秒数)
unsigned int modification_time = 0;// 4 修改时间(相对于UTC时间1904-01-01零点的秒数)
unsigned int track_ID=0; //4 唯一标识该Track的一个非零值
unsigned int reserve = 0; // 4 保留位8字节
unsigned int duration = 0; // 4 该Track的播放时长,需要和时间戳进行一起计算,然后得到播放的时间坐标。
unsigned long long reserve1 = 0; // 8 保留位8字节
unsigned short layer=0;// 2 视频层,值小的在上层
unsigned short alternate_group = 0; // 2 track分组信息,一般默认为0,表示该track和其它track没有建立群组关系
unsigned short volume = 0; // 2 播放此track的音量,1.0为正常音量
unsigned char matrix[36] = {0}; // 36 视频变换矩阵
unsigned int width = 0; // 4 如果该Track为Video Track,则表示图像的宽度(16.16浮点表示)
unsigned int height = 0; // 4 如果该Track为Video Track,则表示图像的高度(16.16浮点表示)
TimeTkhdBox(BoxHeader h);
TimeTkhdBox(BoxHeader h, Timebyte * d): BaseBox(h, d){};
void PrintDataInfo() override;
};
实现
// TimeTkhdBox.cpp
TimeTkhdBox::TimeTkhdBox(BoxHeader h) : BaseBox(h) {
if (h.GetDataSize()) {
data = new Timebyte[h.GetDataSize()];
}
}
void TimeTkhdBox::PrintDataInfo() {
printf("===========================\n");
h.to_string();
TimeBufferStream bufferStream(data, h.GetDataSize());
version = bufferStream.GetUChar();
bufferStream.GetLenData(&flags, 3);
creation_time = bufferStream.GetUInt();
modification_time = bufferStream.GetUInt();
track_ID = bufferStream.GetUInt();
reserve = bufferStream.GetUInt();
duration = bufferStream.GetUInt();
bufferStream.GetLenData(&reserve1, 8);
layer = bufferStream.GetUShort();
alternate_group = bufferStream.GetUShort();
volume = bufferStream.GetUShort();
bufferStream.GetLenData(matrix, 36);
width = bufferStream.GetUInt();
height = bufferStream.GetUInt();
printf("version:%ud \n", version);
printf("flags:%ud \n", flags);
printf("creation_time:%ud \n", creation_time);
printf("creation_time: ");
printf("modification_time:%ud \n", modification_time);
printf("track_ID:%ud \n", track_ID);
printf("duration:%ud \n", duration);
printf("layer:%ud \n", layer);
printf("alternate_group:%ud \n", alternate_group);
printf("volume:%ud \n", volume);
printf("width:%ud \n", width);
printf("height:%ud \n", height);
}
最后修改一下 TimeTrakBox.cpp
// TimeTrakBox.cpp
void TimeTrakBox::AnalyzeBoxHeader(BoxHeader header, size_t offset) {
if (header.GetType() == TKHD) {
TimeTkhdBox* timeTkhdBox = new TimeTkhdBox(header, data + offset + 8);
timeTkhdBox->PrintDataInfo();
PushBox(timeTkhdBox);
}
if (header.GetType() == MDIA) {
printf("===========================\n");
header.to_string();
}
}