diff --git a/scripts/dev-env.ps1 b/scripts/dev-env.ps1 new file mode 100644 index 0000000..0d9cc13 --- /dev/null +++ b/scripts/dev-env.ps1 @@ -0,0 +1,208 @@ +param( + [Parameter(Position = 0)] + [string]$Action = "start", + + [string]$MediaConfig = "configs/sample_cam1.json", + [string]$VideoFile = "", + [string]$SafesightdConfig = "..\safesight-control\safesightd.json" +) + +$ErrorActionPreference = "Stop" + +$scriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path +$edgeDir = (Resolve-Path (Join-Path $scriptDir "..")).Path +$controlDir = (Resolve-Path (Join-Path $edgeDir "..\safesight-control")).Path + +# ── paths ────────────────────────────────────────────── +$mediamtx = "C:\Software\mediamtx\mediamtx.exe" +$ffmpeg = "ffmpeg" +$minio = "C:\Users\Tellme\minio\minio.exe" +$minioData = "C:\Users\Tellme\minio\myminio" +$mockAlarm = Join-Path $scriptDir "mock_alarm_server.py" +$safesightdExe = Join-Path $controlDir "safesightd.exe" +$safesightdConfig = Join-Path $controlDir $SafesightdConfig + +$mediaServerConfig = Join-Path $edgeDir $MediaConfig +$mediaServerExe = Join-Path $edgeDir "build\media-server.exe" + +$rtspUrl = "rtsp://10.0.0.49:8554/cam" +$defaultVideo = "C:\Users\Tellme\Pictures\人脸库\reg_008_unk_011_多人_正面_黑色鞋_白色鞋_1.mp4" + +function Write-Banner { + param([string]$Text) + Write-Host ("`n" + ("=" * 54)) -ForegroundColor Cyan + Write-Host " $Text" -ForegroundColor Cyan + Write-Host ("=" * 54) -ForegroundColor Cyan +} + +function Start-Detached { + param([string]$Name, [string]$Exe, [string[]]$Args) + if (-not (Test-Path $Exe)) { + Write-Host " [SKIP] $Name : 未找到 $Exe" -ForegroundColor Yellow + return $null + } + Write-Host " [START] $Name" -ForegroundColor Green + $proc = Start-Process -FilePath $Exe -ArgumentList $Args -WindowStyle Minimized -PassThru + Start-Sleep -Milliseconds 500 + return $proc +} + +function Stop-ByName { + param([string]$Name) + $procs = Get-Process -Name $Name -ErrorAction SilentlyContinue + if ($procs) { + $procs | Stop-Process -Force + Write-Host " [STOP] $Name" -ForegroundColor DarkYellow + } +} + +# ════════════════════════════════════════════════════════ +# START +# ════════════════════════════════════════════════════════ +function Invoke-Start { + # 1. RTSP server + Write-Banner "1/5 RTSP Server (mediamtx)" + Start-Detached "mediamtx" $mediamtx + + # 2. ffmpeg push + Write-Banner "2/5 RTSP 推流 (ffmpeg)" + $videoToUse = if ($VideoFile -and (Test-Path $VideoFile)) { $VideoFile } elseif (Test-Path $defaultVideo) { $defaultVideo } else { $null } + if ($videoToUse) { + $ffArgs = @("-re", "-stream_loop", "-1", "-i", $videoToUse, + "-c", "copy", "-rtsp_transport", "tcp", "-f", "rtsp", $rtspUrl) + Write-Host " 视频文件: $videoToUse" + } else { + # Try to find a webcam + $webcam = (& $ffmpeg -list_devices true -f dshow -i dummy 2>&1 | + Select-String '\[dshow.*"(.+)"' | + ForEach-Object { $_.Matches.Groups[1].Value } | + Select-Object -First 1) + if ($webcam) { + Write-Host " 摄像头: $webcam" + $ffArgs = @("-f", "dshow", "-rtbufsize", "100M", "-video_size", "1280x720", + "-framerate", "30", "-vcodec", "mjpeg", "-i", "video=$webcam", + "-c:v", "libx264", "-preset", "ultrafast", "-pix_fmt", "yuv420p", + "-f", "rtsp", $rtspUrl) + } else { + Write-Host " [SKIP] 未指定视频文件,也未检测到摄像头" -ForegroundColor Yellow + $ffArgs = $null + } + } + if ($ffArgs) { + Start-Detached "ffmpeg" $ffmpeg $ffArgs + } + + # 3. Media server (edge) + Write-Banner "3/5 Media Server (Edge)" + if (-not (Test-Path $mediaServerExe)) { + Write-Host " [WARN] 未找到 $mediaServerExe,请先编译" -ForegroundColor Yellow + } elseif (-not (Test-Path $mediaServerConfig)) { + Write-Host " [WARN] 未找到配置文件 $mediaServerConfig" -ForegroundColor Yellow + } else { + $msProc = Start-Process -FilePath $mediaServerExe ` + -ArgumentList "-c", $mediaServerConfig ` + -WorkingDirectory $edgeDir ` + -WindowStyle Minimized ` + -PassThru + Write-Host " [START] media-server (PID=$($msProc.Id)) 配置: $MediaConfig" -ForegroundColor Green + } + + # 4. Mock alarm server (if uv available) + Write-Banner "4/5 Mock Alarm Server" + if (Get-Command uv -ErrorAction SilentlyContinue) { + $alarmProc = Start-Process -FilePath "uv" ` + -ArgumentList "run", "--with", "flask", $mockAlarm ` + -WorkingDirectory $scriptDir ` + -WindowStyle Minimized ` + -PassThru + Write-Host " [START] mock_alarm_server (PID=$($alarmProc.Id))" -ForegroundColor Green + } else { + Write-Host " [SKIP] uv 未安装" -ForegroundColor Yellow + } + + # 5. Management server (safesightd) + Write-Banner "5/5 Management Server (safesightd)" + if (Test-Path $safesightdExe) { + Start-Process -FilePath $safesightdExe ` + -ArgumentList $safesightdConfig ` + -WorkingDirectory $controlDir ` + -WindowStyle Minimized + Write-Host " [START] safesightd" -ForegroundColor Green + Write-Host " URL: http://localhost:18080" -ForegroundColor White + } elseif (Get-Command go -ErrorAction SilentlyContinue) { + Write-Host " [START] go run (safesightd 未编译)" -ForegroundColor Green + Start-Process -FilePath "go" ` + -ArgumentList "run", ".\cmd\safesightd\", $safesightdConfig ` + -WorkingDirectory $controlDir ` + -WindowStyle Minimized + } else { + Write-Host " [SKIP] 既无 exe 也无 go" -ForegroundColor Yellow + } + + # 6. MinIO (optional) + Write-Banner "MinIO (object storage)" + if (Test-Path $minio) { + if (-not (Test-Path $minioData)) { New-Item -ItemType Directory -Path $minioData -Force | Out-Null } + Start-Detached "minio" $minio @("server", $minioData, "--address", ":9000", "--console-address", ":9001") + Write-Host " Console: http://localhost:9001 (admin/password)" -ForegroundColor White + } + + # Summary + Write-Banner "全部启动完成" + Write-Host " RTSP 输入: $rtspUrl" + Write-Host " 默认视频: $defaultVideo" + Write-Host " 管理端: http://localhost:18080" + Write-Host " 视频监控: http://localhost:18080/ui/monitor" + Write-Host " MinIO: http://localhost:9001" + Write-Host "" + Write-Host " 停止所有: powershell .\scripts\dev-env.ps1 stop" -ForegroundColor DarkGray +} + +# ════════════════════════════════════════════════════════ +# STOP +# ════════════════════════════════════════════════════════ +function Invoke-Stop { + Write-Banner "停止所有模拟环境进程" + Stop-ByName "mediamtx" + Stop-ByName "ffmpeg" + Stop-ByName "media-server" + Stop-ByName "minio" + Stop-ByName "safesightd" + # Kill python mock_alarm if running + Get-Process -Name "python" -ErrorAction SilentlyContinue | + Where-Object { $_.CommandLine -match "mock_alarm" } | + Stop-Process -Force + Write-Host "" + Write-Host " 已全部停止" -ForegroundColor Green +} + +# ════════════════════════════════════════════════════════ +# STATUS +# ════════════════════════════════════════════════════════ +function Invoke-Status { + Write-Banner "模拟环境状态" + @( + @{Name="mediamtx"; Port=8554; URL="rtsp://localhost:8554"}, + @{Name="safesightd"; Port=18080; URL="http://localhost:18080/health"}, + @{Name="minio"; Port=9000; URL="http://localhost:9000"} + ) | ForEach-Object { + $proc = Get-Process -Name $_.Name -ErrorAction SilentlyContinue + $status = if ($proc) { "● 运行中" } else { "○ 未运行" } + $color = if ($proc) { "Green" } else { "DarkGray" } + Write-Host " $status $($_.Name) $($_.URL)" -ForegroundColor $color + } +} + +# ════════════════════════════════════════════════════════ +switch ($Action.ToLowerInvariant()) { + "start" { Invoke-Start } + "stop" { Invoke-Stop } + "status" { Invoke-Status } + default { + Write-Host "用法: powershell .\scripts\dev-env.ps1 [start|stop|status]" + Write-Host "" + Write-Host "可选参数 (仅 start):" + Write-Host " -MediaConfig media-server 配置 (默认: configs/sample_cam1.json)" + Write-Host " -VideoFile 推流视频文件路径" + } +}