diff --git a/Readme.md b/Readme.md index ecd0483..d93ea93 100644 --- a/Readme.md +++ b/Readme.md @@ -474,6 +474,7 @@ GraphMgr 负责: ``` > 说明:如果不需要后处理: +> > - **推荐**:保留 `pp_cam1` 节点(`enable:true`),并确保其不启用任何处理链(例如:`default.enable=false` 且 `per_class` 为空),此时 `det_post` 会作为轻量透传。 > - 若确实要移除该节点:需要**同时删除并重连拓扑**(例如改回 `ai_cam1 -> osd_cam1` 与 `ai_cam1 -> alarm_cam1`),仅设置 `enable=false` 会导致下游节点无输入而构图失败。 @@ -588,6 +589,7 @@ GraphMgr 负责: `det_post` 是一个 **Filter** 节点,位于 `ai_yolo` 之后,负责对 `frame->det->items` 做**按类别可配置**的后处理。 **设计目标:** + - 不同类别可以挂不同的处理器链(Processor/Strategy Registry),避免“一个类别一个插件”。 - 默认改写 `frame->det`,让 `osd` / `alarm` 读到一致结果。 @@ -634,6 +636,7 @@ GraphMgr 负责: ``` **内置 processors(当前实现):** + - `conf_gate`:按置信度过滤(`conf_min`) - `bbox_gate`:按框尺寸过滤(`min_w`, `min_h`) - `roi_gate`:按 ROI 过滤(`roi:{x,y,w,h}` 归一化;`mode:center` 使用 bbox 中心点判断) @@ -643,6 +646,7 @@ GraphMgr 负责: > 注意:`hsv_ratio/lab_kmeans` 需要 `Frame` 提供可读的像素数据(`frame->data` 可访问)。若上游是纯 DMA-BUF 且未映射到 CPU,这两类处理器会自然退化为“不过滤”。 **ai_yolo 参数说明:** + - `model_version`: `"v5"`, `"v8"` 或 `"auto"`(自动检测) - `num_classes`: 模型类别数(默认 80) - `class_filter`: 只检测指定类别 ID 的数组,如 `[0, 1, 2]` @@ -671,6 +675,7 @@ GraphMgr 负责: ``` **参数说明:** + - `model_path`: RetinaFace RKNN 模型路径 - `conf`: 置信度阈值(默认 0.6) - `nms`: NMS 阈值(默认 0.4) @@ -711,6 +716,7 @@ GraphMgr 负责: ``` **参数说明:** + - `model_path`: ArcFace/MobileFaceNet RKNN 模型路径(输入 112x112,输出 512D embedding) - `align`: 是否使用 5 点关键点做仿射对齐(推荐开启) - `emit_embedding`: 是否在结果中输出 embedding(调试用,生产关闭以省内存) @@ -721,6 +727,7 @@ GraphMgr 负责: - `gallery.expected_dim`: embedding 维度(需与模型匹配) **判定规则:** + - `top1_sim >= accept` 且(可选)`top1_sim - top2_sim >= margin` → 识别为该人 - 否则标记为 `unknown` @@ -779,6 +786,7 @@ CREATE TABLE embedding ( ``` **检索实现:** + - 小库(≤几千人):CPU 暴力点积,无需额外索引 - 大库(≥几万人):可扩展 HNSW/Faiss 等 ANN 索引 @@ -795,6 +803,7 @@ CREATE TABLE embedding ( > 说明:当前实现中 `publish` 的 `proto:"hls"` 为**落盘生成 m3u8/ts 文件**,`path` 应指向 `index.m3u8` 文件路径;若需要通过网络播放,建议新增 `zlm_http` 节点启动内嵌 HTTP,并将 `root` 指向 HLS 父目录(如 `/data/hls`)。 **osd 参数说明:** + - `labels`: 自定义类别标签数组,如 `["cat", "dog", "bird"]`,为空则使用 COCO 默认标签 ### 6.4 alarm 插件详细说明 @@ -802,6 +811,7 @@ CREATE TABLE embedding ( alarm 插件采用**模块化 Actions 架构**,支持多种报警动作的灵活组合: **架构设计:** + ``` ┌─────────────────────────────────────────────────────────┐ │ AlarmNode │ @@ -822,6 +832,7 @@ alarm 插件采用**模块化 Actions 架构**,支持多种报警动作的灵 ``` **完整配置示例:** + ```json { "id": "alarm_cam1", @@ -904,11 +915,13 @@ alarm 插件采用**模块化 Actions 架构**,支持多种报警动作的灵 - `alarmContent`:若配置中未提供 `alarmContent`,默认使用 `rule_name`。 **external_api 参数说明:** + - 必填:`getTokenUrl`, `putMessageUrl`, `tenantCode`, `channelNo` - 常用可选:`timeout_ms`(默认 3000)、`include_media_url`(默认 true)、`token_cache_sec`(默认 600;为 0 时仅在 401/403 时刷新 token) - 其它可选:`token_header`、`token_json_path`、`alarmContent`、`max_queue_size` / `queue_policy`、`max_retries` / `retry_backoff_ms` **规则参数说明:** + - `class_ids`: 要监控的类别 ID 数组(与模型输出对应) - `objects`: 要监控的类别名称数组(需配合 `labels` 使用) - `roi`: 感兴趣区域,归一化坐标 (0-1) @@ -917,6 +930,7 @@ alarm 插件采用**模块化 Actions 架构**,支持多种报警动作的灵 - `schedule`: 有效时间段,格式 "HH:MM-HH:MM" **上传器类型:** + - `local`: 保存到本地文件系统 - `minio`: 上传到 MinIO 对象存储 - `s3`: 上传到 AWS S3(兼容 MinIO) @@ -926,6 +940,7 @@ alarm 插件采用**模块化 Actions 架构**,支持多种报警动作的灵 storage 插件用于**持续录像**(7x24 小时),与 alarm 的事件录像功能互补。 **配置示例:** + ```json { "id": "storage_cam1", @@ -943,6 +958,7 @@ storage 插件用于**持续录像**(7x24 小时),与 alarm 的事件录 ``` **参数说明:** + - `mode`: 录像模式,当前支持 `continuous`(持续录像) - `format`: 输出格式,`mp4` 或 `ts` - `segment_sec`: 单个文件时长(秒) diff --git a/PRD_01_Device_MediaServer_RemoteMgmt.md b/docs/design/PRD_01_Device_MediaServer_RemoteMgmt.md similarity index 99% rename from PRD_01_Device_MediaServer_RemoteMgmt.md rename to docs/design/PRD_01_Device_MediaServer_RemoteMgmt.md index 7d79418..98189d0 100644 --- a/PRD_01_Device_MediaServer_RemoteMgmt.md +++ b/docs/design/PRD_01_Device_MediaServer_RemoteMgmt.md @@ -1,6 +1,7 @@ # PRD ① 设备端(rk3588-agent + media-server)远程管理能力(V1) ## 1. 背景 + 当前 `media-server` 已提供 HTTP 控制台与配置热更新能力(`/api/*`、`/api/config/reload`、`/api/config/rollback` 等)。由于 **大文件模型上传** 在现有 C++ 自研 HTTP Server 上实现成本较高(需要流式接收/写盘/校验/限流),本期采用更工程化的拆分: - `media-server`:继续专注业务图(推理/推流/报警)与热更新。 @@ -9,18 +10,21 @@ > 本 PRD 覆盖“轻量热更新/重载/回滚(业务图级)”。systemd/重启系统等运维级操作可作为后续扩展,但不作为 V1 验收项。 ## 2. 目标 + 1. 管理端可通过 UDP 广播在 1 秒内发现同网段 10 台设备(由 `rk3588-agent` 响应)。 2. 管理端可通过 `rk3588-agent` 上传配置 JSON,设备端原子写入后触发 `media-server` reload 生效。 3. 管理端可通过 `rk3588-agent` 上传模型文件到设备固定目录,并返回可直接在配置中引用的 `model_path`。 4. 所有对外写操作必须鉴权(Token),读操作默认可不鉴权(可配置)。 ## 3. 非目标(V1 不做) + - systemd start/stop/restart `media-server`(可在 agent 后续扩展) - 设备重启/固件升级/插件升级 - 跨网段发现(保留后端可做网段扫描 fallback) - 完整 RBAC/用户体系 ## 4. 现状可复用能力(不修改语义) + - HTTP Server:`src/http_server.cpp` - Graph/热更新:`GraphManager::ReloadFromFile`、`GraphManager::RollbackFromLastGood` - 配置 Expand + Validate:`utils/config_expand.*`、`utils/config_schema.h` @@ -29,6 +33,7 @@ ## 5. 新增功能范围(V1) ### 5.1 新增进程:rk3588-agent(Go) + `rk3588-agent` 作为常驻服务,提供: - UDP 广播发现(Option A):对管理端 Search 做响应。 @@ -36,6 +41,7 @@ - 本地调用 `media-server`:通过 `http://127.0.0.1:/api/...` 触发 reload/rollback/读取 graphs/logs。 #### 5.1.1 agent 代码目录结构(建议,开发可直接照此建工程) + 建议以 Go module 形式独立工程(可放在同仓库 `agent/` 目录,也可独立仓库)。 ```text @@ -56,6 +62,7 @@ agent/ ``` ### 5.2 media-server 变更范围(V1) + V1 目标是将大文件上传从 `media-server` 移出,因此 **media-server 可不新增大文件上传接口**。仅要求: - 保持现有 `/api/config/reload`、`/api/config/rollback`、`/api/graphs`、`/api/logs/recent` 等接口可用。 @@ -64,6 +71,7 @@ V1 目标是将大文件上传从 `media-server` 移出,因此 **media-server ## 6. 配置与落盘约定 ### 6.1 新增 agent 配置项(建议) + agent 需要独立配置(例如 `/etc/rk3588-agent/config.json`)。建议: ```json @@ -87,6 +95,7 @@ agent 需要独立配置(例如 `/etc/rk3588-agent/config.json`)。建议: ``` 字段说明(V1 关键字段): + - `config_path`:agent 写入配置文件的目标路径(与 media-server `--config` 一致)。 - `device_id_path`:device_id 持久化文件路径(不存在则自动生成并写入)。 - `media_server_base_url`:agent 调用 media-server 的本机地址,建议固定 `127.0.0.1`。 @@ -94,6 +103,7 @@ agent 需要独立配置(例如 `/etc/rk3588-agent/config.json`)。建议: - `media_server_retry`:仅对“控制类请求”(reload/rollback)启用的重试策略。 ### 6.2 设备侧文件系统布局(部署约定) + 为保证权限与可维护性,约定如下路径: - 可执行文件: @@ -113,6 +123,7 @@ agent 需要独立配置(例如 `/etc/rk3588-agent/config.json`)。建议: ### 6.3 systemd service(部署字段,开发/运维可直接照抄) #### 6.3.1 rk3588-agent.service + 路径建议:`/etc/systemd/system/rk3588-agent.service` ```ini @@ -142,6 +153,7 @@ WantedBy=multi-user.target ``` #### 6.3.2 media-server.service(建议统一纳入部署约定) + 路径建议:`/etc/systemd/system/media-server.service` ```ini @@ -169,20 +181,24 @@ WantedBy=multi-user.target > V1 不要求 agent 控制 systemd,但要求两服务可开机自启。 ### 6.5 性能调参说明(新增) + - `RK3588_RKNN_CTX_POOL_SIZE`:同一模型的 RKNN context 池大小(默认 3)。 - `RK3588_RGA_MAX_INFLIGHT`:RGA 全局并发上限(默认 2)。 ### 6.4 模型目录结构 + - `${models_dir}/manifest.json` - `${models_dir}/files/__.`(`ext` 默认 `rknn`,白名单控制) ## 7. 约束与安全 + - agent 对外写接口必须 `X-RK-Token`。 - 上传限制:必须 `Content-Length`;大小不得超过 `max_upload_mb`。 - agent 写盘采用原子写(临时文件 + rename)。 - agent 与 `media-server` 的本地通信固定走 `127.0.0.1`(避免暴露内部控制面)。 ### 7.1 agent 内部调用 media-server 的 URL/超时/重试策略 + agent 只调用 media-server 的既有接口(对内 base URL = `media_server_base_url`): - Reload:`POST {base}/api/config/reload` @@ -192,27 +208,32 @@ agent 只调用 media-server 的既有接口(对内 base URL = `media_server_b - Logs:`GET {base}/api/logs/recent?limit=...` 超时策略(建议默认值): + - 读接口(graphs/logs):总超时 `1000ms`(不重试) - 控制接口(reload/rollback):总超时 `media_server_timeout_ms`(默认 `3000ms`),允许重试 重试策略(仅控制接口): + - `max_attempts = 3`(首次 + 2 次重试) - 触发条件:连接失败/超时/5xx(不对 4xx 重试) - backoff:`[200ms, 500ms]` 配置下发联动策略(`PUT /v1/config`): + 1) agent 原子写入 `config_path` 2) 调用 reload(按控制接口重试策略) 3) 若 reload 最终失败:调用 rollback(按控制接口重试策略) 4) 返回 500,错误消息包含 reload 与 rollback 的结果(便于定位) ### 7.2 启动顺序与可用性 + - 建议 systemd 启动顺序:两者都 After network-online。 - agent 对外可先起来;当 media-server 尚未启动时: - `/v1/graphs`、`/v1/logs/recent` 返回 500(error=connect refused/timeout) - `/v1/config` 返回 500(写盘可成功,但 reload 失败会触发 rollback;错误信息提示 media-server 不可用) ## 8. 验收标准(Acceptance Criteria) + 1. 同网段 10 台设备,管理端 Search(UDP broadcast)在 1 秒内都能发现;列表包含 `device_id/ip/agent_port/media_port/version/git_sha`。 2. agent `PUT /v1/config`: - 发送合法 config,设备写盘并触发 `media-server` reload 成功,graphs 状态正常。 @@ -221,6 +242,7 @@ agent 只调用 media-server 的既有接口(对内 base URL = `media_server_b 4. 无 token 调用写接口返回 401;错误返回 JSON:`{"error":"..."}`。 ## 9. 开发任务拆分(建议) + - [ ] 新增 `rk3588-agent`:HTTP 服务 + Token 鉴权 + 日志 - [ ] UDP discovery:协议解析/回复、device_id 获取与持久化、停止逻辑 - [ ] `GET /v1/info`:聚合 device/version/git_sha/ports/uptime diff --git a/PRD_02_Manager_Frontend_React.md b/docs/design/PRD_02_Manager_Frontend_React.md similarity index 98% rename from PRD_02_Manager_Frontend_React.md rename to docs/design/PRD_02_Manager_Frontend_React.md index 33e1b1e..4bf23d5 100644 --- a/PRD_02_Manager_Frontend_React.md +++ b/docs/design/PRD_02_Manager_Frontend_React.md @@ -1,16 +1,19 @@ # PRD ② 管理端前端(React Web UI)V1 ## 1. 产品形态 + - 用户在 PC 上启动 `managerd`(Go 后端),浏览器打开:`http://127.0.0.1:/`。 - 前端只与本机 `managerd` 通信(不直连设备),避免跨域与安全复杂度。 ## 2. 目标 + 1. 一键 Search 发现设备并展示在线状态。 2. 单设备:查看 graphs 状态、查看 logs、执行 reload/rollback。 3. 单设备:上传模型、下发配置并生效。 4. 多设备:批量下发配置(任务化显示进度与失败原因)。 ## 3. UI 风格(V1) + - 风格:极简运维控制台(表格 + 抽屉/弹窗 + 表单),信息密度优先。 - 主题:浅色默认;无需复杂动效。 - 组件库:Ant Design(推荐)。 @@ -21,6 +24,7 @@ - 失败:红色提示 + 可展开错误详情 ## 4. 技术选型与工程要求 + - React 18 + TypeScript + Vite - 路由:React Router - 请求与缓存:React Query(或 SWR) @@ -30,13 +34,16 @@ ## 5. 页面与交互 ### 5.1 设备列表页 `/devices` + **组件**:表格(可搜索/排序) **顶部操作**: + - `Search`(触发发现) - `Batch Apply Config`(进入批量配置向导/弹窗) **表格列**: + - Status(Online/Offline) - Device Name - IP:AgentPort(可在详情页展示 MediaPort) @@ -46,35 +53,43 @@ - Actions:Detail / Reload / Rollback **交互**: + - Search 点击后 1~2 秒 loading,完成后刷新列表。 - Reload/Rollback:弹确认框;提交后显示 toast;失败显示 error 文本。 ### 5.2 设备详情页 `/devices/:deviceId` + 使用 Tabs: 1) **Overview** + - 展示 `info`:device_id、device_name、hostname、ip、version、git_sha、uptime - 展示 graphs 概览(通过后端代理设备 agent 的 graphs 数据) -2) **Graphs** +1) **Graphs** + - Graph 列表(name/running/fps/alarm_total/publish_clients) - 点击某 graph 展开详情(nodes/edges),按后端数据渲染 -3) **Logs** +1) **Logs** + - 最近日志(默认 200 行) - 刷新按钮;(可选)自动刷新开关 -4) **Models** +1) **Models** + - 已上传模型列表(name/sha256/size/mtime/path) - 上传:选择文件 + 填 name(默认用文件名去扩展名) - 上传进度条;成功后自动刷新列表 -5) **Config** +1) **Config** + - JSON 编辑器(Monaco 或轻量 textarea + 格式化按钮) - `Apply` 按钮(调用后端创建任务或直接 apply) - 失败时展示 error,并提示可执行 rollback ### 5.3 模板/配置生成 `/templates` + **目标**:减少手写 JSON。 - 模板列表(后端提供 templates) @@ -84,12 +99,15 @@ - 点击 Apply:创建任务,跳转任务详情 ### 5.4 任务中心 `/tasks` + - 任务列表:类型、创建时间、状态(running/success/failed/partial) - 任务详情:每台设备结果(pending/running/success/failed + error) - 实时更新:SSE(EventSource)订阅 `/api/tasks/:id/events` ## 6. 前端对接 API(本机 managerd) + 前端只调用以下(具体字段见后端 PRD): + - `POST /api/discovery/search` - `GET /api/devices` - `GET /api/devices/:id` @@ -103,6 +121,7 @@ - `POST /api/tasks`、`GET /api/tasks/:id`、`GET /api/tasks/:id/events` ## 7. 验收标准 + 1. 可 Search 并展示设备列表,状态正确。 2. 设备详情可查看 graphs、logs,且 reload/rollback 可用。 3. 可上传模型并在 Models 列表看到。 diff --git a/PRD_03_Manager_Backend_Go.md b/docs/design/PRD_03_Manager_Backend_Go.md similarity index 99% rename from PRD_03_Manager_Backend_Go.md rename to docs/design/PRD_03_Manager_Backend_Go.md index 4abe207..2c296c3 100644 --- a/PRD_03_Manager_Backend_Go.md +++ b/docs/design/PRD_03_Manager_Backend_Go.md @@ -1,6 +1,7 @@ # PRD ③ 管理端后端(Go managerd)V1 ## 1. 目标与运行方式 + - 提供本机 HTTP API 给 React UI 使用。 - 负责 UDP 广播发现(Option A),维护设备缓存与在线状态。 - 通过设备端 `rk3588-agent` 完成配置/模型等运维操作,并可通过 agent 代理读取 graphs/logs。 @@ -9,6 +10,7 @@ 运行:单可执行 `managerd`,默认监听 `127.0.0.1:18080`(可配置)。 ## 2. 外部依赖与约束 + - Go 版本:>= 1.22(建议) - 标准库优先;Web 框架可选 `chi`/`gin`(建议 chi + net/http)。 - 不需要数据库(V1 用内存 + 可选本地 JSON 持久化)。 @@ -16,17 +18,20 @@ ## 3. 模块划分 ### 3.1 Discovery + - 向所有可用网卡的广播地址发送 UDP discover。 - 监听本地 UDP socket 收集 replies(时间窗默认 1200ms)。 - 去重规则:按 `device_id` 去重,以最新 reply 为准。 ### 3.2 Device Registry + - 内存缓存: - `device_id -> {ip, agent_port, media_port, device_name, version, git_sha, last_seen_ms, online}` - 定时刷新(可配置间隔):对 online 设备拉取 `GET /v1/graphs`(agent 代理),更新摘要。 - Offline 规则:超过 `offline_after_ms`(如 10000ms)未见到,则标记离线。 ### 3.3 Device Client + - 统一超时:connect 1s、overall 3s(可配置)。 - 统一错误包装:返回 `error_code + message + device_id`。 - Token: @@ -34,12 +39,14 @@ - 可预留 per-device token(P1) ### 3.4 Templates/Config Builder + - 模板库来源: - V1:managerd 内置(embed)或本地 `templates/` 目录读取 - 返回前端表单 schema:V1 允许手工维护(避免解析占位符带来的不确定性)。 - 生成 root config:基于模板与 params,产出 `{global,templates,instances}`。 ### 3.5 Task Runner + - 任务类型: - `config_apply`(对 N 台设备下发 config) - `reload` @@ -52,28 +59,39 @@ ## 4. managerd 对前端 API 规格(V1) ### 4.1 Discovery + #### `POST /api/discovery/search` + Request: + ```json { "timeout_ms": 1200 } ``` + Response: + ```json { "items": [ {"device_id":"...","ip":"...","agent_port":9100,"media_port":9000,"device_name":"...","version":"...","git_sha":"..."} ] } ``` ### 4.2 Devices + #### `GET /api/devices` + Response: + ```json { "items": [ {"device_id":"...","online":true,"last_seen_ms":0,"ip":"...","agent_port":9100,"media_port":9000,"device_name":"...","version":"...","git_sha":"...","graphs":[...]} ] } ``` #### `GET /api/devices/:id` + Response:包含 `info`、`graphs_summary`、`last_seen`。 ### 4.3 Device actions(代理调用) + 以下全部通过 agent: + - `POST /api/devices/:id/reload` → agent `POST /v1/media-server/reload` - `POST /api/devices/:id/rollback` → agent `POST /v1/media-server/rollback` - `GET /api/devices/:id/graphs` → agent `GET /v1/graphs` @@ -81,28 +99,39 @@ Response:包含 `info`、`graphs_summary`、`last_seen`。 - `GET /api/devices/:id/logs?limit=200` → agent `GET /v1/logs/recent?limit=200` ### 4.4 Config apply + #### `POST /api/devices/:id/config/apply` + Request: + ```json { "config": { } } ``` + Behavior:调用 agent `PUT /v1/config`。 ### 4.5 Model upload + #### `POST /api/devices/:id/models/upload` + Request:`multipart/form-data`,字段: + - `name`: string - `file`: binary Behavior:读取文件流,转发为 agent `PUT /v1/models/{name}`(raw body)。 ### 4.6 Templates + - `GET /api/templates` - `GET /api/templates/:name` ### 4.7 Tasks + #### `POST /api/tasks` + Request: + ```json { "type": "config_apply", @@ -110,25 +139,32 @@ Request: "payload": { "config": {} } } ``` + Response: + ```json { "task_id": "..." } ``` #### `GET /api/tasks/:id/events` (SSE) + Event `device_update` data: + ```json { "device_id":"...","status":"running|success|failed","progress":0.0,"error":"" } ``` ## 5. 错误处理规范(managerd → 前端) + - 成功:2xx + `{"ok":true}` 或正常业务 JSON - 失败:4xx/5xx + + ```json { "error": { "code": "...", "message": "...", "device_id": "...", "detail": "..." } } ``` 建议错误码: + - `DISCOVERY_FAILED` - `DEVICE_NOT_FOUND` - `DEVICE_OFFLINE` @@ -138,7 +174,9 @@ Event `device_update` data: - `VALIDATION_ERROR` ## 6. 配置文件(managerd)建议 + `managerd.json`: + ```json { "listen": "127.0.0.1:18080", @@ -151,6 +189,7 @@ Event `device_update` data: ``` ## 7. 验收标准 + 1. Search 可发现设备并更新 registry;离线判断正确。 2. 可通过 agent 读取 graphs/logs(`GET /v1/graphs`、`GET /v1/logs/recent`)。 3. 单设备 `config/apply`、`reload`、`rollback` 可用,错误可定位。 diff --git a/PRD_04_Manager_ConfigGUI_AgentAPI.md b/docs/design/PRD_04_Manager_ConfigGUI_AgentAPI.md similarity index 98% rename from PRD_04_Manager_ConfigGUI_AgentAPI.md rename to docs/design/PRD_04_Manager_ConfigGUI_AgentAPI.md index 562eb2f..6d3756f 100644 --- a/PRD_04_Manager_ConfigGUI_AgentAPI.md +++ b/docs/design/PRD_04_Manager_ConfigGUI_AgentAPI.md @@ -3,6 +3,7 @@ > 适用版本:V1(2026-01) > > 范围:**仅控制端 GUI/managerd 如何调用设备端 rk3588-agent**。 +> > - 本项目中已在 `agent + media-server` 实现本文档所需能力。 > - **不包含**配置程序(前端/后端)具体 UI 代码实现细节。 @@ -36,15 +37,18 @@ ## 3. 鉴权与错误处理 ### 3.1 鉴权 + - Header:`X-RK-Token: ` - 写接口(会写盘/改状态)必须鉴权。 - 读接口默认可不鉴权;若设备端配置 `agent.require_token_for_read=true`,则读接口也必须鉴权。 ### 3.2 统一错误返回 + - 成功:`2xx`,一般为 `{"ok":true,...}` 或业务 JSON - 失败:`4xx/5xx`,返回 `{"error":"..."}` 常见 HTTP: + - `401`:unauthorized - `400`:validation failed / invalid json - `404`:not found @@ -56,6 +60,7 @@ ## 4. GUI 页面与调用流程 ### 4.1 设备详情页(只读) + 1) 设备信息:`GET /v1/info` 2) 运行态通道摘要:`GET /v1/graphs` 3) 单通道详情(可选):`GET /v1/graphs/{name}` @@ -64,16 +69,20 @@ ### 4.2 通道配置页(核心:instances) #### 4.2.1 初始化 + 1) 获取 schema(渲染表单):`GET /v1/config/ui/schema` 2) 获取当前 state(回显):`GET /v1/config/ui/state` GUI 侧以 `instances[]` 为“通道列表”。 #### 4.2.2 校验/预览(dry-run) + 用户编辑完成后: + - `POST /v1/config/ui/plan` 返回: + - `generated_config`:生成出来的 root config(可用于预览/导出) - `diff`:added/removed/changed(实例级别) @@ -81,15 +90,18 @@ GUI 侧以 `instances[]` 为“通道列表”。 > 真正的构图/插件/模型加载等校验发生在 apply → media-server reload 阶段。 #### 4.2.3 应用配置 + - `POST /v1/config/ui/apply` 行为: + 1) agent 生成新的 root config(只包含 `global/queue/templates/instances`) 2) 写盘到 `agent.config_path` 3) 调用 media-server reload 4) reload 失败则自动 rollback 并返回 500 #### 4.2.4 回滚(手动) + - `POST /v1/media-server/rollback` > 回滚语义:回滚到“上一次成功的**源配置**”(保留 templates/instances,不会被 expanded 覆盖),便于 GUI 二次编辑。 @@ -97,6 +109,7 @@ GUI 侧以 `instances[]` 为“通道列表”。 ### 4.3 人脸库管理页 #### 4.3.1 上传人脸库 + - `PUT /v1/face-gallery` - Content-Type:`application/octet-stream` - Body:SQLite 文件二进制(`face_gallery.db`) @@ -104,9 +117,11 @@ GUI 侧以 `instances[]` 为“通道列表”。 保存位置:`/face_gallery.db` #### 4.3.2 立即生效(无需重启) + - `POST /v1/face-gallery/reload` 行为: + - agent 遍历所有 graphs,找到 `type==ai_face_recog` 的节点 - 对每个节点下发 runtime config patch:bump `gallery.reload_seq` - 节点收到后会重新加载 SQLite db @@ -118,49 +133,69 @@ GUI 侧以 `instances[]` 为“通道列表”。 > Base:`http://:`(默认 9100) ### 5.1 设备信息 + #### `GET /v1/info` + 用于设备列表/详情。 ### 5.2 运行态(只读代理) + #### `GET /v1/graphs` + #### `GET /v1/graphs/{name}` + #### `GET /v1/logs/recent?limit=200` ### 5.3 配置文件(root config) + #### `GET /v1/config` + 返回 `agent.config_path` 对应 JSON(用于导出/高级查看)。 #### `PUT /v1/config` + 上传完整 root config JSON(写盘 + reload;失败自动 rollback)。 ### 5.4 语义化配置(GUI 推荐使用) + #### `GET /v1/config/ui/schema` + 返回:可选模板列表 + 字段 schema(类型/默认/必填)。 #### `GET /v1/config/ui/state` + 返回:当前 config 映射到 GUI state(主要是 `instances[]`)+ 内置模板列表。 #### `POST /v1/config/ui/plan` + 输入 desired state(instances 列表),返回生成 config 与 diff。 #### `POST /v1/config/ui/apply` + 同 plan,但会写盘并 reload(失败自动 rollback)。 ### 5.5 模型管理(可选,但建议 GUI 支持) + #### `PUT /v1/models/{name}` + 上传模型(.rknn),返回可引用的 `path`。 #### `GET /v1/models` + 列出已上传模型(包含 `name/path/sha256/mtime_ms`)。 ### 5.6 人脸库 + #### `GET /v1/face-gallery` + 返回当前 db 文件信息(exists/size/mtime/path)。 #### `PUT /v1/face-gallery` + 上传 `face_gallery.db`。 #### `POST /v1/face-gallery/reload` + 让所有 `ai_face_recog` 节点热加载新 db。 --- @@ -198,6 +233,7 @@ GUI 侧以 `instances[]` 为“通道列表”。 ``` 说明: + - `global/queue` 可省略:agent 会沿用当前 config 中的值。 - `instances` 为全量期望状态:控制端应把当前列表 + 修改后的列表一起提交。 - 当前实现会生成新的 root config(只包含 `global/queue/templates/instances`),不会保留 `graphs`。 @@ -220,20 +256,25 @@ GUI 侧以 `instances[]` 为“通道列表”。 > 模板名来自 `GET /v1/config/ui/schema` 的 `templates[]`。 ### 7.1 `transcode_rtsp_hls` + - 必填:`url` - 常用:`fps,src_w,src_h,gop,bitrate_kbps,rtsp_port,hls_path` ### 7.2 `yolo_rtsp_hls` + - 必填:`url, model_path` ### 7.3 `yolo_alarm_minio` + - 必填:`url, model_path, minio_endpoint, minio_bucket, minio_ak, minio_sk` - 常用:`cooldown_ms`(默认 3000) ### 7.4 `face_det_rtsp_hls` + - 必填:`url, det_model_path` ### 7.5 `face_det_recog_rtsp_hls` + - 必填:`url, det_model_path, recog_model_path` - 默认:`gallery_path=./models/face_gallery.db`,`thr_accept=0.45`,`thr_margin=0.05` @@ -242,6 +283,7 @@ GUI 侧以 `instances[]` 为“通道列表”。 ## 8. 性能调优参数(可选,建议 GUI 以“高级设置”方式暴露) ### 8.1 `preprocess`(AI 分支减拷贝 / RGA 并发) + - `dst_packed`:bool,默认 `false`。 - 说明:当 `dst_format` 为 `rgb/bgr` 时,若开启则输出紧凑 packed(`stride = width * 3`),可避免下游(如 `ai_yolo`)对齐 stride 导致的逐行 memcpy。 - `rga_max_inflight`:int,默认 `0`(表示不在配置里覆盖全局值)。 @@ -249,12 +291,14 @@ GUI 侧以 `instances[]` 为“通道列表”。 - 备注:也可通过环境变量 `RK3588_RGA_MAX_INFLIGHT` 设置。 ### 8.2 `publish/storage`(一次编码,多处复用) + - `publish.attach_encoded_meta`:bool,默认 `true`(当 publish 有下游 output_queues 时)。 - 说明:将已编码视频包(含 codec extradata/pts/key)挂在 `frame.user_meta`,供下游复用(例如报警 clip、storage 复用码流)。 - `storage.reuse_encoded_meta`:bool,默认 `true`。 - 说明:若收到 `EncodedVideoFrameMeta`,storage 将直接 remux 写文件(避免再次 MPP 编码);若未收到则保持原逻辑(MPP 编码录制)。 ### 8.3 推理并发(环境变量,部署侧配置) + - `RK3588_RKNN_CTX_POOL_SIZE`:默认 `3`。 - 说明:同一模型创建的 RKNN context 数量(多路同模型推理可并发,避免被单 context 串行化)。 @@ -263,11 +307,13 @@ GUI 侧以 `instances[]` 为“通道列表”。 ## 9. 人脸库路径对齐建议(避免“上传了但识别不到”) 1) 默认推荐(最省事): + - media-server work_dir:`/opt/rk3588sys` - agent.models_dir:`/opt/rk3588sys/models` - ai_face_recog.gallery.path:`./models/face_gallery.db` -2) 若你们的 work_dir/models_dir 不是这种关系: +1) 若你们的 work_dir/models_dir 不是这种关系: + - 控制端在 instances params 里把 `gallery_path` 设置为**绝对路径**(例如 `/opt/rk3588sys/models/face_gallery.db`)。 --- diff --git a/PRD_05_Device_Tracker_Node.md b/docs/design/PRD_05_Device_Tracker_Node.md similarity index 99% rename from PRD_05_Device_Tracker_Node.md rename to docs/design/PRD_05_Device_Tracker_Node.md index d72c914..2974d44 100644 --- a/PRD_05_Device_Tracker_Node.md +++ b/docs/design/PRD_05_Device_Tracker_Node.md @@ -1,30 +1,37 @@ # PRD_05:Device 侧轻量级 Tracker 节点(可插拔) ## 1. 背景与问题 + 当前 Device 侧媒体服务采用“配置驱动 DAG(Graph)+ 插件节点(Node)+ SPSC 队列”的流水线架构:输入(RTSP/文件)→ 预处理 → AI 推理(检测/识别等)→ OSD/推流/告警。 在实际部署中常见三类痛点: + 1) **重复报警**:同一目标在画面连续出现时,规则可能在采样频率下重复触发。 2) **重复上传(MinIO/HTTP 等)**:报警动作触发后在短时间内重复上传同类素材。 3) **推理开销过高**:虽然已有 `infer_fps` 等限频,但在低推理频率下希望仍保持事件稳定性与可解释性。 现有代码中: + - `Frame::det`(`DetectionResult`)包含 `Detection{cls_id, score, bbox, track_id}`,其中 `track_id` 当前默认 `-1`(未做追踪)。 - `alarm` 侧已有 `rules.cooldown_ms`、`min_duration_ms` 与 `actions.*.min_interval_ms` 的时间窗限流,但属于“按规则/动作的时间窗”粒度。 ## 2. 目标(Goals) + 提供一个 **可选、可插拔** 的 `tracker` 插件节点,用于为检测结果补充稳定的 `track_id`,以支持: + 1) **按目标实例去重**(基于 `track_id`):同一目标在持续存在期间不重复触发/上传。 2) **稳定性/精准性优先,资源占用尽可能低**:不引入 ReID/特征网络,主要使用几何与置信度关联。 3) **按类别选择性追踪**:并非所有类别都追踪,可由配置指定哪些 `cls_id` 参与追踪。 4) **架构适配**:完全符合现有 Graph/Node 插件机制,插入与否由 `configs/*.json` 决定;不插入则不改变任何行为。 ## 3. 非目标(Non-Goals) + 1) 不做跨摄像头/跨 Graph 的关联(不做全局 ID)。 2) 不做基于外观特征(ReID)的强一致性追踪(如 DeepSORT+ReID)。 3) 不保证对极端遮挡/快速运动/密集重叠场景达到 SOTA 跟踪指标;本 PRD 目标是“工程可用+低资源”。 ## 4. 现有架构约束(必须遵守) + 1) Node 单输入、多输出:Graph 当前限制每个节点 **只能有一个 input queue**。 2) Node 的 `Process(FramePtr)` 由框架线程调用(`Graph::Start()` 中的 worker loop),Tracker 节点不应引入额外线程(除非明确需求)。 3) Tracker 节点不得破坏 `Frame` 上其他元信息(尤其是 `publish` 节点可能写入 `frame->user_meta` 用于 clip)。 @@ -32,6 +39,7 @@ ## 5. 功能设计 ### 5.1 节点定义 + - Node type:`tracker` - role:`filter` - 输入:`FramePtr`(读取 `frame->det`) @@ -39,43 +47,54 @@ - 当 `frame->det == nullptr` 或 `items` 为空:直接透传。 ### 5.2 追踪算法(推荐:ByteTrack-lite + IOU 关联) + 在不引入外观特征的前提下,为提高稳定性,采用“两段式关联”策略: **核心思想**: + 1) 将 det 按置信度分成高置信(`score >= high_th`)与低置信(`low_th <= score < high_th`)。 2) 优先用高置信 det 去匹配已有 tracks;未匹配的 tracks 再用低置信 det 做二次匹配(减少断轨)。 3) 匹配度量使用 IOU(可加入 gating:中心点距离/面积比等轻量约束)。 **匹配策略**: + - 为降低资源占用:默认使用 greedy matching(按 IOU 从高到低选择不冲突匹配),不强制使用匈牙利算法。 - 允许后续通过配置切换到 Hungarian(可选增强项),但不作为本 PRD 必需。 **Track 生命周期**: + - 创建:未匹配到现有 track 的高置信 det → 创建新 track。 - 更新:匹配成功 → 更新 bbox、last_seen、hit_streak。 - 丢失:超过 `max_age_ms`(或 `max_age_frames`)未匹配 → 删除。 **分类策略**: + - 默认按 `cls_id` 分组匹配(避免不同类别互相抢 track)。 - 可配置 `per_class=false` 以允许跨类别匹配(默认不建议)。 ### 5.3 按类别选择性追踪 + 支持以下配置(至少实现其一,推荐两者都实现): + - `track_classes`: `int[]`:白名单。非空时仅追踪这些 `cls_id`。 - `ignore_classes`: `int[]`:黑名单。用于排除某些 `cls_id`。 规则: + - 若 `track_classes` 非空,则优先按白名单过滤。 - 否则按 `ignore_classes` 排除。 - 未参与追踪的 det 必须保持 `track_id = -1`。 ### 5.4 按模型类型/推理类型启用(可选,但推荐) + `DetectionResult.model_name` 已存在,Tracker 支持: + - `allowed_models`: `string[]`:当非空时,仅对 `model_name` 在集合内的帧启用。 用途:同一 pipeline 可能挂多种推理节点(yolo/face_det/自定义模型),避免对不需要的输出做追踪。 ### 5.5 插入位置建议(不强制) + 1) 仅为“告警去重/上传去重”服务: - 推荐 `publish -> tracker -> alarm` - 原因:不影响推流;不破坏 `publish` 写入的 `frame->user_meta`(clip 仍可用)。 @@ -83,8 +102,11 @@ - 推荐 `ai_* -> tracker -> osd -> ...` ## 6. 配置(Config Schema) + ### 6.1 tracker 节点配置字段 + 节点 JSON 示例: + ```json { "id": "trk_cam1", @@ -113,6 +135,7 @@ ``` 字段说明: + - `mode`:`"off" | "bytetrack_lite"`(最少实现这两种) - `per_class`:默认 `true`。 - `track_classes`:白名单;默认空(表示全类别)。 @@ -125,7 +148,9 @@ - `max_tracks`:上限保护,避免极端场景内存增长。 ### 6.2 Graph 接入示例 + 在现有 graph 中插入(示例:`pub -> tracker -> alarm`): + ```json "nodes": [ {"id":"pub_cam1","type":"publish","role":"filter","enable":true, ...}, @@ -140,7 +165,9 @@ ``` ## 7. 对外接口与数据契约 + ### 7.1 输入输出契约 + - 输入:`frame->det` 必须由上游检测节点填充;Tracker 不负责生成 det。 - 输出: - `frame` 本体不变; @@ -148,12 +175,16 @@ - 不修改 `frame->user_meta`、不修改 `frame->data/planes`。 ### 7.2 与 alarm/http/minio 的配合 + - `plugins/alarm/actions/http_action.cpp` 已会输出 `track_id` 字段(现有实现),因此 Tracker 生效后 HTTP 报警可以自然携带 `track_id`。 - MinIO 上传去重当前依赖 `actions.*.min_interval_ms`;后续可扩展为 per-track 去重(见第 10 节增强建议)。 ## 8. 指标与可观测性 + ### 8.1 Custom Metrics + Tracker 节点建议实现 `GetCustomMetrics()` 输出: + - `tracks_active` - `tracks_created_total` - `tracks_removed_total` @@ -162,15 +193,19 @@ Tracker 节点建议实现 `GetCustomMetrics()` 输出: - `avg_process_time_ms` ### 8.2 Debug + - `debug.stats`:周期打印关键统计。 - 不输出过多 per-frame 日志,避免影响实时性。 ## 9. 性能与资源约束 + 目标(以单路为单位,具体需实测校准): + - `N_det <= 64` 时,每帧 Tracker 处理耗时应为毫秒级以下(通常 < 1ms,依平台不同)。 - 内存:track 状态结构固定上限 `max_tracks`,避免无界增长。 ## 10. 验收标准(Acceptance Criteria) + 1) **可插拔**:不配置 `tracker` 节点时,系统行为与当前版本一致。 2) **正确写入 track_id**:配置启用时,目标类别的 det `track_id` 在连续帧中稳定且可复用。 3) **按类别控制有效**:不在白名单/在黑名单的 `cls_id` 必须保持 `track_id=-1`。 @@ -178,6 +213,7 @@ Tracker 节点建议实现 `GetCustomMetrics()` 输出: 5) **资源可控**:`max_tracks` 生效;极端场景不会导致内存持续增长。 ## 11. 开发拆解(实现步骤) + 1) 新增插件目录与编译接入:`plugins/tracker/`,更新 `plugins/CMakeLists.txt` 注册编译。 2) 实现 `TrackerNode`: - `Init()` 解析配置。 @@ -187,6 +223,7 @@ Tracker 节点建议实现 `GetCustomMetrics()` 输出: 3) 增加一个示例配置(不强制提交到 README):可在现有 `configs/*` 中添加一份测试 json(若产品流程允许)。 ## 12. 增强建议(不属于本 PRD 必做,但推荐路线) + 1) **Alarm 去重升级为 per-track**:在 `alarm` 节点内部维护 `(rule_name, track_id)` 的冷却/状态机(enter/stay/leave)。 2) **自适应推理频率**:结合最近 N 秒的命中情况动态调整 `infer_fps`(需与现有热更新机制配合)。 3) **Hungarian 可选开关**:当 det 数量大且遮挡多时提升一致性,但要评估 CPU 成本。 diff --git a/PRD_06_Hardware_Decoupling_Plan.md b/docs/design/PRD_06_Hardware_Decoupling_Plan.md similarity index 99% rename from PRD_06_Hardware_Decoupling_Plan.md rename to docs/design/PRD_06_Hardware_Decoupling_Plan.md index 0264a15..e0d3274 100644 --- a/PRD_06_Hardware_Decoupling_Plan.md +++ b/docs/design/PRD_06_Hardware_Decoupling_Plan.md @@ -1,25 +1,31 @@ # PRD_06 多硬件解耦计划(RK3588/Atlas/Jetson) ## 1. 背景与目标 + 当前工程深度绑定 RK3588(RKNN/RGA/MPP/DMA-BUF),限制了 Atlas、Jetson 等平台的接入。目标是在**不破坏现有功能**的前提下,通过接口解耦与默认实现保留现有行为,实现多硬件可插拔支持。 ### 目标 + - 以接口层抽象 **推理、图像处理、编解码、缓冲区** 四个核心模块。 - 默认实现保持 RK3588 行为与性能路径(零拷贝/DMA-BUF)。 - 逐步迁移现有节点,避免一次性大改。 ### 非目标 + - 不改变业务逻辑(检测/识别流程、RTSP/HLS 业务)。 - 不在本阶段引入新 UI/协议或跨平台发布流程。 ## 2. 现状摘要(关键路径) + - 推理:`include/ai_scheduler.h`, `src/ai_scheduler.cpp`(RKNN + DMA-BUF 输入) - 图像处理:`plugins/preprocess/preprocess_node.cpp`(RGA 或 swscale) - 编解码:`plugins/input_rtsp/*`, `plugins/input_file/*`, `plugins/publish/*`(MPP + FFmpeg 混用) - 缓冲:`include/frame/frame.h`(dma_fd/planes/data_owner) ## 3. 总体方案 + 引入四类接口与默认实现: + - **IInferBackend**:推理后端抽象(默认 RKNN) - **IImageProcessor**:图像预处理抽象(默认 RGA + swscale 兜底) - **IDecoder / IEncoder**:编解码抽象(默认 MPP,必要时 FFmpeg) @@ -30,7 +36,9 @@ ## 4. 实施步骤、里程碑与单元测试 ### Step 1:建立基础抽象与工厂 + **实施内容** + - 新建 `include/hw/` 下接口定义:`i_infer_backend.h`, `i_image_processor.h`, `i_decoder.h`, `i_encoder.h`, `frame_buffer.h` - 定义最小能力集: - IInferBackend: `LoadModel`, `Infer`, `InferBorrowed` @@ -40,58 +48,72 @@ - 新建工厂:`hw_factory.h/cpp`,根据配置返回默认实现 **关键里程碑** + - 接口头文件编译通过;工程无行为变化 - 工厂默认返回 RK3588 实现(空实现也可先用占位) **单元测试(GTest)** + - `HwFactory_Defaults_ReturnsRk3588Impls` - `FrameBuffer_Metadata_Preserved`(dma_fd/planes 赋值一致性) --- ### Step 2:推理模块解耦(RKNN → IInferBackend) + **实施内容** + - 将 `AiScheduler` 包装为 `RknnInferBackend` 实现 - `ai_*` 节点依赖 `IInferBackend` 接口注入(保留默认行为) - 保留 `InferBorrowed` 以支持零拷贝输入 **关键里程碑** + - 现有模型推理链路无回归,性能基准一致(同配置) - RKNN 仍可多上下文并发 **单元测试(GTest)** + - `InferBackend_LoadModel_Smoke`(加载模型返回成功) - `InferBackend_BorrowedInput_UsesDmaFd`(检查传入 dma_fd 路径被调用) --- ### Step 3:图像预处理解耦(RGA/CPU → IImageProcessor) + **实施内容** + - 抽取 RGA 路径为 `RgaImageProcessor` - 抽取 swscale 路径为 `SwscaleImageProcessor` - `preprocess_node` 仅面向接口调用 **关键里程碑** + - `use_rga=true/false` 行为完全一致 - RGA 限流逻辑(RgaGate)保留 **单元测试(GTest)** + - `ImageProcessor_RgaVsSwscale_OutputShape`(输出尺寸一致) - `ImageProcessor_ColorConversion_Nv12ToRgb`(像素格式转换) --- ### Step 4:编解码解耦(MPP/FFmpeg → IDecoder/IEncoder) + **实施内容** + - `MppDecoder`, `FfmpegDecoder` 实现 `IDecoder` - `MppEncoder`, `FfmpegEncoder` 实现 `IEncoder` - `input_rtsp/input_file/publish/storage` 节点仅面向接口 **关键里程碑** + - RTSP 输入与 HLS 输出链路不变 - MPP 仍为默认路径,FFmpeg 作为兜底/平台适配 **单元测试(GTest)** + - `Decoder_Open_Close_Smoke` - `Encoder_Open_Close_Smoke` - `Codec_Pipeline_EncodeDecode_OneFrame`(小尺寸样例帧) @@ -99,47 +121,59 @@ --- ### Step 5:缓冲区抽象(Frame → FrameBuffer) + **实施内容** + - 新增 `FrameBuffer`,替代直接使用 `Frame` 的 dma_fd/data_owner - `Frame` 保留为业务结构,内部持有 `FrameBuffer` - 统一 DMA 同步接口以便多硬件适配 **关键里程碑** + - DMA-BUF 与内存缓冲区均可通过统一接口访问 - `Frame` 兼容旧字段,最小侵入替换完成 **单元测试(GTest)** + - `FrameBuffer_Sync_NoCrash` - `FrameBuffer_PlaneAccess_Consistent` --- ### Step 6:多硬件适配接入(Atlas/Jetson) + **实施内容** + - 新增 `AtlasInferBackend/AtlasImageProcessor/AtlasCodec` 实现(占位/实验性) - 新增 `JetsonInferBackend/JetsonImageProcessor/JetsonCodec` 实现 - 通过配置切换平台实现 **关键里程碑** + - 不影响 RK3588 默认路径 - 新平台可在单机完成 smoke 测试 **单元测试(GTest)** + - `HwFactory_SelectsBackend_ByConfig` - `PlatformImpls_Smoke_Construct`(构造/释放) ## 5. 风险与缓解 + - **接口过宽导致迁移成本增加** → 控制最小接口集,逐步扩展 - **性能回退** → 保留 RK3588 默认实现与 DMA-BUF 快路径 - **迁移破坏现有节点** → 节点逐个替换,保持旧路径可回退 ## 6. 验证与回滚 + ### 验证命令 + ``` scripts/build_host.sh ctest --test-dir build/host --output-on-failure ``` ### 回滚策略 + - 以编译开关/配置切换回旧路径 - 保留 RK3588 实现作为默认后端 diff --git a/docs/requirements/deploy_requirements.md b/docs/requirements/deploy_requirements.md new file mode 100644 index 0000000..5a83799 --- /dev/null +++ b/docs/requirements/deploy_requirements.md @@ -0,0 +1,2 @@ +# 部署环境需求 + diff --git a/命令.md b/docs/命令.md similarity index 94% rename from 命令.md rename to docs/命令.md index 54e26f2..2e3aa23 100644 --- a/命令.md +++ b/docs/命令.md @@ -1,5 +1,5 @@ - +# 开发和部署所需的命令 ffmpeg -f dshow -i video="1080P USB Camera" -c:v libx264 -preset ultrafast -pix_fmt yuv420p -f rtsp rtsp://localhost:8554/cam @@ -19,9 +19,6 @@ cmake --build build -j$(nproc) - - - //退出 pidof media-server @@ -29,19 +26,16 @@ ss -lntp | grep ':9000' - - http://10.0.0.81:9000/hls/cam1/index.m3u8 + rtsp://10.0.0.81:8555/live/cam1 - D:\minio\bin>minio.exe server D:\minio\data --address ":9000" --console-address ":9001" //生成人脸模型 python build_gallery.py --dataset "D:\App\python\AddFaceTo3588\faces\dataset" --db_out "D:\App\python\AddFaceTo3588\faces\face_gallery.db" --det_model "D:\App\python\AddFaceTo3588\models\RetinaFace_mobile320.onnx" --recog_model "D:\App\python\AddFaceTo3588\models\mobilefacenet_arcface_prenorm.onnx" --det_outputs_config "D:\App\python\AddFaceTo3588\models\retinaface_mobile320_config.json" --det_score_thresh 0.6 --max_imgs_per_person 10 --pick_face largest --min_face_size 80 --expected_dim 512 --fail_on_empty true - 编译 cd /d D:\App\C++\Rk3588Sys\agent @@ -101,13 +95,13 @@ ls -l ./rk3588-agent_linux_arm64 sudo systemctl daemon-reload sudo systemctl enable --now rk3588-agent - 4) 查看状态与日志 + 1) 查看状态与日志 sh sudo systemctl status rk3588-agent --no-pager sudo journalctl -u rk3588-agent -f - 5) 停止/重启 + 1) 停止/重启 sh sudo systemctl stop rk3588-agent @@ -116,10 +110,9 @@ ls -l ./rk3588-agent_linux_arm64 这样运行后,SSH 断开不会影响进程(由 systemd 托管)。如果你的 agent.config.json 里有相对路径(如 models 目录),记得写成绝对路径,或放到 /opt/rk3588-agent/ 并按配置调整。 +## 后端启动命令 - ## 后端启动命令 go run .\cmd\managerd\main.go .\managerd.json - ##查看npu占用 - sudo watch -n 1 cat /sys/kernel/debug/rknpu/load \ No newline at end of file + sudo watch -n 1 cat /sys/kernel/debug/rknpu/load diff --git a/scripts/systemd/Mannual.md b/scripts/systemd/Mannual.md new file mode 100644 index 0000000..f66a96d --- /dev/null +++ b/scripts/systemd/Mannual.md @@ -0,0 +1,284 @@ +# RK3588 Media Server Systemd 集成 + +本目录包含 RK3588 Media Server 和 Agent 的 systemd 服务配置和管理脚本。 + +## 概述 + +| 服务 | 描述 | 默认端口 | +|------|------|----------| +| `media-server` | C++ 媒体服务器(视频流处理) | 9000 (HTTP), 8554/8555 (RTSP) | +| `rk3588-agent` | Go 管理代理(HTTP API) | 9100 | + +## 快速开始 + +### 方法一:快速设置(推荐用于开发板) + +如果你已经在 Orange Pi 上编译好项目,直接运行: + +```bash +cd /path/to/OrangePi3588Media +sudo ./scripts/systemd/quick-setup.sh +``` + +此脚本会自动: + +1. 检查并编译项目(如需要) +2. 安装 systemd 服务 +3. 启动服务 +4. 显示访问地址 + +### 方法二:手动安装 + +```bash +cd /path/to/OrangePi3588Media + +# 安装服务 +sudo ./scripts/systemd/install-systemd.sh + +# 或指定自定义路径 +sudo ./scripts/systemd/install-systemd.sh \ + --media-bin ./build/media-server \ + --media-config ./configs/sample_cam1.json \ + --agent-bin ./agent/rk3588-agent_linux_arm64 \ + --agent-config ./agent/agent_cam1.config.json +``` + +### 方法三:手动步骤(了解细节) + +```bash +# 1. 复制服务文件 +sudo cp scripts/systemd/media-server.service /etc/systemd/system/ +sudo cp scripts/systemd/rk3588-agent.service /etc/systemd/system/ + +# 2. 创建安装目录并复制文件 +sudo mkdir -p /opt/rk3588-media-server/{bin,lib,etc,logs} +sudo cp build/media-server /opt/rk3588-media-server/bin/ +sudo cp configs/sample_cam1.json /opt/rk3588-media-server/etc/media-server.json + +sudo mkdir -p /opt/rk3588-agent +sudo cp agent/rk3588-agent_linux_arm64 /opt/rk3588-agent/rk3588-agent +sudo cp agent/agent_cam1.config.json /opt/rk3588-agent/agent.config.json + +# 3. 重载 systemd +sudo systemctl daemon-reload + +# 4. 启动并启用服务 +sudo systemctl enable --now media-server +sudo systemctl enable --now rk3588-agent +``` + +## 服务管理 + +### 查看状态 + +```bash +# 使用便捷脚本 +./scripts/systemd/status.sh + +# 或手动查看 +sudo systemctl status media-server +sudo systemctl status rk3588-agent + +# 查看 NPU 负载 +sudo watch -n 1 cat /sys/kernel/debug/rknpu/load +``` + +### 启动/停止/重启 + +```bash +# Media Server +sudo systemctl start media-server +sudo systemctl stop media-server +sudo systemctl restart media-server + +# Agent +sudo systemctl start rk3588-agent +sudo systemctl stop rk3588-agent +sudo systemctl restart rk3588-agent + +# 同时重启两者 +sudo systemctl restart media-server rk3588-agent +``` + +### 开机自启 + +```bash +# 启用开机自启 +sudo systemctl enable media-server +sudo systemctl enable rk3588-agent + +# 禁用开机自启 +sudo systemctl disable media-server +sudo systemctl disable rk3588-agent +``` + +### 查看日志 + +```bash +# 实时跟踪日志 +sudo journalctl -u media-server -f +sudo journalctl -u rk3588-agent -f + +# 查看最近 100 行 +sudo journalctl -u media-server -n 100 --no-pager + +# 查看今天的日志 +sudo journalctl -u media-server --since today + +# 按时间范围查看 +sudo journalctl -u media-server --since "2024-01-01 10:00:00" --until "2024-01-01 12:00:00" +``` + +## 配置文件 + +### Media Server + +位置: `/opt/rk3588-media-server/etc/media-server.json` + +```bash +# 编辑配置 +sudo nano /opt/rk3588-media-server/etc/media-server.json + +# 验证 JSON 格式 +python3 -m json.tool /opt/rk3588-media-server/etc/media-server.json + +# 重启生效 +sudo systemctl restart media-server +``` + +### Agent + +位置: `/opt/rk3588-agent/agent.config.json` + +```bash +sudo nano /opt/rk3588-agent/agent.config.json +sudo systemctl restart rk3588-agent +``` + +## 卸载 + +```bash +# 使用卸载脚本(保留配置备份) +sudo ./scripts/systemd/uninstall-systemd.sh + +# 或手动卸载 +sudo systemctl stop media-server rk3588-agent +sudo systemctl disable media-server rk3588-agent +sudo rm -f /etc/systemd/system/media-server.service +sudo rm -f /etc/systemd/system/rk3588-agent.service +sudo systemctl daemon-reload +# 然后手动删除 /opt/rk3588-media-server/ 和 /opt/rk3588-agent/ +``` + +## 故障排查 + +### 服务无法启动 + +```bash +# 1. 查看详细错误信息 +sudo journalctl -u media-server -n 50 --no-pager + +# 2. 检查配置文件 +sudo /opt/rk3588-media-server/bin/media-server --config /opt/rk3588-media-server/etc/media-server.json --version + +# 3. 检查端口占用 +sudo ss -tlnp | grep -E '(9000|8554|8555|9100)' + +# 4. 检查权限 +ls -la /opt/rk3588-media-server/bin/media-server +``` + +### 端口冲突 + +如果 9000/8554/8555 端口被占用,修改配置文件: + +```json +// media-server.json +{ + "http": { + "port": 9001 // 修改为其他端口 + }, + "rtsp": { + "port": 8556 // 修改为其他端口 + } +} +``` + +### NPU 相关问题 + +```bash +# 检查 NPU 驱动 +cat /sys/kernel/debug/rknpu/version + +# 检查 NPU 负载 +watch -n 1 cat /sys/kernel/debug/rknpu/load + +# 检查设备节点 +ls -la /dev/rknpu* +``` + +## 文件说明 + +``` +scripts/systemd/ +├── README.md # 本文件 +├── media-server.service # Media Server systemd 服务文件 +├── rk3588-agent.service # Agent systemd 服务文件 +├── install-systemd.sh # 安装脚本 +├── uninstall-systemd.sh # 卸载脚本 +├── status.sh # 状态查看脚本 +└── quick-setup.sh # 快速设置脚本(一键部署) +``` + +## 服务文件详解 + +### media-server.service + +```ini +[Unit] +Description=RK3588 Media Server +After=network-online.target + +[Service] +Type=simple +User=root +ExecStart=/opt/rk3588-media-server/bin/media-server --config /opt/rk3588-media-server/etc/media-server.json +Restart=on-failure +RestartSec=5 +LimitNOFILE=65535 + +[Install] +WantedBy=multi-user.target +``` + +关键配置: + +- `Restart=on-failure`: 崩溃后自动重启 +- `LimitNOFILE=65535`: 增加文件描述符限制(视频流需要) +- `After=network-online.target`: 确保网络就绪后启动 + +### rk3588-agent.service + +```ini +[Unit] +Description=RK3588 Agent +After=media-server.service # 可选:确保 media-server 先启动 + +[Service] +Type=simple +ExecStart=/opt/rk3588-agent/rk3588-agent --config /opt/rk3588-agent/agent.config.json +Restart=always +RestartSec=2 +``` + +## 注意事项 + +1. **首次启动**: 确保配置文件路径正确,特别是模型路径和摄像头配置 +2. **权限**: 服务以 root 运行,需要访问 `/dev/rknpu` 设备 +3. **依赖**: Agent 可选依赖 media-server,可根据需要调整 `After=` 和 `Requires=` +4. **日志**: 使用 `journalctl` 查看日志,日志大小由 systemd 管理 + +## 参考 + +- [命令.md](../../docs/命令.md) - 开发和部署命令参考 +- [API_Device_RemoteMgmt_InterfaceTable.md](../../API_Device_RemoteMgmt_InterfaceTable.md) - Agent API 文档 diff --git a/scripts/systemd/install-systemd.sh b/scripts/systemd/install-systemd.sh new file mode 100644 index 0000000..0d3377a --- /dev/null +++ b/scripts/systemd/install-systemd.sh @@ -0,0 +1,271 @@ +#!/bin/bash +# RK3588 Media Server & Agent Systemd 服务安装脚本 +# 适用于 Orange Pi 5 Plus (RK3588) + +set -e + +# 颜色定义 +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +BLUE='\033[0;34m' +NC='\033[0m' # No Color + +# 默认路径 +MEDIA_SERVER_BIN="${MEDIA_SERVER_BIN:-$(pwd)/build/media-server}" +AGENT_BIN="${AGENT_BIN:-$(pwd)/agent/rk3588-agent_linux_arm64}" +MEDIA_SERVER_CONFIG="${MEDIA_SERVER_CONFIG:-$(pwd)/configs/sample_cam1.json}" +AGENT_CONFIG="${AGENT_CONFIG:-$(pwd)/agent/agent_cam1.config.json}" + +INSTALL_DIR="/opt" +SERVICE_DIR="/etc/systemd/system" + +echo -e "${BLUE}╔════════════════════════════════════════════════════════════╗${NC}" +echo -e "${BLUE}║ RK3588 Media Server & Agent Systemd 安装 ║${NC}" +echo -e "${BLUE}╚════════════════════════════════════════════════════════════╝${NC}" +echo "" + +# 检查 root 权限 +if [ "$EUID" -ne 0 ]; then + echo -e "${RED}错误: 请使用 sudo 运行此脚本${NC}" + exit 1 +fi + +# 检查 systemd +if ! command -v systemctl &> /dev/null; then + echo -e "${RED}错误: 未找到 systemctl,此系统可能不支持 systemd${NC}" + exit 1 +fi + +# 函数:安装 media-server +install_media_server() { + echo -e "${YELLOW}[1/6] 安装 Media Server...${NC}" + + # 检查二进制文件 + if [ ! -f "$MEDIA_SERVER_BIN" ]; then + echo -e "${RED}错误: 未找到 media-server 二进制文件: $MEDIA_SERVER_BIN${NC}" + echo "请确认已编译,或设置 MEDIA_SERVER_BIN 环境变量" + return 1 + fi + + # 创建目录 + mkdir -p "$INSTALL_DIR/rk3588-media-server"/{bin,lib,etc,logs} + + # 复制二进制文件 + cp "$MEDIA_SERVER_BIN" "$INSTALL_DIR/rk3588-media-server/bin/" + chmod +x "$INSTALL_DIR/rk3588-media-server/bin/media-server" + + # 复制依赖库(如果有) + if [ -d "$(dirname $MEDIA_SERVER_BIN)/../lib" ]; then + cp -r "$(dirname $MEDIA_SERVER_BIN)/../lib"/* "$INSTALL_DIR/rk3588-media-server/lib/" 2>/dev/null || true + fi + + # 复制或创建配置文件 + if [ -f "$MEDIA_SERVER_CONFIG" ]; then + cp "$MEDIA_SERVER_CONFIG" "$INSTALL_DIR/rk3588-media-server/etc/media-server.json" + echo -e "${GREEN}✓${NC} 配置文件: $INSTALL_DIR/rk3588-media-server/etc/media-server.json" + else + echo -e "${YELLOW}⚠ 未找到配置文件,请手动创建: $INSTALL_DIR/rk3588-media-server/etc/media-server.json${NC}" + fi + + # 安装服务文件 + cp "$(dirname $0)/media-server.service" "$SERVICE_DIR/" + + echo -e "${GREEN}✓${NC} Media Server 安装完成" +} + +# 函数:安装 agent +install_agent() { + echo -e "${YELLOW}[2/6] 安装 RK3588 Agent...${NC}" + + # 检查二进制文件 + if [ ! -f "$AGENT_BIN" ]; then + # 尝试其他可能的名称 + if [ -f "$(dirname $AGENT_BIN)/rk3588-agent" ]; then + AGENT_BIN="$(dirname $AGENT_BIN)/rk3588-agent" + else + echo -e "${YELLOW}⚠ 未找到 Agent 二进制文件,跳过 Agent 安装${NC}" + return 0 + fi + fi + + # 创建目录 + mkdir -p "$INSTALL_DIR/rk3588-agent"/{logs,models} + + # 复制二进制文件 + cp "$AGENT_BIN" "$INSTALL_DIR/rk3588-agent/rk3588-agent" + chmod +x "$INSTALL_DIR/rk3588-agent/rk3588-agent" + + # 复制或创建配置文件 + if [ -f "$AGENT_CONFIG" ]; then + cp "$AGENT_CONFIG" "$INSTALL_DIR/rk3588-agent/agent.config.json" + echo -e "${GREEN}✓${NC} 配置文件: $INSTALL_DIR/rk3588-agent/agent.config.json" + else + echo -e "${YELLOW}⚠ 未找到 Agent 配置文件,请手动创建${NC}" + fi + + # 安装服务文件 + cp "$(dirname $0)/rk3588-agent.service" "$SERVICE_DIR/" + + echo -e "${GREEN}✓${NC} RK3588 Agent 安装完成" +} + +# 函数:重载 systemd +reload_systemd() { + echo -e "${YELLOW}[3/6] 重载 systemd...${NC}" + systemctl daemon-reload + echo -e "${GREEN}✓${NC} systemd 已重载" +} + +# 函数:启动服务 +start_services() { + echo -e "${YELLOW}[4/6] 启动服务...${NC}" + + # 启动 media-server + if [ -f "$SERVICE_DIR/media-server.service" ]; then + echo " 启动 media-server..." + systemctl enable media-server + systemctl start media-server + sleep 2 + if systemctl is-active --quiet media-server; then + echo -e "${GREEN}✓${NC} media-server 运行中" + else + echo -e "${RED}✗${NC} media-server 启动失败,请检查日志" + fi + fi + + # 启动 agent + if [ -f "$SERVICE_DIR/rk3588-agent.service" ] && [ -f "$INSTALL_DIR/rk3588-agent/rk3588-agent" ]; then + echo " 启动 rk3588-agent..." + systemctl enable rk3588-agent + systemctl start rk3588-agent + sleep 1 + if systemctl is-active --quiet rk3588-agent; then + echo -e "${GREEN}✓${NC} rk3588-agent 运行中" + else + echo -e "${RED}✗${NC} rk3588-agent 启动失败,请检查日志" + fi + fi +} + +# 函数:显示状态 +show_status() { + echo -e "${YELLOW}[5/6] 服务状态...${NC}" + echo "" + + if [ -f "$SERVICE_DIR/media-server.service" ]; then + echo -e "${BLUE}Media Server:${NC}" + systemctl status media-server --no-pager | head -5 + echo "" + fi + + if [ -f "$SERVICE_DIR/rk3588-agent.service" ]; then + echo -e "${BLUE}RK3588 Agent:${NC}" + systemctl status rk3588-agent --no-pager | head -5 + echo "" + fi +} + +# 函数:显示使用说明 +show_usage() { + echo -e "${YELLOW}[6/6] 使用说明${NC}" + echo "" + echo "┌─────────────────────────────────────────────────────────────┐" + echo "│ 管理命令 │" + echo "├─────────────────────────────────────────────────────────────┤" + echo "│ 查看状态 │" + echo "│ systemctl status media-server │" + echo "│ systemctl status rk3588-agent │" + echo "│ │" + echo "│ 启动/停止/重启 │" + echo "│ systemctl start media-server │" + echo "│ systemctl stop media-server │" + echo "│ systemctl restart media-server │" + echo "│ │" + echo "│ 开机自启 │" + echo "│ systemctl enable media-server # 启用 │" + echo "│ systemctl disable media-server # 禁用 │" + echo "│ │" + echo "│ 查看日志 │" + echo "│ journalctl -u media-server -f # 实时跟踪 │" + echo "│ journalctl -u media-server -n 100 # 最近100行 │" + echo "│ journalctl -u rk3588-agent -f │" + echo "│ │" + echo "│ 文件位置 │" + echo "│ 安装目录: /opt/rk3588-media-server/ │" + echo "│ 配置文件: /opt/rk3588-media-server/etc/media-server.json │" + echo "│ Agent目录: /opt/rk3588-agent/ │" + echo "│ Agent配置: /opt/rk3588-agent/agent.config.json │" + echo "└─────────────────────────────────────────────────────────────┘" +} + +# 主流程 +main() { + # 如果传入了参数,解析环境变量 + while [[ $# -gt 0 ]]; do + case $1 in + --media-bin) + MEDIA_SERVER_BIN="$2" + shift 2 + ;; + --agent-bin) + AGENT_BIN="$2" + shift 2 + ;; + --media-config) + MEDIA_SERVER_CONFIG="$2" + shift 2 + ;; + --agent-config) + AGENT_CONFIG="$2" + shift 2 + ;; + --help|-h) + echo "用法: $0 [选项]" + echo "" + echo "选项:" + echo " --media-bin <路径> Media Server 二进制文件路径" + echo " --agent-bin <路径> Agent 二进制文件路径" + echo " --media-config <路径> Media Server 配置文件路径" + echo " --agent-config <路径> Agent 配置文件路径" + echo "" + echo "环境变量:" + echo " MEDIA_SERVER_BIN Media Server 二进制文件路径" + echo " AGENT_BIN Agent 二进制文件路径" + echo " MEDIA_SERVER_CONFIG Media Server 配置文件路径" + echo " AGENT_CONFIG Agent 配置文件路径" + exit 0 + ;; + *) + echo "未知选项: $1" + exit 1 + ;; + esac + done + + echo "安装路径: $INSTALL_DIR" + echo "Media Server: $MEDIA_SERVER_BIN" + echo "Agent: $AGENT_BIN" + echo "" + + read -p "确认安装? (y/N): " -n 1 -r + echo + if [[ ! $REPLY =~ ^[Yy]$ ]]; then + echo "安装已取消" + exit 0 + fi + + install_media_server + install_agent + reload_systemd + start_services + show_status + show_usage + + echo "" + echo -e "${GREEN}╔════════════════════════════════════════════════════════════╗${NC}" + echo -e "${GREEN}║ 安装完成! ║${NC}" + echo -e "${GREEN}╚════════════════════════════════════════════════════════════╝${NC}" +} + +main "$@" diff --git a/scripts/systemd/media-server.service b/scripts/systemd/media-server.service new file mode 100644 index 0000000..a88eb5f --- /dev/null +++ b/scripts/systemd/media-server.service @@ -0,0 +1,40 @@ +[Unit] +Description=RK3588 Media Server +Documentation=https://github.com/your-org/OrangePi3588Media +After=network-online.target +Wants=network-online.target + +[Service] +Type=simple +User=root +Group=root +WorkingDirectory=/opt/rk3588-media-server +ExecStart=/opt/rk3588-media-server/bin/media-server --config /opt/rk3588-media-server/etc/media-server.json +ExecReload=/bin/kill -HUP $MAINPID +KillMode=mixed +KillSignal=SIGTERM +TimeoutStopSec=30 +Restart=on-failure +RestartSec=5 +StartLimitInterval=60s +StartLimitBurst=3 + +# 资源限制 +LimitNOFILE=65535 +LimitNPROC=4096 + +# 环境变量 +Environment="LD_LIBRARY_PATH=/opt/rk3588-media-server/lib:$LD_LIBRARY_PATH" + +# 日志输出 +StandardOutput=journal +StandardError=journal +SyslogIdentifier=media-server + +# 安全设置(根据实际需求调整) +# NoNewPrivileges=false +# ProtectSystem=false +# ProtectHome=false + +[Install] +WantedBy=multi-user.target diff --git a/scripts/systemd/quick-setup.sh b/scripts/systemd/quick-setup.sh new file mode 100644 index 0000000..473af6e --- /dev/null +++ b/scripts/systemd/quick-setup.sh @@ -0,0 +1,102 @@ +#!/bin/bash +# RK3588 Media Server 快速设置脚本 +# 适用于开发板直接编译部署 + +set -e + +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +NC='\033[0m' + +echo -e "${YELLOW}========== RK3588 Media Server 快速设置 ==========${NC}" +echo "" + +# 检测是否在 Orange Pi 上 +if [[ "$(uname -m)" != "aarch64" ]]; then + echo "警告: 当前不是 ARM64 架构,此脚本适用于 RK3588 开发板" + read -p "是否继续? (y/N): " -n 1 -r + echo + [[ ! $REPLY =~ ^[Yy]$ ]] && exit 1 +fi + +# 检查 sudo +if [ "$EUID" -ne 0 ]; then + echo "请使用 sudo 运行" + exit 1 +fi + +PROJECT_DIR="$(cd "$(dirname "$0")/../.." && pwd)" +BUILD_DIR="$PROJECT_DIR/build" + +echo "项目目录: $PROJECT_DIR" +echo "" + +# 步骤1: 检查编译 +echo "[1/4] 检查编译状态..." +if [ ! -f "$BUILD_DIR/media-server" ]; then + echo "未找到编译好的 media-server,开始编译..." + echo "" + echo "CMake 配置:" + cmake -S "$PROJECT_DIR" -B "$BUILD_DIR" \ + -DCMAKE_BUILD_TYPE=Release \ + -DBUILD_TESTS=OFF \ + -DBUILD_SAMPLES=ON \ + -DRK3588_ENABLE_FFMPEG=ON \ + -DRK3588_ENABLE_MPP=ON \ + -DRK3588_ENABLE_RGA=ON \ + -DRK3588_ENABLE_ZLMEDIAKIT=ON \ + -DRK3588_ENABLE_RKNN=ON \ + -DRK_ZLMK_API_LIB_PATH="$PROJECT_DIR/third_party/rknpu2/examples/3rdparty/zlmediakit/aarch64/libmk_api.so" \ + -DRK_ZLMEDIAKIT_INCLUDE_DIR="$PROJECT_DIR/third_party/rknpu2/examples/3rdparty/zlmediakit/include" + + echo "" + echo "开始编译(使用 $(nproc) 线程)..." + cmake --build "$BUILD_DIR" -j$(nproc) +else + echo -e "${GREEN}✓${NC} 已编译" +fi +echo "" + +# 步骤2: 安装 systemd 服务 +echo "[2/4] 安装 Systemd 服务..." +"$(dirname "$0")/install-systemd.sh" \ + --media-bin "$BUILD_DIR/media-server" \ + --media-config "$PROJECT_DIR/configs/sample_cam1.json" \ + --agent-bin "$PROJECT_DIR/agent/rk3588-agent_linux_arm64" \ + --agent-config "$PROJECT_DIR/agent/agent_cam1.config.json" + +echo "" + +# 步骤3: 检查端口 +echo "[3/4] 检查端口..." +for port in 9000 8554 8555 9100; do + if ss -tln | grep -q ":$port "; then + echo -e " ${GREEN}✓${NC} 端口 $port 监听正常" + else + echo " 端口 $port 未监听" + fi +done +echo "" + +# 步骤4: 测试 +echo "[4/4] 快速测试..." +sleep 2 +if systemctl is-active --quiet media-server; then + echo -e "${GREEN}Media Server 运行正常${NC}" + echo "" + echo "测试地址:" + IP=$(hostname -I | awk '{print $1}') + echo " HLS: http://$IP:9000/hls/cam1/index.m3u8" + echo " RTSP: rtsp://$IP:8555/live/cam1" +else + echo "Media Server 可能未正常启动,请检查日志:" + echo " journalctl -u media-server -n 20" +fi +echo "" + +echo -e "${GREEN}设置完成!${NC}" +echo "" +echo "常用命令:" +echo " 查看状态: $(dirname "$0")/status.sh" +echo " 查看日志: journalctl -u media-server -f" +echo " 重启服务: systemctl restart media-server" diff --git a/scripts/systemd/rk3588-agent.service b/scripts/systemd/rk3588-agent.service new file mode 100644 index 0000000..eaf7309 --- /dev/null +++ b/scripts/systemd/rk3588-agent.service @@ -0,0 +1,40 @@ +[Unit] +Description=RK3588 Agent (Management API) +Documentation=https://github.com/your-org/OrangePi3588Media +After=network-online.target media-server.service +Wants=network-online.target +# 如果 agent 依赖 media-server,取消下面这行的注释 +# Requires=media-server.service + +[Service] +Type=simple +User=root +Group=root +WorkingDirectory=/opt/rk3588-agent +ExecStart=/opt/rk3588-agent/rk3588-agent --config /opt/rk3588-agent/agent.config.json +ExecReload=/bin/kill -HUP $MAINPID +KillMode=mixed +KillSignal=SIGTERM +TimeoutStopSec=30 +Restart=always +RestartSec=2 +StartLimitInterval=60s +StartLimitBurst=5 + +# 资源限制 +LimitNOFILE=65535 +LimitNPROC=4096 + +# 日志输出 +StandardOutput=journal +StandardError=journal +SyslogIdentifier=rk3588-agent + +# 安全设置 +# NoNewPrivileges=true +# ProtectSystem=strict +# ProtectHome=true +# ReadWritePaths=/opt/rk3588-agent + +[Install] +WantedBy=multi-user.target diff --git a/scripts/systemd/status.sh b/scripts/systemd/status.sh new file mode 100644 index 0000000..4dc9652 --- /dev/null +++ b/scripts/systemd/status.sh @@ -0,0 +1,82 @@ +#!/bin/bash +# RK3588 Media Server & Agent 状态查看脚本 + +GREEN='\033[0;32m' +RED='\033[0;31m' +YELLOW='\033[1;33m' +BLUE='\033[0;34m' +NC='\033[0m' + +echo -e "${BLUE}========== RK3588 Media Server & Agent 状态 ==========${NC}" +echo "" + +# 显示系统信息 +echo -e "${YELLOW}[系统信息]${NC}" +echo " 时间: $(date '+%Y-%m-%d %H:%M:%S')" +echo " 运行时间: $(uptime -p 2>/dev/null || uptime)" +echo "" + +# NPU 负载 +echo -e "${YELLOW}[NPU 负载]${NC}" +if [ -f /sys/kernel/debug/rknpu/load ]; then + cat /sys/kernel/debug/rknpu/load | while read line; do + echo " $line" + done +else + echo " NPU 信息不可用" +fi +echo "" + +# Media Server 状态 +echo -e "${YELLOW}[Media Server]${NC}" +if systemctl is-active --quiet media-server 2>/dev/null; then + echo -e " 状态: ${GREEN}● 运行中${NC}" + PID=$(systemctl show --property=MainPID --value media-server) + echo " PID: $PID" + + # 资源使用 + if [ -n "$PID" ] && [ "$PID" != "0" ]; then + CPU_MEM=$(ps -p $PID -o %cpu,%mem --no-headers 2>/dev/null || echo "N/A") + echo " CPU/MEM: $CPU_MEM" + fi + + # 端口监听 + echo " 端口监听:" + ss -tlnp 2>/dev/null | grep -E "(9000|8554|8555)" | head -3 | while read line; do + echo " $line" + done +else + echo -e " 状态: ${RED}○ 停止${NC}" +fi +echo "" + +# Agent 状态 +echo -e "${YELLOW}[RK3588 Agent]${NC}" +if systemctl is-active --quiet rk3588-agent 2>/dev/null; then + echo -e " 状态: ${GREEN}● 运行中${NC}" + PID=$(systemctl show --property=MainPID --value rk3588-agent) + echo " PID: $PID" + + if [ -n "$PID" ] && [ "$PID" != "0" ]; then + CPU_MEM=$(ps -p $PID -o %cpu,%mem --no-headers 2>/dev/null || echo "N/A") + echo " CPU/MEM: $CPU_MEM" + fi +else + echo -e " 状态: ${RED}○ 停止${NC}" +fi +echo "" + +# 日志摘要 +echo -e "${YELLOW}[最近日志]${NC}" +echo "Media Server (最后3行):" +journalctl -u media-server --no-pager -n 3 2>/dev/null | tail -3 || echo " 无日志" +echo "" +echo "Agent (最后3行):" +journalctl -u rk3588-agent --no-pager -n 3 2>/dev/null | tail -3 || echo " 无日志" +echo "" + +# 操作提示 +echo -e "${YELLOW}[管理命令]${NC}" +echo " 重启服务: sudo systemctl restart media-server" +echo " 查看日志: sudo journalctl -u media-server -f" +echo " 查看NPU: sudo watch -n 1 cat /sys/kernel/debug/rknpu/load" diff --git a/scripts/systemd/uninstall-systemd.sh b/scripts/systemd/uninstall-systemd.sh new file mode 100644 index 0000000..02ef018 --- /dev/null +++ b/scripts/systemd/uninstall-systemd.sh @@ -0,0 +1,81 @@ +#!/bin/bash +# RK3588 Media Server & Agent Systemd 服务卸载脚本 + +set -e + +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +NC='\033[0m' + +echo -e "${YELLOW}========== RK3588 Media Server & Agent 卸载 ==========${NC}" +echo "" + +if [ "$EUID" -ne 0 ]; then + echo -e "${RED}错误: 请使用 sudo 运行${NC}" + exit 1 +fi + +# 确认 +read -p "确定要卸载并停止所有服务? 数据将保留。 (y/N): " -n 1 -r +echo +if [[ ! $REPLY =~ ^[Yy]$ ]]; then + echo "卸载已取消" + exit 0 +fi + +# 停止服务 +echo "[1/4] 停止服务..." +systemctl stop media-server 2>/dev/null || true +systemctl stop rk3588-agent 2>/dev/null || true +systemctl disable media-server 2>/dev/null || true +systemctl disable rk3588-agent 2>/dev/null || true +echo -e "${GREEN}✓${NC} 服务已停止并禁用" + +# 删除服务文件 +echo "[2/4] 删除服务文件..." +rm -f /etc/systemd/system/media-server.service +rm -f /etc/systemd/system/rk3588-agent.service +systemctl daemon-reload +echo -e "${GREEN}✓${NC} 服务文件已删除" + +# 备份配置 +echo "[3/4] 备份配置..." +BACKUP_DIR="/root/rk3588-backup-$(date +%Y%m%d%H%M%S)" +mkdir -p "$BACKUP_DIR" + +if [ -f "/opt/rk3588-media-server/etc/media-server.json" ]; then + cp "/opt/rk3588-media-server/etc/media-server.json" "$BACKUP_DIR/" + echo " 已备份 media-server 配置" +fi + +if [ -f "/opt/rk3588-agent/agent.config.json" ]; then + cp "/opt/rk3588-agent/agent.config.json" "$BACKUP_DIR/" + echo " 已备份 agent 配置" +fi + +echo -e "${GREEN}✓${NC} 配置已备份到: $BACKUP_DIR" + +# 提示删除文件 +echo "[4/4] 清理文件..." +echo "" +echo "以下目录需要手动删除(如需完全清理):" +echo " /opt/rk3588-media-server/" +echo " /opt/rk3588-agent/" +echo "" + +read -p "是否删除这些目录? (y/N): " -n 1 -r +echo +if [[ $REPLY =~ ^[Yy]$ ]]; then + rm -rf /opt/rk3588-media-server/ + rm -rf /opt/rk3588-agent/ + echo -e "${GREEN}✓${NC} 目录已删除" +else + echo "保留目录,如需删除请手动执行:" + echo " sudo rm -rf /opt/rk3588-media-server/" + echo " sudo rm -rf /opt/rk3588-agent/" +fi + +echo "" +echo -e "${GREEN}卸载完成${NC}" +echo "备份位置: $BACKUP_DIR"