Skip to content

fix: bound waveform extraction memory usage for large video files#1544

Open
smirk-dev wants to merge 1 commit into
magic-peach:mainfrom
smirk-dev:fix/waveform-large-file-memory-smirk
Open

fix: bound waveform extraction memory usage for large video files#1544
smirk-dev wants to merge 1 commit into
magic-peach:mainfrom
smirk-dev:fix/waveform-large-file-memory-smirk

Conversation

@smirk-dev
Copy link
Copy Markdown

Summary

Waveform extraction for large videos no longer reads the entire file into memory. useAudioWaveform previously called file.arrayBuffer() on the full uploaded video regardless of size; for uploads near the 2 GB cap this allocated multiple gigabytes (raw buffer + decoded PCM + processing buffers) and crashed browser tabs before editing even began. Extraction is now bounded by a configurable size threshold, with a graceful placeholder for files above it.

Closes #1013

Technical details

File-size threshold

  • New MAX_WAVEFORM_FILE_SIZE_BYTES (default 300 MB) in src/lib/constants.ts, overridable per call via a third useAudioWaveform argument.
  • Files at or below the threshold are decoded; files above it skip extraction entirely and are never read into memory.

Bounded / sliced decode strategy

  • The hook now reads audio through file.slice(0, maxFileSizeBytes).arrayBuffer() instead of file.arrayBuffer() on the whole file. For inputs within the threshold this is the entire file (unchanged behaviour); the slice caps the worst-case allocation so decodeAudioData never receives more than the threshold's worth of bytes.
  • Oversized files short-circuit before any read — file.slice/arrayBuffer are never invoked, so the catastrophic multi-GB allocation can't happen.

New status shape

  • useAudioWaveform now returns a discriminated status: "idle" | "loading" | "ready" | "disabled" | "error" (plus waveform and a retained isLoading flag for backward compatibility).
  • TrimControl renders based on status: the (previously unused) WaveformCanvas is wired in for normal files, and a static placeholder with helper text is shown when status === "disabled".

Cancellation / lifecycle

  • In-flight reads/decodes bail out on unmount, file change, or bar-count change before constructing an AudioContext or calling setState, preventing updates on unmounted components and stale waveforms after a new file is selected.

User experience

  • Large files (> 300 MB): a clean placeholder bar with the text "Waveform preview is disabled for very large files to keep the editor responsive." The clip stays fully editable — no frozen UI, no tab crash.
  • Small files: unchanged — the waveform renders exactly as before.

Testing

Commands run locally:

  • npx vitest run130 passed (15 files), including 9 new tests.
  • npx next lint — no warnings or errors.
  • npx next build — static export succeeds.

New tests:

  • src/hooks/__tests__/useAudioWaveform.test.tsx
    • waveform extracted for files within the threshold (correct shape),
    • extraction skipped (status: "disabled") for very large files with an assertion that slice/arrayBuffer are never called — no full read,
    • custom threshold respected,
    • decode failure surfaces status: "error",
    • unmount mid-load cancels work and never advances to ready.
  • src/components/__tests__/TrimControl.test.tsx
    • disabled placeholder renders for large files,
    • waveform canvas renders for normal files,
    • no waveform UI when no file is selected.

Notes

Scope is intentionally limited to waveform extraction — no changes to FFmpeg export flows or other behaviour. Types follow the existing patterns in the hook and components.

🤖 Generated with Claude Code

Waveform extraction called file.arrayBuffer() on the full uploaded video
regardless of size. For uploads up to the 2GB cap this allocated multiple
gigabytes (raw buffer + decoded PCM), spiking the heap and crashing browser
tabs before editing began.

- Add MAX_WAVEFORM_FILE_SIZE_BYTES (300MB) config in src/lib/constants.ts.
- Refactor useAudioWaveform to a discriminated status union
  (idle | loading | ready | disabled | error). Files over the threshold are
  never read into memory; within the threshold audio is read through a bounded
  Blob.slice so decodeAudioData never receives more than the threshold's bytes.
  Small files are unchanged.
- Strengthen cancellation: in-flight reads/decodes bail out on unmount or file
  change before creating an AudioContext or setting state.
- Wire WaveformCanvas into TrimControl and render a placeholder + helper text
  when extraction is disabled for large files.
- Add tests for threshold behaviour, the no-full-read guarantee, custom
  thresholds, decode errors, and unmount cancellation.

Closes magic-peach#1013

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@vercel
Copy link
Copy Markdown

vercel Bot commented Jun 7, 2026

@smirk-dev is attempting to deploy a commit to the magic-peach1's projects Team on Vercel.

A member of the Team first needs to authorize it.

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Jun 7, 2026

✅ PR Format Check Passed — @smirk-dev

Basic format checks passed. A maintainer will review your code changes.

This does not mean the PR is approved — it just means the format is correct.

@github-actions github-actions Bot added the level:advanced Advanced level - 55 pts label Jun 7, 2026
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Jun 7, 2026

👋 Thanks for your PR, @smirk-dev!

Welcome to Reframe — a browser-based video editor built for everyone 🎬

What happens next

  1. 🤖 Automated checks — build & TypeScript typecheck will run automatically
  2. Vercel preview — a preview deployment will be created (requires maintainer authorization for fork PRs)
  3. 👀 Code review — a maintainer will review your changes
  4. 🚀 Merge — once approved, your PR will be merged!

Quick checklist

  • PR title follows Conventional Commits (e.g. feat: add dark mode)
  • Linked the issue this PR closes (e.g. Closes #123)
  • Tested the changes locally (bun run dev)
  • Build passes (bun run build)

Useful links

Happy coding! 🎉

@github-actions github-actions Bot added type:bug Bug fix type:design UI/UX design type:testing Testing labels Jun 7, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

level:advanced Advanced level - 55 pts type:bug Bug fix type:design UI/UX design type:testing Testing

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[BUG] Large Video Waveform Extraction Reads Entire File Into Memory and Crashes Browser Tabs

1 participant