You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Python多线程录制5路RTSP流仅存最后一帧的问题求助

RTSP多线程录制仅保存最后一帧的问题分析与修复

问题根源

你的代码存在三个核心问题,导致每个视频仅保存最后一帧:

  • 录制逻辑只执行一次:主线程仅调用了一次record_vid()方法,每个摄像头只写入了当前内存中的那一帧,没有持续写入后续帧。
  • 显示与退出逻辑不完整:仅调用了一次show_frame(),既无法持续显示画面,也只能处理第一个摄像头的退出事件,其他摄像头的资源无法正常释放。
  • 线程读取无控制:update线程持续无间隔读取帧,会导致CPU占用过高,且没有处理读取失败的异常情况。

修复后的代码

以下是调整后的完整代码,解决了上述问题:

from threading import Thread
import cv2
import os
import time

class RTSPVideoWriterObject(object):
    def __init__(self, src, camname, folder):
        # 创建VideoCapture对象
        self.capture = cv2.VideoCapture(src)
        self.camname = camname
        self.folder = folder
        self.status = False
        self.frame = None

        # 获取视频流参数,兼容FPS获取失败的情况
        self.frame_width = int(self.capture.get(3))
        self.frame_height = int(self.capture.get(4))
        self.fps = int(self.capture.get(5)) if self.capture.get(5) > 0 else 25
        
        # 创建存储目录
        folder_path = time.strftime(os.path.join(self.folder, '%Y_%m_%d/%Hh'))
        if not os.path.exists(folder_path):
            os.makedirs(folder_path)
        filename = os.path.join(folder_path, time.strftime(f"{self.camname} %Y_%m_%d - %Hh%M") + '.mp4')
        
        # 初始化视频写入器
        self.codec = cv2.VideoWriter_fourcc(*'avc1')
        self.output_video = cv2.VideoWriter(filename, self.codec, self.fps, (self.frame_width, self.frame_height))
        
        # 启动帧读取线程
        self.thread = Thread(target=self.update, args=())
        self.thread.daemon = True
        self.thread.start()

    def update(self):
        # 持续读取帧,添加延迟降低CPU占用
        while True:
            if self.capture.isOpened():
                ret, frame = self.capture.read()
                if ret:
                    self.status = True
                    self.frame = frame
                else:
                    self.status = False
                    time.sleep(0.1)  # 读取失败时短暂等待
            time.sleep(1/self.fps)  # 按原FPS间隔读取,避免帧堆积

    def show_frame(self):
        # 显示当前帧(需在主线程调用)
        if self.status:
            cv2.imshow(self.camname, self.frame)

    def record_vid(self):
        # 写入当前帧到视频文件
        if self.status:
            self.output_video.write(self.frame)

    def release(self):
        # 统一释放资源
        self.capture.release()
        self.output_video.release()
        cv2.destroyWindow(self.camname)

if __name__ == '__main__':
    # 替换为你的RTSP链接、文件名和存储目录
    rtsp_configs = [
        ("My RTSP link1", "MyFileName1", "MyFolder1"),
        ("My RTSP link2", "MyFileName2", "MyFolder2"),
        ("My RTSP link3", "MyFileName3", "MyFolder3"),
        ("My RTSP link4", "MyFileName4", "MyFolder4"),
        ("My RTSP link5", "MyFileName5", "MyFolder5"),
    ]

    # 初始化所有摄像头对象
    video_widgets = []
    for src, name, folder in rtsp_configs:
        widget = RTSPVideoWriterObject(src, name, folder)
        video_widgets.append(widget)

    # 主循环:持续显示与录制,监听退出事件
    try:
        while True:
            # 遍历所有摄像头,执行显示和录制
            for widget in video_widgets:
                widget.show_frame()
                widget.record_vid()
            
            # 监听键盘事件,按Q退出
            if cv2.waitKey(1) & 0xFF == ord('q'):
                break
    finally:
        # 退出时统一释放所有资源
        for widget in video_widgets:
            widget.release()
        cv2.destroyAllWindows()

关键修改点说明

  • 主循环持续执行:在主线程中添加循环,持续调用每个摄像头的show_frame()和record_vid(),实现持续显示与录制。
  • 线程读取控制:在update线程中添加time.sleep(1/self.fps),按原视频流的FPS间隔读取帧,避免CPU空转和帧堆积;同时处理读取失败的情况,添加短暂等待。
  • 统一资源释放:新增release()方法,在退出时统一释放所有摄像头的捕获和写入资源,避免内存泄漏。
  • 兼容处理:增加FPS获取失败的默认值(25),避免参数错误导致的初始化失败。

内容的提问来源于stack exchange,提问作者Jul Pandoa

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.18 20:24:52