cdaf0cf091
The composite action .github/actions/e2e-screen-record owns setup and lifecycle on all three OSes: ffmpeg via apt/brew-verify/winget+cache, capture via x11grab/gdigrab/avfoundation, mkv at 15fps stopped by 'q' on live stdin with kill fallback. Linux runners have no display, so start brings up a dedicated Xvfb :99 and exports DISPLAY - one display serves both the recorder and any app a later step launches. Recording moves out of the GUI driver into workflow infrastructure - that is what makes it uniform - and a missing ffmpeg or a zero-frame file now FAILS the leg instead of skipping silently: the graceful-skip path is how the windows leg shipped no recording.mkv while green. Lifecycle proven locally: start against lavfi testsrc, q-stop, ffprobe duration check (record-start.sh/record-stop.sh under nix ffmpeg).
63 lines
2.5 KiB
PowerShell
63 lines
2.5 KiB
PowerShell
# Start a continuous ffmpeg screen recording in the background (windows).
|
|
#
|
|
# Usage: powershell -File record-start.ps1 -OutFile recording.mkv
|
|
#
|
|
# The graceful stop is the character 'q' on ffmpeg's LIVE stdin, which only
|
|
# System.Diagnostics.Process exposes (Start-Process -RedirectStandardInput
|
|
# hands ffmpeg a file handle already at EOF). This script therefore spawns a
|
|
# detached HOLDER powershell that owns the ffmpeg process and its stdin pipe,
|
|
# and stops it when a STOP marker file appears; record-stop.ps1 writes the
|
|
# marker. mkv on purpose: it stays playable even unfinalized. A missing
|
|
# ffmpeg is a HARD error - a graceful skip makes the missing tool invisible
|
|
# and the artifact silently loses its recording.
|
|
|
|
#Requires -Version 5.1
|
|
param(
|
|
[Parameter(Mandatory = $true)][string]$OutFile
|
|
)
|
|
$ErrorActionPreference = "Stop"
|
|
|
|
if (-not (Get-Command ffmpeg -ErrorAction SilentlyContinue)) {
|
|
Write-Host "record-start: ffmpeg not on PATH (the workflow must install it)"
|
|
exit 1
|
|
}
|
|
|
|
$outDir = Split-Path -Parent $OutFile
|
|
if ($outDir -and -not (Test-Path -LiteralPath $outDir)) {
|
|
New-Item -ItemType Directory -Path $outDir -Force | Out-Null
|
|
}
|
|
$stopMarker = "$OutFile.stop"
|
|
$stateFile = "$OutFile.state"
|
|
Remove-Item -LiteralPath $stopMarker, $stateFile -Force -ErrorAction SilentlyContinue
|
|
|
|
$holder = "$OutFile.holder.ps1"
|
|
@'
|
|
param([string]$OutFile, [string]$StopMarker)
|
|
$psi = New-Object System.Diagnostics.ProcessStartInfo
|
|
$psi.FileName = "ffmpeg"
|
|
$psi.Arguments = "-y -f gdigrab -framerate 15 -i desktop " +
|
|
"-hide_banner -loglevel error " +
|
|
"-c:v libx264 -preset ultrafast -pix_fmt yuv420p `"$OutFile`""
|
|
$psi.RedirectStandardInput = $true
|
|
$psi.UseShellExecute = $false
|
|
$proc = [System.Diagnostics.Process]::Start($psi)
|
|
Set-Content -LiteralPath "$OutFile.ffpid" -Value $proc.Id
|
|
while (-not $proc.HasExited) {
|
|
if (Test-Path -LiteralPath $StopMarker) {
|
|
try {
|
|
$proc.StandardInput.Write("q")
|
|
$proc.StandardInput.Close()
|
|
} catch {}
|
|
if (-not $proc.WaitForExit(15000)) { try { $proc.Kill() } catch {} }
|
|
break
|
|
}
|
|
Start-Sleep -Milliseconds 500
|
|
}
|
|
'@ | Set-Content -LiteralPath $holder -Encoding UTF8
|
|
|
|
$holderProc = Start-Process -FilePath "powershell.exe" `
|
|
-ArgumentList "-NoProfile", "-ExecutionPolicy", "Bypass", "-File", $holder, "-OutFile", $OutFile, "-StopMarker", $stopMarker `
|
|
-WindowStyle Hidden -PassThru
|
|
Set-Content -LiteralPath $stateFile -Value "$($holderProc.Id) $stopMarker"
|
|
Write-Host "record-start: recording to $OutFile (holder pid $($holderProc.Id))"
|