diff --git a/rtsp_service_ws_Zoulang.py b/rtsp_service_ws_Zoulang.py index c513b46..e19c5b8 100644 --- a/rtsp_service_ws_Zoulang.py +++ b/rtsp_service_ws_Zoulang.py @@ -450,29 +450,90 @@ class RTSPCaptureWorker(threading.Thread): self.camera_cfg = camera_cfg self.raw_queue = raw_queue self.stop_event = stop_event + # 添加重连计数器 + self.reconnect_count = 0 + self.max_reconnects = 10 def run(self): - cap = cv2.VideoCapture(self.camera_cfg.rtsp_url, cv2.CAP_FFMPEG) - if not cap.isOpened(): - print(f"[ERROR] Cannot open RTSP: {self.camera_cfg.rtsp_url}") - return - print(f"[INFO] Capturing {self.camera_cfg.name} (ID:{self.camera_cfg.id})") - while not self.stop_event.is_set(): - ret, frame = cap.read() - if not ret: - time.sleep(0.2) - continue - item = { - "camera_id": self.camera_cfg.id, - "camera_name": self.camera_cfg.name, - "timestamp": time.time(), - "frame": frame, - } + while not self.stop_event.is_set() and self.reconnect_count < self.max_reconnects: try: - self.raw_queue.put(item, timeout=1.0) - except queue.Full: - pass - cap.release() + # 方法1:使用TCP传输(更稳定) + rtsp_url = self.camera_cfg.rtsp_url + if "?" not in rtsp_url: + rtsp_url += "?transport=tcp" # 强制TCP传输 + else: + rtsp_url += "&transport=tcp" + + # 方法2:添加更多FFmpeg参数 + cap = cv2.VideoCapture(rtsp_url, cv2.CAP_FFMPEG) + + # 方法3:设置缓冲区大小 + cap.set(cv2.CAP_PROP_BUFFERSIZE, 10) # 增加缓冲区 + + # 方法4:设置超时和重连参数 + os.environ["OPENCV_FFMPEG_CAPTURE_OPTIONS"] = \ + "rtsp_transport;tcp|buffer_size;1024000|max_delay;500000|stimeout;2000000" + + # 方法5:设置解码器flags,忽略解码错误 + # cap.set(cv2.CAP_PROP_HW_ACCELERATION, cv2.VIDEO_ACCELERATION_ANY) + + if not cap.isOpened(): + print(f"[ERROR] Cannot open RTSP: {self.camera_cfg.rtsp_url}") + time.sleep(2) + self.reconnect_count += 1 + continue + + print(f"[INFO] Successfully opened RTSP: {self.camera_cfg.name}") + self.reconnect_count = 0 # 重置重连计数 + + # # 设置帧率(可选) + # cap.set(cv2.CAP_PROP_FPS, 25) + + while not self.stop_event.is_set(): + ret, frame = cap.read() + if not ret: + # 检查流是否结束 + print(f"[WARN] Failed to read frame from {self.camera_cfg.name}") + + # 检查是否还有数据 + time.sleep(0.1) + # 尝试几次后重连 + break + + item = { + "camera_id": self.camera_cfg.id, + "camera_name": self.camera_cfg.name, + "timestamp": time.time(), + "frame": frame, + } + + try: + # 添加队列满时的处理 + if self.raw_queue.full(): + # 丢弃最旧的一帧 + try: + self.raw_queue.get_nowait() + self.raw_queue.task_done() + except queue.Empty: + pass + + self.raw_queue.put(item, timeout=0.5) + except queue.Full: + print(f"[WARN] Queue full, dropping frame from {self.camera_cfg.name}") + continue + + # 控制读取速度,避免过快 + time.sleep(0.02) # 约50ms间隔 + + cap.release() + + except Exception as e: + print(f"[ERROR] Error in RTSP capture for {self.camera_cfg.name}: {e}") + time.sleep(2) + self.reconnect_count += 1 + + if self.reconnect_count >= self.max_reconnects: + print(f"[ERROR] Max reconnects reached for {self.camera_cfg.name}, stopping.") # ========================= 帧处理线程 =========================