OpenCV录制RTSP流视频时长异常:实际与播放时长不符
问题:RTSP流录制视频播放时长远短于实际录制时长
我用OpenCV基于RTSP流制作视频,能正常生成视频文件,但录制完成后播放时长比实际录制时长短很多——测试时录了10秒,视频却只播放2秒,但所有录制的帧都在文件里。
补充测试:在保存帧的循环里加了print("frame"),5秒内一共打印了30次。
相关代码
保存帧的线程
self.rec = False self.thread = Thread(target=self.grava_frame, args=()) self.thread.daemon = True self.thread.start() def grava_frame(self): while True: if self.rec: while not self.thread_end: frame = cv2.cvtColor(self.resized_cropped, cv2.COLOR_RGB2BGR) self.video_writer.write(frame) cv2.waitKey(1) self.video_writer.release()
捕获帧的线程
self.at_frame = Thread(target=self.atualiza_frame, args=()) self.at_frame.daemon = True self.at_frame.start() def atualiza_frame(self): ap = argparse.ArgumentParser() ap.add_argument("-v", "--video", required=True, help="rtsp://admin:@192.168.1.10:554/live/0/MAIN") args = vars(ap.parse_args()) print("[INFO] starting video file thread...") fvs = FileVideoStream(args["video"]).start() time.sleep(1.0) fps = FPS().start() while fvs.more(): frame = fvs.read() self.resized_cropped = cv2.resize(frame, (1024, 600)) cv2.waitKey(1) fps.update()
录制控制按钮代码
def record_button(self): if self.is_recording_on: # 开始录制 data = self.dataname() self.codec = cv2.VideoWriter_fourcc(*'mp4v') self.video_writer = cv2.VideoWriter(data+'.MP4', self.codec, 25, (self.frame_width, self.frame_height)) self.thread_end = False self.rec = True else: # 停止录制 self.rec = False self.thread_end = True
问题原因分析
核心问题是帧写入线程的速度远快于RTSP流的实际帧率:
- 你设置的
VideoWriter帧率是25fps,但实际RTSP流的帧率可能远低于这个值(比如补充测试中5秒仅捕获30帧,实际帧率只有6fps)。 - 写入线程在循环中不断重复写入同一帧(因为捕获线程还没更新
self.resized_cropped),导致视频文件内的帧数量远超实际录制时长对应的合理帧数。播放器按25fps播放时,就会快速播完所有帧,造成时长缩短的假象。
解决方案
1. 用线程安全队列控制帧写入,避免重复写帧
通过队列传递捕获到的新帧,写入线程只处理队列中的新帧,杜绝重复写入同一帧的情况:
from queue import Queue # 初始化队列,限制大小防止内存溢出 self.frame_queue = Queue(maxsize=10) # 修改捕获帧线程 def atualiza_frame(self): ap = argparse.ArgumentParser() ap.add_argument("-v", "--video", required=True, help="rtsp://admin:@192.168.1.10:554/live/0/MAIN") args = vars(ap.parse_args()) print("[INFO] starting video file thread...") fvs = FileVideoStream(args["video"]).start() time.sleep(1.0) fps = FPS().start() while fvs.more(): frame = fvs.read() if frame is not None: resized_frame = cv2.resize(frame, (1024, 600)) # 队列未满时才放入新帧 if not self.frame_queue.full(): self.frame_queue.put(resized_frame) cv2.waitKey(1) fps.update() # 修改保存帧线程 def grava_frame(self): while True: if self.rec: while not self.thread_end: # 队列有帧才读取写入,无帧则等待 if not self.frame_queue.empty(): frame = self.frame_queue.get() frame_bgr = cv2.cvtColor(frame, cv2.COLOR_RGB2BGR) self.video_writer.write(frame_bgr) cv2.waitKey(1) self.video_writer.release()
2. 匹配RTSP流的实际帧率初始化VideoWriter
先获取RTSP流的真实帧率,再用该值初始化VideoWriter,确保播放器的播放速度与实际录制速度一致:
def record_button(self): if not self.is_recording_on: # 获取RTSP流实际帧率 cap = cv2.VideoCapture("rtsp://admin:@192.168.1.10:554/live/0/MAIN") actual_fps = cap.get(cv2.CAP_PROP_FPS) cap.release() # 若获取帧率失败, fallback到25fps或统计的真实FPS if actual_fps <= 0: actual_fps = 25 # 开始录制 data = self.dataname() self.codec = cv2.VideoWriter_fourcc(*'mp4v') self.video_writer = cv2.VideoWriter(data+'.MP4', self.codec, actual_fps, (1024, 600)) self.thread_end = False self.rec = True self.is_recording_on = True else: # 停止录制 self.rec = False self.thread_end = True self.is_recording_on = False
3. 修复录制控制逻辑的小问题
原代码中record_button的判断逻辑可能颠倒,上述代码已修正:未录制时点击开始录制,录制中点击停止录制。
内容的提问来源于stack exchange,提问作者Jorge Augusto Wilchen
相关产品推荐
相关产品推荐

