Single-Threaded vs Multi-Threaded In-Browser Transcoding
Running ffmpeg in a browser is no longer news — but the same site runs at very different speeds in different browsers, and some environments quietly switch to a compatibility mode. The story behind it is a story about threads.
How ffmpeg runs inside a browser
Desktop ffmpeg is a native program with full access to the operating system. Web pages live in a sandbox: no filesystem access, no free thread creation. The bridge is WebAssembly — ffmpeg compiled to wasm bytecode running in a browser-hosted VM at roughly 70-80 percent of native speed.
The hard constraint is threads: an ordinary page gets one main thread, so the wasm ffmpeg inside it runs single-threaded — one core burning while the rest of the CPU watches.
The conditions and costs of multi-threading
Real threading needs SharedArrayBuffer (shared memory) plus true Worker threads, and enabling SharedArrayBuffer requires the page to be delivered with cross-origin isolation (COOP/COEP headers) — a security requirement dating from the 2018 Spectre disclosures. With isolation in place, ffmpeg’s multi-threaded build splits the encode across cores for a several-fold speedup.
The cost is a narrower compatibility surface: some browsers, especially mobile ones and embedded webviews, half-support isolation — threads start but hang silently and the task never returns. This is a documented community-wide pitfall, not one site’s bug.
Automatic fallback: when multi-threading fails
The engineering answer is dual cores with automatic fallback: when isolation checks pass, load the multi-threaded core; if loading or running fails (timeout, hang, error), switch to the single-threaded core and retry — surfaced to the user as a compatibility-mode notice. Single-threaded is slower but never hangs on any device that runs a modern browser.
What it means for you: once a session has fallen back, later tasks also run single-threaded — let them finish rather than re-probing multi-threading. The same file can take several times longer in Safari (often fallback) than in Chrome (multi-threaded); that is normal, not laziness.
What belongs in a browser, and what does not
The sweet spot for in-browser local processing is everyday volume: clips of minutes to tens of minutes, single or small batches — zero upload, zero queue, acceptable total time. The triple stack (very long files, many files, extreme quality settings) magnifies the single-thread gap and stresses memory limits; that is desktop territory, or a case for splitting the job.
One practical rule: keep the processing tab in the foreground when queueing multiple jobs — background-tab throttling can slow things to a fraction, and no number of threads helps a frozen tab.