Skip to content

[Feature]: Raise the 16x playback-speed cap (frame-seek preview + offline audio for fast segments) #79

Description

@rainyflash

Search existing issues

  • I have searched the existing issues

Is your feature request related to a problem?

Speed regions are currently capped at 16× (MAX_PLAYBACK_SPEED = 16 in src/components/video-editor/types.ts). For long recordings this is limiting: condensing a 2-hour capture into a short timelapse segment needs far more than 16× (at 16× a 2 h 11 m recording still takes ~8 minutes). Desktop editors commonly allow much more: CapCut desktop goes to 100×, Premiere Pro's Speed/Duration dialog to 10,000 % (100×), Final Cut Pro accepts arbitrary custom rates.

I dug into why the cap exists, and it is not arbitrary — it is a hard Chromium engine limit, but one that only binds two of the three speed-handling paths:

  1. Chromium hard-caps HTMLMediaElement.playbackRate to [0.0625, 16]. Verified on the exact engine Openscreen ships (Electron, Chromium 146):

    v.playbackRate = 16    → ok
    v.playbackRate = 16.1  → NotSupportedError: Failed to set the 'playbackRate' property on
                             'HTMLMediaElement': The provided playback rate (16.1) is not in
                             the supported playback range.
    
  2. Two paths assign the region speed directly to playbackRate, so they inherit the cap:

    • Editor preview: videoEventHandlers.ts (video.playbackRate = activeSpeedRegion.speed), plus the webcam element and supplemental audio in VideoPlayback.tsx.
    • Export audio: audioEncoder.tsrenderPitchPreservedTimelineAudio() plays the timeline in real time through a hidden <audio> element (for preservesPitch) and captures it with MediaRecorder. Anything above 16× would throw.
  3. The export video path is already unlimited. streamingDecoder.ts retimes frames offline (sourceTime = segmentStart + (frameIndex / fps) × speed), so 100× video export works today — it is only fenced off by the UI cap.

There is also a practical preview constraint noted in types.ts ("above 16× the decoder can't keep up and the playhead stalls"), which any solution needs to respect: real-time decode at 16× of a 60 fps recording is already ~960 fps.

Describe the solution you'd like

Raise the cap to 100× (the de-facto industry ceiling — ffmpeg's atempo audio filter, Premiere's audio time remapping, and CapCut all cap at 100) by taking the two playbackRate-bound paths off the real-time engine for fast segments:

  1. Preview, segments > 16×: rAF-driven seek stepping. Instead of letting the media element play, advance the playhead by speed × Δt per animation frame and set video.currentTime to the target. Visually this is the fast-slideshow behaviour native NLEs show at extreme rates. The existing native-playback path stays untouched for ≤ 16× segments, so today's smooth preview is not affected.

  2. Export audio, segments > 16×: drop real-time capture.

    • Phase 1 (pragmatic): render silence for > 16× segments. At those rates audio carries no usable information anyway, and this matches what users get from timelapse features elsewhere. Segments ≤ 16× keep the current pitch-preserved real-time path.
    • Phase 2 (optional follow-up): offline pitch-preserved time-stretch (WSOLA) in a worker fed by AudioDecoder, reusing the streaming infrastructure from fix: stream large local recordings so the editor and export don't exhaust memory #74. This would give real audio up to 100× and, as a bonus, could eventually replace the real-time capture path entirely (audio export would no longer take output-duration wall-clock time).
  3. UI: raise MAX_PLAYBACK_SPEED to 100, keep the preset list as is, and let the custom-speed input accept up to 100. Optionally hint in the speed popover that > 16× segments preview as frame-stepping and export with silenced (Phase 1) audio.

Describe alternatives you've considered

  • Keep 16×: simplest, but condensing long recordings is a core screen-recording use case, and the video half of the work is already done.
  • WebAudio AudioBufferSourceNode.playbackRate: no pitch preservation and requires decoding the full track into memory, which conflicts with the large-recording streaming work from fix: stream large local recordings so the editor and export don't exhaust memory #74.
  • A "timelapse" toggle instead of higher speeds: avoids the audio question entirely, but a unified speed control up to 100× is more discoverable and matches user expectations from other editors.

Additional context

Comparison of caps elsewhere:

Tool Max speed Approach
CapCut desktop 100× offline retiming, offline audio stretch
Premiere Pro 10,000 % (time remapping 20,000 %) offline; audio remap capped at 100×
Final Cut Pro arbitrary custom offline
ffmpeg video unlimited (setpts); atempo 0.5–100 offline
Openscreen today 16× real-time playbackRate

The pattern across tools: video retiming is effectively unlimited, ~100× is the recognised ceiling for meaningful audio, and every tool that exceeds 16× does so by not driving a real-time media element.

Metadata

Metadata

Assignees

No one assigned

    Labels

    status: fixed in mainWork is merged into main but may not be in a downloadable release yet.status: pending releaseMerged change is waiting for a packaged desktop release.

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions