diff --git a/agent/agent_cam1.config.json b/agent/agent_cam1.config.json index db8b95d..3ba571c 100644 --- a/agent/agent_cam1.config.json +++ b/agent/agent_cam1.config.json @@ -8,18 +8,18 @@ "discovery_port": 35688, "device_name": "cam1_strict_minio_alarm", - "device_id_path": "./device_id", + "device_id_path": "/var/lib/rk3588-agent/device_id", - "models_dir": "./models", + "models_dir": "/opt/rk3588-media-server/models", "max_upload_mb": 200, - "config_path": "./configs/test_cam1_strict_minio_alarm_rtsp_server.json", + "config_path": "/opt/rk3588-media-server/etc/media-server.json", "media_server_process": { "enable": true, - "exec_path": "../build/media-server", - "work_dir": "..", - "configs_dir": "../configs", - "pid_file": "./rk3588sys-media-server.pid", + "exec_path": "/opt/rk3588-media-server/bin/systemctl-wrapper.sh", + "work_dir": "/opt/rk3588-media-server", + "configs_dir": "/opt/rk3588-media-server/etc", + "pid_file": "/var/run/rk3588sys-media-server.pid", "graceful_timeout_ms": 5000 }, "media_server_base_url": "http://127.0.0.1:9000", diff --git a/docs/deployment.md b/docs/deployment.md new file mode 100644 index 0000000..d3e8753 --- /dev/null +++ b/docs/deployment.md @@ -0,0 +1,224 @@ +# RK3588 Media Server 部署指南 + +## 快速开始 + +### 1. 编译 + +在 RK3588 设备上编译: + +```bash +cd ~/apps/OrangePi3588Media + +# 编译 Media Server +mkdir -p build && cd build +cmake .. -DCMAKE_BUILD_TYPE=Release +make -j$(nproc) + +# 编译 Agent(可选,用于 Web 管理) +cd ../agent +GOOS=linux GOARCH=arm64 go build -o rk3588-agent_linux_arm64 ./cmd +``` + +### 2. 安装 + +使用统一脚本安装: + +```bash +cd ~/apps/OrangePi3588Media +sudo ./scripts/manage.sh install +``` + +安装过程会提示: +- **运行模式**: + - `独立模式` - Media Server 由 systemd 直接管理 + - `Agent 模式` - Media Server 由 Agent 管理(推荐,支持 Web 界面) +- **配置文件**: + - `test_cam1_face_det_rtsp_server.json` - 人脸检测(推荐) + - `sample_cam1_native_rtsp_face.json` - 完整功能 + - `test_cam1_face_det_recog_rtsp_server.json` - 人脸识别 + - `sample_cam1.json` - 完整功能(需手动修复) + +### 3. 查看状态 + +```bash +sudo ./scripts/manage.sh status +``` + +显示内容: +- 系统运行时间 +- NPU 负载 +- Media Server 状态(PID、CPU/内存、端口) +- Agent 状态(如果安装) +- 最近日志 + +### 4. 卸载 + +```bash +sudo ./scripts/manage.sh uninstall +``` + +卸载会: +1. 停止所有服务 +2. 删除 systemd 服务文件 +3. 自动备份配置文件和模型到 `/root/rk3588-backup-时间戳/` +4. 提示是否删除安装目录 + +--- + +## 升级 + +升级步骤与安装相同,脚本会自动处理: + +```bash +cd ~/apps/OrangePi3588Media + +# 1. 拉取最新代码(如果是 git 仓库) +git pull + +# 2. 重新编译 +mkdir -p build && cd build +cmake .. -DCMAKE_BUILD_TYPE=Release +make -j$(nproc) + +# 3. 重新安装(会自动备份旧配置) +cd .. +sudo ./scripts/manage.sh install +``` + +--- + +## 管理命令 + +### 独立模式 + +```bash +# 启动/停止/重启 +sudo systemctl start media-server +sudo systemctl stop media-server +sudo systemctl restart media-server + +# 查看状态 +sudo systemctl status media-server + +# 查看日志 +sudo journalctl -u media-server -f +``` + +### Agent 模式 + +```bash +# 启动/停止/重启 +sudo systemctl start rk3588-agent +sudo systemctl stop rk3588-agent +sudo systemctl restart rk3588-agent + +# 查看状态 +sudo systemctl status rk3588-agent + +# 查看日志 +sudo journalctl -u rk3588-agent -f + +# Web 管理界面 +http://<设备IP>:9100 +``` + +--- + +## 配置修改 + +编辑配置文件: + +```bash +sudo nano /opt/rk3588-media-server/etc/media-server.json +``` + +常用修改: +- **修改 RTSP 输入源**:找到 `input_rtsp` 节点,修改 `url` 字段 +- **修改输出端口**:找到 `publish` 节点,修改 `port` 字段 + +修改后重启服务: + +```bash +# 独立模式 +sudo systemctl restart media-server + +# Agent 模式 +sudo systemctl restart rk3588-agent +``` + +--- + +## 目录结构 + +安装后的目录结构: + +``` +/opt/rk3588-media-server/ +├── bin/ +│ ├── media-server # 主程序 +│ └── plugins/ # 插件目录 +│ ├── libinput_rtsp.so +│ ├── libai_yolo.so +│ └── ... +├── lib/ # 依赖库 +├── etc/ +│ └── media-server.json # 配置文件 +├── models/ # AI 模型 +├── logs/ # 日志目录 +└── web/hls/ # HLS 输出目录 + +/opt/rk3588-agent/ # Agent 安装目录(如果使用) +├── rk3588-agent +└── agent.config.json +``` + +--- + +## 故障排查 + +### 服务无法启动 + +```bash +# 查看详细错误 +sudo journalctl -u media-server -n 50 +# 或 +sudo journalctl -u rk3588-agent -n 50 +``` + +### 检查 NPU 是否正常 + +```bash +# 查看 NPU 负载 +cat /sys/kernel/debug/rknpu/load + +# 查看 NPU 驱动 +ls /dev/rknpu +``` + +### RTSP 流无法播放 + +```bash +# 在设备上测试播放 +ffplay rtsp://localhost:8555/live/cam1_face_det + +# 测试输入源 +ffplay rtsp://输入源IP:端口/路径 +``` + +### 端口占用 + +```bash +# 查看端口占用 +sudo ss -tlnp | grep -E "(8554|8555|9000|9100)" +``` + +--- + +## 系统要求 + +- **硬件**: Orange Pi 5 Plus (RK3588) +- **系统**: Ubuntu 22.04 LTS (ARM64) +- **依赖**: + - RKNN Runtime + - MPP (Media Process Platform) + - FFmpeg (带 rkmpp 支持) diff --git a/docs/requirements/guide.md b/docs/requirements/guide.md index 185ec31..0bd844a 100644 --- a/docs/requirements/guide.md +++ b/docs/requirements/guide.md @@ -9,4 +9,13 @@ winget install Gyan.FFmpeg ffmpeg -version - 推流到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 \ No newline at end of file +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 + +- 本地验证RTSP拉流正确 +ffplay rtsp://localhost:8554/cam + +在3588上测试RTSP输出 +ffplay rtsp://localhost:8555/live/cam1_face_det + +- 在 Windows 上用 VLC 播放处理后的流: +rtsp://3588的IP:8555/live/cam1_face_det \ No newline at end of file diff --git a/scripts/manage.sh b/scripts/manage.sh new file mode 100755 index 0000000..8942789 --- /dev/null +++ b/scripts/manage.sh @@ -0,0 +1,439 @@ +#!/bin/bash +# RK3588 Media Server + Agent 统一管理脚本 +# 用法: sudo ./install.sh [install|status|uninstall] + +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" +INSTALL_DIR="/opt/rk3588-media-server" +AGENT_INSTALL_DIR="/opt/rk3588-agent" +SERVICE_DIR="/etc/systemd/system" + +# ==================== 功能函数 ==================== + +cmd_install() { + echo -e "${BLUE}╔════════════════════════════════════════════════════════════╗${NC}" + echo -e "${BLUE}║ RK3588 Media Server + Agent 安装脚本 ║${NC}" + echo -e "${BLUE}╚════════════════════════════════════════════════════════════╝${NC}" + echo "" + + if [ "$EUID" -ne 0 ]; then + echo -e "${RED}错误: 请使用 sudo 运行此脚本${NC}" + exit 1 + fi + + echo "项目目录: $PROJECT_DIR" + echo "Media Server 安装目录: $INSTALL_DIR" + echo "Agent 安装目录: $AGENT_INSTALL_DIR" + echo "" + + # 检查编译产物 + if [ ! -f "$BUILD_DIR/media-server" ]; then + echo -e "${RED}错误: 未找到编译好的 media-server${NC}" + echo "请先编译项目:" + echo " cd $PROJECT_DIR" + echo " cmake -S . -B build -DCMAKE_BUILD_TYPE=Release ..." + echo " cmake --build build -j\$(nproc)" + exit 1 + fi + + # 检查插件 + if [ ! -d "$BUILD_DIR/plugins" ] || [ -z "$(ls -A $BUILD_DIR/plugins/*.so 2>/dev/null)" ]; then + echo -e "${YELLOW}警告: 未找到插件目录或插件为空${NC}" + read -p "是否继续? (y/N): " -n 1 -r + echo + [[ ! $REPLY =~ ^[Yy]$ ]] && exit 1 + fi + + # 检查 agent + AGENT_SOURCE="" + if [ -f "$PROJECT_DIR/agent/rk3588-agent_linux_arm64" ]; then + AGENT_SOURCE="$PROJECT_DIR/agent/rk3588-agent_linux_arm64" + elif [ -f "$PROJECT_DIR/agent/cmd/rk3588-agent" ]; then + AGENT_SOURCE="$PROJECT_DIR/agent/cmd/rk3588-agent" + fi + + if [ -z "$AGENT_SOURCE" ]; then + echo -e "${YELLOW}警告: 未找到编译好的 rk3588-agent${NC}" + echo " 如需 Agent 功能,请先编译:" + echo " cd $PROJECT_DIR/agent" + echo " GOOS=linux GOARCH=arm64 go build -o rk3588-agent_linux_arm64 ./cmd" + fi + + echo -e "${GREEN}✓${NC} 编译产物检查通过" + echo "" + + # 选择模式 + echo "请选择运行模式:" + echo " 1) 独立模式 - Media Server 由 systemd 直接管理 (简单)" + echo " 2) Agent 模式 - Media Server 由 Agent 管理 (推荐,支持 Web 管理)" + echo "" + read -p "请输入选项 [1-2,默认2]: " mode_choice + mode_choice=${mode_choice:-2} + + USE_AGENT=false + if [ "$mode_choice" = "2" ] && [ -n "$AGENT_SOURCE" ]; then + USE_AGENT=true + elif [ "$mode_choice" = "2" ] && [ -z "$AGENT_SOURCE" ]; then + echo -e "${YELLOW}Agent 未编译,使用独立模式${NC}" + fi + echo "" + + # 选择配置文件 + echo "请选择配置文件:" + echo " 1) test_cam1_face_det_rtsp_server.json (人脸检测)" + echo " 2) sample_cam1_native_rtsp_face.json (完整功能)" + echo " 3) test_cam1_face_det_recog_rtsp_server.json (人脸识别)" + echo " 4) sample_cam1.json (完整功能,需手动修复)" + echo "" + read -p "请输入选项 [1-4,默认1]: " choice + choice=${choice:-1} + + case $choice in + 1) CONFIG_FILE="$PROJECT_DIR/configs/test_cam1_face_det_rtsp_server.json" ;; + 2) CONFIG_FILE="$PROJECT_DIR/configs/sample_cam1_native_rtsp_face.json" ;; + 3) CONFIG_FILE="$PROJECT_DIR/configs/test_cam1_face_det_recog_rtsp_server.json" ;; + 4) CONFIG_FILE="$PROJECT_DIR/configs/sample_cam1.json" ;; + *) CONFIG_FILE="$PROJECT_DIR/configs/test_cam1_face_det_rtsp_server.json" ;; + esac + + echo "" + echo -e "运行模式: ${GREEN}$([ "$USE_AGENT" = true ] && echo "Agent 模式" || echo "独立模式")${NC}" + echo "" + + # 安装 Media Server + echo -e "${YELLOW}[1/4] 安装 Media Server...${NC}" + rm -rf "$INSTALL_DIR" + mkdir -p "$INSTALL_DIR"/{bin/plugins,lib,etc,logs,models,web/hls} + + cp "$BUILD_DIR/media-server" "$INSTALL_DIR/bin/" + chmod +x "$INSTALL_DIR/bin/media-server" + + if [ -d "$BUILD_DIR/plugins" ]; then + cp "$BUILD_DIR"/plugins/*.so "$INSTALL_DIR/bin/plugins/" 2>/dev/null || true + fi + + if ls "$BUILD_DIR"/*.so 1> /dev/null 2>&1; then + cp "$BUILD_DIR"/*.so "$INSTALL_DIR/lib/" 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 + fi + if [ -d "$PROJECT_DIR/models" ]; then + cp -r "$PROJECT_DIR/models"/* "$INSTALL_DIR/models/" 2>/dev/null || true + fi + + # 处理配置 + cp "$CONFIG_FILE" "$INSTALL_DIR/etc/media-server.json" + python3 << EOF +import json, os +config_file = "$INSTALL_DIR/etc/media-server.json" +install_dir = "$INSTALL_DIR" +project_dir = "$PROJECT_DIR" + +def fix_path(path): + if not path or not isinstance(path, str): + return path + if path.startswith('./'): + if path.startswith('./web/'): + return os.path.join(install_dir, path[2:]) + elif path.startswith('./models/'): + return os.path.join(install_dir, path[2:]) + else: + abs_path = os.path.join(project_dir, path) + if os.path.exists(abs_path): + return abs_path + return os.path.join(install_dir, path[2:]) + return path + +try: + with open(config_file, 'r') as f: + config = json.load(f) + for graph in config.get('graphs', []): + nodes = graph.get('nodes', []) + edges = graph.get('edges', []) + node_ids = {node['id'] for node in nodes} + nodes_with_input = set() + for edge in edges: + if isinstance(edge, list) and len(edge) >= 2: + nodes_with_input.add(edge[1]) + for node in nodes: + if node.get('role') in ['filter', 'sink'] and node['id'] not in nodes_with_input: + if node.get('enable', True): + node['enable'] = False + if 'model_path' in node: + node['model_path'] = fix_path(node['model_path']) + if 'gallery' in node and 'path' in node['gallery']: + node['gallery']['path'] = fix_path(node['gallery']['path']) + if 'outputs' in node: + for output in node['outputs']: + if 'path' in output: + output['path'] = fix_path(output['path']) + with open(config_file, 'w') as f: + json.dump(config, f, indent=2) + print("配置处理完成") +except Exception as e: + print(f"配置处理出错: {e}") +EOF + echo -e "${GREEN}✓${NC} Media Server 安装完成" + + # 安装 Agent + if [ "$USE_AGENT" = true ] && [ -n "$AGENT_SOURCE" ]; then + echo -e "${YELLOW}[2/4] 安装 Agent...${NC}" + rm -rf "$AGENT_INSTALL_DIR" + mkdir -p "$AGENT_INSTALL_DIR" + mkdir -p "/var/lib/rk3588-agent" + + cp "$AGENT_SOURCE" "$AGENT_INSTALL_DIR/rk3588-agent" + chmod +x "$AGENT_INSTALL_DIR/rk3588-agent" + + cat > "$AGENT_INSTALL_DIR/agent.config.json" << 'AGENT_CONFIG' +{ + "agent": { + "listen": "0.0.0.0:9100", + "token": "CHANGE_ME", + "require_token_for_read": false, + "discovery_enable": true, + "discovery_port": 35688, + "device_name": "rk3588_cam1", + "device_id_path": "/var/lib/rk3588-agent/device_id", + "models_dir": "/opt/rk3588-media-server/models", + "max_upload_mb": 200, + "config_path": "/opt/rk3588-media-server/etc/media-server.json", + "media_server_process": { + "enable": true, + "exec_path": "/opt/rk3588-media-server/bin/media-server", + "work_dir": "/opt/rk3588-media-server", + "configs_dir": "/opt/rk3588-media-server/etc", + "pid_file": "/var/run/rk3588sys-media-server.pid", + "graceful_timeout_ms": 5000 + }, + "media_server_base_url": "http://127.0.0.1:9000", + "media_server_timeout_ms": 3000, + "media_server_retry": { "max_attempts": 3, "backoff_ms": [200, 500] } + } +} +AGENT_CONFIG + chown -R orangepi:orangepi "/var/lib/rk3588-agent" + chmod 755 "$AGENT_INSTALL_DIR" + echo -e "${GREEN}✓${NC} Agent 安装完成" + fi + + # 安装服务 + echo -e "${YELLOW}[3/4] 安装 Systemd 服务...${NC}" + + cat > "$SERVICE_DIR/media-server.service" << 'EOF' +[Unit] +Description=RK3588 Media Server +After=network.target + +[Service] +Type=simple +User=root +WorkingDirectory=/opt/rk3588-media-server +ExecStart=/opt/rk3588-media-server/bin/media-server --config /opt/rk3588-media-server/etc/media-server.json +Restart=always +RestartSec=5 +StandardOutput=journal +StandardError=journal + +[Install] +WantedBy=multi-user.target +EOF + + if [ "$USE_AGENT" = true ] && [ -n "$AGENT_SOURCE" ]; then + cat > "$SERVICE_DIR/rk3588-agent.service" << 'EOF' +[Unit] +Description=RK3588 Agent Service +After=network.target + +[Service] +Type=simple +User=root +WorkingDirectory=/opt/rk3588-agent +ExecStart=/opt/rk3588-agent/rk3588-agent --config /opt/rk3588-agent/agent.config.json +Restart=always +RestartSec=5 +StandardOutput=journal +StandardError=journal + +[Install] +WantedBy=multi-user.target +EOF + fi + + systemctl daemon-reload + touch /var/run/rk3588sys-media-server.pid + chmod 666 /var/run/rk3588sys-media-server.pid + echo -e "${GREEN}✓${NC} 服务安装完成" + + # 启动服务 + echo -e "${YELLOW}[4/4] 启动服务...${NC}" + if [ "$USE_AGENT" = true ] && [ -n "$AGENT_SOURCE" ]; then + systemctl disable media-server 2>/dev/null || true + systemctl stop media-server 2>/dev/null || true + systemctl enable rk3588-agent + systemctl start rk3588-agent + else + systemctl enable media-server + systemctl start media-server + fi + echo -e "${GREEN}✓${NC} 服务已启动" + + # 完成 + echo "" + echo -e "${GREEN}╔════════════════════════════════════════════════════════════╗${NC}" + echo -e "${GREEN}║ 安装完成! ║${NC}" + echo -e "${GREEN}╚════════════════════════════════════════════════════════════╝${NC}" + echo "" + if [ "$USE_AGENT" = true ] && [ -n "$AGENT_SOURCE" ]; then + echo "管理命令:" + echo " 状态: sudo $0 status" + echo " 日志: sudo journalctl -u rk3588-agent -f" + echo " 界面: http://<设备IP>:9100" + else + echo "管理命令:" + echo " 状态: sudo $0 status" + echo " 日志: sudo journalctl -u media-server -f" + fi +} + +cmd_status() { + echo -e "${BLUE}========== RK3588 Media Server 状态 ==========${NC}" + echo "" + + echo -e "${YELLOW}[系统信息]${NC}" + echo " 时间: $(date '+%Y-%m-%d %H:%M:%S')" + echo " 运行时间: $(uptime -p 2>/dev/null || uptime | awk -F',' '{print $1}')" + echo "" + + echo -e "${YELLOW}[NPU 负载]${NC}" + if [ -f /sys/kernel/debug/rknpu/load ]; then + cat /sys/kernel/debug/rknpu/load | sed 's/^/ /' + else + echo " NPU 信息不可用" + fi + echo "" + + 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 2>/dev/null) + 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 | sed 's/^/ /' + else + echo -e " 状态: ${RED}○ 停止${NC}" + fi + echo "" + + if systemctl list-unit-files 2>/dev/null | grep -q rk3588-agent; then + 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 2>/dev/null) + 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 " 管理界面: http://$(hostname -I | awk '{print $1}'):9100" + else + echo -e " 状态: ${RED}○ 停止${NC}" + fi + echo "" + fi + + echo -e "${YELLOW}[最近日志]${NC}" + if systemctl is-active --quiet rk3588-agent 2>/dev/null; then + journalctl -u rk3588-agent --no-pager -n 5 2>/dev/null | tail -5 || echo " 无日志" + else + journalctl -u media-server --no-pager -n 5 2>/dev/null | tail -5 || echo " 无日志" + fi + echo "" + + echo "常用命令:" + echo " 重启: sudo systemctl restart media-server|rk3588-agent" + echo " 日志: sudo journalctl -u media-server|rk3588-agent -f" + echo " 配置: sudo nano /opt/rk3588-media-server/etc/media-server.json" +} + +cmd_uninstall() { + echo -e "${YELLOW}========== RK3588 Media Server 卸载 ==========${NC}" + echo "" + + if [ "$EUID" -ne 0 ]; then + echo -e "${RED}错误: 请使用 sudo 运行${NC}" + exit 1 + fi + + read -p "确定要卸载并停止所有服务? (y/N): " -n 1 -r + echo + [[ ! $REPLY =~ ^[Yy]$ ]] && echo "已取消" && exit 0 + + echo "[1/3] 停止服务..." + systemctl stop media-server rk3588-agent 2>/dev/null || true + systemctl disable media-server rk3588-agent 2>/dev/null || true + echo -e "${GREEN}✓${NC} 服务已停止" + + echo "[2/3] 删除服务文件..." + rm -f "$SERVICE_DIR/media-server.service" + rm -f "$SERVICE_DIR/rk3588-agent.service" + systemctl daemon-reload + echo -e "${GREEN}✓${NC} 服务文件已删除" + + echo "[3/3] 备份并清理..." + BACKUP_DIR="/root/rk3588-backup-$(date +%Y%m%d%H%M%S)" + mkdir -p "$BACKUP_DIR" + [ -f "$INSTALL_DIR/etc/media-server.json" ] && cp "$INSTALL_DIR/etc/media-server.json" "$BACKUP_DIR/" + [ -d "$INSTALL_DIR/models" ] && cp -r "$INSTALL_DIR/models" "$BACKUP_DIR/" 2>/dev/null || true + echo -e "${GREEN}✓${NC} 配置已备份到: $BACKUP_DIR" + + read -p "是否删除安装目录? (y/N): " -n 1 -r + echo + if [[ $REPLY =~ ^[Yy]$ ]]; then + rm -rf "$INSTALL_DIR" "$AGENT_INSTALL_DIR" + echo -e "${GREEN}✓${NC} 目录已删除" + else + echo "保留目录,手动删除: sudo rm -rf $INSTALL_DIR $AGENT_INSTALL_DIR" + fi + + echo "" + echo -e "${GREEN}卸载完成${NC}" +} + +# ==================== 主入口 ==================== + +case "${1:-install}" in + install) + cmd_install + ;; + status) + cmd_status + ;; + uninstall) + cmd_uninstall + ;; + *) + echo "用法: sudo ./manage.sh [install|status|uninstall]" + echo "" + echo "命令:" + echo " install - 安装/更新 Media Server 和 Agent (默认)" + echo " status - 查看运行状态" + echo " uninstall - 卸载服务" + exit 1 + ;; +esac diff --git a/scripts/systemd/README.md b/scripts/systemd/README.md deleted file mode 100644 index a5bbb14..0000000 --- a/scripts/systemd/README.md +++ /dev/null @@ -1,150 +0,0 @@ -# RK3588 Media Server Systemd 部署脚本 - -本目录包含 RK3588 Media Server 的完整 systemd 部署方案,适用于 Orange Pi 5 Plus。 - -## 文件说明 - -| 文件 | 用途 | -|------|------| -| `install.sh` | **主安装脚本** - 一键安装media-server到systemd | -| `uninstall.sh` | 卸载脚本 | -| `status.sh` | 状态查看脚本 | -| `media-server.service` | Systemd服务文件 | -| `rk3588-agent.service` | Agent服务文件(可选) | - -## 快速开始 - -### 1. 编译项目 - -确保已编译项目: - -```bash -cd /path/to/OrangePi3588Media -cmake -S . -B build \ - -DCMAKE_BUILD_TYPE=Release \ - -DBUILD_TESTS=OFF \ - -DRK3588_ENABLE_FFMPEG=ON \ - -DRK3588_ENABLE_MPP=ON \ - -DRK3588_ENABLE_RGA=ON \ - -DRK3588_ENABLE_RKNN=ON -cmake --build build -j$(nproc) -``` - -### 2. 安装服务 - -```bash -cd /path/to/OrangePi3588Media -sudo ./scripts/systemd/install.sh -``` - -安装脚本会: -1. 自动选择配置文件(推荐用 `test_cam1_face_det_rtsp_server.json`) -2. 复制主程序和**所有插件**到 `/opt/rk3588-media-server/` -3. 复制模型文件 -4. **自动修复配置文件**(处理路径、禁用无输入的gate节点) -5. 安装并启动systemd服务 - -### 3. 修改RTSP源地址 - -编辑配置文件,修改为你的RTSP源: - -```bash -sudo nano /opt/rk3588-media-server/etc/media-server.json -``` - -找到 `"url": "rtsp://..."`,改成你的摄像头/推流地址。 - -### 4. 管理服务 - -```bash -# 查看状态 -sudo ./scripts/systemd/status.sh - -# 或手动管理 -sudo systemctl start media-server # 启动 -sudo systemctl stop media-server # 停止 -sudo systemctl restart media-server # 重启 -sudo systemctl status media-server # 查看状态 - -# 查看日志 -sudo journalctl -u media-server -f # 实时跟踪 -sudo journalctl -u media-server -n 100 # 最近100行 -``` - -## 目录结构 - -安装后的目录结构: - -``` -/opt/rk3588-media-server/ -├── bin/ -│ ├── media-server # 主程序 -│ └── plugins/ # 插件目录 -│ ├── libinput_rtsp.so -│ ├── libpublish.so -│ ├── libpreprocess.so -│ ├── libai_yolo.so -│ └── ... -├── lib/ # 依赖库 -├── etc/ -│ └── media-server.json # 配置文件 -├── models/ # 模型文件 -│ ├── yolov5s-640-640.rknn -│ └── ... -├── web/hls/ # HLS输出目录 -└── logs/ # 日志目录 -``` - -## 故障排查 - -### 服务启动失败 - -```bash -# 1. 查看详细错误 -sudo journalctl -u media-server -n 50 --no-pager - -# 2. 检查插件是否存在 -ls -la /opt/rk3588-media-server/bin/plugins/ - -# 3. 检查模型文件 -ls -la /opt/rk3588-media-server/models/ - -# 4. 直接运行看错误 -sudo /opt/rk3588-media-server/bin/media-server --config /opt/rk3588-media-server/etc/media-server.json -``` - -### 常见错误 - -**错误1**: `Failed to load plugin 'input_rtsp': ... No such file or directory` -- 原因:插件未复制 -- 解决:重新运行 `sudo ./scripts/systemd/install.sh` - -**错误2**: `Node gate_face_cam1 role=filter must have input` -- 原因:配置文件中的gate节点没有输入连接 -- 解决:安装时选择 `test_cam1_face_det_rtsp_server.json`(选项1),或手动禁用该节点 - -**错误3**: `Failed to open input: Connection refused` -- 原因:RTSP源无法连接 -- 解决:检查RTSP源地址和端口 - -## 卸载 - -```bash -sudo ./scripts/systemd/uninstall.sh -``` - -会保留配置备份到 `/root/rk3588-backup-xxx/`。 - -## 更新配置 - -修改配置后重启服务: - -```bash -sudo nano /opt/rk3588-media-server/etc/media-server.json -sudo systemctl restart media-server -``` - -## 相关文档 - -- [命令.md](../../docs/命令.md) - 开发和部署命令参考 -- [API_Device_RemoteMgmt_InterfaceTable.md](../../API_Device_RemoteMgmt_InterfaceTable.md) - Agent API文档 diff --git a/scripts/systemd/install.sh b/scripts/systemd/install.sh deleted file mode 100644 index 992b9ef..0000000 --- a/scripts/systemd/install.sh +++ /dev/null @@ -1,271 +0,0 @@ -#!/bin/bash -# RK3588 Media Server 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' - -echo -e "${BLUE}╔════════════════════════════════════════════════════════════╗${NC}" -echo -e "${BLUE}║ RK3588 Media Server Systemd 安装脚本 ║${NC}" -echo -e "${BLUE}╚════════════════════════════════════════════════════════════╝${NC}" -echo "" - -# 检查 root 权限 -if [ "$EUID" -ne 0 ]; then - echo -e "${RED}错误: 请使用 sudo 运行此脚本${NC}" - exit 1 -fi - -# 确定项目目录 -SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" -PROJECT_DIR="$(cd "$SCRIPT_DIR/../.." && pwd)" -BUILD_DIR="$PROJECT_DIR/build" -INSTALL_DIR="/opt/rk3588-media-server" -SERVICE_DIR="/etc/systemd/system" - -echo "项目目录: $PROJECT_DIR" -echo "安装目录: $INSTALL_DIR" -echo "" - -# 检查编译产物 -if [ ! -f "$BUILD_DIR/media-server" ]; then - echo -e "${RED}错误: 未找到编译好的 media-server${NC}" - echo "请先编译项目:" - echo " cd $PROJECT_DIR" - echo " cmake -S . -B build -DCMAKE_BUILD_TYPE=Release ..." - echo " cmake --build build -j\$(nproc)" - exit 1 -fi - -# 检查插件 -if [ ! -d "$BUILD_DIR/plugins" ] || [ -z "$(ls -A $BUILD_DIR/plugins/*.so 2>/dev/null)" ]; then - echo -e "${YELLOW}警告: 未找到插件目录或插件为空${NC}" - echo "请确保编译了插件: cmake --build build -j\$(nproc)" - read -p "是否继续? (y/N): " -n 1 -r - echo - [[ ! $REPLY =~ ^[Yy]$ ]] && exit 1 -fi - -echo -e "${GREEN}✓${NC} 编译产物检查通过" -echo "" - -# 选择配置文件 -echo "请选择配置文件:" -echo "" -echo " 1) test_cam1_face_det_rtsp_server.json (推荐 - 简单稳定,无gate问题)" -echo " 2) sample_cam1_native_rtsp_face.json (完整功能 - YOLO+人脸检测+识别)" -echo " 3) test_cam1_face_det_recog_rtsp_server.json (人脸识别)" -echo " 4) sample_cam1.json (完整功能 - 需要手动禁用gate_face_cam1)" -echo "" -read -p "请输入选项 [1-4,默认1]: " choice -choice=${choice:-1} - -case $choice in - 1) - CONFIG_FILE="$PROJECT_DIR/configs/test_cam1_face_det_rtsp_server.json" - CONFIG_DESC="test_cam1_face_det_rtsp_server.json (简单稳定)" - ;; - 2) - CONFIG_FILE="$PROJECT_DIR/configs/sample_cam1_native_rtsp_face.json" - CONFIG_DESC="sample_cam1_native_rtsp_face.json (完整功能)" - ;; - 3) - CONFIG_FILE="$PROJECT_DIR/configs/test_cam1_face_det_recog_rtsp_server.json" - CONFIG_DESC="test_cam1_face_det_recog_rtsp_server.json (人脸识别)" - ;; - 4) - CONFIG_FILE="$PROJECT_DIR/configs/sample_cam1.json" - CONFIG_DESC="sample_cam1.json (完整功能,需手动修复)" - ;; - *) - echo "无效选项,使用默认配置" - CONFIG_FILE="$PROJECT_DIR/configs/test_cam1_face_det_rtsp_server.json" - CONFIG_DESC="test_cam1_face_det_rtsp_server.json (默认)" - ;; -esac - -echo "" -echo -e "选择配置: ${GREEN}$CONFIG_DESC${NC}" -echo "" - -# 开始安装 -echo -e "${YELLOW}[1/6] 创建安装目录...${NC}" -mkdir -p "$INSTALL_DIR"/{bin/plugins,lib,etc,logs,models,web/hls} -echo -e "${GREEN}✓${NC} 目录创建完成" - -echo -e "${YELLOW}[2/6] 复制主程序和插件...${NC}" -cp "$BUILD_DIR/media-server" "$INSTALL_DIR/bin/" -chmod +x "$INSTALL_DIR/bin/media-server" - -# 复制插件 -if [ -d "$BUILD_DIR/plugins" ]; then - cp "$BUILD_DIR"/plugins/*.so "$INSTALL_DIR/bin/plugins/" 2>/dev/null || true - echo -e "${GREEN}✓${NC} 插件复制完成 ($(ls $INSTALL_DIR/bin/plugins/*.so 2>/dev/null | wc -l) 个)" -else - echo -e "${YELLOW}⚠ 未找到插件目录${NC}" -fi - -# 复制依赖库 -if ls "$BUILD_DIR"/*.so 1> /dev/null 2>&1; then - cp "$BUILD_DIR"/*.so "$INSTALL_DIR/lib/" 2>/dev/null || true - echo -e "${GREEN}✓${NC} 依赖库复制完成" -fi - -echo -e "${YELLOW}[3/6] 复制模型文件...${NC}" -# 复制第三方模型 -if [ -d "$PROJECT_DIR/third_party/rknpu2/examples/rknn_yolov5_demo/model/RK3588" ]; then - mkdir -p "$INSTALL_DIR/models" - cp "$PROJECT_DIR/third_party/rknpu2/examples/rknn_yolov5_demo/model/RK3588"/*.rknn "$INSTALL_DIR/models/" 2>/dev/null || true -fi -# 复制项目模型目录 -if [ -d "$PROJECT_DIR/models" ]; then - cp -r "$PROJECT_DIR/models"/* "$INSTALL_DIR/models/" 2>/dev/null || true -fi -echo -e "${GREEN}✓${NC} 模型文件复制完成" - -echo -e "${YELLOW}[4/6] 处理配置文件...${NC}" -# 复制并修复配置 -cp "$CONFIG_FILE" "$INSTALL_DIR/etc/media-server.json" - -# 使用 Python 修复配置文件中的路径 -python3 << EOF -import json -import os - -config_file = "$INSTALL_DIR/etc/media-server.json" -install_dir = "$INSTALL_DIR" -project_dir = "$PROJECT_DIR" - -def fix_path(path): - if not path or not isinstance(path, str): - return path - if path.startswith('./'): - # web/ 路径指向安装目录 - if path.startswith('./web/'): - return os.path.join(install_dir, path[2:]) - # models/ 路径指向安装目录 - elif path.startswith('./models/'): - return os.path.join(install_dir, path[2:]) - # 其他路径,优先相对于项目目录查找,否则安装目录 - else: - abs_path = os.path.join(project_dir, path) - if os.path.exists(abs_path): - return abs_path - return os.path.join(install_dir, path[2:]) - return path - -try: - with open(config_file, 'r') as f: - config = json.load(f) - - # 修复 sample_cam1.json 中的 gate_face_cam1 问题 - for graph in config.get('graphs', []): - nodes = graph.get('nodes', []) - edges = graph.get('edges', []) - - # 找到所有节点ID - node_ids = {node['id'] for node in nodes} - # 找到有输入边的节点 - nodes_with_input = set() - for edge in edges: - if isinstance(edge, list) and len(edge) >= 2: - nodes_with_input.add(edge[1]) - - # 禁用没有输入的 filter/sink 节点 - for node in nodes: - if node.get('role') in ['filter', 'sink'] and node['id'] not in nodes_with_input: - if node.get('enable', True): - print(f"禁用无输入节点: {node['id']} (role={node.get('role')})") - node['enable'] = False - - # 修复所有路径 - for node in nodes: - if 'model_path' in node: - old = node['model_path'] - node['model_path'] = fix_path(old) - if old != node['model_path']: - print(f"修复路径: {old} -> {node['model_path']}") - - if 'gallery' in node and 'path' in node['gallery']: - old = node['gallery']['path'] - node['gallery']['path'] = fix_path(old) - if old != node['gallery']['path']: - print(f"修复路径: {old} -> {node['gallery']['path']}") - - if 'outputs' in node: - for output in node['outputs']: - if 'path' in output: - old = output['path'] - output['path'] = fix_path(old) - if old != output['path']: - print(f"修复路径: {old} -> {output['path']}") - - with open(config_file, 'w') as f: - json.dump(config, f, indent=2) - - print("配置文件处理完成") -except Exception as e: - print(f"处理配置文件时出错: {e}") - # 保留原始文件 -EOF - -echo -e "${GREEN}✓${NC} 配置文件处理完成" -echo " 配置文件: $INSTALL_DIR/etc/media-server.json" -echo "" - -echo -e "${YELLOW}[5/6] 安装 Systemd 服务...${NC}" -cp "$SCRIPT_DIR/media-server.service" "$SERVICE_DIR/" - -# 重新加载 systemd -systemctl daemon-reload -systemctl enable media-server - -echo -e "${GREEN}✓${NC} Systemd 服务安装完成" - -echo -e "${YELLOW}[6/6] 验证安装...${NC}" -echo "" -echo "安装内容:" -echo " 主程序: $(ls -lh $INSTALL_DIR/bin/media-server | awk '{print $5, $9}')" -echo " 插件数: $(ls $INSTALL_DIR/bin/plugins/*.so 2>/dev/null | wc -l) 个" -echo " 模型数: $(ls $INSTALL_DIR/models/*.rknn 2>/dev/null | wc -l) 个" -echo " 配置: $INSTALL_DIR/etc/media-server.json" -echo "" - -echo -e "${GREEN}╔════════════════════════════════════════════════════════════╗${NC}" -echo -e "${GREEN}║ 安装完成! ║${NC}" -echo -e "${GREEN}╚════════════════════════════════════════════════════════════╝${NC}" -echo "" -echo "管理命令:" -echo " 启动: sudo systemctl start media-server" -echo " 停止: sudo systemctl stop media-server" -echo " 状态: sudo systemctl status media-server" -echo " 日志: sudo journalctl -u media-server -f" -echo "" -echo "重要提示:" -echo " 1. 编辑配置修改RTSP源地址:" -echo " sudo nano $INSTALL_DIR/etc/media-server.json" -echo "" -echo " 2. 确保模型文件存在:" -echo " ls $INSTALL_DIR/models/" -echo "" -echo " 3. 首次启动前检查RTSP源是否可访问" -echo "" - -read -p "是否立即启动服务? (y/N): " -n 1 -r -echo -if [[ $REPLY =~ ^[Yy]$ ]]; then - systemctl start media-server - sleep 2 - if systemctl is-active --quiet media-server; then - echo -e "${GREEN}✓${NC} 服务启动成功!" - systemctl status media-server --no-pager - else - echo -e "${RED}✗${NC} 服务启动失败,查看日志:" - echo " sudo journalctl -u media-server -n 20" - fi -fi diff --git a/scripts/systemd/rk3588-agent.service b/scripts/systemd/rk3588-agent.service deleted file mode 100644 index eaf7309..0000000 --- a/scripts/systemd/rk3588-agent.service +++ /dev/null @@ -1,40 +0,0 @@ -[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 deleted file mode 100644 index 41d1874..0000000 --- a/scripts/systemd/status.sh +++ /dev/null @@ -1,81 +0,0 @@ -#!/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 状态 ==========${NC}" -echo "" - -# 显示系统信息 -echo -e "${YELLOW}[系统信息]${NC}" -echo " 时间: $(date '+%Y-%m-%d %H:%M:%S')" -echo " 运行时间: $(uptime -p 2>/dev/null || uptime | awk -F',' '{print $1}')" -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 2>/dev/null) - 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}" - echo " 最后错误:" - journalctl -u media-server --no-pager -n 3 2>/dev/null | tail -3 | sed 's/^/ /' -fi -echo "" - -# Agent 状态(如果安装了) -if systemctl list-unit-files | grep -q rk3588-agent; then - 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 2>/dev/null) - 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 "" -fi - -# 日志摘要 -echo -e "${YELLOW}[最近日志 - Media Server]${NC}" -journalctl -u media-server --no-pager -n 5 2>/dev/null | tail -5 || 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" -echo " 编辑配置: sudo nano /opt/rk3588-media-server/etc/media-server.json" diff --git a/scripts/systemd/uninstall.sh b/scripts/systemd/uninstall.sh deleted file mode 100644 index ac959bb..0000000 --- a/scripts/systemd/uninstall.sh +++ /dev/null @@ -1,78 +0,0 @@ -#!/bin/bash -# RK3588 Media Server 卸载脚本 - -set -e - -RED='\033[0;31m' -GREEN='\033[0;32m' -YELLOW='\033[1;33m' -NC='\033[0m' - -INSTALL_DIR="${1:-/opt/rk3588-media-server}" - -echo -e "${YELLOW}========== RK3588 Media Server 卸载 ==========${NC}" -echo "安装目录: $INSTALL_DIR" -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 disable media-server 2>/dev/null || true -echo -e "${GREEN}✓${NC} 服务已停止并禁用" - -# 删除服务文件 -echo "[2/4] 删除服务文件..." -rm -f /etc/systemd/system/media-server.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 "$INSTALL_DIR/etc/media-server.json" ]; then - cp "$INSTALL_DIR/etc/media-server.json" "$BACKUP_DIR/" - echo " 已备份配置文件" -fi - -if [ -d "$INSTALL_DIR/models" ]; then - cp -r "$INSTALL_DIR/models" "$BACKUP_DIR/" 2>/dev/null || true - echo " 已备份模型文件" -fi - -echo -e "${GREEN}✓${NC} 配置已备份到: $BACKUP_DIR" - -# 提示删除文件 -echo "[4/4] 清理文件..." -echo "" -echo "以下目录需要手动删除(如需完全清理):" -echo " $INSTALL_DIR/" -echo "" - -read -p "是否删除这些目录? (y/N): " -n 1 -r -echo -if [[ $REPLY =~ ^[Yy]$ ]]; then - rm -rf "$INSTALL_DIR" - echo -e "${GREEN}✓${NC} 目录已删除" -else - echo "保留目录,如需删除请手动执行:" - echo " sudo rm -rf $INSTALL_DIR" -fi - -echo "" -echo -e "${GREEN}卸载完成${NC}" -echo "备份位置: $BACKUP_DIR"