diff --git a/services/playout/src/playout-manager.js b/services/playout/src/playout-manager.js index bef98e4..989c767 100644 --- a/services/playout/src/playout-manager.js +++ b/services/playout/src/playout-manager.js @@ -221,9 +221,22 @@ export class PlayoutManager { '-fflags', '+genpts', '-analyzeduration', '2000000', '-probesize', '2000000', '-i', `${PREVIEW_UDP_URL}?fifo_size=1000000&overrun_nonfatal=1`, - // Drop the (broken) audio entirely; copy the clean video bitstream. + // Drop the (broken) audio entirely. '-an', - '-c:v', 'copy', + // Re-encode (NOT -c:v copy) to uniform, keyframe-aligned 2s segments with + // regenerated CFR timestamps. -c:v copy passed CasparCG's erratic + // real-time keyframes straight through, producing segments of 0.6–2.8s + // and irregular PTS; hls.js can't build a live timeline from that — it + // 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', + '-force_key_frames', 'expr:gte(t,n_forced*2)', '-f', 'hls', '-hls_time', '2', '-hls_list_size', '8',