传送门:MP4 文档 P32页
这个 Box 是记录每一次采样出来的 sample 的时间,也可以理解为解码当前 sample 的解码时间DTS,所以这个 Bos 主要是用来找到任意时间的 sample。Stts Box 这个表格有两项值,其中一项是连续的样点数目即 sample count 和样点相对时间差值,即 sample delta 即表格中每个条目提供了在同一个时间偏移量里面连续的 sample 序号以及 sample 偏移量。
Sample delta简单可以理解为当前这个 sample 的时长,也就是采样了一次过后多久再采样一次,所以把全部 sample 的 sample delta 加起来就是当前这个 track 的总时长。
大家把这个时间理解为该帧数据当前的解码时间即可,计算公式:
DT(n+1) = DT(n) + STTS(n)
从上面图可以看出,第一个 sample 默认是从0开始,也就是说第一个 sample 的 Dts 是0,根据公式所以第二个 sample 第一个的 Dts = 0 + 413 = 413。同理第三个 sample 的 Dts 就是 413 + 416 = 829。
我们在 mdhd box 里面可以获取到 Time scale,也就是可以把1s划分为多少个单位,这个MP4文件的 Time scale 是6000,所以一秒钟有6000个单位,第二个 sample Dts = 413,所以经过413个单位就解码第二个sample。
如果sample count 不为1时,相当于有多个 sample 的采样间隔时间是一样的。如果 sample count 数量只有一个的话说明这个 MP4 是固定帧率。
音频 Stts box
音频有1495个采样,每一个采样1024个时间单位,这里音频的 Time scale 是48000。
1495 * 1024 = 1530880
1530880 / 48000 = 31.893333333333334
所以音频时长 31.89秒
其中该 Box 是 Full Box,后面有四字节的 version 和 flag 字段,其中 flag 默认值用0,这里分析略过,这里就直接解析 Data 的字段。
字段 | 大小 | 实际值(16进制) | 含义 |
---|---|---|---|
entry count | 4 | 00 00 04 FD | 描述了下面采样 sample 的信息个数 |
sample count | 4 | 连续相同时间长度sample delta的sample个数。 | |
sample delta | 4 | 每个sample delta即以timescale为单位的时间长度。 |
// BaseBox.h
// ...
// 其他 Box 的定义
class TimeSttsBox : public BaseBox {
public:
Timebyte version = 0;
Timebyte flags = 0;
unsigned int entry_count = 0;
unsigned int sample_count = 0;
unsigned int sample_delta = 0;
///// 这里的数据不在data数据区里面
unsigned int allSample = 0;
unsigned int allDelta = 0;
///// =========================
TimeSttsBox(BoxHeader h, Timebyte * d): BaseBox(h, d){};
void PrintDataInfo() override;
};
实现
// TimeSttsBox.cpp
void TimeSttsBox::PrintDataInfo() {
TimeBufferStream timeBufferStream(data, h.GetDataSize());
version = timeBufferStream.GetUChar();
timeBufferStream.GetLenData(&flags, 3);
entry_count = timeBufferStream.GetUInt();
sample_count = timeBufferStream.GetUInt();
sample_delta = timeBufferStream.GetUInt();
printf("===========================\n");
h.to_string();
allSample = sample_count;
allDelta = sample_count * sample_delta;
printf("entry_count: %d\n", entry_count);
if (entry_count == 1) {
// 如果为1 要么是固定帧率的视频 或者 是音频
printf("sample_count: %d\n", sample_count);
printf("sample_delta: %d\n", sample_delta);
printf("all Delta: %ud\n", allDelta);
} else {
for (int i = 0; i < entry_count; ++i) {
sample_count = timeBufferStream.GetUInt();
sample_delta = timeBufferStream.GetUInt();
allSample += sample_count;
allDelta += sample_delta * sample_count;
}
printf("all Sample: %ud\n", allSample);
printf("all Delta: %ud\n", allDelta);
}
}
1007668733@qq.com
2024-03-27 11:05:46