增加检测模型,增加模拟告警服务,增加压测方案和配置
This commit is contained in:
parent
a69463bd51
commit
ad13ad0f88
BIN
best_cxn.onnx
Normal file
BIN
best_cxn.onnx
Normal file
Binary file not shown.
BIN
check0_base_optimize.onnx
Normal file
BIN
check0_base_optimize.onnx
Normal file
Binary file not shown.
BIN
check1_fold_constant.onnx
Normal file
BIN
check1_fold_constant.onnx
Normal file
Binary file not shown.
BIN
check2_correct_ops.onnx
Normal file
BIN
check2_correct_ops.onnx
Normal file
Binary file not shown.
BIN
check3_fuse_ops.onnx
Normal file
BIN
check3_fuse_ops.onnx
Normal file
Binary file not shown.
1
configs/sample_cam2.json.last_good.json
Normal file
1
configs/sample_cam2.json.last_good.json
Normal file
File diff suppressed because one or more lines are too long
281
configs/sample_cam3.json
Normal file
281
configs/sample_cam3.json
Normal file
@ -0,0 +1,281 @@
|
||||
{
|
||||
"queue": { "size": 8, "strategy": "drop_oldest" },
|
||||
"graphs": [
|
||||
{
|
||||
"name": "cam1_sample_full_pipeline",
|
||||
"nodes": [
|
||||
{
|
||||
"id": "in_cam1",
|
||||
"type": "input_rtsp",
|
||||
"role": "source",
|
||||
"enable": true,
|
||||
"url": "rtsp://10.0.0.49:8554/cam",
|
||||
"fps": 30,
|
||||
"width": 1280,
|
||||
"height": 720,
|
||||
"use_mpp": true,
|
||||
"use_ffmpeg": false,
|
||||
"force_tcp": true,
|
||||
"reconnect_sec": 5,
|
||||
"reconnect_backoff_max_sec": 30
|
||||
},
|
||||
{
|
||||
"id": "pre_cam1",
|
||||
"type": "preprocess",
|
||||
"role": "filter",
|
||||
"enable": true,
|
||||
"dst_w": 640,
|
||||
"dst_h": 640,
|
||||
"dst_format": "rgb",
|
||||
"dst_packed": true,
|
||||
"keep_ratio": false,
|
||||
"rga_gate": "cam1_sample_full_pipeline",
|
||||
"use_rga": true
|
||||
},
|
||||
{
|
||||
"id": "yolo_cam1",
|
||||
"type": "ai_yolo",
|
||||
"role": "filter",
|
||||
"enable": true,
|
||||
"infer_fps": 10,
|
||||
"model_path": "./models/yolov5s-640-640.rknn",
|
||||
"model_version": "v5",
|
||||
"num_classes": 80,
|
||||
"conf": 0.35,
|
||||
"nms": 0.45,
|
||||
"class_filter": []
|
||||
},
|
||||
{
|
||||
"id": "face_det_cam1",
|
||||
"type": "ai_face_det",
|
||||
"role": "filter",
|
||||
"enable": true,
|
||||
"model_path": "./models/RetinaFace_mobile320.rknn",
|
||||
"conf": 0.7,
|
||||
"nms": 0.4,
|
||||
"max_faces": 10,
|
||||
"output_landmarks": true,
|
||||
"input_format": "rgb"
|
||||
},
|
||||
{
|
||||
"id": "face_recog_cam1",
|
||||
"type": "ai_face_recog",
|
||||
"role": "filter",
|
||||
"enable": true,
|
||||
"model_path": "./models/mobilefacenet_arcface.rknn",
|
||||
"align": true,
|
||||
"emit_embedding": false,
|
||||
"max_faces": 10,
|
||||
"input_format": "rgb",
|
||||
"input_dtype": "uint8",
|
||||
"threshold": { "accept": 0.45, "margin": 0.05 },
|
||||
"gallery": {
|
||||
"backend": "sqlite",
|
||||
"path": "./models/face_gallery.db",
|
||||
"load_on_start": true,
|
||||
"expected_dim": 512,
|
||||
"dtype": "auto"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "trk_cam1",
|
||||
"type": "tracker",
|
||||
"role": "filter",
|
||||
"enable": true,
|
||||
"mode": "bytetrack_lite",
|
||||
"per_class": true,
|
||||
"state_key": "cam1_sample_full_pipeline",
|
||||
"track_classes": [0],
|
||||
"ignore_classes": [],
|
||||
"allowed_models": ["yolov5", "yolov8"],
|
||||
"high_th": 0.5,
|
||||
"low_th": 0.1,
|
||||
"iou_th": 0.3,
|
||||
"max_age_ms": 1500,
|
||||
"min_hits": 2,
|
||||
"max_tracks": 128,
|
||||
"debug": { "stats": false, "stats_interval": 200 }
|
||||
},
|
||||
{
|
||||
"id": "pre_face_cam1",
|
||||
"type": "preprocess",
|
||||
"role": "filter",
|
||||
"enable": true,
|
||||
"dst_w": 0,
|
||||
"dst_h": 0,
|
||||
"dst_format": "rgb",
|
||||
"dst_packed": true,
|
||||
"keep_ratio": false,
|
||||
"rga_gate": "cam1_sample_full_pipeline",
|
||||
"use_rga": true
|
||||
},
|
||||
{
|
||||
"id": "osd_cam1",
|
||||
"type": "osd",
|
||||
"role": "filter",
|
||||
"enable": true,
|
||||
"draw_bbox": true,
|
||||
"draw_text": true,
|
||||
"draw_face_det": false,
|
||||
"draw_face_bbox": false,
|
||||
"line_width": 2,
|
||||
"font_scale": 1,
|
||||
"use_rga_bbox": false,
|
||||
"labels": []
|
||||
},
|
||||
{
|
||||
"id": "post_cam1",
|
||||
"type": "preprocess",
|
||||
"role": "filter",
|
||||
"enable": true,
|
||||
"dst_w": 1280,
|
||||
"dst_h": 720,
|
||||
"dst_format": "nv12",
|
||||
"keep_ratio": false,
|
||||
"rga_gate": "cam1_sample_full_pipeline",
|
||||
"use_rga": true
|
||||
},
|
||||
{
|
||||
"id": "pub_cam1",
|
||||
"type": "publish",
|
||||
"role": "filter",
|
||||
"enable": true,
|
||||
"codec": "h264",
|
||||
"fps": 30,
|
||||
"gop": 60,
|
||||
"bitrate_kbps": 2000,
|
||||
"use_mpp": true,
|
||||
"use_ffmpeg_mux": true,
|
||||
"outputs": [
|
||||
{ "proto": "rtsp_server", "port": 8555, "path": "/live/cam1" },
|
||||
{ "proto": "hls", "path": "./web/hls/cam1/index.m3u8", "segment_sec": 2 }
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "alarm_cam1",
|
||||
"type": "alarm",
|
||||
"role": "sink",
|
||||
"enable": true,
|
||||
"eval_fps": 10,
|
||||
"labels": [],
|
||||
"rules": [
|
||||
{
|
||||
"name": "person_in_view",
|
||||
"class_ids": [0],
|
||||
"roi": { "x": 0.0, "y": 0.0, "w": 1.0, "h": 1.0 },
|
||||
"min_score": 0.4,
|
||||
"min_box_area_ratio": 0.02,
|
||||
"require_track_id": true,
|
||||
"min_duration_ms": 1500,
|
||||
"min_hits": 3,
|
||||
"hit_window_ms": 1500,
|
||||
"cooldown_ms": 5000,
|
||||
"per_track_cooldown_ms": 5000
|
||||
}
|
||||
],
|
||||
"face_rules": [],
|
||||
"actions": {
|
||||
"log": { "enable": true, "level": "info" },
|
||||
"snapshot": {
|
||||
"enable": true,
|
||||
"format": "jpg",
|
||||
"quality": 85,
|
||||
"upload": {
|
||||
"type": "minio",
|
||||
"endpoint": "http://10.0.0.49:9000",
|
||||
"bucket": "myminio",
|
||||
"region": "us-east-1",
|
||||
"access_key": "minioadmin",
|
||||
"secret_key": "minioadmin"
|
||||
}
|
||||
},
|
||||
"clip": {
|
||||
"enable": true,
|
||||
"pre_sec": 5,
|
||||
"post_sec": 10,
|
||||
"format": "mp4",
|
||||
"fps": 30,
|
||||
"upload": {
|
||||
"type": "minio",
|
||||
"endpoint": "http://10.0.0.49:9000",
|
||||
"bucket": "myminio",
|
||||
"region": "us-east-1",
|
||||
"access_key": "minioadmin",
|
||||
"secret_key": "minioadmin"
|
||||
}
|
||||
},
|
||||
"http": {
|
||||
"enable": false,
|
||||
"url": "http://127.0.0.1:8080/api/alarm",
|
||||
"timeout_ms": 3000,
|
||||
"include_media_url": true,
|
||||
"method": "POST"
|
||||
},
|
||||
"external_api": {
|
||||
"enable": true,
|
||||
"getTokenUrl": "http://127.0.0.1:8080/api/getToken",
|
||||
"putMessageUrl": "http://127.0.0.1:8080/api/putMessage",
|
||||
"tenantCode": "32",
|
||||
"channelNo": "${vod_channelNo}",
|
||||
"timeout_ms": 3000,
|
||||
"include_media_url": true,
|
||||
"token_header": "X-Access-Token",
|
||||
"token_json_path": "responseBody.token",
|
||||
"token_cache_sec": 1200
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "alarm_face_cam1",
|
||||
"type": "alarm",
|
||||
"role": "sink",
|
||||
"enable": true,
|
||||
"eval_fps": 5,
|
||||
"labels": [],
|
||||
"rules": [],
|
||||
"face_rules": [
|
||||
{ "name": "unknown_face", "type": "unknown", "cooldown_ms": 7000, "min_sim": 0.35, "min_hits": 2, "hit_window_ms": 1500, "min_face_area_ratio": 0.01, "min_face_aspect": 0.6, "max_face_aspect": 1.6 },
|
||||
{ "name": "known_person", "type": "person", "cooldown_ms": 7000, "min_sim": 0.6, "min_hits": 2, "hit_window_ms": 1500, "min_face_area_ratio": 0.01, "min_face_aspect": 0.6, "max_face_aspect": 1.6 }
|
||||
],
|
||||
"actions": {
|
||||
"log": { "enable": false, "level": "info" },
|
||||
"snapshot": {
|
||||
"enable": true,
|
||||
"format": "jpg",
|
||||
"quality": 85,
|
||||
"upload": {
|
||||
"type": "minio",
|
||||
"endpoint": "http://10.0.0.49:9000",
|
||||
"bucket": "myminio",
|
||||
"region": "us-east-1",
|
||||
"access_key": "minioadmin",
|
||||
"secret_key": "minioadmin"
|
||||
}
|
||||
},
|
||||
"clip": { "enable": false },
|
||||
"http": {
|
||||
"enable": true,
|
||||
"url": "http://127.0.0.1:8080/api/alarm",
|
||||
"timeout_ms": 3000,
|
||||
"include_media_url": true,
|
||||
"method": "POST"
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"edges": [
|
||||
["in_cam1", "pre_cam1"],
|
||||
["in_cam1", "pre_face_cam1"],
|
||||
["pre_cam1", "yolo_cam1"],
|
||||
["yolo_cam1", "trk_cam1"],
|
||||
["trk_cam1", "osd_cam1"],
|
||||
["osd_cam1", "post_cam1"],
|
||||
["post_cam1", "pub_cam1"],
|
||||
["pub_cam1", "alarm_cam1"],
|
||||
["pre_face_cam1", "face_det_cam1"],
|
||||
["face_det_cam1", "face_recog_cam1"],
|
||||
["face_recog_cam1", "alarm_face_cam1"]
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
1
configs/sample_cam3.json.last_good.json
Normal file
1
configs/sample_cam3.json.last_good.json
Normal file
File diff suppressed because one or more lines are too long
1105
configs/stress_test_4ch_shared_source.json
Normal file
1105
configs/stress_test_4ch_shared_source.json
Normal file
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
BIN
docs/requirements/32视频内容识别集成方案3.docx
Normal file
BIN
docs/requirements/32视频内容识别集成方案3.docx
Normal file
Binary file not shown.
@ -8,6 +8,12 @@ winget install Gyan.FFmpeg
|
||||
- 安装完成后,关闭并重新打开终端,验证:
|
||||
ffmpeg -version
|
||||
|
||||
-查看本地摄像头信息
|
||||
ffmpeg -list_devices true -f dshow -i dummy
|
||||
|
||||
- 本地运行RTSP服务器
|
||||
mediamtx.exe
|
||||
|
||||
- 推流到RTSP服务器(设置摄像头的分辨率为720P)
|
||||
ffmpeg -f dshow -rtbufsize 100M -video_size 1280x720 -framerate 30 -vcodec mjpeg -i video="4K AutoFocus Webcam" -c:v libx264 -preset ultrafast -pix_fmt yuv420p -f rtsp rtsp://localhost:8554/cam
|
||||
|
||||
|
||||
526
docs/stress_test_4ch_full_pipeline.md
Normal file
526
docs/stress_test_4ch_full_pipeline.md
Normal file
@ -0,0 +1,526 @@
|
||||
# RK3588 4路全流程压力测试方案
|
||||
|
||||
本文档描述在单台 RK3588 设备上进行 4 路全流程视频处理的压力测试方案。
|
||||
|
||||
**方案说明:** 本方案使用单一 RTSP 视频源 (`rtsp://10.0.0.49:8554/test`),4 条流水线独立处理同一路输入,模拟 4 路摄像头并发场景。配置与 `sample_cam2.json` 完全一致。
|
||||
|
||||
---
|
||||
|
||||
## 1. 测试目标
|
||||
|
||||
### 1.1 核心指标
|
||||
|
||||
| 指标项 | 目标值 | 说明 |
|
||||
|--------|--------|------|
|
||||
| **并发路数** | 4 路 | 单设备同时处理 4 路视频 |
|
||||
| **输入分辨率** | 1280×720 @ 30fps | 每路输入为 720p 实时视频 |
|
||||
| **端到端延迟** | ≤ 500ms | 从采集到输出的完整延迟 |
|
||||
| **NPU 利用率** | ≥ 70% | NPU 高效利用,但不超载 |
|
||||
| **CPU 占用** | ≤ 50% | 预留系统余量 |
|
||||
| **内存占用** | ≤ 2.5GB | 避免内存压力 |
|
||||
| **运行稳定性** | 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 ←─────────────────────────────┘
|
||||
│
|
||||
preprocess (后处理)
|
||||
│
|
||||
publish (RTSP/HLS 输出)
|
||||
│
|
||||
┌──────────┴──────────┐
|
||||
│ │
|
||||
alarm (目标) alarm_face (人脸)
|
||||
```
|
||||
|
||||
**节点类型统计(每路,与 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`
|
||||
|
||||
**4路总计:**
|
||||
- 4 个 input_rtsp 节点(连接同一 RTSP 源)
|
||||
- 28 个 Filter 节点
|
||||
- 12 个 Sink 节点
|
||||
|
||||
---
|
||||
|
||||
## 2. 测试环境要求
|
||||
|
||||
### 2.1 硬件要求
|
||||
|
||||
| 项目 | 规格 | 说明 |
|
||||
|------|------|------|
|
||||
| **主控芯片** | RK3588 | 4×A76@2.4GHz + 4×A55@1.8GHz |
|
||||
| **NPU** | 6 TOPS@INT8 | 用于 AI 推理 |
|
||||
| **内存** | ≥ 8GB LPDDR4/LPDDR5 | 建议 8GB 或以上 |
|
||||
| **存储** | ≥ 32GB eMMC/SSD | 用于 HLS 切片存储 |
|
||||
| **网络** | 千兆以太网 | 单路 4-8Mbps 输入,4路约 16-32Mbps |
|
||||
| **散热** | 主动散热 | 长时间高负载运行 |
|
||||
|
||||
### 2.2 软件要求
|
||||
|
||||
| 项目 | 版本/配置 | 说明 |
|
||||
|------|-----------|------|
|
||||
| **操作系统** | Ubuntu 22.04 / Debian 11 | ARM64 架构 |
|
||||
| **内核** | Linux 5.10+ | 需支持 RGA、MPP、DMA-BUF |
|
||||
| **NPU 驱动** | rknpu driver 0.9.6+ | 建议最新版本 |
|
||||
| **CMake** | ≥ 3.20 | 构建工具 |
|
||||
| **GCC** | ≥ 10.0 | 编译器 |
|
||||
|
||||
### 2.3 依赖库检查
|
||||
|
||||
```bash
|
||||
# 检查 NPU 驱动
|
||||
ls /dev/rknpu
|
||||
|
||||
# 检查 RGA 驱动
|
||||
ls /dev/rga
|
||||
|
||||
# 检查内存
|
||||
free -h
|
||||
|
||||
# 检查存储空间
|
||||
df -h
|
||||
```
|
||||
|
||||
### 2.4 视频源要求
|
||||
|
||||
| 项目 | 要求 | 说明 |
|
||||
|------|------|------|
|
||||
| **视频源类型** | RTSP Server | 建议使用 ffmpeg 或 ZLMediaKit 推流 |
|
||||
| **视频源数量** | 1 路共享流 | 4 条流水线共用同一输入 |
|
||||
| **视频规格** | 1280×720 @ 30fps, H.264 | 模拟真实摄像头 |
|
||||
| **码率** | 4-8 Mbps | 总输入带宽 4-8 Mbps |
|
||||
| **内容要求** | 包含行人和人脸 | 用于验证检测和识别功能 |
|
||||
|
||||
**视频源准备命令(在 10.0.0.49 服务器执行):**
|
||||
|
||||
```bash
|
||||
# 使用 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
|
||||
|
||||
# 或使用 ZLMediaKit 等 RTSP 服务器
|
||||
```
|
||||
|
||||
**测试视频内容建议:**
|
||||
- 包含行人移动(验证目标检测和跟踪)
|
||||
- 包含正脸人像(验证人脸识别)
|
||||
- 时长 5-10 分钟,循环播放
|
||||
|
||||
### 2.5 外部服务要求
|
||||
|
||||
| 服务 | 用途 | 配置 |
|
||||
|------|------|------|
|
||||
| **MinIO** | 报警截图/录像存储 | 地址: `10.0.0.49:9000`<br>Bucket: `stress-test`<br>账号: `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
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 3. 测试配置文件
|
||||
|
||||
### 3.1 主配置文件
|
||||
|
||||
配置文件路径:`configs/stress_test_4ch_shared_source.json`
|
||||
|
||||
**配置特点:**
|
||||
- 4 个独立 Graph(stress_cam1 ~ stress_cam4)
|
||||
- 所有 Graph 的输入 RTSP URL 相同:`rtsp://10.0.0.49:8554/test`
|
||||
- 每路独立输出到不同端口(8555-8558)
|
||||
- **节点拓扑和参数与 `sample_cam2.json` 完全一致**
|
||||
|
||||
**节点配置详情(每路,与 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 |
|
||||
| `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` |
|
||||
|
||||
**模型文件清单:**
|
||||
|
||||
| 模型文件 | 路径 | 说明 |
|
||||
|----------|------|------|
|
||||
| yolov8n-640.rknn | `./models/yolov8n-640.rknn` | YOLOv8 目标检测 |
|
||||
| RetinaFace_mobile320.rknn | `./models/RetinaFace_mobile320.rknn` | 人脸检测 |
|
||||
| mobilefacenet_arcface.rknn | `./models/mobilefacenet_arcface.rknn` | 人脸识别 |
|
||||
| face_gallery.db | `./models/face_gallery.db` | 人脸库 |
|
||||
|
||||
---
|
||||
|
||||
## 4. 测试步骤
|
||||
|
||||
### 4.1 环境准备
|
||||
|
||||
```bash
|
||||
# 1. 检查 NPU 驱动
|
||||
ls /dev/rknpu
|
||||
|
||||
# 2. 检查内存
|
||||
free -h
|
||||
|
||||
# 3. 检查存储空间
|
||||
df -h
|
||||
|
||||
# 4. 准备模型文件
|
||||
ls models/
|
||||
# 应有:yolov8n-640.rknn, RetinaFace_mobile320.rknn, mobilefacenet_arcface.rknn, face_gallery.db
|
||||
|
||||
# 5. 创建 HLS 输出目录
|
||||
mkdir -p web/hls/cam{1,2,3,4}
|
||||
|
||||
# 6. 检查网络连接
|
||||
ping 10.0.0.49
|
||||
```
|
||||
|
||||
### 4.2 启动视频源
|
||||
|
||||
在服务器(10.0.0.49)上执行:
|
||||
|
||||
```bash
|
||||
# 推送单路 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
|
||||
```
|
||||
|
||||
### 4.3 启动测试程序
|
||||
|
||||
```bash
|
||||
cd /home/orangepi/apps/OrangePi3588Media
|
||||
|
||||
# 启动 media-server
|
||||
./build/media-server --config configs/stress_test_4ch_shared_source.json
|
||||
```
|
||||
|
||||
### 4.4 监控脚本
|
||||
|
||||
创建监控脚本 `monitor_4ch.sh`:
|
||||
|
||||
```bash
|
||||
#!/bin/bash
|
||||
|
||||
LOG_FILE="stress_test_4ch_$(date +%Y%m%d_%H%M%S).log"
|
||||
|
||||
echo "Time,CPU%,MemMB,NPU%,Temp°C" > $LOG_FILE
|
||||
|
||||
while true; do
|
||||
TIME=$(date '+%H:%M:%S')
|
||||
|
||||
# CPU 使用率
|
||||
CPU=$(top -bn1 | grep "Cpu(s)" | awk '{print $2}' | cut -d'%' -f1)
|
||||
|
||||
# 内存使用 (MB)
|
||||
MEM=$(free -m | awk 'NR==2{printf "%.0f", $3}')
|
||||
|
||||
# NPU 使用率
|
||||
NPU=$(cat /sys/kernel/debug/rknpu/load 2>/dev/null || echo "0")
|
||||
|
||||
# CPU 温度
|
||||
TEMP=$(cat /sys/class/thermal/thermal_zone0/temp 2>/dev/null | awk '{print $1/1000}')
|
||||
|
||||
echo "$TIME,$CPU,$MEM,$NPU,$TEMP" >> $LOG_FILE
|
||||
echo "[$TIME] CPU:${CPU}% Mem:${MEM}MB NPU:${NPU}% Temp:${TEMP}°C"
|
||||
|
||||
sleep 5
|
||||
done
|
||||
```
|
||||
|
||||
运行监控:
|
||||
```bash
|
||||
chmod +x monitor_4ch.sh
|
||||
./monitor_4ch.sh
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 5. 测试结果验证方法
|
||||
|
||||
### 5.1 功能验证
|
||||
|
||||
| 验证项 | 方法 | 通过标准 |
|
||||
|--------|------|----------|
|
||||
| **输入连接** | 查看日志 | 4 路都显示 "connected" |
|
||||
| **视频输出** | VLC 播放 | `rtsp://<rk3588_ip>:8555/live/cam1` ~ `:8558/live/cam4` 都能正常播放 |
|
||||
| **HLS 输出** | 浏览器/播放器 | 4 路 HLS 流可正常播放 |
|
||||
| **目标检测** | 观察 OSD 输出 | 画面中出现检测框和 "person" 标签 |
|
||||
| **人脸识别** | 观察 OSD 输出 | 人脸被框选,显示姓名或 "unknown" |
|
||||
| **目标跟踪** | 观察 OSD 输出 | 同一目标的 ID 保持稳定 |
|
||||
| **报警触发** | 查看日志 | alarm 节点输出 "person_detect" 或 "unknown_face" |
|
||||
| **MinIO 上传** | 检查 MinIO | `stress-test` bucket 中有截图/录像文件 |
|
||||
| **4路并发** | 同时播放4路输出 | 4路输出画面都流畅,无明显卡顿 |
|
||||
|
||||
### 5.2 性能验证
|
||||
|
||||
| 指标 | 测量方法 | 通过标准 |
|
||||
|------|----------|----------|
|
||||
| **帧率** | 日志中 node_output_fps | ≥ 25 fps(每路) |
|
||||
| **延迟** | 对比输入输出时间戳 | ≤ 500ms |
|
||||
| **NPU 利用率** | `/sys/kernel/debug/rknpu/load` | 50-90% |
|
||||
| **CPU 占用** | `top` 命令 | ≤ 50% |
|
||||
| **内存占用** | `free` 命令 | ≤ 2.5GB |
|
||||
| **队列积压** | 日志中 queue_length | 不持续增长 |
|
||||
|
||||
### 5.3 稳定性验证
|
||||
|
||||
| 测试项 | 时长 | 通过标准 |
|
||||
|--------|------|----------|
|
||||
| **短稳测试** | 1 小时 | 无崩溃,无内存泄漏 |
|
||||
| **中稳测试** | 8 小时 | 性能指标稳定,无异常重启 |
|
||||
| **长稳测试** | 24 小时 | 无崩溃,内存增长 < 100MB |
|
||||
|
||||
### 5.4 验证命令示例
|
||||
|
||||
```bash
|
||||
# 1. 检查 4 路进程状态
|
||||
ps aux | grep media-server
|
||||
|
||||
# 2. 查看 NPU 负载
|
||||
watch -n 1 cat /sys/kernel/debug/rknpu/load
|
||||
|
||||
# 3. 查看资源使用
|
||||
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 &
|
||||
|
||||
# 5. 检查 HLS 文件生成
|
||||
ls -la web/hls/cam*/
|
||||
|
||||
# 6. 查看日志中的报警
|
||||
tail -f media-server.log | grep alarm
|
||||
|
||||
# 7. 检查 MinIO 上传(在 10.0.0.49 上)
|
||||
mc ls myminio/stress-test
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 6. 预期结果
|
||||
|
||||
### 6.1 正常情况
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────┐
|
||||
│ 4 路 720p 全流程测试预期结果 │
|
||||
├─────────────────────────────────────────────────────────┤
|
||||
│ • 4 路视频正常解码、处理、输出 │
|
||||
│ • 端到端延迟: 200-400ms │
|
||||
│ • NPU 利用率: 70-90% │
|
||||
│ • CPU 占用: 30-50% │
|
||||
│ • 内存占用: 1.5-2.5GB │
|
||||
│ • 无丢帧或轻微丢帧 (< 1%) │
|
||||
│ • 报警功能正常触发,MinIO上传成功 │
|
||||
│ • 4路输出画面质量一致 │
|
||||
└─────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
### 6.2 性能数据记录表
|
||||
|
||||
| 指标 | 测试前 | 1小时 | 8小时 | 24小时 |
|
||||
|------|--------|-------|-------|--------|
|
||||
| CPU 平均占用 | - | | | |
|
||||
| CPU 峰值占用 | - | | | |
|
||||
| 内存占用 (MB) | - | | | |
|
||||
| NPU 平均利用率 | - | | | |
|
||||
| NPU 峰值利用率 | - | | | |
|
||||
| 平均延迟 (ms) | - | | | |
|
||||
| 帧率 cam1 (fps) | - | | | |
|
||||
| 帧率 cam2 (fps) | - | | | |
|
||||
| 帧率 cam3 (fps) | - | | | |
|
||||
| 帧率 cam4 (fps) | - | | | |
|
||||
| 报警次数 (目标) | - | | | |
|
||||
| 报警次数 (人脸) | - | | | |
|
||||
| MinIO 文件数 | - | | | |
|
||||
| 异常重启次数 | - | | | |
|
||||
|
||||
### 6.3 输出验证清单
|
||||
|
||||
- [ ] 4 路 RTSP 流均可正常播放
|
||||
- [ ] 4 路 HLS 流均可正常播放
|
||||
- [ ] 画面中有检测框(OSD 正常工作)
|
||||
- [ ] 检测到人脸时显示姓名或 "unknown"
|
||||
- [ ] 目标 ID 保持稳定(跟踪正常工作)
|
||||
- [ ] 日志中有报警输出
|
||||
- [ ] MinIO `stress-test` bucket 中有文件上传
|
||||
- [ ] 无 Error/Warning 刷屏
|
||||
|
||||
---
|
||||
|
||||
## 7. 故障排查
|
||||
|
||||
### 7.1 常见问题
|
||||
|
||||
| 现象 | 可能原因 | 解决方法 |
|
||||
|------|----------|----------|
|
||||
| **启动失败** | NPU 驱动未加载 | `ls /dev/rknpu` 检查,重新加载驱动 |
|
||||
| **拉流失败** | 网络不通/视频源问题 | 检查网络,`ping 10.0.0.49`,验证 RTSP 流 |
|
||||
| **高 CPU 占用** | RGA 未启用 | 检查配置 `use_rga: true`,`use_mpp: true` |
|
||||
| **高延迟** | 队列积压 | 检查 `queue.size`,适当调小 |
|
||||
| **NPU 利用率低** | 推理频率设置过低 | 调整 `infer_fps` |
|
||||
| **4路中某路无输出** | 端口冲突 | 检查端口 8555-8558 是否被占用 |
|
||||
| **OSD 不显示** | 格式不支持 | 确保 OSD 输入为 RGB/BGR/NV12 格式 |
|
||||
| **MinIO 上传失败** | 网络/认证问题 | 检查 MinIO 地址和账号密码 |
|
||||
|
||||
### 7.2 调试命令
|
||||
|
||||
```bash
|
||||
# 查看 NPU 状态
|
||||
cat /sys/kernel/debug/rknpu/version
|
||||
cat /sys/kernel/debug/rknpu/load
|
||||
|
||||
# 查看 RGA 状态
|
||||
cat /sys/kernel/debug/rga/info
|
||||
|
||||
# 查看进程资源使用
|
||||
pidof media-server | xargs -I {} ps -p {} -o pid,ppid,cmd,%cpu,%mem
|
||||
|
||||
# 查看线程数
|
||||
ps -eLf | grep media-server | wc -l
|
||||
|
||||
# 查看端口占用
|
||||
netstat -tlnp | grep media-server
|
||||
|
||||
# 查看系统日志
|
||||
sudo dmesg | tail -50
|
||||
```
|
||||
|
||||
### 7.3 日志分析
|
||||
|
||||
```bash
|
||||
# 检查错误
|
||||
grep -i "error\|fail\|warn" media-server.log | head -20
|
||||
|
||||
# 检查各路口连接状态
|
||||
grep "input_rtsp\|connected\|disconnected" media-server.log
|
||||
|
||||
# 检查帧率
|
||||
grep "output_fps" media-server.log | tail -20
|
||||
|
||||
# 检查报警触发
|
||||
grep "alarm" media-server.log | tail -20
|
||||
|
||||
# 检查 MinIO 上传
|
||||
grep "minio\|snapshot\|clip" media-server.log | tail -20
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 8. 测试报告模板
|
||||
|
||||
### 8.1 基本信息
|
||||
|
||||
- **测试时间**:
|
||||
- **测试人员**:
|
||||
- **设备型号**:
|
||||
- **固件版本**:
|
||||
- **软件版本**:
|
||||
- **视频源**: `rtsp://10.0.0.49:8554/test` (1280×720@30fps)
|
||||
- **MinIO**: `http://10.0.0.49:9000`, bucket: `stress-test`
|
||||
|
||||
### 8.2 测试结论
|
||||
|
||||
- [ ] 4 路全流程测试通过
|
||||
- [ ] 性能指标达标
|
||||
- [ ] 稳定性测试通过
|
||||
- [ ] MinIO 上传功能正常
|
||||
|
||||
### 8.3 详细数据
|
||||
|
||||
(填入第 6 章的表格数据)
|
||||
|
||||
### 8.4 问题记录
|
||||
|
||||
| 序号 | 问题描述 | 严重程度 | 状态 |
|
||||
|------|----------|----------|------|
|
||||
| 1 | | | |
|
||||
| 2 | | | |
|
||||
|
||||
### 8.5 优化建议
|
||||
|
||||
(根据测试结果填写)
|
||||
|
||||
---
|
||||
|
||||
## 9. 附录
|
||||
|
||||
### 9.1 快速开始
|
||||
|
||||
```bash
|
||||
# 1. 准备环境
|
||||
cd /home/orangepi/apps/OrangePi3588Media
|
||||
mkdir -p web/hls/cam{1,2,3,4}
|
||||
|
||||
# 2. 确认模型存在
|
||||
ls models/yolov8n-640.rknn models/RetinaFace_mobile320.rknn \
|
||||
models/mobilefacenet_arcface.rknn models/face_gallery.db
|
||||
|
||||
# 3. 启动测试
|
||||
./build/media-server --config configs/stress_test_4ch_shared_source.json
|
||||
|
||||
# 4. 另开终端监控
|
||||
./monitor_4ch.sh
|
||||
|
||||
# 5. 验证输出
|
||||
ffplay rtsp://localhost:8555/live/cam1
|
||||
```
|
||||
|
||||
### 9.2 相关文档
|
||||
|
||||
- [Readme.md](../Readme.md) - 项目总览
|
||||
- [deployment.md](deployment.md) - 部署说明
|
||||
- [dag_graph_node_edge.md](architecture/dag_graph_node_edge.md) - 架构说明
|
||||
|
||||
### 9.3 配置文件清单
|
||||
|
||||
| 文件 | 说明 |
|
||||
|------|------|
|
||||
| `configs/stress_test_4ch_shared_source.json` | 4路全流程测试配置(共享源,与 sample_cam2.json 一致) |
|
||||
| `monitor_4ch.sh` | 资源监控脚本 |
|
||||
BIN
models/best-640.rknn
Normal file
BIN
models/best-640.rknn
Normal file
Binary file not shown.
BIN
models/yolov5s-640-640.rknn
Normal file
BIN
models/yolov5s-640-640.rknn
Normal file
Binary file not shown.
BIN
models/yolov8n-640.rknn
Normal file
BIN
models/yolov8n-640.rknn
Normal file
Binary file not shown.
1206
scripts/d8_1.py
Normal file
1206
scripts/d8_1.py
Normal file
File diff suppressed because it is too large
Load Diff
186
scripts/mock_alarm_server.py
Executable file
186
scripts/mock_alarm_server.py
Executable file
@ -0,0 +1,186 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
模拟告警服务器
|
||||
用于测试 RK3588 Media Server 的 alarm 节点 external_api 功能
|
||||
|
||||
提供两个接口:
|
||||
1. POST /api/getToken - 获取访问令牌
|
||||
2. POST /api/putMessage - 接收告警信息
|
||||
|
||||
使用方法:
|
||||
python3 mock_alarm_server.py
|
||||
|
||||
默认监听:0.0.0.0:8080
|
||||
"""
|
||||
|
||||
from flask import Flask, request, jsonify
|
||||
from datetime import datetime
|
||||
import json
|
||||
import sys
|
||||
|
||||
app = Flask(__name__)
|
||||
|
||||
# 模拟 token 存储
|
||||
mock_token = "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.mock_token_for_testing"
|
||||
token_expire_time = 30 * 60 # 30分钟过期时间(秒)
|
||||
|
||||
# 统计信息
|
||||
stats = {
|
||||
"token_requests": 0,
|
||||
"alarm_requests": 0,
|
||||
"last_alarm": None
|
||||
}
|
||||
|
||||
|
||||
@app.route('/api/getToken', methods=['POST'])
|
||||
def get_token():
|
||||
"""
|
||||
模拟获取 token 接口
|
||||
返回格式与 d8_1.py 中一致
|
||||
"""
|
||||
stats["token_requests"] += 1
|
||||
|
||||
# 打印请求信息
|
||||
print(f"\n[{datetime.now().strftime('%Y-%m-%d %H:%M:%S')}] 收到 Token 请求")
|
||||
print(f" 请求头: {dict(request.headers)}")
|
||||
print(f" 请求体: {request.data.decode('utf-8') if request.data else 'None'}")
|
||||
|
||||
response = {
|
||||
"errorDesc": None,
|
||||
"message": None,
|
||||
"responseBody": {
|
||||
"userInfo": {
|
||||
"username": "szls",
|
||||
"realname": "数字孪生",
|
||||
"deptName": "精密铸造厂",
|
||||
"id": "8a746b7d91deb3270191df35f42e000e"
|
||||
},
|
||||
"expireTime": str(token_expire_time),
|
||||
"token": mock_token,
|
||||
"refreshToken": mock_token + "_refresh"
|
||||
},
|
||||
"retCode": "200"
|
||||
}
|
||||
|
||||
print(f" 响应: 返回 mock token")
|
||||
return jsonify(response)
|
||||
|
||||
|
||||
@app.route('/api/putMessage', methods=['POST'])
|
||||
def put_message():
|
||||
"""
|
||||
模拟接收告警信息接口
|
||||
接收格式与 d8_1.py 中 send_post_request 一致
|
||||
"""
|
||||
stats["alarm_requests"] += 1
|
||||
|
||||
# 获取请求头中的 token
|
||||
token = request.headers.get('X-Access-Token', 'None')
|
||||
|
||||
# 解析请求体
|
||||
try:
|
||||
data = request.json if request.is_json else json.loads(request.data)
|
||||
except:
|
||||
data = {}
|
||||
|
||||
# 打印告警信息
|
||||
print(f"\n[{datetime.now().strftime('%Y-%m-%d %H:%M:%S')}] 收到告警信息")
|
||||
print(f" Token: {token[:30]}...")
|
||||
print(f" 租户代码: {data.get('tenantCode', 'N/A')}")
|
||||
print(f" 频道号: {data.get('channelNo', 'N/A')}")
|
||||
print(f" 告警内容: {data.get('alarmContent', 'N/A')}")
|
||||
print(f" 告警时间: {data.get('alarmTime', 'N/A')}")
|
||||
|
||||
# 打印图片/视频信息
|
||||
pic_info = data.get('picInfo', [])
|
||||
video_info = data.get('videoInfo', [])
|
||||
|
||||
if pic_info:
|
||||
print(f" 图片地址: {len(pic_info)} 张")
|
||||
for i, pic in enumerate(pic_info[:3]): # 只打印前3个
|
||||
print(f" [{i+1}] {pic.get('url', 'N/A')}")
|
||||
if len(pic_info) > 3:
|
||||
print(f" ... 还有 {len(pic_info) - 3} 张")
|
||||
|
||||
if video_info:
|
||||
print(f" 视频地址: {len(video_info)} 个")
|
||||
for i, video in enumerate(video_info[:3]):
|
||||
print(f" [{i+1}] {video.get('url', 'N/A')}")
|
||||
|
||||
# 更新统计
|
||||
stats["last_alarm"] = {
|
||||
"time": datetime.now().strftime('%Y-%m-%d %H:%M:%S'),
|
||||
"content": data.get('alarmContent', 'N/A'),
|
||||
"channel": data.get('channelNo', 'N/A')
|
||||
}
|
||||
|
||||
# 返回成功响应
|
||||
response = {
|
||||
"responseBody": "1",
|
||||
"message": None,
|
||||
"retCode": "200",
|
||||
"errorDesc": None
|
||||
}
|
||||
|
||||
print(f" 响应: 告警接收成功")
|
||||
return jsonify(response)
|
||||
|
||||
|
||||
@app.route('/stats', methods=['GET'])
|
||||
def get_stats():
|
||||
"""查看统计信息"""
|
||||
return jsonify({
|
||||
"token_requests": stats["token_requests"],
|
||||
"alarm_requests": stats["alarm_requests"],
|
||||
"last_alarm": stats["last_alarm"]
|
||||
})
|
||||
|
||||
|
||||
@app.route('/', methods=['GET'])
|
||||
def index():
|
||||
"""首页说明"""
|
||||
return """
|
||||
<h1>RK3588 模拟告警服务器</h1>
|
||||
<p>可用接口:</p>
|
||||
<ul>
|
||||
<li><b>POST /api/getToken</b> - 获取访问令牌</li>
|
||||
<li><b>POST /api/putMessage</b> - 接收告警信息</li>
|
||||
<li><b>GET /stats</b> - 查看统计信息</li>
|
||||
</ul>
|
||||
<p>当前统计:</p>
|
||||
<ul>
|
||||
<li>Token 请求次数: {token_requests}</li>
|
||||
<li>告警请求次数: {alarm_requests}</li>
|
||||
</ul>
|
||||
""".format(**stats)
|
||||
|
||||
|
||||
def main():
|
||||
host = "0.0.0.0"
|
||||
port = 8080
|
||||
|
||||
print("=" * 60)
|
||||
print("RK3588 模拟告警服务器")
|
||||
print("=" * 60)
|
||||
print(f"启动时间: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
|
||||
print(f"监听地址: http://{host}:{port}")
|
||||
print("")
|
||||
print("接口列表:")
|
||||
print(f" 1. POST http://{host}:{port}/api/getToken")
|
||||
print(f" 2. POST http://{host}:{port}/api/putMessage")
|
||||
print(f" 3. GET http://{host}:{port}/stats")
|
||||
print("")
|
||||
print("按 Ctrl+C 停止服务")
|
||||
print("=" * 60)
|
||||
|
||||
try:
|
||||
app.run(host=host, port=port, debug=False, threaded=True)
|
||||
except KeyboardInterrupt:
|
||||
print("\n\n服务已停止")
|
||||
print(f"总计 Token 请求: {stats['token_requests']}")
|
||||
print(f"总计告警请求: {stats['alarm_requests']}")
|
||||
sys.exit(0)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
BIN
yolov8n_cxn.onnx
BIN
yolov8n_cxn.onnx
Binary file not shown.
Loading…
Reference in New Issue
Block a user