Repository navigation
video: thin recording bursts by time, never skip the frame that matters - #31
Merged
Merged
Conversation
`Page.startScreencast` was started with `everyNthFrame: 2`. Chromium only emits a frame when the compositor paints, so on a page that changes once after recording starts there are exactly two paints, and the second one, the result, was the frame being skipped: the clip came back as a single frame of 100 ms. Seen four times in a row while an agent recorded a fixed page transition (a click, then the new page). A repro with three paints survived as two frames, which hid the problem for "before" clips. Every paint is now kept. A still page costs nothing however long the recording runs, an animating page runs at its own rate, and the existing frame cap bounds a long animation. Adds a live test: one DOM change between two pauses yields at least two frames and a clip that spans the pause. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
The count skip is gone for good; in its place the journal thins frames by time. A frame at least 33 ms after the last kept one is written at once. A frame inside that interval is the burst's newest and is held: written when the burst ends (the next frame is a full interval away, so this one was on screen long enough to see) or when the journal finishes, so the final state is never lost to thinning. Animated pages still land near 30 fps with the same file sizes, which is what everyNthFrame 2 was for, and a lone paint after a pause, the result of a click, is always kept. Four journal tests cover the lone paint, a 60 Hz burst, a burst whose last frame stayed on screen (blank, then content, then a five-second pause: the count skip showed blank for five seconds), and interval zero. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Page.startScreencastwas started witheveryNthFrame: 2. Chromium emits a screencast frame only when the compositor paints, so a recording of one interaction has two paints: the state before, and the result. The result's paint was the skipped one, and the clip came back as a single frame of 100 ms. Seen four times in a row on a headless-shell VM while an agent recorded a fixed page transition. A repro of the bug on the same page (click, blank article, content 2.4 s later) has three paints and survived as two frames, which is why "before" recordings looked fine and "after" recordings never did.The
2was there for a reason: every WebM frame is a VP8 keyframe, so a 60 Hz animation at every paint doubles bytes and encode time. Skipping by count just can't tell an animation frame from the only frame that matters.Change
DEFAULT_VIDEO_EVERY_NTH_FRAME1). The builder option stays for callers who want Chromium-side skipping.FrameJournalthins by time instead: a frame at least 33 ms after the last kept one is written at once; a frame inside that interval is the burst's newest and is held, then written when the burst ends (the next frame is a full interval away, so this one was on screen long enough to matter) or atfinish, so the final state is always in the clip.with_min_frame_interval_us(0)keeps everything.Tests
cargo test --locked397/397,cliandmcpsuites unchanged and green, live recording tests 2/2 twice against Playwright's Chromium 1232 on macOS arm64.🤖 Generated with Claude Code