272 lines
9.8 KiB
Bash
272 lines
9.8 KiB
Bash
#!/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
|