关于ffprobe提取视频帧时间戳的若干技术问题咨询
视频帧时间戳提取的三个问题解答
1. 优先使用packet=还是frame=参数?
不能“始终”用packet=,核心差异在于解码需求和帧顺序:
packet=参数速度快的原因:ffprobe无需解码视频帧,仅读取封装层的数据包元数据,处理耗时远低于frame=- 适用场景:如果视频编码无B帧(解码顺序与显示顺序一致,比如多数H.264 Baseline、MPEG-2编码),
packet=pts_time返回的时间戳和frame=pts_time完全对应,此时用packet=效率更高,结果可靠 - 注意例外:若视频包含B帧,数据包顺序是解码顺序,而帧顺序是显示顺序,此时
packet=pts_time的顺序和实际显示帧的序号不匹配,必须用frame=参数才能拿到与显示帧一一对应的时间戳
2. 无pts_time时的替代字段选择
三个字段的优先级和适用逻辑:
- 首选
pts_time:这是帧的实际显示时间戳,是建立显示帧-时间映射的最优值 - 其次
best_effort_timestamp_time:当pts_time缺失时,这是ffprobe根据视频流上下文估算的显示时间戳,比dts_time更贴近实际显示时间 - 最后考虑
dts_time:这是帧的解码时间戳,仅在前两个字段都不可用时使用——因为解码时间和显示时间可能存在差异(比如B帧的dts早于pts)
不要直接默认用dts_time,优先用best_effort_timestamp_time作为替代更可靠。
3. 直接获取毫秒级时间值的方法
ffprobe默认输出秒级浮点数(如0.042对应42ms),可以通过两种方式获取毫秒级结果:
方式1:Python内转换
读取到pts_time后直接做浮点运算:
# 假设从JSON中读取的pts_time为字符串,先转成浮点数 pts_seconds = float(packet_data["pts_time"]) # 转成毫秒并取整(round处理浮点精度问题) pts_milliseconds = int(round(pts_seconds * 1000))
方式2:让ffprobe直接输出整数毫秒
通过读取原始pts值和流的time_base(时基)计算,时基表示每个pts单位对应的秒数:
ffprobe -select_streams v:0 -show_entries stream=time_base -show_entries packet=pts -print_format json VIDEO.mkv
计算逻辑:毫秒数 = pts * (time_base_num / time_base_den) * 1000,比如时基为1/90000、pts为3780,毫秒数即为3780 * (1/90000) * 1000 = 42ms
也可以用ffprobe的格式化输出直接计算:
ffprobe -select_streams v:0 -show_entries packet=pts_time -of csv=p=0 VIDEO.mkv | awk '{print int($1*1000)}'
内容的提问来源于stack exchange,提问作者jeremie bergeron
相关产品推荐
相关产品推荐

