6.7 KiB
Executable File
6.7 KiB
Executable File
视频双后端说明(RTSP / 海康 HCNetSDK)
目标容器
- 推荐:
Linux x86_64+ glibc(与当前python:3.13-slim-bookworm一致)。 - 不推荐:Alpine(musl)加载海康预编译
.so往往失败。 - 镜像已安装 ffmpeg 与 OpenCV 常用系统库,便于
cv2.VideoCapture(..., cv2.CAP_FFMPEG)拉 RTSP。
RTSP 模式(默认)
- 配置
**camera_id→ RTSP URL** 映射:
**OR_SITE_CONFIG_JSON_FILE**(推荐):UTF-8 JSON 文件,仅支持站点对象:{"video_rtsp_urls":{...},"voice_or_room_bindings":[...]}。根级只允许这两个键;voice_or_room_bindings可为[]。见[app/resources/or_site_config.sample.json](../app/resources/or_site_config.sample.json)。服务每次解析映射时会重新读文件,便于联调覆盖video_rtsp_urls。**VIDEO_RTSP_URL_TEMPLATE**(可选):单模板字符串,可用{camera_id};在video_rtsp_urls未给出某路时使用。
- 调用
POST /client/surgeries/start时,camera_ids必须能在上述配置中解析出 RTSP 地址。 - 开录确认:每路摄像头在超时内成功打开并读到首帧后,才认为该路已开录。
Docker 与 RTSP 地址
- 站点 JSON 中的局域网 IP(如
[or_site_config.sample.json](../app/resources/or_site_config.sample.json)的192.168.3.x):API 在默认 bridge 网络下出站流量经 宿主机 转发,只要宿主机能访问该网段,容器内一般可直接使用相同 URL,无需改成172.x等。 127.0.0.1/localhost:在容器内指向容器自身。若 RTSP 服务跑在宿主机(含fake_rtsp_from_file.py、本机 MediaMTX),URL 应使用rtsp://host.docker.internal:<端口>/<路径>。backend/docker-compose.yml已为api服务配置extra_hosts: host.docker.internal:host-gateway(Linux 兼容;macOS/Windows Desktop 通常已内置该主机名)。- 传输协议:compose 默认设置环境变量
OPENCV_FFMPEG_CAPTURE_OPTIONS=rtsp_transport;tcp,使 OpenCV 经 FFmpeg 以 TCP 拉 RTSP,降低容器/NAT 下 UDP 丢包导致的首帧超时;可通过环境变量覆盖。
海康官方 SDK 模式(可选)
SDK 不作为构建期依赖:将厂商提供的 Linux x86_64 动态库挂载到容器内(例如 /opt/hikvision/lib/libhcnetsdk.so),并设置:
HIKVISION_SDK_ENABLED=trueHIKVISION_DEVICE_IP/HIKVISION_USER/HIKVISION_PASSWORD(以及可选端口)HIKVISION_PREVIEW_RTSP_TEMPLATE或HIKVISION_CAMERA_RTSP_URLS_JSON:登录成功后仍通过 RTSP 取帧送模型(与常见部署一致:SDK 负责设备会话,码流仍走 RTSP)。
行为概要:
- 进程内对
NET_DVR_Init使用引用计数;每路使用 SDK 的工作线程在登录后NET_DVR_Logout,线程结束时配对NET_DVR_Cleanup。 - 若
HIKVISION_SDK_FALLBACK_TO_RTSP=true(默认),在无法加载动态库、登录失败或未配置凭据时,自动回退到 OR 站点配置中的video_rtsp_urls或VIDEO_RTSP_URL_TEMPLATE拉流。
注意:NET_DVR_Login_V30 的设备信息结构体在不同 SDK 版本上可能存在差异;若登录异常,请优先使用 RTSP 回退或按厂商文档校对 ctypes 绑定。
推理与结果查询
链路 1/2:实时(python -m app.algorithm_runner)
- 开录后子进程从 RTSP 读帧,经 ActionFormer gated 流水线(VideoSwin → 段检测 + 手检/好坏帧/耗材投票)产出 JSONL 事件。
- 候选耗材清单(
candidate_consumables):非空时仅清单内名称参与自动记账与待确认;缺省或[]时,用consumable_classifier_labels.yaml的 全部类名作为候选。 - 当段内 Top1 置信度 ≥
VIDEO_AUTO_CONFIRM_CONFIDENCE(默认 0.9)且标签在候选清单内时,自动写入source=vision明细;中间区间产生needs_voice_confirm,由语音终端 TTS/确认。 - 客户端
GET /client/surgeries/{surgery_id}/pending-confirmation,确认后POST .../pending-confirmation/{id}/resolve等。
链路 3:离线 batch(POST /internal/demo/offline-batch)
- FastAPI 编排层
app/algo_host为 5.15 准备工作目录(config.yaml、白名单、商品表),子进程直调algorithm_subprocesses/5.15/main.py --config;解析result.tsv后入库。不在 API 进程内加载模型,不修改 5.15 源码。 - 可选标注视频由子进程
visualize_result_video.py生成;结果缓存键为sha256(video) + candidate_list(跨手术号复用)。 - 不启动实时会话、不触发语音终端。
通用
GET /client/surgeries/{surgery_id}/result仅在存在至少一条消耗明细时返回 200;否则 503RESULT_NOT_READY。GET /client/surgeries/{surgery_id}/result仅在存在至少一条消耗明细时返回 200;无明细(已开录但尚未记账、已结束但零消耗、或尚无归档等)返回 503RESULT_NOT_READY。- 同类物品写入受
VIDEO_DETAIL_COOLDOWN_SEC节流。 - RTSP 读帧连续失败达到
VIDEO_READ_FAILURE_RECONNECT_THRESHOLD时会release并尝试重连,间隔VIDEO_RECONNECT_BACKOFF_SECONDS。
Demo 联调台:HLS 浏览器预览
浏览器无法直接播放 RTSP。联调台通过 MediaMTX 将 RTSP 转为 HLS,由 FastAPI 反代 m3u8/ts 后由 hls.js 播放。
| 部署方式 | 行为 |
|---|---|
| Docker Compose(推荐) | 固定服务 mediamtx-hls(宿主机 127.0.0.1:18888,容器内 mediamtx-hls:8888);hls-preview-init 种子共享卷后 MediaMTX 直接读 /config/mediamtx.yml(官方镜像是 scratch,勿用 /bin/sh entrypoint);ensure 写共享 mediamtx.yml 并 docker restart orm-mediamtx-hls;DEMO_HLS_PREVIEW_UPSTREAM=http://mediamtx-hls:8888 |
| 本机 uvicorn | 未设 upstream 时按需 docker run 临时 MediaMTX(端口默认 127.0.0.1:18888) |
| 链路 | 行为 |
|---|---|
| 链路 1(真 RTSP) | POST /internal/demo/hls-preview/ensure 按 or_site_config 的 video_rtsp_urls 配置 MediaMTX 路径 |
| 链路 2(模拟实时) | 不使用 HLS;联调台在各路槽位用本地 <video> 预览所选文件 |
- 播放地址:
GET /internal/demo/hls-preview/{camera_id}/index.m3u8(playlist 内 URL 重写为 API 路径)。 - Compose 需将 docker.sock 挂入
api(用于 reload mediamtx-hls),与模拟假流 orchestrator 相同。
单帧 JPEG 预览仍保留:GET /internal/demo/rtsp-preview/{camera_id}/frame.jpg。
相关环境变量
详见 backend/.env.example 中「视频:RTSP + 可选海康 HCNetSDK」与 HLS 预览相关注释。