Repository navigation
fix(core): the first cut after Play starts on time instead of running ahead - #6794
Conversation
Edit accuracy: accurate 271 (base branch 271), smooth 106 of thoseThe gate passes. Quarantined, measured but not gated (0) Unstable (3)
|
There was a problem hiding this comment.
Verdict: APPROVE · 0 blocker · 0 important · 0 nits · head a142f3da
I ran the named test locally. does not learn from a video started by Play fails with main's media.ts and passes here (179/179). Pause and a non-continuing seek both sync with playing: false, so the next Play's first tick is never sampled. A seek during playback still learns, as the body says. The first-frame cost of about one frame on the first cut after Play is disclosed and is the owner's call. All workflows are green on this head.
Scope
I read the whole diff (media.ts, media.test.ts) and checked syncRuntimeMedia's only caller, syncMediaForCurrentState in init.ts, on the play, pause and seek paths.
There was a problem hiding this comment.
Verdict: APPROVE · 0 resolved, 0 open, 0 new · a142f3da → 8e804432. The named test passes here and fails under both mutations I tried: a Play start counted in full (main's behaviour) and counted as zero (the previous head). All workflows are green on this head.
What
The first cut after Play no longer starts its incoming video too early. Before, that video ran about 50 ms ahead of the playhead for its whole clip: it caught up by holding a frame just after the cut, then reached its last frame early and held it until the next cut. On a short first clip that was one or two dropped frames on every Play from the start.
Why
#6494 starts an upcoming video early by the start delay learned from earlier starts. It also learns from the video that Play itself starts, and that start waits on the playhead's own start as well as the video's. Measured in Studio preview, a start at Play took 64-74 ms against 41-60 ms for a start at a cut. The learned value is an average, so that one sample set the lead for the first cut alone and pulled the next ones up.
Skipping that sample is not enough: with nothing learned, the first cut starts on its tick about 45 ms late, and a late clip catches up by skipping a frame, usually its last one before the next cut.
How
syncRuntimeMediarecords whether the playhead was running on the previous call. A video started on a call where it was not (the first tick of playback) counts at half weight; starts at cuts, and starts after a seek during playback, count in full as before. Half is picked from the measurement above, not derived: a cut's delay was 0.55-0.94 of Play's, so half errs late by well under a frame rather than early, and cut samples then take over the average.Size
Under 100 lines on purpose: one fix to how the first cut after Play learns its start delay, with its test. Every Play from the start drops frames at the first cuts until it lands, and no other open PR touches this code to carry it.
Related work
Refines #6494.
Test plan
media.test.tslearns half the start delay of a video started by Play. The other start-latency tests now start their first video with the playhead already running, which is the case they describe.learns half the start delay of a video started by Playand only that test.vitest run src/runtimeinpackages/core: 109 files, 2655 tests passed. oxfmt, oxlint, coretscand the comment ratchet clean.Play at 0 s, 20 s per run, picture timed from each video's
requestVideoFrameCallback:Before, the drops sat at the first two cuts (6.9-7.0 s and 7.6-7.7 s).
An earlier head of this branch skipped the Play sample instead: 4 drops in 9 runs, the first cut's first frame 64 ms late (median), and a lost last frame in 6 of 9 runs. Half weight removes all three.
With Play at 64 s, where Play itself starts the video under the playhead, the 1-3 drops within 2 s of Play are not this change's: 9 runs interleaved run by run with the previous head, 19 → 16.
For scale: one plain
<video>playing the same file on the same machine drops 1-2 frames a minute, and started mid-file it held one frame in its first second in 2 of 9 runs.