Python OpenCV加载视频列表热键切换异常问题咨询
程序崩溃核心原因
- 切换视频时未释放之前的
VideoCapture对象,视频解码句柄持续泄漏,多次切换后资源耗尽直接崩溃 - 切换视频时从未更新
counter变量,按p永远固定打开索引为1的第二个视频,按u永远固定打开索引为-1的最后一个视频,索引越界时直接触发崩溃 - 未校验
img.read()的返回值ret,视频解码失败、播放到末尾时返回的空帧传入cv2.imshow会直接触发崩溃 - 未做列表边界校验,当视频在列表首尾时继续按切换键会访问超出列表长度的索引,触发越界崩溃
cv2.waitKey(1)延时仅1ms,视频会以CPU能支持的最高速度刷帧,不符合正常播放逻辑;且部分系统下waitKey返回值会携带高位标志,直接和ASCII码比较会出现按键无响应的问题
修复后的基础可运行代码
import glob import cv2 import os # 加载目录下所有mp4文件 d = r"L:\Projects\vids" fl = glob.glob(os.path.join(d, "*.mp4")) # 过滤无效路径 fl = [f for f in fl if os.path.isfile(f)] if not fl: print("指定目录下未找到可用mp4文件") exit() counter = 0 cap = cv2.VideoCapture(fl[counter]) # 根据视频帧率计算播放延时,帧率读取失败默认按30fps处理 fps = cap.get(cv2.CAP_PROP_FPS) wait_ms = int(1000 / fps) if fps > 0 else 33 while True: ret, frame = cap.read() if not ret: # 当前视频播放完自动切下一个,到列表末尾则停在最后一帧 if counter < len(fl) - 1: cap.release() counter += 1 cap = cv2.VideoCapture(fl[counter]) fps = cap.get(cv2.CAP_PROP_FPS) wait_ms = int(1000 / fps) if fps > 0 else 33 continue else: cap.set(cv2.CAP_PROP_POS_FRAMES, cap.get(cv2.CAP_PROP_FRAME_COUNT) - 1) ret, frame = cap.read() cv2.imshow('viewer', frame) # 屏蔽waitKey返回值高位,兼容不同操作系统 k = cv2.waitKey(wait_ms) & 0xFF if k == ord('q'): break elif k == ord('p'): # 切换下一个视频 if counter < len(fl) - 1: cap.release() counter += 1 cap = cv2.VideoCapture(fl[counter]) fps = cap.get(cv2.CAP_PROP_FPS) wait_ms = int(1000 / fps) if fps > 0 else 33 elif k == ord('u'): # 切换上一个视频 if counter > 0: cap.release() counter -= 1 cap = cv2.VideoCapture(fl[counter]) fps = cap.get(cv2.CAP_PROP_FPS) wait_ms = int(1000 / fps) if fps > 0 else 33 cap.release() cv2.destroyAllWindows()
后续规划功能实现参考
- 视频进度拖拽浏览:用
cv2.createTrackbar在播放窗口绑定进度条,拖动进度条时通过cap.set(cv2.CAP_PROP_POS_FRAMES, 目标帧号)跳转即可,跳转后可以读1-2帧空走解码流程,避免出现花屏 - 标记视频入点与出点:绑定两个热键(比如
i标记入点、o标记出点),触发时通过cap.get(cv2.CAP_PROP_POS_FRAMES)拿到当前帧号存入变量,同时可以在播放画面上叠半透明提示条,显示当前标记的区间位置 - 为选中片段添加关键词标签:可以做简单的热键触发文本输入逻辑,把标签和对应视频路径、入出点帧号统一存在本地JSON文件中,不需要额外部署数据库
- 获取视频起止段的运动方向:在标记的入出点区间均匀抽帧,计算帧间特征点光流或者稠密光流,统计水平、垂直方向的位移矢量和,就能判断片段的主运动方向(左右平移、上下平移、推拉镜头等)
- 对接ffmpeg完成转码:拿到入出点对应的时间戳(帧号/视频帧率=对应秒数),直接拼接ffmpeg命令行参数,通过Python的
subprocess模块调用即可,把入点参数放在-i参数前可以实现快速seek,转码速度更快
内容的提问来源于stack exchange,提问作者Fuppiz
相关产品推荐
相关产品推荐

