OpenCut/apps/web
Andrés Villagrán b1b3b1c9d1 feat(export): MediaRecorder fallback when WebCodecs encoders are missing
The existing exporter uses mediabunny, which delegates to the
WebCodecs VideoEncoder and AudioEncoder. On browsers where those
APIs are not exposed (the same environments that needed the decode
fallback in #794), export currently fails with
"AudioEncoder is not supported by this browser" before producing
any output.

This change adds a parallel fallback path in SceneExporter:

- New helpers \`isWebCodecsExportSupported()\` and
  \`detectMediaRecorderSupport()\` live in a tiny dependency-free
  module so they can be unit-tested without dragging in WASM.
- New \`exportWithMediaRecorder\` drives the existing CanvasRenderer
  at real-time wall-clock, captures the output canvas with
  \`HTMLCanvasElement.captureStream(fps)\`, mixes the project audio
  buffer through a \`MediaStreamAudioDestinationNode\`, and records
  the combined MediaStream with MediaRecorder, producing a WebM
  blob the same browser can play back natively.
- \`SceneExporter.export()\` detects \`!isWebCodecsExportSupported()\`
  at entry and delegates to the new path. The WebCodecs path is
  unchanged for capable browsers.

Trade-offs of the fallback path:

- Output is always WebM (most browsers don't expose an MP4 muxer
  via MediaRecorder). The user's requested format is honoured
  best-effort.
- Rendering runs at real time, so a 60-second timeline takes
  roughly 60 seconds to export. mediabunny's WebCodecs path
  continues to render faster than real-time on capable browsers.
- Bitrate is mapped per quality preset to a numeric value
  compatible with \`MediaRecorder.videoBitsPerSecond\`.

Unit tests cover the feature-detection helpers across the four
states of \`VideoEncoder\` / \`AudioEncoder\` / \`MediaRecorder\`
availability.
2026-05-16 21:47:34 -04:00
..
migrations chore: normalize line endings 2026-03-29 15:56:48 +02:00
public chore: delete ffmpeg public assets 2026-04-21 13:00:26 +02:00
scripts chore: normalize line endings 2026-03-29 15:56:48 +02:00
src feat(export): MediaRecorder fallback when WebCodecs encoders are missing 2026-05-16 21:47:34 -04:00
.env.example chore: remove transcription envs 2026-04-04 08:53:10 +02:00
.gitignore chore: update .gitignore 2026-03-29 18:55:56 +02:00
Dockerfile chore: remove transcription envs 2026-04-04 08:53:10 +02:00
components.json chore: normalize line endings 2026-03-29 15:56:48 +02:00
content-collections.ts feat: new-release notice and colocate changelog under domain 2026-04-15 02:05:41 +02:00
drizzle.config.ts fix: correct schema path in drizzle config 2026-04-15 06:04:29 +02:00
next.config.ts feat: migrate GPU renderer from WebGL to wgpu/WASM 2026-04-01 13:57:32 +02:00
open-next.config.ts chore: add missing open-next config 2026-03-29 15:58:46 +02:00
package.json chore: switch from biome to eslint + prettier; fix ton of lint issues 2026-05-02 03:27:23 +02:00
postcss.config.mjs feat: masks, properties refactor, shaders, storage migrations, and more 2026-03-29 15:48:22 +02:00
tsconfig.json chore: switch from biome to eslint + prettier; fix ton of lint issues 2026-05-02 03:27:23 +02:00
wrangler.jsonc chore: normalize line endings 2026-03-29 15:56:48 +02:00