diff --git a/config.yaml b/config.yaml index edb8b96..9ff58b2 100644 --- a/config.yaml +++ b/config.yaml @@ -1,5 +1,5 @@ cameras: - - id: 1 - name: "Entrance" -# rtsp_url: "rtsp://8.130.165.33:8554/test" - rtsp_url: "rtsp://localhost:8554/test" +- id: 1 + index: testindexcode + name: Entrance + rtsp_url: rtsp://localhost:8554/test diff --git a/rtsp_service_ws_Zoulang.py b/rtsp_service_ws_Zoulang.py index e19c5b8..345e9e7 100644 --- a/rtsp_service_ws_Zoulang.py +++ b/rtsp_service_ws_Zoulang.py @@ -16,6 +16,7 @@ import websockets from dataclasses import dataclass from typing import Dict, Any, Tuple, List from datetime import datetime +from test_cam import get_camera_preview_url # -------------------------- Kadian 检测相关导入 -------------------------- from npu_yolo_onnx_person_car_phone import YOLOv8_ONNX # 主检测模型(人/车/后备箱/手机) @@ -52,6 +53,7 @@ ws_clients_2 = set() # 新增:第二个WebSocket客户端集合 class CameraConfig: id: int name: str + index: str rtsp_url: str @@ -452,13 +454,35 @@ class RTSPCaptureWorker(threading.Thread): self.stop_event = stop_event # 添加重连计数器 self.reconnect_count = 0 - self.max_reconnects = 10 + self.max_reconnects = 5 + self.rtsp_url = "" def run(self): - while not self.stop_event.is_set() and self.reconnect_count < self.max_reconnects: + while not self.stop_event.is_set(): try: + + if self.reconnect_count >= self.max_reconnects: + print(f"[WARN] RTSP: {self.camera_cfg.name} reach max reconnects, refresh url") + self.reconnect_count = 0 + new_url = self.refresh_video_url() + if new_url: + self.rtsp_url = new_url + else: + print(f"[ERROR] refresh RTSP URL is empty, do nothing") + + # 检查rtsp_url是否为空或None,如果是则重新获取 + if not self.rtsp_url: + print(f"[WARN] RTSP URL is empty, refreshing...") + new_url = self.refresh_video_url() + if new_url: + self.rtsp_url = new_url + else: + print(f"[ERROR] RTSP URL is still empty, retrying in 5 seconds") + time.sleep(5) + continue + # 方法1:使用TCP传输(更稳定) - rtsp_url = self.camera_cfg.rtsp_url + rtsp_url = self.rtsp_url if "?" not in rtsp_url: rtsp_url += "?transport=tcp" # 强制TCP传输 else: @@ -478,12 +502,12 @@ class RTSPCaptureWorker(threading.Thread): # 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}") + print(f"[ERROR] Cannot open RTSP: {self.rtsp_url}") time.sleep(2) self.reconnect_count += 1 continue - print(f"[INFO] Successfully opened RTSP: {self.camera_cfg.name}") + print(f"[INFO] Successfully opened RTSP: {self.name}") self.reconnect_count = 0 # 重置重连计数 # # 设置帧率(可选) @@ -535,6 +559,34 @@ class RTSPCaptureWorker(threading.Thread): if self.reconnect_count >= self.max_reconnects: print(f"[ERROR] Max reconnects reached for {self.camera_cfg.name}, stopping.") + def refresh_video_url(self): + """ + 重新通过视频ID获取视频URL,调用test_cam.py中的get_camera_preview_url方法 + + 返回: + str: 新的视频URL,如果获取失败则返回None + """ + try: + + # 获取视频ID(camera_cfg.index) + video_id = self.camera_cfg.index + + # 调用test_cam.py中的函数 + result = get_camera_preview_url(video_id) + + # 解析结果(与test_cam.py相同) + if 'data' in result and 'url' in result['data']: + new_url = result['data']['url'] + print(f"[INFO] get rtsp url success, URL: {new_url}") + return new_url + else: + print(f"[ERROR] get rtsp url failed: {result}") + return None + + except Exception as e: + print(f"[ERROR] get rtsp url error: {str(e)}") + return None + # ========================= 帧处理线程 ========================= class FrameProcessorWorker(threading.Thread): @@ -646,7 +698,7 @@ class RTSPService: def __init__(self, config_path: str = "config.yaml"): with open(config_path, "r", encoding="utf-8") as f: cfg = yaml.safe_load(f) - self.cameras = [CameraConfig(id=c["id"], name=c.get("name", f"cam_{c['id']}"), rtsp_url=c["rtsp_url"]) + self.cameras = [CameraConfig(id=c["id"], name=c.get("name", f"cam_{c['id']}"), index = c["index"], rtsp_url=c["rtsp_url"]) for c in cfg.get("cameras", [])] self.stop_event = threading.Event() diff --git a/test_cam.py b/test_cam.py index 55249b3..4c0d4ca 100644 --- a/test_cam.py +++ b/test_cam.py @@ -26,28 +26,40 @@ def get_camera_preview_url(camera_index_code): response = requests.request(method, url, headers=headers, data=body, verify=False) return response.json() -# 读取 config.yaml -with open('config.yaml', 'r', encoding='utf-8') as f: - config = yaml.safe_load(f) +# # for test +# def get_camera_preview_url(camera_index_code): +# """测试用的方法,直接返回固定结果""" +# return { +# "code": "0", +# "msg": "SUCCESS", +# "data": { +# "url": "rtsp://localhost:8554/test" +# } +# } -# 遍历所有摄像头 -for camera in config['cameras']: - if 'index' in camera: - index = camera['index'] - print(f"正在获取摄像头 {camera['name']} (index: {index}) 的预览地址...") - result = get_camera_preview_url(index) - print(f"API返回结果: {result}") - # 提取 url 并更新到 config - if 'data' in result and 'url' in result['data']: - rtsp_url = result['data']['url'] - camera['rtsp_url'] = rtsp_url - print(f"更新 rtsp_url: {rtsp_url}") - else: - print(f"未找到 url 在返回结果中") - -# 保存更新后的 config.yaml -with open('config.yaml', 'w', encoding='utf-8') as f: - yaml.dump(config, f, default_flow_style=False, allow_unicode=True) - -print("config.yaml 已更新") +# # 读取 config.yaml +# with open('config.yaml', 'r', encoding='utf-8') as f: +# config = yaml.safe_load(f) +# +# # 遍历所有摄像头 +# for camera in config['cameras']: +# if 'index' in camera: +# index = camera['index'] +# print(f"正在获取摄像头 {camera['name']} (index: {index}) 的预览地址...") +# result = get_camera_preview_url(index) +# print(f"API返回结果: {result}") +# +# # 提取 url 并更新到 config +# if 'data' in result and 'url' in result['data']: +# rtsp_url = result['data']['url'] +# camera['rtsp_url'] = rtsp_url +# print(f"更新 rtsp_url: {rtsp_url}") +# else: +# print(f"未找到 url 在返回结果中") +# +# # 保存更新后的 config.yaml +# with open('config.yaml', 'w', encoding='utf-8') as f: +# yaml.dump(config, f, default_flow_style=False, allow_unicode=True) +# +# print("config.yaml 已更新")