* fix(engine): GPU renders use the NVENC preset names the host's ffmpeg lists
* fix(engine): one ffmpeg stdout reader for encoder detection and preset listing
* ci(engine): raise the engine unpacked size budget for the NVENC preset reader
* perf(engine,cli): a machine's GPU encoder probe runs once, not on every render
* refactor(engine): one shared probe per process, no answer kept on disk
* fix(engine): use ANGLE-EGL for Linux GPU path, bump NVENC probe size
Chrome 131+ rejects --use-gl=egl in headless shell; the GPU process
exits and the renderer silently falls back to SwiftShader. Switch to
(gl=angle, angle=gl-egl) which is on the headless-shell allowlist,
and add --ignore-gpu-blocklist + --disable-software-rasterizer so
data-center GPUs (L4/T4/A10) are not blocked.
Also bump the NVENC probe frame from 16×16 to 320×240 — NVIDIA
data-center cards require ≥257 on each dimension and reject the
smaller size with "Frame Dimension less than the minimum supported
value", causing the encoder probe to silently fall back to libx264.
Closes#1493
* fix(engine): address review feedback — probe test, observability, comments
- Export getProbeArgs and add test pinning 320×240 probe dimensions
across all 5 GPU encoder backends (nvenc/videotoolbox/vaapi/qsv/amf)
- Add driver/SKU rationale comment on the probe size constant with
context about NVIDIA data-center card behavior vs documented minimums
- Add rationale comment on --ignore-gpu-blocklist (operator opted into
hardware mode explicitly)
- Log resolved GL flags at browser launch for GPU fallback observability
NVENC rejects the libx264 preset vocabulary (ultrafast / medium / slow /
...) with AVERROR(EINVAL) ("Error applying encoder options: Invalid
argument"), which surfaces as a bare `FFmpeg exited with code -22` from
spawn(). Because ENCODER_PRESETS passes these names straight through to
h264_nvenc / hevc_nvenc, every `--gpu` render using the `draft` tier
failed; `standard` (medium) and `high` (slow) only worked coincidentally
on ffmpeg builds that happened to accept those aliases. QSV has the same
problem on a narrower set (ultrafast / superfast / placebo).
Add `mapPresetForGpuEncoder` in utils/gpuEncoder.ts that translates the
libx264 vocabulary to each encoder's native names:
- nvenc: libx264 -> p1..p7 (already-native pN values pass through);
unknown values fall back to p4 (medium)
- qsv: ultrafast / superfast -> veryfast; placebo -> veryslow;
everything else passes through
- videotoolbox / vaapi / null: unchanged
Both buildEncoderArgs (chunkEncoder.ts) and buildStreamingArgs
(streamingEncoder.ts) now route through the helper before pushing
`-preset` to the ffmpeg arg vector.
To make the next encoder-options failure diagnosable without re-running
ffmpeg by hand, \`formatFfmpegError\` in utils/runFfmpeg.ts now appends
the last 15 non-empty stderr lines to the error string. The four call
sites that previously swallowed stderr (encodeFramesFromDir,
muxVideoWithAudio, applyFaststart, and the streaming encoder exit
handler) have been updated.
Tested end-to-end on an RTX 4080 with ffmpeg 8.1 NVENC across
\`--quality draft|standard|high\` plus \`--video-bitrate\` and \`--crf\`
overrides; the 6 renders were visually equivalent to the CPU baseline.
Co-authored-by: roi32 <75878108+roi32@users.noreply.github.com>