OpenCV如何读取动态FPS的H.265视频并计算已播放时长?
核心思路
动态FPS场景下计算累计播放时长的核心逻辑是不依赖固定帧率换算,直接使用每帧的实际显示时长或者帧的显示时间戳(PTS)判断,有两种常用实现方案:
方案1:预计算拆分点(批量处理优先)
适合不需要逐帧处理内容、只需要先确定拆分位置的场景,直接用你已经拿到的ffprobe输出计算即可:
- ffprobe返回的每个视频packet的
duration_time字段就是当前帧的实际显示时长,单位为秒,25FPS时该值为0.04,1FPS时该值为1.0,直接累加该值即可得到精确的累计播放时长。 - 示例代码如下:
import json # 加载ffprobe输出的JSON文件 with open("ffprobe_output.json", "r", encoding="utf-8") as f: ffprobe_data = json.load(f) split_frame_indexes = [] # 存储每个5分钟分段的最后一帧索引 accumulated_duration = 0.0 split_threshold = 5 * 60 # 5分钟等于300秒 for frame_idx, packet in enumerate(ffprobe_data["packets"]): # 跳过非视频帧 if packet["codec_type"] != "video": continue accumulated_duration += float(packet["duration_time"]) # 累计时长达到阈值则记录拆分点 if accumulated_duration >= split_threshold: split_frame_indexes.append(frame_idx) accumulated_duration = 0.0 # 重置下一个分段的时长计数器
方案2:OpenCV逐帧处理时实时判断
适合边读帧边分析内容的场景,直接读取OpenCV提供的帧时间戳判断即可:
- OpenCV的
VideoCapture接口提供了CAP_PROP_POS_MSEC参数,可以直接返回当前帧对应的实际播放时间戳,单位为毫秒,不需要自己累加计算。 - 示例代码如下:
import cv2 cap = cv2.VideoCapture("你的视频文件路径.mp4") current_segment_start_ms = 0 split_threshold_ms = 5 * 60 * 1000 # 5分钟换算为毫秒 while cap.isOpened(): ret, frame = cap.read() if not ret: break # 读取当前帧的实际播放时间戳 current_time_ms = cap.get(cv2.CAP_PROP_POS_MSEC) # 判断是否到达拆分点 if current_time_ms - current_segment_start_ms >= split_threshold_ms: # 此处执行你的分段保存、分段统计逻辑 print(f"到达5分钟拆分点,当前累计播放时长:{current_time_ms/1000}秒") current_segment_start_ms = current_time_ms # 此处执行你的单帧分析逻辑 cap.release()
注意事项
- 不要依赖OpenCV返回的
CAP_PROP_FPS值计算时长,动态FPS视频的该值一般是平均帧率或者最高帧率,计算出来的时长和实际播放时长误差极大 - 如果发现
CAP_PROP_POS_MSEC返回值不准,优先用ffprobe预读所有帧的duration_time累加的方案,精度更高
内容的提问来源于stack exchange,提问作者s.paszko
相关产品推荐
相关产品推荐

