Skip to content

trms/mediabunny-screen-capture

Repository files navigation

MediaBunny VFR Screen Recording Bug Repro

View on GitHub

Minimal reproduction demonstrating that MediaStreamVideoTrackSource produces a variable frame rate (VFR) MP4 with very few frames when recording a static screen.

Problem

When recording a static screen (e.g., a presentation slide) with getDisplayMedia(), Chrome drastically reduces frame delivery to save power. MediaStreamVideoTrackSource only encodes the frames the browser actually delivers, resulting in an MP4 with huge timestamp gaps — for example, ~102 frames spread across a 279-second recording.

This causes problems for downstream processing (e.g., AWS MediaConvert, ffmpeg) which may misinterpret the duration or produce artifacts.

Expected Behavior

A 60-second recording should produce an MP4 with roughly 1800 frames (60s x 30fps), or at minimum a consistent frame rate even when the source content is static.

Actual Behavior

A 60-second recording of a static slide produces an MP4 with far fewer frames than expected (sometimes as low as 2-3 fps effective rate), with variable frame timing.

Repro Steps

  1. Open the demo in Chrome (HTTPS required for getDisplayMedia)
  2. Click Start Recording
  3. Share a screen showing a static slide or document (no animations)
  4. Wait 30-60 seconds without moving the mouse or changing content
  5. Click Stop Recording
  6. Download the MP4

Verify with ffprobe

# Check frame count and frame rate
ffprobe -v error -select_streams v:0 \
  -show_entries stream=nb_frames,duration,r_frame_rate,avg_frame_rate \
  -of default=noprint_wrappers=1 recording.mp4

# Count actual frames
ffprobe -v error -select_streams v:0 \
  -count_frames -show_entries stream=nb_read_frames \
  -of default=noprint_wrappers=1 recording.mp4

# Show per-frame timestamps to see gaps
ffprobe -v error -select_streams v:0 \
  -show_entries frame=pts_time,duration_time \
  -of csv=p=0 recording.mp4 | head -20

Environment

  • Browser: Chrome 130+ (tested on macOS)
  • mediabunny: 1.34.2
  • Encoding: MediaStreamVideoTrackSource with AVC codec, 2.5 Mbps, keyframe interval 2s
  • Output: Fragmented MP4 via StreamTarget

Live Demo

https://trms.github.io/mediabunny-screen-capture/

Local Development

Prerequisites

  • Node.js 20+
  • npm

Setup

git clone https://github.com/trms/mediabunny-screen-capture.git
cd mediabunny-screen-capture
npm install

Run

npm run dev

This starts a Vite dev server with HTTPS (required for getDisplayMedia()). Open https://localhost:5173/mediabunny-screen-capture/ in Chrome.

Your browser will warn about the self-signed certificate — click "Advanced" → "Proceed" to continue.

Build for production

npm run build
npm run preview   # Preview the production build locally

Code Reference

The encoding pipeline in this repro matches our production code exactly:

  • Screen constraints: getDisplayMedia({ video: { aspectRatio: { ideal: 16/9 }, width: { ideal: 1920 }, height: { ideal: 1080 } } })
  • Output: Mp4OutputFormat({ fastStart: 'fragmented' }) with StreamTarget
  • Video: MediaStreamVideoTrackSource with { codec: 'avc', bitrate: 2_500_000, keyFrameInterval: 2 }
  • Audio: MediaStreamAudioTrackSource with { codec: 'aac', bitrate: 128_000 }
  • Frame rate: output.addVideoTrack(source, { frameRate: 30 })

About

Minimal reproduction of VFR screen recording bug with mediabunny

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors