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:
+13
-3
@@ -105,9 +105,19 @@ Both halves were solved by OBS/libyuv long ago; do not re-derive:
|
||||
frame makes the period `render + submit + interval` — the producer can hit ≤ half
|
||||
the declared rate even with a free render. OBS's `video_thread`
|
||||
(`libobs/media-io/video-io.c`) advances an absolute `nextTick += intervalTicks` and
|
||||
sleeps only the remainder; if the deadline blew, skip the wait AND the missed ticks
|
||||
(rebase, no catch-up burst — a burst queues stale frames). Critical with rawvideo:
|
||||
pts is stamped by ARRIVAL, so a starved producer silently time-lapses the file.
|
||||
sleeps only the remainder. **NEVER "rebase" the deadline to wall-now when it blows** —
|
||||
the take-3 note I originally wrote here ("skip … the missed ticks (rebase)") was the
|
||||
PROVEN-wrong advice: resetting `nextTick` erases the missed slots, so a 43fps reality
|
||||
was authored into a 60fps container and every recording played ~1.4x fast (take 12/13,
|
||||
2026-09-10). The rebase even kept the stats looking honest (render+wait == period, no
|
||||
loss) because a rebased frame is never "late". OBS keeps the counter MOVING and outputs
|
||||
ONE frame per interval tick — a late render shows as REPEATED footage (judder; duration
|
||||
stays correct), never a skip and never a wall-now reset. Critical with rawvideo:
|
||||
pts is stamped by ARRIVAL, so the muxed duration is pure frame count ÷ fps — the only
|
||||
way to make duration == wall time under ANY load is exactly one frame per interval slot.
|
||||
Corollary: **never add a second pacer.** `ffmpeg -re` on the rawvideo input throttles
|
||||
the pipe independently and fights the pump (its "Resumed reading … after a lag" grew
|
||||
0.79s→4.82s in the same take). Removed; the pump IS the pacer.
|
||||
2. **A 1080p frame is ~2.07M pixels — the hot path must be row-simple.** Per-pixel
|
||||
`Math.Round` + float source-over in managed code costs ~100ns/px = the whole 258ms.
|
||||
libyuv's pattern (https://chromium.googlesource.com/libyuv/libyuv/): branch per
|
||||
|
||||
Reference in New Issue
Block a user