bd396e488c
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.
58 lines
3.3 KiB
Markdown
58 lines
3.3 KiB
Markdown
# 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):**
|
|
1. `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). `nextTick` NEVER rebases to wall-now.
|
|
2. `FfmpegArgs`: `-re` deleted 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.mp4` measured -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.exe` before 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.exe`
|
|
via 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) |