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.
3.3 KiB
HANDOFF — 2026-09-10
Branch / Commit State
main HEAD = 1a39b09, ahead of origin by 12, working tree carries THE recording-timing
fix (uncommitted): count-based CFR emission in FramePump.cs + -re removal in
FfmpegArgs.cs, plus this handoff / ai.md slice 9 / MyMistakes.md recipe correction.
tools/ holds ticker.c + the built ticker (WSL, unused by git yet).
Recording TIMING — the fix (the "plays too fast" saga)
Root cause, proven by measurement (not guessed): the pump's take-3 "rebase on overrun"
reset nextTick to wall-now every time it fell behind, silently erasing missed slots. The
pump delivered 215-219/300 per 5s (~43fps) but ffmpeg muxes rawvideo by frame count at
-framerate 60 — no per-frame timestamps — so every recording played ~1.4x fast with
stats that looked honest (a rebased frame is never "late"). -re on the demux was a second
fighting pacer ("Resumed reading … after a lag" grew 0.79s→4.82s).
Fix (the OBS video-io.c shape — one frame per interval slot, deadline never reset):
FramePump.PumpAsync:while (now >= nextTick) { SubmitFrame(frame); nextTick += intervalTicks; }— one submit per crossed slot; a slow render re-writes the current composite (judder, never a skip).nextTickNEVER rebases to wall-now.FfmpegArgs:-redeleted from the rawvideo input; the pump is the pacer.
Verified: build 0 warnings; full suite 288/289 — the sole failure
(Composite_FullScene_MasterPixels line 109, pixel (1380,700) cyan vs magenta) ALSO fails
with this fix stashed, i.e. pre-existing and untouched by it. DO NOT fix it here; it is a
separate compositor investigation.
NEXT STEP (ONE user run required)
Record ~30s with the WSL ticker visible in the preview (cd tools && ./ticker in a terminal,
Ctrl-C to stop), then check:
- recording duration ≈ wall time (should be, by frame-count construction)
%APPDATA%\ytLlive\startup.log"FramePump stats:" shows ≈ n/n per 5s, n = 300 @60fps- NO "Resumed reading … after a lag" lines remain
- ticker advances ~1s per second of footage
Still Open
- Web overlay: the pre-parse transparency injection (committed
1a39b09) is NOT yet proven — both recorded diagnostic PNGs (%TEMP%\ytLive-web-<id>.png) were 100% alpha=0 AND RGB=0 (an EMPTY capture, not an opaque one). Diagnosis "capture is empty" needs a fresh run; the first-capture dump may be the pre-load about:blank frame. Frozen pending the timing verification. - Audio silence:
no audio.mp4measured -91dB (digital silence), 3KiB muxed audio stream — the named-pipe audio delivered ~nothing. Separate from timing; not yet touched. - Pre-existing:
Composite_FullScene_MasterPixels(see above).
Landmines
- testhost shares startup.log with app — filter by time when triaging
- testhost/exe lock DLLs:
taskkill /F /IM testhost.exe /IM ytLive.exebefore rebuild - Build via the Windows dotnet host:
/mnt/c/Program Files/dotnet/dotnet.exe build … - Kill app before build:
/mnt/c/Windows/System32/taskkill.exe /F /IM ytLive.exe - No Linux ffmpeg / no sudo on this box — probing uses
/mnt/c/Program Files/Krita (x64)/bin/ffmpeg.exevia WSL interop; frames landed in/mnt/c/Users/gramp/AppData/Local/Temp/ylf/ tools/ticker: constant ~+982ms offset on the FIRST line is cosmetic (t0 captured a beat late)