据我所知 - "mp4"容器源自QuickTime原子结构.您可以阅读QuickTime文件格式的说明.
解析quicktime原子并不是什么大问题(看看atomicParsley项目).我不确定MP4,但对于MOV文件 - "mvhd"(电影标题)原子和"tkhd"(轨道标题)原子中都有"持续时间"字段.此持续时间通常是多个帧乘以"时间刻度"属性.时间尺度可以在相同的原子中找到.
对于Red5 MP4阅读器,我使用了"mvhd"原子,因为它包含时间刻度和持续时间字段.从原子获取持续时间将根据使用的版本而有所不同,下面您可以看到一个示例:
public long create_full_atom(MP4DataStream bitstream) throws IOException {
long value = bitstream.readBytes(4);
version = (int)value >> 24;
flags = (int)value & 0xffffff;
readed += 4;
return readed;
}
public long create_movie_header_atom(MP4DataStream bitstream) throws IOException {
create_full_atom(bitstream);
if (version == 1) {
creationTime = createDate(bitstream.readBytes(8));
modificationTime = createDate(bitstream.readBytes(8));
timeScale = (int)bitstream.readBytes(4);
duration = bitstream.readBytes(8);
readed += 28;
} else {
creationTime = createDate(bitstream.readBytes(4));
modificationTime = createDate(bitstream.readBytes(4));
timeScale = (int)bitstream.readBytes(4);
duration = bitstream.readBytes(4);
readed += 16;
}
int qt_preferredRate = (int)bitstream.readBytes(4);
int qt_preferredVolume = (int)bitstream.readBytes(2);
bitstream.skipBytes(10);
long qt_matrixA = bitstream.readBytes(4);
long qt_matrixB = bitstream.readBytes(4);
long qt_matrixU = bitstream.readBytes(4);
long qt_matrixC = bitstream.readBytes(4);
long qt_matrixD = bitstream.readBytes(4);
long qt_matrixV = bitstream.readBytes(4);
long qt_matrixX = bitstream.readBytes(4);
long qt_matrixY = bitstream.readBytes(4);
long qt_matrixW = bitstream.readBytes(4);
long qt_previewTime = bitstream.readBytes(4);
long qt_previewDuration = bitstream.readBytes(4);
long qt_posterTime = bitstream.readBytes(4);
long qt_selectionTime = bitstream.readBytes(4);
long qt_selectionDuration = bitstream.readBytes(4);
long qt_currentTime = bitstream.readBytes(4);
long nextTrackID = bitstream.readBytes(4);
readed += 80;
return readed;
}
Run Code Online (Sandbox Code Playgroud)
在旁注中,我使用值来计算播放时间和fps,如下所示:
videoSampleCount变量来自"stsz"原子.
double fps = (videoSampleCount * timeScale) / (double) duration;
double videoTime = ((double) duration / (double) timeScale);