Tactical Media Broadcast Hub — initial release
Self-hosted multi-platform broadcast newsroom for activist collectives: publishing pipeline with group approval and DST-proof scheduling, TweetDeck-style column wall with hostile-content-safe rendering, live control room with Auto Director, bridged chat governance with polls and quorum, distributed sandboxed transcode workers, encrypted content-addressed archive, monthly analytics. MIT licensed. See README.md and docs/.
This commit is contained in:
commit
aa5e262f3a
880 changed files with 111042 additions and 0 deletions
159
infra/peertube-workers/win/selftest-qsv.ps1
Normal file
159
infra/peertube-workers/win/selftest-qsv.ps1
Normal file
|
|
@ -0,0 +1,159 @@
|
|||
# Windows QSV self-test for the PeerTube transcode worker (validator).
|
||||
#
|
||||
# Gates registration. A real encode MUST produce a positive PDH
|
||||
# \GPU Engine\Utilization Percentage (engtype_VideoEncode) signal; exit 0 alone
|
||||
# is insufficient. No CPU fallback exists anywhere in this worker.
|
||||
#
|
||||
# Usage (PowerShell 5.1+, from C:\pt-worker\bin after the ffmpeg zip is unpacked):
|
||||
# powershell -ExecutionPolicy Bypass -File selftest-qsv.ps1
|
||||
# Writes C:\pt-worker\state\qsv.json on completion.
|
||||
|
||||
$ErrorActionPreference = 'Continue'
|
||||
$State = 'C:\pt-worker\state'
|
||||
$Bin = 'C:\pt-worker\bin'
|
||||
$FFmpeg = Join-Path $Bin 'ffmpeg.exe'
|
||||
$FFprobe = Join-Path $Bin 'ffprobe.exe'
|
||||
New-Item -ItemType Directory -Force -Path $State | Out-Null
|
||||
|
||||
function HexToBytes([string]$hex) {
|
||||
$bytes = New-Object byte[] ($hex.Length / 2)
|
||||
for ($i = 0; $i -lt $bytes.Length; $i++) { $bytes[$i] = [Convert]::ToByte($hex.Substring($i * 2, 2), 16) }
|
||||
return ,$bytes
|
||||
}
|
||||
|
||||
# 5-second synthetic 1080p30 clip (testsrc2 -> x264 -> mp4). No network, no libx264 use at encode time.
|
||||
$TestClip = Join-Path $State 'self-test-source.mp4'
|
||||
& $FFmpeg -hide_banner -loglevel error -y -f lavfi -i 'testsrc2=size=1920x1080:rate=30' -t 5 -c:v libx264 -pix_fmt yuv420p $TestClip
|
||||
if ($LASTEXITCODE -ne 0) { Write-Error 'failed to build self-test source clip'; exit 2 }
|
||||
|
||||
function Get-VideoEncodeBusy([int]$ProcId, [double]$Seconds = 3.0) {
|
||||
# Sum of engtype_VideoEncode instances of \GPU Engine(pid_<id>_*)\Utilization Percentage.
|
||||
# Locale-sensitive counter names/decimal separators: unparseable => -1 (unknown, never 0).
|
||||
$out = & typeperf "\GPU Engine(pid_$ProcId`_*)\Utilization Percentage" -sc 1 2>$null
|
||||
$rows = @($out | Where-Object { $_ -like '"*' })
|
||||
if ($rows.Count -lt 2) { return -1 }
|
||||
$headers = ($rows[0] -replace '^"|"$','').split('","')
|
||||
$values = ($rows[1] -replace '^"|"$','').split('","')
|
||||
$total = 0.0; $seen = $false
|
||||
for ($i = 0; $i -lt $headers.Count; $i++) {
|
||||
if ($headers[$i] -notmatch 'engtype_VideoEncode') { continue }
|
||||
if ($i -ge $values.Count) { return -1 }
|
||||
$raw = $values[$i]
|
||||
$num = 0.0
|
||||
if (-not [double]::TryParse($raw, [Globalization.NumberStyles]::Float,
|
||||
[Globalization.CultureInfo]::InvariantCulture, [ref]$num)) {
|
||||
$raw = $raw -replace '\.', '' -replace ',', '.'
|
||||
if (-not [double]::TryParse($raw, [Globalization.NumberStyles]::Float,
|
||||
[Globalization.CultureInfo]::InvariantCulture, [ref]$num)) { return -1 }
|
||||
}
|
||||
$total += $num; $seen = $true
|
||||
}
|
||||
if (-not $seen) { return -1 }
|
||||
return $total
|
||||
}
|
||||
|
||||
function Test-RealEncode([string]$Name, [string[]]$ExtraArgs, [int]$ProcId) {
|
||||
$log = Join-Path $State "selftest-$Name.log"
|
||||
$proc = Start-Process -FilePath $FFmpeg -ArgumentList $ExtraArgs -NoNewWindow -PassThru `
|
||||
-RedirectStandardError $log -RedirectStandardOutput (Join-Path $State "selftest-$Name.out")
|
||||
$maxBusy = 0.0; $samples = 0; $readable = $false
|
||||
while (-not $proc.HasExited) {
|
||||
$busy = Get-VideoEncodeBusy -ProcId ($proc.Id)
|
||||
if ($busy -ge 0) { $readable = $true; $samples++; if ($busy -gt $maxBusy) { $maxBusy = $busy } }
|
||||
Start-Sleep -Milliseconds 800
|
||||
}
|
||||
$proc.WaitForExit() | Out-Null
|
||||
return @{ name = $Name; exit = $proc.ExitCode; max_busy = $maxBusy;
|
||||
samples = $samples; counters_readable = $readable; log = $log }
|
||||
}
|
||||
|
||||
$report = [ordered]@{
|
||||
schema = 'pt-worker-qsv-selftest/1'
|
||||
tested_at = [DateTimeOffset]::UtcNow.ToUnixTimeSeconds()
|
||||
gpu = @(); driver_version = $null
|
||||
dispatcher_dlls = @{ libmfx = (Test-Path (Join-Path $Bin 'libmfx64-gen.dll'));
|
||||
libvpl = (Test-Path (Join-Path $Bin 'libvpl64-1.dll')) }
|
||||
ffmpeg_version = $null; qsv_h264_ok = $false; qsv_hevc_ok = $false
|
||||
h264_mf_ok = $false; av1_decode_ok = $null; av1_encode_ok = $false
|
||||
tests = @{}; failures = @(); boot_id = (Get-CimInstance Win32_OperatingSystem).LastBootUpTime.ToString('o')
|
||||
}
|
||||
|
||||
$gpus = @(); try {
|
||||
$gpus = @(Get-CimInstance Win32_VideoController | Select-Object Name, DriverVersion, Status)
|
||||
} catch { }
|
||||
$report.gpu = $gpus
|
||||
$intel = $gpus | Where-Object { $_.Name -match 'Intel.*(?:Iris|UHD|Graphics)' } | Select-Object -First 1
|
||||
if (-not $intel) { $report.failures += 'no Intel graphics adapter found via WMI' }
|
||||
else { $report.driver_version = $intel.DriverVersion }
|
||||
$report.ffmpeg_version = (& $FFmpeg -version | Select-Object -First 1)
|
||||
|
||||
# --- capability listing (necessary, not sufficient) ---
|
||||
$encoders = (& $FFmpeg -hide_banner -encoders) -join "`n"
|
||||
foreach ($codec in @('h264_qsv', 'hevc_qsv', 'h264_mf', 'av1_qsv')) {
|
||||
$report.tests["encoder_$codec"] = ($encoders -match [regex]::Escape($codec))
|
||||
}
|
||||
if ($report.tests.encoder_h264_qsv -ne $true) { $report.failures += 'h264_qsv encoder missing from ffmpeg build' }
|
||||
|
||||
# --- session init proof (device open) ---
|
||||
$initLog = Join-Path $State 'selftest-qsv-init.log'
|
||||
& $FFmpeg -hide_banner -v verbose -y -init_hw_device qsv=hw -f lavfi -i 'testsrc2=size=1280x720:rate=30' `
|
||||
-frames:v 10 -c:v h264_qsv -f null - 2> $initLog
|
||||
$initExit = $LASTEXITCODE
|
||||
$initText = Get-Content $initLog -Raw
|
||||
$report.tests.qsv_device_init_exit = $initExit
|
||||
if ($initExit -ne 0) { $report.failures += "h264_qsv session init failed (exit $initExit); see selftest-qsv-init.log" }
|
||||
|
||||
# --- REAL H.264 1080p encode with mandatory VideoEncode counter proof ---
|
||||
$h264 = Test-RealEncode -Name 'qsv-h264' -ProcId 0 -ExtraArgs @(
|
||||
'-hide_banner', '-nostdin', '-v', 'info',
|
||||
'-init_hw_device', 'qsv=qs', '-filter_hw_device', 'qs',
|
||||
'-hwaccel', 'qsv', '-hwaccel_output_format', 'qsv', '-c:v', 'h264_qsv',
|
||||
'-i', $TestClip,
|
||||
'-vf', 'scale_qsv=w=1280:h=720:format=nv12',
|
||||
'-c:v', 'h264_qsv', '-preset', 'medium', '-b:v', '2M', '-maxrate', '2M', '-bufsize', '4M', '-bf', '2',
|
||||
'-an', '-f', 'null', '-'
|
||||
)
|
||||
$report.tests.h264 = $h264
|
||||
if ($h264.exit -eq 0 -and $h264.counters_readable -and $h264.samples -ge 3 -and $h264.max_busy -gt 0) {
|
||||
$report.qsv_h264_ok = $true
|
||||
} elseif ($h264.exit -eq 0) {
|
||||
$report.failures += 'h264_qsv exited 0 without a positive VideoEncode counter; not accepted as hardware proof'
|
||||
}
|
||||
|
||||
# --- HEVC encode attempt (capability discovery; not enabled in production) ---
|
||||
$hevc = Test-RealEncode -Name 'qsv-hevc' -ProcId 0 -ExtraArgs @(
|
||||
'-hide_banner', '-nostdin', '-v', 'info',
|
||||
'-init_hw_device', 'qsv=qs', '-filter_hw_device', 'qs',
|
||||
'-hwaccel', 'qsv', '-hwaccel_output_format', 'qsv', '-c:v', 'hevc_qsv',
|
||||
'-i', $TestClip,
|
||||
'-vf', 'scale_qsv=w=1280:h=720:format=nv12',
|
||||
'-c:v', 'hevc_qsv', '-preset', 'medium', '-b:v', '2M',
|
||||
'-an', '-f', 'null', '-'
|
||||
)
|
||||
$report.tests.hevc = $hevc
|
||||
$report.qsv_hevc_ok = ($hevc.exit -eq 0 -and $hevc.counters_readable -and $hevc.samples -ge 3 -and $hevc.max_busy -gt 0)
|
||||
|
||||
# --- AV1: decode-only expectation on Alder Lake; verify, never assume ---
|
||||
# Build an AV1 source only if an AV1 encoder (software) exists in this build;
|
||||
# decoding AV1 hardware-wise is the capability under test.
|
||||
$av1DecodeOk = $false
|
||||
$av1Source = Join-Path $State 'self-test-source-av1.mp4'
|
||||
& $FFmpeg -hide_banner -loglevel error -y -f lavfi -i 'testsrc2=size=320x180:rate=30' -t 1 -c:v libaom-av1 $av1Source 2>$null
|
||||
if ($LASTEXITCODE -eq 0) {
|
||||
$av1Log = Join-Path $State 'selftest-av1-decode.log'
|
||||
& $FFmpeg -hide_banner -v error -y -c:v av1_qsv -i $av1Source -frames:v 5 -f null - 2> $av1Log
|
||||
$av1DecodeOk = ($LASTEXITCODE -eq 0)
|
||||
}
|
||||
$report.av1_decode_ok = $av1DecodeOk
|
||||
$encAv1 = ($encoders -match 'av1_qsv')
|
||||
$report.av1_encode_ok = $false
|
||||
$report.tests.av1_encoder_present = $encAv1
|
||||
|
||||
# --- Record + verdict. NO CPU fallback exists; registration is blocked on failure. ---
|
||||
$report | ConvertTo-Json -Depth 5 | Set-Content -Encoding UTF8 (Join-Path $State 'qsv.json')
|
||||
if ($report.failures.Count -gt 0 -or -not $report.qsv_h264_ok) {
|
||||
Write-Host 'SELF-TEST FAILED:' ($report.failures -join '; ')
|
||||
exit 1
|
||||
}
|
||||
Write-Host 'SELF-TEST PASSED: h264_qsv with positive VideoEncode counter proof'
|
||||
exit 0
|
||||
Loading…
Add table
Add a link
Reference in a new issue