Skip to content

Commit 65cb530

Browse files
feat(posts): add "File Converter with FFmpeg WebAssembly"
Post: 2026-08-20-file-converter-ffmpeg-wasm.md
1 parent b8a0db9 commit 65cb530

1 file changed

Lines changed: 68 additions & 0 deletions

File tree

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
---
2+
layout: post
3+
title: File Converter with FFmpeg WebAssembly
4+
date: 2026-08-20 22:12:02
5+
excerpt: How I built a browser-based file converter that converts media files client-side using FFmpeg WebAssembly.
6+
categories: ffmpeg wasm react javascript site browser
7+
---
8+
9+
How I built a [File Converter](https://remarkablemark.org/file-converter/) that converts media files in the browser. It runs [FFmpeg](https://ffmpeg.org/) compiled to WebAssembly via [@ffmpeg/ffmpeg](https://github.com/ffmpegwasm/ffmpeg.wasm).
10+
11+
## Motivation
12+
13+
Traditional file converters send files to a server. That raises privacy concerns, requires bandwidth for large files, and costs money to host — which is why many existing services are ad-supported. With FFmpeg.wasm, all processing happens client-side in the browser.
14+
15+
## File Types
16+
17+
The file converter supports the file types:
18+
19+
| Category | Inputs | Outputs |
20+
| -------- | ----------------------------------- | ------------------------------ |
21+
| Image | PNG, JPEG, WebP, GIF, BMP, ICO, SVG | PNG, JPEG, WebP, GIF, BMP, ICO |
22+
| Video | MP4, WebM, MOV, AVI, MKV, GIF | MP4, WebM, MOV, AVI, MKV, GIF |
23+
| Audio | MP3, WAV, OGG, AAC, FLAC, M4A | MP3, WAV, OGG, AAC, FLAC, M4A |
24+
25+
SVG inputs are rasterized to the chosen bitmap format.
26+
27+
## How It Works
28+
29+
1. **Upload a file** — drag-and-drop or click to upload. It auto-detects the category (image, video, audio) from the MIME type and file extension.
30+
2. **Select a format** — only compatible output formats are shown for the detected category.
31+
3. **Controls** — an advanced options panel appears based on the category:
32+
- **Image**: dimensions, fit mode (contain, cover, stretch, force), quality, transparency preservation, background color.
33+
- **Video**: dimensions, fit mode, frame rate, CRF quality, audio preservation with bitrate, GIF loop toggle.
34+
- **Audio**: bitrate, sample rate, channels (mono/stereo).
35+
4. **Convert** — FFmpeg.wasm processes the file and a progress bar tracks the transcode.
36+
5. **Download** — the converted file is ready to download with an editable filename.
37+
38+
## Technical Decisions
39+
40+
### Lazy-Loading FFmpeg
41+
42+
FFmpeg core and WASM are loaded from the [jsDelivr](https://cdn.jsdelivr.net) CDN only after the user clicks "Convert". This keeps the initial page load fast since the ~30 MB WASM payload loads on demand, not on page render. The assets are pinned at the specific URLs:
43+
44+
- [https://cdn.jsdelivr.net/npm/@ffmpeg/core@0.12.10/dist/esm/ffmpeg-core.js](https://cdn.jsdelivr.net/npm/@ffmpeg/core@0.12.10/dist/esm/ffmpeg-core.js)
45+
- [https://cdn.jsdelivr.net/npm/@ffmpeg/core@0.12.10/dist/esm/ffmpeg-core.wasm](https://cdn.jsdelivr.net/npm/@ffmpeg/core@0.12.10/dist/esm/ffmpeg-core.wasm)
46+
47+
Local serving via a Vite plugin was attempted but reverted since Vite intercepts the dynamic `import()` calls inside the FFmpeg worker, which breaks loading.
48+
49+
### Conversion Flow
50+
51+
FFmpeg.wasm runs in a Web Worker with its own virtual file system. The conversion pipeline is:
52+
53+
1. Write the input file to the virtual FS with `ffmpeg.writeFile()`
54+
2. Execute the FFmpeg command with `ffmpeg.exec()` — args are built from the selected format and options
55+
3. Read the output file from the virtual FS with `ffmpeg.readFile()`
56+
4. Wrap the result in a `Blob` and generate a download link with `URL.createObjectURL()`
57+
58+
### MP4 to WebM
59+
60+
The default VP9 encoder hangs in the single-threaded ffmpeg.wasm build. Switching to VP8 with `-deadline good -cpu-used 5` fixes it.
61+
62+
### Large File Limitation
63+
64+
Since FFmpeg.wasm runs entirely in memory, very large files can fail or freeze the tab. The app warns when a file exceeds 100 MB but conversions are not blocked.
65+
66+
## Try It
67+
68+
You can try the [File Converter](https://remarkablemark.org/file-converter/) or check out the [source code](https://github.com/remarkablemark/file-converter).

0 commit comments

Comments
 (0)