在PHP中获取视频时间总长度,除了常见的使用FFmpeg命令行工具或安装PHP扩展如ffmpegphp外,还可以通过解析视频文件的元数据信息来实现,这种方法无需依赖外部工具或扩展,仅通过PHP内置函数即可完成,尤其适合在受限环境中使用,以下是详细实现步骤和原理分析。

视频元数据与文件结构
视频文件(如MP4、AVI、MKV等)通常包含元数据信息,其中存储了视频的时长、分辨率、编码格式等关键数据,这些元数据位于文件的开头或特定位置,以特定格式(如MP4的ftyp和moov盒子)存储,通过读取并解析这些数据,可以提取出视频时长信息。
实现方法:解析MP4文件的mdhd盒子
以MP4文件为例,其元数据存储在moov盒子的mdhd(Media Header)子盒子中。mdhd盒子的结构如下:
- 长度(4字节):盒子总长度(包括头部)。
- 类型(4字节):固定为
mdhd。 - 版本(1字节):通常为0。
- 标志(3字节):保留字段。
- 创建时间(4字节):文件创建时间。
- 修改时间(4字节):文件修改时间。
- 时间尺度(4字节):每秒的tick数。
- 时长(4字节):总tick数。
视频时长计算公式为:时长 = 时长值 / 时间尺度。

PHP代码实现
以下代码通过读取MP4文件并解析mdhd盒子获取时长:
function getVideoDuration($filePath) {
// 打开文件
$file = fopen($filePath, 'rb');
if (!$file) {
return false;
}
// 读取文件头部,查找'moov'盒子
$moovOffset = false;
while (!feof($file)) {
$boxHeader = fread($file, 8);
if (strlen($boxHeader) < 8) break;
// 解析盒子长度和类型
$boxLength = unpack('Nlength', substr($boxHeader, 0, 4))['length'];
$boxType = substr($boxHeader, 4, 4);
if ($boxType === 'moov') {
$moovOffset = ftell($file) 8; // 记录'moov'起始位置
break;
}
// 跳过当前盒子内容
fseek($file, $boxLength 8, SEEK_CUR);
}
if ($moovOffset === false) {
fclose($file);
return false; // 未找到'moov'盒子
}
// 在'moov'盒子中查找'mdhd'盒子
fseek($file, $moovOffset);
while (!feof($file)) {
$boxHeader = fread($file, 8);
if (strlen($boxHeader) < 8) break;
$boxLength = unpack('Nlength', substr($boxHeader, 0, 4))['length'];
$boxType = substr($boxHeader, 4, 4);
if ($boxType === 'mdhd') {
// 跳过版本和标志字段
fseek($file, 4, SEEK_CUR);
// 跳过创建时间和修改时间
fseek($file, 8, SEEK_CUR);
// 读取时间尺度和时长
$timeScaleAndDuration = fread($file, 8);
$timeScale = unpack('NtimeScale', substr($timeScaleAndDuration, 0, 4))['timeScale'];
$duration = unpack('Nduration', substr($timeScaleAndDuration, 4, 4))['duration'];
fclose($file);
// 计算时长(秒)
return $duration / $timeScale;
}
fseek($file, $boxLength 8, SEEK_CUR);
}
fclose($file);
return false; // 未找到'mdhd'盒子
}
// 使用示例
$duration = getVideoDuration('example.mp4');
if ($duration !== false) {
echo "视频时长: " . gmdate('H:i:s', $duration);
} else {
echo "无法获取视频时长";
}
代码解析
- 文件读取:以二进制模式打开文件,逐个解析盒子结构。
- 盒子定位:通过遍历盒子头部找到
moov和mdhd的位置。 - 数据提取:从
mdhd盒子中提取时间尺度和时长值,并计算最终时长。 - 错误处理:若文件格式不符合预期或元数据缺失,返回
false。
支持的格式与局限性
- 支持格式:MP4(ISO基础媒体文件格式)及其变种(如M4V、MOV)。
- 局限性:
- 不支持所有视频格式(如AVI、MKV需不同解析逻辑)。
- 若视频文件未正确封装元数据(如某些流媒体文件),可能无法获取时长。
- 大文件读取效率较低,需优化内存使用。
与其他方法的对比
| 方法 | 优点 | 缺点 |
|---|---|---|
| 解析元数据 | 无需外部依赖,轻量级 | 仅支持特定格式,解析复杂 |
| FFmpeg命令 | 支持格式广泛,功能强大 | 需安装FFmpeg,服务器环境受限 |
ffmpegphp扩展 |
集成度高,调用简单 | 需额外安装扩展,维护成本高 |
优化建议
- 缓存结果:对频繁访问的视频文件,缓存时长信息以减少重复解析。
- 多格式支持:扩展代码以支持其他格式(如AVI的
idx1标签或MKV的Segment信息)。 - 性能优化:使用
fseek和fread的组合减少内存占用,避免读取整个文件。
相关问答FAQs
Q1: 为什么解析MP4文件时找不到mdhd盒子?
A1: 可能原因包括:文件损坏、非标准MP4封装(如某些流媒体切片)、或元数据未写入,建议使用工具如MP4Box修复文件或检查文件结构。
Q2: 此方法能否处理加密的视频文件?
A2: 不能,加密视频(如DRM保护)的元数据可能被隐藏或加密,需特定密钥或工具才能解析,此方法仅适用于未加密的标准视频文件。

原创文章,发布者:酷盾叔,转转请注明出处:https://www.kd.cn/ask/298826.html