Skip to content

fix(recording): Windows encoders repeat a stalled frame only after three intervals - #2669

Draft
richiemcilroy wants to merge 3 commits into
mainfrom
fix/windows-frame-pacing
Draft

richiemcilroy wants to merge 3 commits into
mainfrom
fix/windows-frame-pacing

Conversation

@richiemcilroy

@richiemcilroy richiemcilroy commented Oct 17, 2026 •

Copy link
Copy Markdown
Member

Windows recordings repeated the last frame as soon as one frame interval passed without a new one, which duplicated camera frames under ordinary arrival jitter. Also in cap-v0.6.0.

Cause

Every Windows encoder loop (screen and camera, MP4 and fragmented, and the out-of-process muxer) waited recv_timeout(frame_interval). On a timeout it re-encoded the last frame stamped one interval later. That is the slot the next real frame is stamped for when it is only slightly late.

sequenceDiagram
    participant Camera
    participant Encoder
    Camera->>Encoder: frame 9 (t = 0.300)
    Note over Encoder: no frame within 33.3 ms
    Encoder->>Encoder: repeat frame 9 at t = 0.333
    Camera->>Encoder: frame 10 (t = 0.333), 1 ms late
    Encoder->>Encoder: same timestamp: muxer moves it to 0.333344
Loading

The real frame then lasts 11 µs. The real-capture oracle on Windows (#2667) found 11 to 41 duplicated camera frames per 8 s recording (pts 0.266667, 0.266678).

Fix

FramePacer (crates/recording/src/output_pipeline/frame_pacing.rs) decides when to repeat, for all seven loops:

  • A frame from the source is encoded at once, at its own timestamp.
  • The last frame is repeated only after three frame intervals of silence. A repeat takes the next slot on the last frame's grid, and is sent once a frame for that slot would be two intervals late, so a late real frame never finds its slot taken.
  • Nothing is repeated while the recording is paused. The fragmented muxers had no pause check and repeated frames through a pause; they now get the pause flag (SharedPauseState::flag).

Unit tests cover jittered frames (no repeats), a stall (repeats on the grid, behind real time), a pause, and the end of the stream.

Measured

recording/studio-camera/startup-drops, real capture on hosted Windows, synthetic 30 fps camera:

main This PR
Duplicated camera frames per recording 16, 28, 11, 41 (runs 39000141528, 39004015045, 39004601866, 39005636945) 1 (run 39004346646)

Still open, and separate from pacing: the remaining duplicate is near the start of the track (0.33 s), and the first 3.5 s of camera frames sit 66.7 ms off their steady offset, which main shows too.

@vercel

vercel Bot commented Oct 17, 2026 •

Copy link
Copy Markdown
Contributor

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
cap-status Ready Ready Preview Oct 17, 2026 10:42pm UTC

This branch was successfully deployed

2 active deployments
Preview – cap-web — 099d1f96 Deployed Oct 17, 2026 by vercel[bot]
Preview – cap-status — 099d1f96 Deployed Oct 17, 2026 by vercel[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant