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 (1)
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?