fix(rec): recordings played ~1.4x fast — CFR emission, drop -re

Root cause (measured, not guessed): the take-3 'rebase on overrun' reset
nextTick to wall-now, erasing every missed slot. Pump delivered 215-219/300
per 5s (~43fps) but rawvideo carries no timestamps — ffmpeg muxes by frame
count at -framerate 60, so every recording played fast with honest-looking
stats. A second pacer, ffmpeg -re, throttled the demux separately
('Resumed reading ... after a lag' 0.79s->4.82s).

Fix follows libobs video-io.c (https://github.com/obsproject/obs-studio)
- the video thread never resets its deadline; one frame per interval slot,
a late render repeats content (judder), never skips time:
1. FramePump: count-based emission, while(now>=nextTick){Submit; nextTick+=I}
2. FfmpegArgs: -re removed - the pump is the pacer

Muxed duration is now frame-count/fps == wall time by construction. Covers
game background + webcam (one shared pump). 0 warnings; suite 288/289 -
the one failure (Composite_FullScene_MasterPixels 1380,700) also fails with
this change stashed: pre-existing, untouched, recorded as follow-up.
This commit is contained in:
2026-09-10 08:35:30 -07:00
parent d212d5ae2c
commit bd396e488c
5 changed files with 117 additions and 62 deletions
+3 -2
View File
@@ -2,7 +2,9 @@ namespace ytLive.Services.Encoder;
/// <summary>
/// Builds the FFmpeg command line for a live RTMP push (TASK 4 ship step 3):
/// raw BGRA frames via stdin (paced <c>-re</c>), real audio via the named pipe
/// raw BGRA frames via stdin (paced by the frame pump — the pump holds a strict
/// CFR cadence, so <c>-re</c> would only add a second, fighting pacer), real
/// audio via the named pipe
/// (TASK 9 — the mixer streams f32le at 48 kHz stereo into <c>\\.\pipe\&lt;name&gt;</c>;
/// WASAPI loopback + the mic ride the pipe instead of the old anullsrc silence),
/// H.264 + AAC encoding, FLV muxing to the ingestion URL. Pure — the encoder
@@ -16,7 +18,6 @@ public static class FfmpegArgs
{
"-hide_banner", "-loglevel", "info",
"-stats", "-stats_period", "0.5",
"-re",
"-f", "rawvideo", "-pix_fmt", "bgra",
"-video_size", $"{options.Width}x{options.Height}",
"-framerate", options.Fps.ToString(),