feat(video): 可配置 RTSP 打开超时并提高默认时长

- Settings 增加 video_open_timeout_sec(VIDEO_OPEN_TIMEOUT_SEC),默认 45s
- SessionManager 全部就绪等待为该值 + 5s;StreamWorker 传入单路超时
- baked pipeline 回退默认值与配置对齐;.env.example 补充说明
- or_site_config.sample.json 扩展穿透摄像头与术间绑定示例
- 同步 uv.lock
This commit is contained in:
Kevin
2026-04-29 10:51:23 +08:00
parent 17d27be18d
commit 869ea21bbe
7 changed files with 986 additions and 962 deletions

View File

@@ -19,6 +19,8 @@ POSTGRES_PORT=35432
# UVICORN_RELOAD=true
# --- VideoRTSP 与按路后端(须与客户端 camera_ids 一致)---
# 单路 RTSP 首次打开超时(秒);四路须在「该值 + 5」秒内全部就绪穿透/公网链路可调大(默认 45
# VIDEO_OPEN_TIMEOUT_SEC=45
# VIDEO_DEFAULT_BACKEND=rtsp
# VIDEO_CAMERA_BACKEND_OVERRIDES_JSON={"or-cam-01":"rtsp","or-cam-02":"hikvision_sdk"}
# 站点 JSON术间↔摄像头↔语音终端只在这里维护voice_or_room_bindings须同时含 video_rtsp_urls可为 []。

View File

@@ -5,7 +5,8 @@ SURGERY_RECORDING_MAX_ATTEMPTS: int = 3
SURGERY_RECORDING_RETRY_DELAY_SECONDS: float = 1.0
# --- RTSP 连接与抽帧、推理门控(不含 URLURL 在 Settings---
VIDEO_OPEN_TIMEOUT_SEC: float = 15.0
# 运行时以 Settings.video_open_timeout_sec环境变量 VIDEO_OPEN_TIMEOUT_SEC为准此处为未注入 Settings 时的回退默认。
VIDEO_OPEN_TIMEOUT_SEC: float = 45.0
VIDEO_READ_FAILURE_RECONNECT_THRESHOLD: int = 15
VIDEO_RECONNECT_BACKOFF_SECONDS: float = 1.0
VIDEO_INFERENCE_INTERVAL_SEC: float = 2.0

View File

@@ -41,6 +41,7 @@ class _VideoGroup(_SettingsGroup):
"video_default_backend",
"video_camera_backend_overrides_json",
"video_rtsp_url_template",
"video_open_timeout_sec",
"or_site_config_json_file",
)
@@ -142,6 +143,13 @@ class Settings(BaseSettings):
video_default_backend: Literal["rtsp", "hikvision_sdk", "auto"] = "rtsp"
video_camera_backend_overrides_json: str = ""
video_rtsp_url_template: str = ""
#: 单路 RTSP 首次打开超时(秒);术间「全部摄像头就绪」等待为该值 + 5s。穿透/公网链路可调大。
video_open_timeout_sec: float = Field(
default=45.0,
ge=5.0,
le=900.0,
validation_alias=AliasChoices("VIDEO_OPEN_TIMEOUT_SEC", "video_open_timeout_sec"),
)
#: 手术室站点配置UTF-8 JSON须含 video_rtsp_urls 与 voice_or_room_bindings见 or_site_config.sample.json
or_site_config_json_file: str = ""

View File

@@ -1,9 +1,6 @@
{
"video_rtsp_urls": {
"or-cam-01": "rtsp://admin:Aa183137@192.168.3.2:554/Streaming/Channels/101",
"or-cam-02": "rtsp://admin:Aa183137@192.168.3.3:554/Streaming/Channels/101",
"or-cam-03": "rtsp://admin:Aa183137@192.168.3.4:554/Streaming/Channels/101",
"or-cam-04": "rtsp://admin:Aa183137@192.168.3.5:554/Streaming/Channels/101"
"or-cam-01": "rtsp://127.0.0.1:18554/demo1"
},
"voice_or_room_bindings": [
{
@@ -13,6 +10,16 @@
"or-cam-03",
"or-cam-04"
],
"or_room_id": "OR-ROOM1",
"voice_terminal_id": "desktop-2"
},
{
"camera_ids": [
"or-cam-101",
"or-cam-102",
"or-cam-103",
"or-cam-104"
],
"or_room_id": "OR-TEST",
"voice_terminal_id": "desktop-1"
}

View File

@@ -183,7 +183,7 @@ class CameraSessionManager:
stop_event = asyncio.Event()
readies = [asyncio.Event() for _ in camera_ids]
tasks: list[asyncio.Task[None]] = []
open_timeout = bp.VIDEO_OPEN_TIMEOUT_SEC + 5.0
open_timeout = float(self._s.video_open_timeout_sec) + 5.0
for cam_id, ready in zip(camera_ids, readies, strict=True):
tasks.append(
@@ -438,6 +438,7 @@ class CameraSessionManager:
surgery_id=surgery_id,
camera_id=camera_id,
url=url,
open_timeout_sec=self._s.video_open_timeout_sec,
)
try:
await w_tear.run(
@@ -518,6 +519,7 @@ class CameraSessionManager:
surgery_id=surgery_id,
camera_id=camera_id,
url=url,
open_timeout_sec=self._s.video_open_timeout_sec,
)
await worker.run(
stream_ready=stream_ready,

View File

@@ -41,10 +41,14 @@ class CameraStreamWorker:
surgery_id: str,
camera_id: str,
url: str,
open_timeout_sec: float | None = None,
) -> None:
self._surgery_id = surgery_id
self._camera_id = camera_id
self._url = url
self._open_timeout_sec = (
float(open_timeout_sec) if open_timeout_sec is not None else bp.VIDEO_OPEN_TIMEOUT_SEC
)
async def run(
self,
@@ -63,7 +67,7 @@ class CameraStreamWorker:
if cap is None:
try:
cap = RtspCapture(
self._url, open_timeout_sec=bp.VIDEO_OPEN_TIMEOUT_SEC
self._url, open_timeout_sec=self._open_timeout_sec
)
await asyncio.to_thread(cap.open)
consecutive_failures = 0

1910
uv.lock generated

File diff suppressed because it is too large Load Diff