一般播放器用于展示的视频总时长,使用的是 mediainfo中的哪个字段?

在使用 MediaInfo 获取视频信息时,播放器用于展示的“视频总时长” 通常对应以下字段:


推荐字段:Duration(或 Duration/String

完整路径(在 MediaInfo 输出中):

  • General track(全局轨道)下的 Duration

示例(命令行输出):

mediainfo --Inform="General;Duration: %Duration% ms" video.mp4
# 输出:Duration: 123456 ms

mediainfo --Inform="General;Duration: %Duration/String%" video.mp4
# 输出:Duration: 2 min 3 s

🔍 详细说明

字段名 类型 说明
Duration 数值(毫秒) 视频总时长,单位为 毫秒(ms),适合程序计算
Duration/String 字符串 人类可读格式,如 1 h 23 min 45 s00:23:45.123
Duration/String1 ~ String5 不同格式的字符串 String3: 00:23:45.123(标准时间码格式)

📌 播放器应优先使用 General 轨道的 Duration,而不是 Video 或 Audio 轨道的 Duration,因为:

  • 全局 Duration 是容器层面的总时长(最权威);
  • 音视频轨道的 Duration 可能因编码差异略有不同(如音频比视频长 1 帧)。

🛠 如何通过 MediaInfo 库获取(编程示例)

Python(使用 pymediainfo):

from pymediainfo import MediaInfo

media_info = MediaInfo.parse("video.mp4")
general_track = media_info.tracks[0]  # General track is first
duration_ms = general_track.duration  # 单位:毫秒(int)
print(f"总时长: {duration_ms} ms")     # e.g., 123456

JavaScript(前端 mediainfo.js):

const result = await mediaInfo.analyzeData(...);
const tracks = JSON.parse(result).media.track;
const general = tracks.find(t => t["@type"] === "General");
const durationMs = parseInt(general.Duration); // 字符串转数字
console.log(`总时长: ${durationMs} 毫秒`);

⚠️ 注意事项

  1. 单位是毫秒
    MediaInfo 的 Duration 字段默认以 毫秒 为单位(即使原始文件用 PTS 表示),可直接用于播放器进度条计算。

  2. 避免使用 Video/Audio 轨道的 Duration

    ❌ Video Duration: 123400 ms
    ❌ Audio Duration: 123500 ms
    ✅ General Duration: 123456 ms  ← 正确!
    
  3. 某些损坏文件可能无 Duration
    若文件 moov 在尾部(后置 MP4)且未完全下载,MediaInfo 可能无法读取时长 → 返回空或 0。

  4. 直播流/实时流无 Duration
    对于 HLS/DASH 直播或 RTMP 流,Duration 通常为 0N/A,因为内容是无限的。


✅ 总结

用途 推荐 MediaInfo 字段
播放器显示总时长(程序计算) General.Duration(单位:毫秒)
UI 显示人类可读时长 General.Duration/String3(格式:HH:MM:SS.mmm

💡 最佳实践
播放器初始化时,优先从 容器(General)层级 读取 Duration,若为空再 fallback 到 Video 轨道,并做好异常处理。

若文件 moov 在尾部(后置 MP4),但是是完整视频,可以获取到总时长吗

如果文件是完整的(moov 在尾部但文件已全部下载/存在)MediaInfo、FFmpeg、播放器等工具仍然可以准确获取到视频的总时长


✅ 核心结论

只要 MP4 文件完整(即使 moov 在尾部),就能 100% 获取总时长。

因为 moov 原子中包含了所有元数据,包括:

  • 视频/音频轨道的时长(duration
  • 时间刻度(timescale
  • 帧数、码率、关键帧位置等

只要程序能读到文件末尾的 moov,就能解析出正确时长。


🔍 技术原理

MP4 文件结构简述:

[ftyp] → [mdat](媒体数据) → [moov](元数据)
  • moov 包含
    movie duration = sum of track durations
    track duration = (last DTS - first DTS) × timescale
    
  • 即使 moov 在尾部,只要文件完整,解析器会:
    1. 从文件末尾向前扫描(或直接 seek 到末尾)
    2. 找到 moov 原子
    3. 解析其中的 mvhd.durationtkhd.duration

📌 注意:这个过程需要读取文件末尾,所以:

  • 如果文件未完全下载(如只下了一半),则无法获取时长;
  • 如果文件已完整存储在本地或服务器上,则毫无问题。

🧪 实验验证

1. 用 MediaInfo 测试后置 MP4

# 生成一个 moov 在尾部的 MP4(默认行为)
ffmpeg -i input.mp4 -c copy output_back_moov.mp4

# 查看时长
mediainfo --Inform="General;Duration: %Duration% ms" output_back_moov.mp4
# ✅ 正常输出:Duration: 123456 ms

2. 用 FFprobe 验证

ffprobe -v quiet -show_entries format=duration -of csv=p=0 output_back_moov.mp4
# ✅ 输出:123.456(秒)

3. 用浏览器 <video> 加载

<video src="output_back_moov.mp4" controls></video>
  • 虽然首帧加载慢(需先读完文件才能解析 moov),
  • 但一旦加载完成,进度条和总时长显示完全正常

⚠️ 唯一限制:文件必须完整

场景 能否获取时长? 原因
本地完整 MP4(moov 在尾) ✅ 能 可读取整个文件
云存储完整文件(HTTPS URL) ✅ 能 HTTP 支持 Range 请求,工具会自动 fetch 末尾
仅下载了前 10MB 的 MP4 ❌ 不能 moov 在尾部,未下载到
流式传输中(直播录制) ❌ 不能 文件未结束,moov 尚未写入

💡 提示:
即使 moov 在尾部,HTTP 服务器支持 Range 请求(如 AWS S3、阿里云 OSS),MediaInfo 或 FFprobe 会自动发起 Range: bytes=-65536 请求读取文件末尾,从而快速定位 moov 并解析时长——无需下载整个文件


✅ 总结

问题 答案
后置 MP4(moov 在尾)能否获取总时长? 能,只要文件完整
是否需要转换为前置 MP4 才能读时长? 不需要
什么情况下读不到时长? 文件不完整 / 网络中断 / 服务器不支持 Range 请求

📌 最佳实践

  • 对于点播视频,即使 moov 在尾部,只要文件完整,所有工具都能正确读取时长;
  • 但为了提升首屏加载速度(用户体验),仍建议用 ffmpeg -movflags +faststart 转为前置 MP4。
  • 时长解析 ≠ 快速播放:前者只需读 moov(可在尾部),后者要求 moov 在头部。
posted @ 2026-03-17 09:52  龙陌  阅读(7)  评论(0)    收藏  举报