Converting MOV to MP4 or extracting audio from video has historically required either:
- Downloading sketchy desktop software bundled with adware.
- Uploading files to cloud conversion websites with 100MB limits and queue timers.
By compiling FFmpeg C code to WebAssembly with Emscripten, the entire transcoding pipeline runs directly inside the client's sandboxed browser process.
We built the In-Browser Converter on SolveMyMedia.
In-Memory Media Transcode via FFmpeg WASM
import { createFFmpeg, fetchFile } from '@ffmpeg/ffmpeg';
const ffmpeg = createFFmpeg({ log: false });
export async function convertMediaInMemory(file, targetFormat = 'mp4') {
if (!ffmpeg.isLoaded()) await ffmpeg.load();
ffmpeg.FS('writeFile', 'input_raw', await fetchFile(file));
await ffmpeg.run('-i', 'input_raw', '-c:v', 'libx264', '-preset', 'ultrafast', `output.${targetFormat}`);
const data = ffmpeg.FS('readFile', `output.${targetFormat}`);
return new Blob([data.buffer]);
}
Features:
- Convert MOV, MKV, AVI, WebM to MP4.
- Extract MP3 and WAV audio streams in 0.3 seconds.
- 100% client-side privacy.
Test it live:
👉 Converter: https://solvemymedia.com/convert-video
👉 Extract Audio: https://solvemymedia.com/video-to-audio
Top comments (2)
One thing to watch with this pattern: FS('writeFile') copies the whole input into the wasm heap, and the output sits there too, so a 1 GB MOV needs well over 2 GB of memory before the Blob is even created. Mobile Safari tends to kill the tab long before that. Mounting the File through WORKERFS avoids the input copy. Also worth unlinking input_raw and the output after each run, otherwise the second conversion starts with the first one's files still on the heap. Are you on the single-thread core, or did you set up COOP/COEP for the multi-thread build?
This is actually a really good catch thank you for taking the time to point this out! I hadn't fully accounted for how expensive the input copy becomes at larger file sizes, especially on mobile Safari. The WORKERFS approach makes a lot of sense here, and I’ll definitely look into unlinking the files between runs as well.
And yep, I’m currently on the single-thread core. I haven’t set up COOP/COEP for the multi-thread build yet, so that’s another thing I’ll need to explore. Really appreciate the detailed feedback this is exactly the kind of stuff that’s easy to miss when testing mostly with smaller files. 🙌
Some comments may only be visible to logged-in visitors. Sign in to view all comments.