Skip to content

fix(web): make the MP4 to MP3 converter write MP3 - #3427

Open
patrickballard wants to merge 2 commits into
CapSoftware:mainfrom
patrickballard:fix/mp3-converter-output
Open

patrickballard wants to merge 2 commits into
CapSoftware:mainfrom
patrickballard:fix/mp3-converter-output

Conversation

@patrickballard

@patrickballard patrickballard commented Oct 26, 2026 •

Copy link
Copy Markdown
Contributor

Closes #3426.

extractAudioFromVideo now converts with mediabunny, which apps/web already depends on for Loom imports, to Mp3OutputFormat. No browser encodes MP3 through WebCodecs, so it registers @mediabunny/mp3-encoder, mediabunny's LAME extension, which encodes in a worker. Both load only when someone converts to MP3, as Remotion already does in this component.

3-second MP4, H.264 + AAC 48 kHz stereo before after
download tone-test.mp3 tone-test.mp3
contents WAV, 16-bit PCM, 569,388 bytes MP3 (MPEG-1 Layer III), 120,168 bytes

A video without audio used to finish with "Conversion complete!" and a 44-byte WAV; it now shows "Conversion failed: This video has no audio track." If the video has audio the browser can't decode (AC-3 in Chrome, say), it shows "Your browser can't decode this video's audio."

Switching formats while converting cancels the conversion and shows "Conversion was cancelled", as Remotion's path did.

New dependency: @mediabunny/mp3-encoder 1.62.1 (MPL-2.0, like mediabunny; peer mediabunny ^1.0.0, and the lockfile keeps mediabunny at 1.49.0). Its chunk is about 312 KB with the LAME WASM inlined, loaded only on conversion. The bitrate is mediabunny's default (QUALITY_HIGH, 320 kbps for 48 kHz stereo).

Tests

  • Three new cases in media-format-converter.test.ts (already in CI's web test list), running real mediabunny and LAME (in a worker_threads worker under Node):
    • a new 17.8 KB fixture, converter-audio.mp4 (H.264 plus 0.25 s of PCM audio, which mediabunny decodes without WebCodecs), comes out as an audio/mpeg MP3 of about 0.25 s, downloaded as clip.mp3;
    • gif-6s.mp4, which has no audio, shows the no-audio error and saves nothing;
    • switching the target format to GIF during a real conversion shows "Conversion was cancelled" and tracks no failure; without the change it shows "Conversion failed: Output has been canceled."
      The first two fail without the change (audio/wav, and "Conversion complete!").
  • Checked in Chromium 152 on cap.so with the same builds (mediabunny 1.49.0 and the encoder 1.62.1, byte-identical to the installed packages): the 3-second MP4 above converted in 66 ms to a 120,168-byte MP3 that plays in an <audio> element and decodes to 3.0 s with its 440 Hz tone intact; cap.so's presenter.mp4, which has no audio, gets the no-audio error.
  • CI doesn't build the web app, so I built a throwaway Next 16.3.0 app (next build, Turbopack) that imports both packages the same way. Its output has one copy each of mediabunny and the encoder, the encoder's Node-only worker_threads fallback resolves to an empty module, and the built page converted the same 3-second MP4 to the same 120,168-byte MP3.
  • bun install --frozen-lockfile: no changes. bun run typecheck: no errors. Biome: the test file is clean, and the component's ten existing lint errors are unchanged, none on the changed lines.

RetriggerView in GreptileConfidence Score: 4/5

The PR appears safe to merge, with a non-blocking fix needed for how canceled MP3 conversions are reported.

Findings

  1. P2 Cancellation shows a failure ▶
Fix with agent prompt
### Issue 1
apps/web/components/tools/MediaFormatConverter.tsx:436-439
Switching formats during MP3 conversion calls `conversion.cancel()`, which rejects the running conversion with `ConversionCanceledError`. The shared catch only checks `MediaParser.hasBeenAborted`, so users see “Conversion failed” and the page sends `media_format_conversion_failed` for work they intentionally stopped. Recognize `ConversionCanceledError` or translate it to the existing cancellation error before rethrowing.

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

Summary

Replaces WAV output in the MP4-to-MP3 tool with actual MP3 encoding.

  • MP4-to-MP3 conversion now downloads audio in MP3 format.
  • Videos without usable audio now get a clear conversion error.

Reviews (1) · Last reviewed commit: "fix(web): make the MP4 to MP3 converter ..." · Reviewed by Greptile

The MP4 to MP3 tool asked Remotion for a WAV container and downloaded the
result as .mp3. Convert with mediabunny, which the web app already uses,
to an MP3 output encoded by its LAME extension, since browsers can't
encode MP3 through WebCodecs. A video without an audio track now gets an
error instead of an empty file.
@vercel

vercel Bot commented Oct 26, 2026

Copy link
Copy Markdown
Contributor

@patrickballard is attempting to deploy a commit to the Cap Software Inc Team on Vercel.

A member of the Team first needs to authorize it.

@socket-security

socket-security Bot commented Oct 26, 2026 •

Copy link
Copy Markdown

Review the following changes in direct dependencies. Learn more about Socket for GitHub.

Diff Package Supply Chain
Security
Vulnerability Quality Maintenance License
Addednpm/​@​mediabunny/​mp3-encoder@​1.62.11001001009670

View full report

Comment on lines +436 to 439
parserControllerRef.current = {
abort: () => {
void conversion.cancel();
},

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Cancellation shows a failure

Switching formats during MP3 conversion calls conversion.cancel(), which rejects the running conversion with ConversionCanceledError. The shared catch only checks MediaParser.hasBeenAborted, so users see “Conversion failed” and the page sends media_format_conversion_failed for work they intentionally stopped. Recognize ConversionCanceledError or translate it to the existing cancellation error before rethrowing.

Prompt To Fix With AI
This is a comment left during a code review.
Path: apps/web/components/tools/MediaFormatConverter.tsx
Line: 436-439

Comment:
**Cancellation shows a failure**

Switching formats during MP3 conversion calls `conversion.cancel()`, which rejects the running conversion with `ConversionCanceledError`. The shared catch only checks `MediaParser.hasBeenAborted`, so users see “Conversion failed” and the page sends `media_format_conversion_failed` for work they intentionally stopped. Recognize `ConversionCanceledError` or translate it to the existing cancellation error before rethrowing.

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in adf49e1. Switching formats mid-conversion now shows "Conversion was cancelled" and no longer tracks a failure. A cancel mid-write rejects with mediabunny's "Output has been canceled." rather than ConversionCanceledError (seen in Chromium and in the test), so the converter rethrows any error after a cancel as ConversionCanceledError and the catch recognises it by name, as the Loom import does. A new test switches to GIF during a real conversion.

Switching formats during an MP3 conversion cancels it, but the converter
only recognised Remotion's abort error, so it showed "Conversion failed:
Output has been canceled." and tracked a failed conversion. A cancelled
mediabunny conversion can reject with the output's own error rather than
ConversionCanceledError, so rethrow any error after a cancel as
ConversionCanceledError and treat that as a cancellation.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

MP4 to MP3 converter saves a WAV file named .mp3

1 participant