Files
NODEDC_MISSION_CORE/experiments/perception/worker/Prepare-RectifiedCameraReplay.ps1
T

125 lines
4.0 KiB
PowerShell

[CmdletBinding()]
param(
[Parameter(Mandatory = $true)]
[string]$JobRoot,
[Parameter(Mandatory = $true)]
[string]$OutputPath,
[ValidateRange(1, 1000)]
[int]$FreeGiBFloor = 360
)
$ErrorActionPreference = "Stop"
$ProgressPreference = "SilentlyContinue"
function Assert-DDrivePath {
param([string]$Path, [string]$Label)
$fullPath = [IO.Path]::GetFullPath($Path)
if ([IO.Path]::GetPathRoot($fullPath).TrimEnd("\") -ine "D:") {
throw "$Label must be stored on D:"
}
return $fullPath
}
function Assert-FreeSpace {
param([string]$Phase, [int64]$RequiredAdditionalBytes = 0)
$freeBytes = [int64](Get-PSDrive -Name D).Free
$floorBytes = [int64]$FreeGiBFloor * 1GB
Write-Output (
"DISK_GUARD PHASE={0} FREE_GIB={1} FLOOR_GIB={2}" -f
$Phase,
[math]::Round($freeBytes / 1GB, 3),
$FreeGiBFloor
)
if ($freeBytes -lt ($floorBytes + $RequiredAdditionalBytes)) {
throw "D: does not have the guarded replay reserve during $Phase"
}
}
$jobDirectory = Assert-DDrivePath (
(Resolve-Path -LiteralPath $JobRoot).Path
) "Job root"
$output = Assert-DDrivePath $OutputPath "Output path"
if (Test-Path -LiteralPath $output) {
Write-Output "REPLAY_ALREADY_PRESENT=$output"
exit 0
}
$jobPath = Join-Path $jobDirectory "job.json"
$job = Get-Content -LiteralPath $jobPath -Raw | ConvertFrom-Json
if (
$job.schema_version -ne "missioncore.compute-job/v1" -or
$job.job_id -ne "recorded-camera-602ac89026ed12978619801d" -or
$job.input.session_id -ne "20260720T065719Z_viewer_live" -or
$job.input.source_id -ne "sensor.camera.right" -or
[int]$job.input.segment_count -ne 4489
) {
throw "The requested job is not the immutable RAVNOVES00 right-camera source"
}
$epochRoot = Join-Path $jobDirectory "input\camera\sensor.camera.right\epoch-1"
$initPath = Join-Path $epochRoot "init.mp4"
$segmentsRoot = Join-Path $epochRoot "segments"
if (-not (Test-Path -LiteralPath $initPath -PathType Leaf)) {
throw "Camera initialization segment is absent"
}
if (-not (Test-Path -LiteralPath $segmentsRoot -PathType Container)) {
throw "Camera segment directory is absent"
}
$parent = Split-Path $output -Parent
$null = New-Item -ItemType Directory -Path $parent -Force
$temporary = Join-Path $parent (".{0}.{1}.partial" -f (Split-Path $output -Leaf), [Guid]::NewGuid().ToString("N"))
$requiredBytes = [int64]$job.input.byte_length + 1GB
Assert-FreeSpace "preflight" $requiredBytes
try {
$destination = [IO.File]::Open(
$temporary,
[IO.FileMode]::CreateNew,
[IO.FileAccess]::Write,
[IO.FileShare]::None
)
try {
$source = [IO.File]::OpenRead($initPath)
try { $source.CopyTo($destination) } finally { $source.Dispose() }
for ($sequence = 1; $sequence -le 4489; $sequence++) {
$segment = Join-Path $segmentsRoot ("{0}.m4s" -f $sequence)
if (-not (Test-Path -LiteralPath $segment -PathType Leaf)) {
throw "Camera segment is absent: $sequence"
}
$source = [IO.File]::OpenRead($segment)
try { $source.CopyTo($destination) } finally { $source.Dispose() }
}
$destination.Flush($true)
}
finally {
$destination.Dispose()
}
$probe = & ffprobe -v error -select_streams v:0 -count_frames `
-show_entries stream=width,height,nb_read_frames `
-of json $temporary | ConvertFrom-Json
if ($LASTEXITCODE -ne 0) {
throw "ffprobe failed for the reconstructed camera source"
}
$stream = @($probe.streams)[0]
if (
[int]$stream.width -ne 800 -or
[int]$stream.height -ne 600 -or
[int]$stream.nb_read_frames -ne 4489
) {
throw "Reconstructed camera stream violates the immutable frame contract"
}
Move-Item -LiteralPath $temporary -Destination $output
Assert-FreeSpace "published"
Write-Output "REPLAY_PATH=$output"
Write-Output "FRAME_COUNT=4489"
}
finally {
if (Test-Path -LiteralPath $temporary) {
Remove-Item -LiteralPath $temporary -Force
}
}