Skip to content

fix(browser-actions): smooth 30fps high-quality video via the CDP screencast - #2564

Merged
chubes4 merged 1 commit into
mainfrom
fix/high-video-screencast
Oct 3, 2026
Merged

chubes4 merged 1 commit into
mainfrom
fix/high-video-screencast

Conversation

@chubes4

@chubes4 chubes4 commented Oct 3, 2026

Copy link
Copy Markdown
Collaborator

Follow-up to #2563 (video-quality=high).

Problem

High-quality capture took a full page.screenshot() about every 100ms. A screenshot at 1080x1920 takes most of that budget, so motion recorded at about 10fps (gap p50 105ms, p90 156ms). Cursor glides (600ms) and smooth scrolls showed up as visible jumps in a real phone demo.

Fix

  • Capture with Page.startScreencast (JPEG q92) instead of a screenshot loop. Chromium pushes a frame on every repaint: about 60fps during motion (gap p50 17ms in a probe), and none while idle.

  • Each frame keeps its CDP paint timestamp. At encode time, highVideoFrameTimeline() resamples frames onto a constant 30fps timeline anchored at the recording origin that step markers already use. Each tick shows the latest frame painted at or before it. Encoding is unchanged: VP8 via Playwright's bundled ffmpeg.

  • summary.video.fps is now 30.

  • Device pixels: the screencast composites at CSS pixels unless the scale is forced at launch. Verified with probes:

    Setup Frame size
    context deviceScaleFactor: 2 only 540x960
    --force-device-scale-factor=2 only 1080x1920, but page DPR 1
    both 1080x1920 with DPR 2 (sharp images)

    So when video-quality=high is requested with a scale above 1, launchChromiumBrowser() gets the flag. The launcher now accepts optional extra args. Sessions that reuse a browser are unchanged.

Tests

  • New highVideoFrameTimeline unit test covers resampling, ticks before the first paint, and no frames.
  • The existing high-quality capture test now asserts 30fps and still decodes a 1080x1920 VP8 stream with the bundled ffmpeg.
  • All 6 video tests pass with no system ffmpeg on PATH. npm run build is clean.

Real-world check

I re-recorded a 72-step live phone journey (extrachill.com → events calendar → event → RSVP). It produced 1277 screencast frames, versus 410 screenshots before, at 1080x1920 30fps. In a 3s window during a cursor glide, 67 of 75 output frames change.

AI-assisted: authored by Extra Chill Bot.

…st so motion stays smooth

video-quality=high captured a full-page screenshot every ~100ms, so cursor glides and smooth scrolls rendered as ~10fps jumps.
Stream compositor frames with Page.startScreencast instead (~60fps during motion, nothing while idle) and resample them by paint timestamp onto a constant 30fps timeline anchored at the marker origin.
Chromium only composites screencast frames at device pixels when the scale is forced at launch, so high-quality capture launches with --force-device-scale-factor alongside the context scale.
@chubes4
chubes4 merged commit a7dc8f9 into main Oct 3, 2026
5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant