fix(playout): lighter 360p/20fps preview encode so the CPU re-mux keeps up

The 720p30 libx264 preview re-encode couldn't sustain real time on the
CPU-only sidecar (running alongside CasparCG's mixer + STREAM consumer):
the UDP input overran and the HLS output stalled, freezing the playlist so
hls.js saw a static live edge (monitor black). Drop the confidence monitor
to 360p / 20fps / ultrafast (-g 40 = 2.0s GOP) — a fraction of the cost,
sustains real time comfortably. NVENC would be ideal but the image's static
ffmpeg has no nvenc encoder; 360p ultrafast is plenty for a preview.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Zac Gaetano 2026-05-31 16:15:16 -04:00
parent d3ad2397fb
commit 7451d7c703

View file

@ -230,12 +230,19 @@ export class PlayoutManager {
// logs "sliding 0.00 / MISSED", never loads a fragment, and the monitor
// stays black even though the stream decodes cleanly server-side. A
// standalone ffmpeg honours -force_key_frames, so every GOP (and thus
// every HLS segment) is exactly 2.0s. fps=30 forces CFR; scale to 720p
// keeps the confidence monitor cheap.
'-vf', 'fps=30,scale=-2:720,format=yuv420p',
'-c:v', 'libx264', '-preset', 'veryfast', '-tune', 'zerolatency',
'-b:v', '1500k', '-maxrate', '2M', '-bufsize', '4M',
'-g', '60', '-keyint_min', '60', '-sc_threshold', '0',
// every HLS segment) is exactly 2.0s.
//
// This is a CONFIDENCE MONITOR, kept deliberately tiny: 360p / 20fps /
// ultrafast. The sidecar has no NVENC, so this is a CPU libx264 encode
// running ALONGSIDE CasparCG's mixer + its own STREAM consumer. At 720p30
// the re-encode couldn't sustain real time, the UDP input overran, and the
// HLS output stalled (playlist froze → monitor black). 360p20 ultrafast is
// a fraction of the cost and keeps up comfortably. fps=20 forces CFR;
// -g 40 = 2.0s GOP at 20fps.
'-vf', 'fps=20,scale=-2:360,format=yuv420p',
'-c:v', 'libx264', '-preset', 'ultrafast', '-tune', 'zerolatency',
'-b:v', '600k', '-maxrate', '800k', '-bufsize', '1200k',
'-g', '40', '-keyint_min', '40', '-sc_threshold', '0',
'-force_key_frames', 'expr:gte(t,n_forced*2)',
'-f', 'hls',
'-hls_time', '2',