From ea6f095b76be0bbf3dec2aca0c54569cb50dc1b1 Mon Sep 17 00:00:00 2001 From: Developer Date: Fri, 27 Feb 2026 10:37:42 +0800 Subject: [PATCH] =?UTF-8?q?=E5=AE=8C=E5=96=84=E9=83=A8=E7=BD=B2=E8=84=9A?= =?UTF-8?q?=E6=9C=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...ress_5ch_cam4_template.json.last_good.json | 1 - docs/deployment.md | 113 ++++++--- ...eline.md => stress_test_5ch_face_recog.md} | 217 ++++++++++-------- docs/命令.md | 3 + scripts/build.sh | 208 +++++++++++++++++ scripts/deploy.sh | 47 ++-- 6 files changed, 447 insertions(+), 142 deletions(-) delete mode 100644 configs/stress_5ch_cam4_template.json.last_good.json rename docs/{stress_test_4ch_full_pipeline.md => stress_test_5ch_face_recog.md} (65%) create mode 100755 scripts/build.sh diff --git a/configs/stress_5ch_cam4_template.json.last_good.json b/configs/stress_5ch_cam4_template.json.last_good.json deleted file mode 100644 index 9115ba5..0000000 --- a/configs/stress_5ch_cam4_template.json.last_good.json +++ /dev/null @@ -1 +0,0 @@ -{"global":{"metrics_port":9000,"web_root":"web"},"instances":[{"name":"cam1","params":{"bitrate_kbps":2000,"fps":30,"gop":60,"minio_ak":"minioadmin","minio_bucket":"myminio","minio_endpoint":"http://10.0.0.49:9000","minio_sk":"minioadmin","model_path":"./models/best-640.rknn","name":"cam1","src_h":720,"src_w":1280,"url":"rtsp://10.0.0.49:8554/cam"},"template":"strict_minio_alarm_pipeline"},{"name":"cam2","params":{"bitrate_kbps":2000,"fps":30,"gop":60,"minio_ak":"minioadmin","minio_bucket":"myminio","minio_endpoint":"http://10.0.0.49:9000","minio_sk":"minioadmin","model_path":"./models/best-640.rknn","name":"cam2","src_h":720,"src_w":1280,"url":"rtsp://10.0.0.49:8554/cam"},"template":"strict_minio_alarm_pipeline"},{"name":"cam3","params":{"bitrate_kbps":2000,"fps":30,"gop":60,"minio_ak":"minioadmin","minio_bucket":"myminio","minio_endpoint":"http://10.0.0.49:9000","minio_sk":"minioadmin","model_path":"./models/best-640.rknn","name":"cam3","src_h":720,"src_w":1280,"url":"rtsp://10.0.0.49:8554/cam"},"template":"strict_minio_alarm_pipeline"},{"name":"cam4","params":{"bitrate_kbps":2000,"fps":30,"gop":60,"minio_ak":"minioadmin","minio_bucket":"myminio","minio_endpoint":"http://10.0.0.49:9000","minio_sk":"minioadmin","model_path":"./models/best-640.rknn","name":"cam4","src_h":720,"src_w":1280,"url":"rtsp://10.0.0.49:8554/cam"},"template":"strict_minio_alarm_pipeline"},{"name":"cam5","params":{"bitrate_kbps":2000,"fps":30,"gop":60,"minio_ak":"minioadmin","minio_bucket":"myminio","minio_endpoint":"http://10.0.0.49:9000","minio_sk":"minioadmin","model_path":"./models/best-640.rknn","name":"cam5","src_h":720,"src_w":1280,"url":"rtsp://10.0.0.49:8554/cam"},"template":"strict_minio_alarm_pipeline"}],"queue":{"size":4,"strategy":"drop_oldest"},"templates":{"strict_minio_alarm_pipeline":{"edges":[["in","pre"],["pre","ai"],["ai","trk"],["trk","osd"],["osd","post"],["post","pub"],["pub","alarm"]],"nodes":[{"enable":true,"force_tcp":true,"fps":"${fps}","height":"${src_h}","id":"in","reconnect_backoff_max_sec":30,"reconnect_sec":5,"role":"source","type":"input_rtsp","url":"${url}","use_ffmpeg":false,"use_mpp":true,"width":"${src_w}"},{"dst_format":"rgb","dst_h":640,"dst_packed":true,"dst_w":640,"enable":true,"id":"pre","keep_ratio":false,"rga_gate":"${name}","role":"filter","type":"preprocess","use_rga":true},{"class_filter":[],"conf":0.35,"enable":true,"id":"ai","infer_fps":10,"model_path":"./models/best-640.rknn","model_version":"v8","nms":0.45,"num_classes":3,"role":"filter","type":"ai_yolo"},{"allowed_models":["yolov5","yolov8"],"debug":{"stats":false,"stats_interval":200},"enable":true,"high_th":0.5,"id":"trk","ignore_classes":[],"iou_th":0.3,"low_th":0.1,"max_age_ms":1500,"max_tracks":128,"min_hits":2,"mode":"bytetrack_lite","per_class":true,"role":"filter","state_key":"${name}","track_classes":[0,1,2],"type":"tracker"},{"draw_bbox":true,"draw_face_bbox":false,"draw_face_det":false,"draw_text":true,"enable":true,"font_scale":1,"id":"osd","labels":[],"line_width":2,"role":"filter","type":"osd","use_rga_bbox":false},{"dst_format":"nv12","dst_h":"${src_h}","dst_w":"${src_w}","enable":true,"id":"post","keep_ratio":false,"queue":{"policy":"drop_oldest","size":2},"rga_gate":"${name}","role":"filter","type":"preprocess","use_rga":true},{"actions":{"clip":{"enable":true,"format":"mp4","fps":"${fps}","min_interval_ms":15000,"post_sec":10,"pre_sec":5,"upload":{"access_key":"${minio_ak}","bucket":"${minio_bucket}","endpoint":"${minio_endpoint}","region":"us-east-1","secret_key":"${minio_sk}","type":"minio"}},"external_api":{"channelNo":"${name}","enable":true,"getTokenUrl":"http://10.0.0.49:8080/api/getToken","include_media_url":true,"putMessageUrl":"http://10.0.0.49:8080/api/putMessage","tenantCode":"32","timeout_ms":3000,"token_cache_sec":1200,"token_header":"X-Access-Token","token_json_path":"responseBody.token"},"http":{"enable":false,"include_media_url":true,"method":"POST","timeout_ms":3000,"url":"http://127.0.0.1:8080/api/alarm"},"log":{"enable":true,"level":"info"},"snapshot":{"enable":true,"format":"jpg","min_interval_ms":15000,"quality":85,"upload":{"access_key":"${minio_ak}","bucket":"${minio_bucket}","endpoint":"${minio_endpoint}","region":"us-east-1","secret_key":"${minio_sk}","type":"minio"}}},"enable":true,"eval_fps":10,"id":"alarm","labels":[],"role":"sink","rules":[{"class_ids":[0,1,2],"cooldown_ms":5000,"hit_window_ms":1500,"min_box_area_ratio":0.02,"min_duration_ms":1500,"min_hits":3,"min_score":0.4,"name":"object_in_view","per_track_cooldown_ms":5000,"require_track_id":true,"roi":{"h":1,"w":1,"x":0,"y":0}}],"type":"alarm"},{"bitrate_kbps":"${bitrate_kbps}","codec":"h264","debug":{"stats":true,"stats_interval":100},"enable":true,"fps":"${fps}","gop":"${gop}","id":"pub","outputs":[{"path":"/live/${name}","port":8555,"proto":"rtsp_server"},{"path":"./web/hls/${name}/index.m3u8","proto":"hls","segment_sec":2}],"queue":{"policy":"drop_oldest","size":2},"role":"filter","type":"publish","use_ffmpeg_mux":true,"use_mpp":true}]}}} \ No newline at end of file diff --git a/docs/deployment.md b/docs/deployment.md index 1949553..9caa944 100644 --- a/docs/deployment.md +++ b/docs/deployment.md @@ -19,10 +19,10 @@ │ ┌───────────────────────────────────────────────────┐ │ │ │ 运行时数据目录 │ │ │ │ /var/lib/rk3588-media-server/ │ │ -│ │ ├── hls/ - HLS分片输出 │ │ -│ │ ├── logs/ - 应用日志 │ │ -│ │ ├── alarms/ - 告警截图 │ │ -│ │ └── clips/ - 告警视频片段 │ │ +│ │ ├── hls/ - HLS分片输出 (root) │ │ +│ │ ├── logs/ - 应用日志 (orangepi) │ │ +│ │ ├── alarms/ - 告警截图 (orangepi) │ │ +│ │ └── clips/ - 告警视频片段 (orangepi) │ │ │ └───────────────────────────────────────────────────┘ │ │ │ │ /opt/rk3588-media-server/ # 程序文件 │ @@ -49,16 +49,61 @@ ```bash cd ~/apps/OrangePi3588Media -# 编译 Media Server -mkdir -p build && cd build -cmake .. -DCMAKE_BUILD_TYPE=Release -make -j$(nproc) +# 一键编译(推荐) +./scripts/build.sh -# 编译 Agent(可选) -cd ../agent -go build -o rk3588-agent_linux_arm64 ./cmd/rk3588-agent +# 或使用完整 cmake 命令 +cmake -S . -B build \ + -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=$PWD/third_party/rknpu2/examples/3rdparty/zlmediakit/aarch64/libmk_api.so \ + -DRK_ZLMEDIAKIT_INCLUDE_DIR=$PWD/third_party/rknpu2/examples/3rdparty/zlmediakit/include + +cmake --build build -j$(nproc) + +# 仅编译 Media Server +./scripts/build.sh -m + +# 仅编译 Agent +./scripts/build.sh -a + +# Debug 模式编译 +./scripts/build.sh -d + +# 清理后重新编译 +./scripts/build.sh -c ``` +**编译脚本选项:** + +| 选项 | 说明 | +|------|------| +| `-h, --help` | 显示帮助 | +| `-c, --clean` | 清理构建目录后编译 | +| `-j N` | 指定并行编译线程数 | +| `-m, --media-only` | 仅编译 Media Server | +| `-a, --agent-only` | 仅编译 Agent | +| `-d, --debug` | Debug 模式编译 | + +**环境变量:** + +| 变量 | 默认值 | 说明 | +|------|--------|------| +| `BUILD_TYPE` | Release | 编译类型 | +| `BUILD_TESTS` | OFF | 是否编译测试 | +| `BUILD_SAMPLES` | ON | 是否编译示例 | +| `ENABLE_FFMPEG` | ON | 启用 FFmpeg | +| `ENABLE_MPP` | ON | 启用 MPP | +| `ENABLE_RGA` | ON | 启用 RGA | +| `ENABLE_ZLMEDIAKIT` | ON | 启用 ZLMediaKit | +| `ENABLE_RKNN` | ON | 启用 RKNN | + ### 2. 部署 ```bash @@ -110,9 +155,13 @@ sudo systemctl restart media-server # 查看状态 sudo systemctl status media-server -# 查看日志 +# 查看日志 (systemd) sudo journalctl -u media-server -f sudo journalctl -u media-server --since "1 hour ago" + +# 直接查看日志文件 (无需 sudo) +ls -la /var/lib/rk3588-media-server/logs/ +cat /var/lib/rk3588-media-server/logs/media-server.log ``` ### Agent 服务管理 @@ -126,8 +175,11 @@ sudo systemctl restart rk3588-agent # 查看状态 sudo systemctl status rk3588-agent -# 查看日志 +# 查看日志 (systemd) sudo journalctl -u rk3588-agent -f + +# Agent 日志文件位置 +cat /var/lib/rk3588-agent/agent.log ``` --- @@ -169,21 +221,26 @@ sudo journalctl -u rk3588-agent -f ``` /var/lib/rk3588-media-server/ -├── hls/ # HLS直播分片 +├── hls/ # HLS直播分片 (root:root, 755) │ ├── cam1/ │ │ ├── index.m3u8 │ │ ├── index0.ts │ │ └── ... │ ├── cam2/ │ └── ... -├── logs/ # 应用日志 -├── alarms/ # 告警截图 -└── clips/ # 告警视频片段 +├── logs/ # 应用日志 (orangepi:orangepi, 755) +├── alarms/ # 告警截图 (orangepi:orangepi, 755) +└── clips/ # 告警视频片段 (orangepi:orangepi, 755) /var/lib/rk3588-agent/ -└── device_id # 设备唯一标识 +└── device_id # 设备唯一标识 (orangepi:orangepi) ``` +**权限说明:** +- `logs/`, `alarms/`, `clips/` 目录归属于 `orangepi:orangepi`,方便默认用户查看和管理 +- `hls/` 目录归属于 `root:root`,但权限 755 允许 orangepi 组读取 +- Agent 相关目录归属于 `orangepi:orangepi` + --- ## 配置修改 @@ -217,6 +274,7 @@ HLS 分片自动清理策略: - **保留周期**: 7天 - **压缩**: 启用 - **位置**: `/var/lib/rk3588-media-server/logs/` +- **文件归属**: `orangepi:orangepi`(方便默认用户查看) ### 告警数据清理 @@ -227,7 +285,11 @@ HLS 分片自动清理策略: 查看当前存储使用: ```bash +# 使用部署脚本查看(推荐) sudo ./scripts/deploy.sh status + +# 或直接查看目录大小 +du -sh /var/lib/rk3588-media-server/*/ ``` --- @@ -242,16 +304,10 @@ cd ~/apps/OrangePi3588Media # 1. 拉取最新代码 git pull -# 2. 重新编译 -mkdir -p build && cd build -cmake .. -DCMAKE_BUILD_TYPE=Release -make -j$(nproc) - -cd ../agent -go build -o rk3588-agent_linux_arm64 ./cmd/rk3588-agent +# 2. 重新编译(清理后编译确保干净) +./scripts/build.sh -c # 3. 执行升级 -cd .. sudo ./scripts/deploy.sh upgrade ``` @@ -297,6 +353,11 @@ sudo cat /opt/rk3588-media-server/etc/media-server.json | python3 -m json.tool # 检查目录权限 ls -la /var/lib/rk3588-media-server/ ls -la /opt/rk3588-media-server/ + +# 修复日志目录权限(如需要) +sudo chown orangepi:orangepi /var/lib/rk3588-media-server/logs +sudo chown orangepi:orangepi /var/lib/rk3588-media-server/alarms +sudo chown orangepi:orangepi /var/lib/rk3588-media-server/clips ``` ### NPU 问题 diff --git a/docs/stress_test_4ch_full_pipeline.md b/docs/stress_test_5ch_face_recog.md similarity index 65% rename from docs/stress_test_4ch_full_pipeline.md rename to docs/stress_test_5ch_face_recog.md index c4b73ba..5010ace 100644 --- a/docs/stress_test_4ch_full_pipeline.md +++ b/docs/stress_test_5ch_face_recog.md @@ -1,8 +1,8 @@ -# RK3588 4路全流程压力测试方案 +# RK3588 5路人脸识别全流程压力测试方案 -本文档描述在单台 RK3588 设备上进行 4 路全流程视频处理的压力测试方案。 +本文档描述在单台 RK3588 设备上进行 5 路人脸识别全流程视频处理的压力测试方案。 -**方案说明:** 本方案使用单一 RTSP 视频源 (`rtsp://10.0.0.49:8554/test`),4 条流水线独立处理同一路输入,模拟 4 路摄像头并发场景。配置与 `sample_cam2.json` 完全一致。 +**方案说明:** 本方案使用单一 RTSP 视频源 (`rtsp://10.0.0.49:8554/cam`),5 条流水线独立处理同一路输入,模拟 5 路摄像头并发场景。 --- @@ -12,53 +12,51 @@ | 指标项 | 目标值 | 说明 | |--------|--------|------| -| **并发路数** | 4 路 | 单设备同时处理 4 路视频 | +| **并发路数** | 5 路 | 单设备同时处理 5 路视频 | | **输入分辨率** | 1280×720 @ 30fps | 每路输入为 720p 实时视频 | | **端到端延迟** | ≤ 500ms | 从采集到输出的完整延迟 | | **NPU 利用率** | ≥ 70% | NPU 高效利用,但不超载 | -| **CPU 占用** | ≤ 50% | 预留系统余量 | -| **内存占用** | ≤ 2.5GB | 避免内存压力 | +| **CPU 占用** | ≤ 60% | 预留系统余量 | +| **内存占用** | ≤ 3GB | 避免内存压力 | | **运行稳定性** | 24 小时无崩溃 | 长稳测试 | ### 1.2 全流程覆盖 -测试需覆盖所有节点类型(与 `sample_cam2.json` 一致的拓扑): +测试需覆盖所有节点类型: ``` [共享输入源] │ - ┌────────────────┼────────────────┐ - │ │ │ - [Pipeline 1] [Pipeline 2] [Pipeline 3] [Pipeline 4] + ┌────────────────┼────────────────┬────────────────┐ │ │ │ │ - input_rtsp input_rtsp input_rtsp input_rtsp - │ │ │ │ - preprocess preprocess preprocess preprocess - │ │ │ │ - ai_yolo ──→ tracker ─┤ ai_yolo ──→ tracker (目标检测+跟踪) - │ │ │ │ - ai_face_det ──→ ai_face_recog (人脸识别) - │ │ │ │ - └──────────→ osd ←─────────────────────────────┘ + [Pipeline 1] [Pipeline 2] [Pipeline 3] [Pipeline 4] [Pipeline 5] + │ │ │ │ │ + input_rtsp input_rtsp input_rtsp input_rtsp input_rtsp + │ │ │ │ │ + preprocess preprocess preprocess preprocess preprocess + │ │ │ │ │ + ai_yolo ──→ tracker ─┤ ai_yolo ──→ tracker (目标检测+跟踪) + │ │ │ │ │ + face_det ──→ face_recog (人脸检测+识别) + │ │ │ │ │ + └──────────→ osd ←─────────────────────────────────────────────┘ │ preprocess (后处理) │ publish (RTSP/HLS 输出) │ - ┌──────────┴──────────┐ - │ │ - alarm (目标) alarm_face (人脸) + alarm (目标报警) ``` -**节点类型统计(每路,与 sample_cam2.json 一致):** +**节点类型统计(每路):** - **Source (1)**:`input_rtsp` - **Filter (7)**:`preprocess`×2, `ai_yolo`, `ai_face_det`, `ai_face_recog`, `tracker`, `osd` -- **Sink (3)**:`alarm`×2, `publish` +- **Sink (2)**:`alarm`, `publish` -**4路总计:** -- 4 个 input_rtsp 节点(连接同一 RTSP 源) -- 28 个 Filter 节点 -- 12 个 Sink 节点 +**5路总计:** +- 5 个 input_rtsp 节点(连接同一 RTSP 源) +- 35 个 Filter 节点 +- 10 个 Sink 节点 --- @@ -72,7 +70,7 @@ | **NPU** | 6 TOPS@INT8 | 用于 AI 推理 | | **内存** | ≥ 8GB LPDDR4/LPDDR5 | 建议 8GB 或以上 | | **存储** | ≥ 32GB eMMC/SSD | 用于 HLS 切片存储 | -| **网络** | 千兆以太网 | 单路 4-8Mbps 输入,4路约 16-32Mbps | +| **网络** | 千兆以太网 | 单路 4-8Mbps 输入,5路约 20-40Mbps | | **散热** | 主动散热 | 长时间高负载运行 | ### 2.2 软件要求 @@ -106,7 +104,7 @@ df -h | 项目 | 要求 | 说明 | |------|------|------| | **视频源类型** | RTSP Server | 建议使用 ffmpeg 或 ZLMediaKit 推流 | -| **视频源数量** | 1 路共享流 | 4 条流水线共用同一输入 | +| **视频源数量** | 1 路共享流 | 5 条流水线共用同一输入 | | **视频规格** | 1280×720 @ 30fps, H.264 | 模拟真实摄像头 | | **码率** | 4-8 Mbps | 总输入带宽 4-8 Mbps | | **内容要求** | 包含行人和人脸 | 用于验证检测和识别功能 | @@ -117,7 +115,7 @@ df -h # 使用 ffmpeg 推送 1 路 720p 测试流 ffmpeg -re -stream_loop -1 -i test_video.mp4 \ -c:v libx264 -preset fast -b:v 4M -r 30 -s 1280x720 \ - -f rtsp rtsp://0.0.0.0:8554/test + -f rtsp rtsp://0.0.0.0:8554/cam # 或使用 ZLMediaKit 等 RTSP 服务器 ``` @@ -131,14 +129,14 @@ ffmpeg -re -stream_loop -1 -i test_video.mp4 \ | 服务 | 用途 | 配置 | |------|------|------| -| **MinIO** | 报警截图/录像存储 | 地址: `10.0.0.49:9000`
Bucket: `stress-test`
账号: `minioadmin/minioadmin` | +| **MinIO** | 报警截图/录像存储 | 地址: `10.0.0.49:9000`
Bucket: `myminio`
账号: `minioadmin/minioadmin` | **MinIO 准备(在 10.0.0.49 上执行):** ```bash # 创建 bucket mc alias set myminio http://10.0.0.49:9000 minioadmin minioadmin -mc mb myminio/stress-test +mc mb myminio/myminio ``` --- @@ -147,48 +145,51 @@ mc mb myminio/stress-test ### 3.1 主配置文件 -配置文件路径:`configs/stress_test_4ch_shared_source.json` +配置文件路径:`configs/stress_5ch_face_recog.json` **配置特点:** -- 4 个独立 Graph(stress_cam1 ~ stress_cam4) -- 所有 Graph 的输入 RTSP URL 相同:`rtsp://10.0.0.49:8554/test` -- 每路独立输出到不同端口(8555-8558) -- **节点拓扑和参数与 `sample_cam2.json` 完全一致** +- 5 个独立 Graph(cam1 ~ cam5) +- 所有 Graph 的输入 RTSP URL 相同:`rtsp://10.0.0.49:8554/cam` +- 每路共用 RTSP 端口 8555,通过路径区分(/live/cam1 ~ /live/cam5) +- 包含人脸识别全流程节点 -**节点配置详情(每路,与 sample_cam2.json 一致):** +**节点配置详情(每路):** | 节点 | 类型 | 作用 | 关键参数 | |------|------|------|----------| | `input_rtsp` | source | 拉取 RTSP 流 | 1280×720@30fps, use_mpp=true | | `preprocess` | filter | 图像预处理 | 720p → 640×640 RGB, use_rga=true | -| `ai_yolo` | filter | 目标检测 | yolov8n-640.rknn, v8, conf=0.35, nms=0.45, infer_fps=10 | -| `ai_face_det` | filter | 人脸检测 | RetinaFace_mobile320.rknn, conf=0.7, max_faces=10 | -| `ai_face_recog` | filter | 人脸识别 | mobilefacenet_arcface.rknn, align=true, max_faces=10 | -| `tracker` | filter | 目标跟踪 | bytetrack_lite, max_age_ms=1500, track_classes=[0] | -| `preprocess` | filter | 人脸分支预处理 | 原始分辨率 → RGB (pre_face) | -| `osd` | filter | 屏幕显示 | draw_bbox=true, draw_text=true, line_width=2 | +| `ai_yolo` | filter | 目标检测 | best-640.rknn, v8, conf=0.35, nms=0.45, infer_fps=10, num_classes=3 | +| `tracker` | filter | 目标跟踪 | bytetrack_lite, max_age_ms=1500, track_classes=[0,1,2] | +| `face_det` | filter | 人脸检测 | RetinaFace_mobile320.rknn, conf=0.7, max_faces=10 | +| `face_recog` | filter | 人脸识别 | mobilefacenet_arcface.rknn, align=true, max_faces=10, threshold.accept=0.45 | +| `osd` | filter | 屏幕显示 | draw_bbox=true, draw_text=true, draw_face_det=true, draw_face_bbox=true | | `preprocess` | filter | 后处理 | 640×640 → 720p NV12, use_rga=true | | `publish` | sink | 视频输出 | h264, 30fps, 2000kbps, RTSP+HLS | | `alarm` | sink | 目标报警 | eval_fps=10, MinIO上传截图+录像 | -| `alarm_face` | sink | 人脸报警 | eval_fps=5, MinIO上传截图 | **输出端口分配:** -| Graph | RTSP 端口 | HLS 路径 | -|-------|-----------|----------| -| stress_cam1 | 8555 | `./web/hls/cam1/index.m3u8` | -| stress_cam2 | 8556 | `./web/hls/cam2/index.m3u8` | -| stress_cam3 | 8557 | `./web/hls/cam3/index.m3u8` | -| stress_cam4 | 8558 | `./web/hls/cam4/index.m3u8` | +| Graph | RTSP 端口 | RTSP 路径 | HLS 路径 | +|-------|-----------|-----------|----------| +| cam1 | 8555 | `/live/cam1` | `./web/hls/cam1/index.m3u8` | +| cam2 | 8555 | `/live/cam2` | `./web/hls/cam2/index.m3u8` | +| cam3 | 8555 | `/live/cam3` | `./web/hls/cam3/index.m3u8` | +| cam4 | 8555 | `/live/cam4` | `./web/hls/cam4/index.m3u8` | +| cam5 | 8555 | `/live/cam5` | `./web/hls/cam5/index.m3u8` | **模型文件清单:** | 模型文件 | 路径 | 说明 | |----------|------|------| -| yolov8n-640.rknn | `./models/yolov8n-640.rknn` | YOLOv8 目标检测 | +| best-640.rknn | `./models/best-640.rknn` | YOLOv8 目标检测 (3 classes) | | RetinaFace_mobile320.rknn | `./models/RetinaFace_mobile320.rknn` | 人脸检测 | | mobilefacenet_arcface.rknn | `./models/mobilefacenet_arcface.rknn` | 人脸识别 | -| face_gallery.db | `./models/face_gallery.db` | 人脸库 | +| face_gallery_cam1.db | `./models/face_gallery_cam1.db` | 人脸库 (cam1) | +| face_gallery_cam2.db | `./models/face_gallery_cam2.db` | 人脸库 (cam2) | +| face_gallery_cam3.db | `./models/face_gallery_cam3.db` | 人脸库 (cam3) | +| face_gallery_cam4.db | `./models/face_gallery_cam4.db` | 人脸库 (cam4) | +| face_gallery_cam5.db | `./models/face_gallery_cam5.db` | 人脸库 (cam5) | --- @@ -208,10 +209,11 @@ df -h # 4. 准备模型文件 ls models/ -# 应有:yolov8n-640.rknn, RetinaFace_mobile320.rknn, mobilefacenet_arcface.rknn, face_gallery.db +# 应有:best-640.rknn, RetinaFace_mobile320.rknn, mobilefacenet_arcface.rknn +# 以及人脸库:face_gallery_cam1.db ~ face_gallery_cam5.db # 5. 创建 HLS 输出目录 -mkdir -p web/hls/cam{1,2,3,4} +mkdir -p web/hls/cam{1,2,3,4,5} # 6. 检查网络连接 ping 10.0.0.49 @@ -225,7 +227,7 @@ ping 10.0.0.49 # 推送单路 720p 测试流 ffmpeg -re -stream_loop -1 -i test_video.mp4 \ -c:v libx264 -preset fast -b:v 4M -r 30 -s 1280x720 \ - -f rtsp rtsp://0.0.0.0:8554/cam1 + -f rtsp rtsp://0.0.0.0:8554/cam ``` ### 4.3 启动测试程序 @@ -234,17 +236,17 @@ ffmpeg -re -stream_loop -1 -i test_video.mp4 \ cd /home/orangepi/apps/OrangePi3588Media # 启动 media-server -./build/media-server --config configs/stress_test_4ch_shared_source.json +./build/media-server --config configs/stress_5ch_face_recog.json ``` ### 4.4 监控脚本 -创建监控脚本 `monitor_4ch.sh`: +创建监控脚本 `monitor_5ch.sh`: ```bash #!/bin/bash -LOG_FILE="stress_test_4ch_$(date +%Y%m%d_%H%M%S).log" +LOG_FILE="stress_test_5ch_$(date +%Y%m%d_%H%M%S).log" echo "Time,CPU%,MemMB,NPU%,Temp°C" > $LOG_FILE @@ -272,8 +274,8 @@ done 运行监控: ```bash -chmod +x monitor_4ch.sh -./monitor_4ch.sh +chmod +x monitor_5ch.sh +./monitor_5ch.sh ``` --- @@ -284,15 +286,16 @@ chmod +x monitor_4ch.sh | 验证项 | 方法 | 通过标准 | |--------|------|----------| -| **输入连接** | 查看日志 | 4 路都显示 "connected" | -| **视频输出** | VLC 播放 | `rtsp://:8555/live/cam1` ~ `:8558/live/cam4` 都能正常播放 | -| **HLS 输出** | 浏览器/播放器 | 4 路 HLS 流可正常播放 | -| **目标检测** | 观察 OSD 输出 | 画面中出现检测框和 "person" 标签 | -| **人脸识别** | 观察 OSD 输出 | 人脸被框选,显示姓名或 "unknown" | +| **输入连接** | 查看日志 | 5 路都显示 "connected" | +| **视频输出** | VLC 播放 | `rtsp://:8555/live/cam1` ~ `/live/cam5` 都能正常播放 | +| **HLS 输出** | 浏览器/播放器 | 5 路 HLS 流可正常播放 | +| **目标检测** | 观察 OSD 输出 | 画面中出现检测框和目标标签 | +| **人脸检测** | 观察 OSD 输出 | 人脸被框选 | +| **人脸识别** | 观察 OSD 输出 | 人脸显示姓名或 "unknown" | | **目标跟踪** | 观察 OSD 输出 | 同一目标的 ID 保持稳定 | -| **报警触发** | 查看日志 | alarm 节点输出 "person_detect" 或 "unknown_face" | -| **MinIO 上传** | 检查 MinIO | `stress-test` bucket 中有截图/录像文件 | -| **4路并发** | 同时播放4路输出 | 4路输出画面都流畅,无明显卡顿 | +| **报警触发** | 查看日志 | alarm 节点输出报警信息 | +| **MinIO 上传** | 检查 MinIO | `myminio` bucket 中有截图/录像文件 | +| **5路并发** | 同时播放5路输出 | 5路输出画面都流畅,无明显卡顿 | ### 5.2 性能验证 @@ -300,9 +303,9 @@ chmod +x monitor_4ch.sh |------|----------|----------| | **帧率** | 日志中 node_output_fps | ≥ 25 fps(每路) | | **延迟** | 对比输入输出时间戳 | ≤ 500ms | -| **NPU 利用率** | `/sys/kernel/debug/rknpu/load` | 50-90% | -| **CPU 占用** | `top` 命令 | ≤ 50% | -| **内存占用** | `free` 命令 | ≤ 2.5GB | +| **NPU 利用率** | `/sys/kernel/debug/rknpu/load` | 50-95% | +| **CPU 占用** | `top` 命令 | ≤ 60% | +| **内存占用** | `free` 命令 | ≤ 3GB | | **队列积压** | 日志中 queue_length | 不持续增长 | ### 5.3 稳定性验证 @@ -316,7 +319,7 @@ chmod +x monitor_4ch.sh ### 5.4 验证命令示例 ```bash -# 1. 检查 4 路进程状态 +# 1. 检查 5 路进程状态 ps aux | grep media-server # 2. 查看 NPU 负载 @@ -327,9 +330,10 @@ htop # 4. 播放测试(另开终端) ffplay rtsp://localhost:8555/live/cam1 & -ffplay rtsp://localhost:8556/live/cam2 & -ffplay rtsp://localhost:8557/live/cam3 & -ffplay rtsp://localhost:8558/live/cam4 & +ffplay rtsp://localhost:8555/live/cam2 & +ffplay rtsp://localhost:8555/live/cam3 & +ffplay rtsp://localhost:8555/live/cam4 & +ffplay rtsp://localhost:8555/live/cam5 & # 5. 检查 HLS 文件生成 ls -la web/hls/cam*/ @@ -338,7 +342,7 @@ ls -la web/hls/cam*/ tail -f media-server.log | grep alarm # 7. 检查 MinIO 上传(在 10.0.0.49 上) -mc ls myminio/stress-test +mc ls myminio/myminio ``` --- @@ -349,16 +353,17 @@ mc ls myminio/stress-test ``` ┌─────────────────────────────────────────────────────────┐ -│ 4 路 720p 全流程测试预期结果 │ +│ 5 路 720p 人脸识别全流程测试预期结果 │ ├─────────────────────────────────────────────────────────┤ -│ • 4 路视频正常解码、处理、输出 │ +│ • 5 路视频正常解码、处理、输出 │ │ • 端到端延迟: 200-400ms │ -│ • NPU 利用率: 70-90% │ -│ • CPU 占用: 30-50% │ -│ • 内存占用: 1.5-2.5GB │ +│ • NPU 利用率: 80-95% (目标检测+人脸检测+人脸识别) │ +│ • CPU 占用: 40-60% │ +│ • 内存占用: 2-3GB │ │ • 无丢帧或轻微丢帧 (< 1%) │ │ • 报警功能正常触发,MinIO上传成功 │ -│ • 4路输出画面质量一致 │ +│ • 人脸识别功能正常,能识别已知人脸 │ +│ • 5路输出画面质量一致 │ └─────────────────────────────────────────────────────────┘ ``` @@ -376,20 +381,21 @@ mc ls myminio/stress-test | 帧率 cam2 (fps) | - | | | | | 帧率 cam3 (fps) | - | | | | | 帧率 cam4 (fps) | - | | | | +| 帧率 cam5 (fps) | - | | | | | 报警次数 (目标) | - | | | | -| 报警次数 (人脸) | - | | | | +| 人脸识别次数 | - | | | | | MinIO 文件数 | - | | | | | 异常重启次数 | - | | | | ### 6.3 输出验证清单 -- [ ] 4 路 RTSP 流均可正常播放 -- [ ] 4 路 HLS 流均可正常播放 +- [ ] 5 路 RTSP 流均可正常播放 +- [ ] 5 路 HLS 流均可正常播放 - [ ] 画面中有检测框(OSD 正常工作) - [ ] 检测到人脸时显示姓名或 "unknown" - [ ] 目标 ID 保持稳定(跟踪正常工作) - [ ] 日志中有报警输出 -- [ ] MinIO `stress-test` bucket 中有文件上传 +- [ ] MinIO `myminio` bucket 中有文件上传 - [ ] 无 Error/Warning 刷屏 --- @@ -405,7 +411,7 @@ mc ls myminio/stress-test | **高 CPU 占用** | RGA 未启用 | 检查配置 `use_rga: true`,`use_mpp: true` | | **高延迟** | 队列积压 | 检查 `queue.size`,适当调小 | | **NPU 利用率低** | 推理频率设置过低 | 调整 `infer_fps` | -| **4路中某路无输出** | 端口冲突 | 检查端口 8555-8558 是否被占用 | +| **人脸识别失败** | 人脸库未加载 | 检查 `face_gallery_path` 配置和人脸库文件 | | **OSD 不显示** | 格式不支持 | 确保 OSD 输入为 RGB/BGR/NV12 格式 | | **MinIO 上传失败** | 网络/认证问题 | 检查 MinIO 地址和账号密码 | @@ -447,6 +453,9 @@ grep "output_fps" media-server.log | tail -20 # 检查报警触发 grep "alarm" media-server.log | tail -20 +# 检查人脸识别 +grep "face_recog\|face_det" media-server.log | tail -20 + # 检查 MinIO 上传 grep "minio\|snapshot\|clip" media-server.log | tail -20 ``` @@ -462,15 +471,16 @@ grep "minio\|snapshot\|clip" media-server.log | tail -20 - **设备型号**: - **固件版本**: - **软件版本**: -- **视频源**: `rtsp://10.0.0.49:8554/test` (1280×720@30fps) -- **MinIO**: `http://10.0.0.49:9000`, bucket: `stress-test` +- **视频源**: `rtsp://10.0.0.49:8554/cam` (1280×720@30fps) +- **MinIO**: `http://10.0.0.49:9000`, bucket: `myminio` ### 8.2 测试结论 -- [ ] 4 路全流程测试通过 +- [ ] 5 路人脸识别全流程测试通过 - [ ] 性能指标达标 - [ ] 稳定性测试通过 - [ ] MinIO 上传功能正常 +- [ ] 人脸识别功能正常 ### 8.3 详细数据 @@ -496,19 +506,22 @@ grep "minio\|snapshot\|clip" media-server.log | tail -20 ```bash # 1. 准备环境 cd /home/orangepi/apps/OrangePi3588Media -mkdir -p web/hls/cam{1,2,3,4} +mkdir -p web/hls/cam{1,2,3,4,5} # 2. 确认模型存在 -ls models/yolov8n-640.rknn models/RetinaFace_mobile320.rknn \ - models/mobilefacenet_arcface.rknn models/face_gallery.db +ls models/best-640.rknn models/RetinaFace_mobile320.rknn \ + models/mobilefacenet_arcface.rknn -# 3. 启动测试 -./build/media-server --config configs/stress_test_4ch_shared_source.json +# 3. 确认人脸库存在 +ls models/face_gallery_cam{1,2,3,4,5}.db -# 4. 另开终端监控 -./monitor_4ch.sh +# 4. 启动测试 +./build/media-server --config configs/stress_5ch_face_recog.json -# 5. 验证输出 +# 5. 另开终端监控 +./monitor_5ch.sh + +# 6. 验证输出 ffplay rtsp://localhost:8555/live/cam1 ``` @@ -522,5 +535,5 @@ ffplay rtsp://localhost:8555/live/cam1 | 文件 | 说明 | |------|------| -| `configs/stress_test_4ch_shared_source.json` | 4路全流程测试配置(共享源,与 sample_cam2.json 一致) | -| `monitor_4ch.sh` | 资源监控脚本 | +| `configs/stress_5ch_face_recog.json` | 5路人脸识别全流程测试配置(共享源) | +| `monitor_5ch.sh` | 资源监控脚本 | diff --git a/docs/命令.md b/docs/命令.md index 8abd189..f198428 100644 --- a/docs/命令.md +++ b/docs/命令.md @@ -19,6 +19,9 @@ cmake --build build -j$(nproc) +- 运行media-server + ./build/media-server -c configs/sample_cam4_best.json + //退出 pidof media-server diff --git a/scripts/build.sh b/scripts/build.sh new file mode 100755 index 0000000..0e1c641 --- /dev/null +++ b/scripts/build.sh @@ -0,0 +1,208 @@ +#!/bin/bash +# RK3588 Media Server 编译脚本 +# 一键编译 Media Server 和 Agent + +set -e + +# 颜色定义 +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +BLUE='\033[0;34m' +NC='\033[0m' + +# 项目目录 +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" +PROJECT_DIR="$(cd "$SCRIPT_DIR/.." && pwd)" +BUILD_DIR="$PROJECT_DIR/build" + +# 编译选项(可通过环境变量覆盖) +BUILD_TYPE="${BUILD_TYPE:-Release}" +BUILD_TESTS="${BUILD_TESTS:-OFF}" +BUILD_SAMPLES="${BUILD_SAMPLES:-ON}" +ENABLE_FFMPEG="${ENABLE_FFMPEG:-ON}" +ENABLE_MPP="${ENABLE_MPP:-ON}" +ENABLE_RGA="${ENABLE_RGA:-ON}" +ENABLE_ZLMEDIAKIT="${ENABLE_ZLMEDIAKIT:-ON}" +ENABLE_RKNN="${ENABLE_RKNN:-ON}" + +show_help() { + echo "RK3588 Media Server 编译脚本" + echo "" + echo "用法: ./scripts/build.sh [选项]" + echo "" + echo "选项:" + echo " -h, --help 显示帮助信息" + echo " -c, --clean 清理构建目录" + echo " -j N 并行编译任务数(默认: $(nproc))" + echo " -a, --agent-only 仅编译 Agent" + echo " -m, --media-only 仅编译 Media Server" + echo " -d, --debug Debug 模式编译" + echo "" + echo "环境变量:" + echo " BUILD_TYPE 编译类型 (Release/Debug, 默认: Release)" + echo " BUILD_TESTS 编译测试 (ON/OFF, 默认: OFF)" + echo " BUILD_SAMPLES 编译示例 (ON/OFF, 默认: ON)" + echo " ENABLE_FFMPEG 启用 FFmpeg (ON/OFF, 默认: ON)" + echo " ENABLE_MPP 启用 MPP (ON/OFF, 默认: ON)" + echo " ENABLE_RGA 启用 RGA (ON/OFF, 默认: ON)" + echo " ENABLE_ZLMEDIAKIT 启用 ZLMediaKit (ON/OFF, 默认: ON)" + echo " ENABLE_RKNN 启用 RKNN (ON/OFF, 默认: ON)" + echo "" + echo "示例:" + echo " ./scripts/build.sh # 完整编译" + echo " ./scripts/build.sh -c # 清理后编译" + echo " ./scripts/build.sh -j4 # 使用4线程编译" + echo " ./scripts/build.sh -m # 仅编译 Media Server" + echo " BUILD_TYPE=Debug ./scripts/build.sh # Debug 模式" +} + +# 解析参数 +CLEAN=0 +JOBS=$(nproc) +BUILD_AGENT=1 +BUILD_MEDIA=1 + +while [[ $# -gt 0 ]]; do + case $1 in + -h|--help) + show_help + exit 0 + ;; + -c|--clean) + CLEAN=1 + shift + ;; + -j) + if [[ -n "$2" && "$2" != -* ]]; then + JOBS="$2" + shift 2 + else + echo -e "${RED}错误: -j 选项需要指定线程数${NC}" + exit 1 + fi + ;; + -j[0-9]*) + # 支持 -j4 这种格式 + JOBS="${1#-j}" + shift + ;; + -a|--agent-only) + BUILD_MEDIA=0 + shift + ;; + -m|--media-only) + BUILD_AGENT=0 + shift + ;; + -d|--debug) + BUILD_TYPE="Debug" + shift + ;; + *) + echo -e "${RED}未知选项: $1${NC}" + show_help + exit 1 + ;; + esac +done + +echo -e "${BLUE}╔════════════════════════════════════════════════════════════╗${NC}" +echo -e "${BLUE}║ RK3588 Media Server 编译脚本 ║${NC}" +echo -e "${BLUE}╚════════════════════════════════════════════════════════════╝${NC}" +echo "" + +cd "$PROJECT_DIR" + +# 清理构建目录 +if [ $CLEAN -eq 1 ]; then + echo -e "${YELLOW}[清理构建目录]${NC}" + rm -rf "$BUILD_DIR" + echo -e "${GREEN}✓${NC} 构建目录已清理" + echo "" +fi + +# 编译 Media Server +if [ $BUILD_MEDIA -eq 1 ]; then + echo -e "${BLUE}[编译 Media Server]${NC}" + echo "编译选项:" + echo " BUILD_TYPE: $BUILD_TYPE" + echo " BUILD_TESTS: $BUILD_TESTS" + echo " BUILD_SAMPLES: $BUILD_SAMPLES" + echo " ENABLE_FFMPEG: $ENABLE_FFMPEG" + echo " ENABLE_MPP: $ENABLE_MPP" + echo " ENABLE_RGA: $ENABLE_RGA" + echo " ENABLE_ZLMEDIAKIT: $ENABLE_ZLMEDIAKIT" + echo " ENABLE_RKNN: $ENABLE_RKNN" + echo "" + + # 配置 ZLMediaKit 路径 + ZLMK_LIB_PATH="$PROJECT_DIR/third_party/rknpu2/examples/3rdparty/zlmediakit/aarch64/libmk_api.so" + ZLMK_INCLUDE_DIR="$PROJECT_DIR/third_party/rknpu2/examples/3rdparty/zlmediakit/include" + + # 检查 ZLMediaKit 库是否存在 + if [ ! -f "$ZLMK_LIB_PATH" ]; then + echo -e "${YELLOW}警告: ZLMediaKit 库未找到,禁用 ZLMediaKit 支持${NC}" + ENABLE_ZLMEDIAKIT="OFF" + fi + + # 配置 CMake + echo -e "${CYAN}[配置 CMake]${NC}" + cmake -S . -B "$BUILD_DIR" \ + -DCMAKE_BUILD_TYPE="$BUILD_TYPE" \ + -DBUILD_TESTS="$BUILD_TESTS" \ + -DBUILD_SAMPLES="$BUILD_SAMPLES" \ + -DRK3588_ENABLE_FFMPEG="$ENABLE_FFMPEG" \ + -DRK3588_ENABLE_MPP="$ENABLE_MPP" \ + -DRK3588_ENABLE_RGA="$ENABLE_RGA" \ + -DRK3588_ENABLE_ZLMEDIAKIT="$ENABLE_ZLMEDIAKIT" \ + -DRK3588_ENABLE_RKNN="$ENABLE_RKNN" \ + -DRK_ZLMK_API_LIB_PATH="$ZLMK_LIB_PATH" \ + -DRK_ZLMEDIAKIT_INCLUDE_DIR="$ZLMK_INCLUDE_DIR" + + # 编译 + echo -e "${CYAN}[编译中... 使用 $JOBS 线程]${NC}" + cmake --build "$BUILD_DIR" -j"$JOBS" + + echo -e "${GREEN}✓${NC} Media Server 编译完成" + echo " 输出: $BUILD_DIR/media-server" + ls -lh "$BUILD_DIR/media-server" + echo "" +fi + +# 编译 Agent +if [ $BUILD_AGENT -eq 1 ]; then + echo -e "${BLUE}[编译 Agent]${NC}" + + AGENT_DIR="$PROJECT_DIR/agent" + if [ ! -d "$AGENT_DIR" ]; then + echo -e "${YELLOW}警告: Agent 目录不存在,跳过编译${NC}" + elif [ ! -f "$AGENT_DIR/go.mod" ]; then + echo -e "${YELLOW}警告: Agent 不是 Go 项目,跳过编译${NC}" + else + cd "$AGENT_DIR" + + # 检查 go 是否安装 + if ! command -v go &> /dev/null; then + echo -e "${RED}错误: Go 未安装,无法编译 Agent${NC}" + exit 1 + fi + + # 编译 Agent + echo -e "${CYAN}[编译 Agent]${NC}" + go build -o rk3588-agent_linux_arm64 ./cmd/rk3588-agent + + echo -e "${GREEN}✓${NC} Agent 编译完成" + echo " 输出: $AGENT_DIR/rk3588-agent_linux_arm64" + ls -lh "$AGENT_DIR/rk3588-agent_linux_arm64" + fi + echo "" +fi + +echo -e "${GREEN}╔════════════════════════════════════════════════════════════╗${NC}" +echo -e "${GREEN}║ 编译完成! ║${NC}" +echo -e "${GREEN}╚════════════════════════════════════════════════════════════╝${NC}" +echo "" +echo "下一步:" +echo " 部署服务: sudo ./scripts/deploy.sh install" +echo " 查看状态: sudo ./scripts/deploy.sh status" diff --git a/scripts/deploy.sh b/scripts/deploy.sh index 7d7956e..a4764ee 100755 --- a/scripts/deploy.sh +++ b/scripts/deploy.sh @@ -43,19 +43,29 @@ create_runtime_dirs() { mkdir -p "$ALARMS_DIR" mkdir -p "$CLIPS_DIR" - # 设置权限(root用户运行,但允许orangepi组读取) + # 设置权限(日志目录使用 orangepi 用户,方便查看和管理) chown -R root:root "$RUNTIME_DIR" - chmod 755 "$RUNTIME_DIR" + + # HLS 输出目录 - root 所有,但 orangepi 可读取 chmod 755 "$HLS_DIR" + + # 日志目录 - orangepi 用户完全控制 + chown orangepi:orangepi "$LOGS_DIR" chmod 755 "$LOGS_DIR" + + # 告警目录 - orangepi 用户完全控制 + chown orangepi:orangepi "$ALARMS_DIR" chmod 755 "$ALARMS_DIR" + + # 视频片段目录 - orangepi 用户完全控制 + chown orangepi:orangepi "$CLIPS_DIR" chmod 755 "$CLIPS_DIR" echo -e "${GREEN}✓${NC} 运行时目录创建完成:" - echo " HLS输出: $HLS_DIR" - echo " 日志: $LOGS_DIR" - echo " 告警图片: $ALARMS_DIR" - echo " 告警视频: $CLIPS_DIR" + echo " HLS输出: $HLS_DIR (root:orangepi, 755)" + echo " 日志: $LOGS_DIR (orangepi:orangepi, 755)" + echo " 告警图片: $ALARMS_DIR (orangepi:orangepi, 755)" + echo " 告警视频: $CLIPS_DIR (orangepi:orangepi, 755)" } # 安装日志轮转配置 @@ -71,7 +81,7 @@ install_logrotate() { delaycompress missingok notifempty - create 644 root root + create 644 orangepi orangepi sharedscripts postrotate /bin/kill -HUP $(cat /var/run/syslogd.pid 2>/dev/null) 2>/dev/null || true @@ -184,6 +194,8 @@ cmd_install_media_server() { # 复制插件 if [ -d "$BUILD_DIR/plugins" ]; then cp "$BUILD_DIR"/plugins/*.so "$INSTALL_DIR/bin/plugins/" 2>/dev/null || true + PLUGIN_COUNT=$(ls "$INSTALL_DIR/bin/plugins/"/*.so 2>/dev/null | wc -l) + echo -e "${GREEN}✓${NC} 已复制插件 ($PLUGIN_COUNT 个)" fi # 复制依赖库 @@ -191,17 +203,24 @@ cmd_install_media_server() { cp "$BUILD_DIR"/*.so "$INSTALL_DIR/lib/" 2>/dev/null || true fi + # 复制共享状态库(rk_shared_state) + if [ -f "$BUILD_DIR/librk_shared_state.so" ]; then + cp "$BUILD_DIR/librk_shared_state.so" "$INSTALL_DIR/lib/" + echo -e "${GREEN}✓${NC} 已复制 librk_shared_state.so" + fi + # 复制 web 静态文件 if [ -d "$PROJECT_DIR/web" ]; then cp -r "$PROJECT_DIR/web"/* "$INSTALL_DIR/web/" 2>/dev/null || true + WEB_FILES=$(find "$INSTALL_DIR/web" -type f | wc -l) + echo -e "${GREEN}✓${NC} 已复制 web 静态文件 ($WEB_FILES 个文件)" fi - # 复制模型文件 + # 复制模型文件(包括 .rknn 模型和 .db 人脸库) if [ -d "$PROJECT_DIR/models" ]; then cp -r "$PROJECT_DIR/models"/* "$INSTALL_DIR/models/" 2>/dev/null || true - fi - if [ -d "$PROJECT_DIR/third_party/rknpu2/examples/rknn_yolov5_demo/model/RK3588" ]; then - cp "$PROJECT_DIR/third_party/rknpu2/examples/rknn_yolov5_demo/model/RK3588"/*.rknn "$INSTALL_DIR/models/" 2>/dev/null || true + MODEL_COUNT=$(find "$INSTALL_DIR/models" -type f \( -name "*.rknn" -o -name "*.db" \) | wc -l) + echo -e "${GREEN}✓${NC} 已复制模型文件 ($MODEL_COUNT 个模型/人脸库)" fi # 选择并复制配置文件 @@ -356,12 +375,14 @@ EOF cmd_install_agent() { echo -e "${BLUE}[2/5] 安装 Agent...${NC}" - # 查找 Agent 编译产物 + # 查找 Agent 编译产物(优先使用预编译的 arm64 二进制) AGENT_SOURCE="" if [ -f "$PROJECT_DIR/agent/rk3588-agent_linux_arm64" ]; then AGENT_SOURCE="$PROJECT_DIR/agent/rk3588-agent_linux_arm64" + echo -e "${GREEN}✓${NC} 找到预编译 Agent: rk3588-agent_linux_arm64" elif [ -f "$PROJECT_DIR/agent/cmd/rk3588-agent/rk3588-agent" ]; then AGENT_SOURCE="$PROJECT_DIR/agent/cmd/rk3588-agent/rk3588-agent" + echo -e "${GREEN}✓${NC} 找到源码编译 Agent: rk3588-agent" fi if [ -z "$AGENT_SOURCE" ]; then @@ -422,7 +443,7 @@ Group=root WorkingDirectory=$INSTALL_DIR Environment="LD_LIBRARY_PATH=$INSTALL_DIR/lib:/usr/local/lib" Environment="RKNPU_LOG_LEVEL=2" -ExecStartPre=/bin/mkdir -p $HLS_DIR $LOGS_DIR $ALARMS_DIR $CLIPS_DIR +ExecStartPre=/bin/bash -c 'mkdir -p $HLS_DIR $LOGS_DIR $ALARMS_DIR $CLIPS_DIR && chown orangepi:orangepi $LOGS_DIR $ALARMS_DIR $CLIPS_DIR && chmod 755 $LOGS_DIR $ALARMS_DIR $CLIPS_DIR' ExecStart=$INSTALL_DIR/bin/media-server --config $INSTALL_DIR/etc/media-server.json Restart=always RestartSec=5