How to Load Multi-Threaded FFmpeg.wasm with COOP/COEP
This article provides a direct guide on running the multi-threaded
version of ffmpeg.wasm in the browser. To utilize
multi-threading, modern web browsers require the use of
SharedArrayBuffer, which is disabled by default for
security reasons. Below, you will learn why Cross-Origin Opener Policy
(COOP) and Cross-Origin Embedder Policy (COEP) headers are mandatory,
how to configure these headers across common server environments, and
how to write the JavaScript code to initialize the multi-threaded FFmpeg
core.
Step 1: Configure COOP and COEP Headers
Multi-threading in WebAssembly relies on web workers sharing memory
via SharedArrayBuffer. Browsers only expose
SharedArrayBuffer in a cross-origin isolated context. To
enable this context, your web server must deliver the following HTTP
response headers for the top-level document and all associated
assets:
Cross-Origin-Opener-Policy: same-origin
Cross-Origin-Embedder-Policy: require-corp
Node.js (Express)
const express = require('express');
const app = express();
app.use((req, res, next) => {
res.setHeader('Cross-Origin-Opener-Policy', 'same-origin');
res.setHeader('Cross-Origin-Embedder-Policy', 'require-corp');
next();
});
app.use(express.static('public'));
app.listen(3000);Nginx
server {
listen 80;
server_name localhost;
location / {
root /path/to/dist;
try_files $uri $uri/ =404;
add_header Cross-Origin-Opener-Policy "same-origin";
add_header Cross-Origin-Embedder-Policy "require-corp";
}
}
Vite Dev Server
(vite.config.js)
import { defineConfig } from 'vite';
export default defineConfig({
server: {
headers: {
'Cross-Origin-Opener-Policy': 'same-origin',
'Cross-Origin-Embedder-Policy': 'require-corp',
},
},
});Step 2: Install Required Dependencies
Ensure you have @ffmpeg/ffmpeg and the multi-threaded
core @ffmpeg/core-mt installed along with
@ffmpeg/util for loading assets as Blob URLs.
npm install @ffmpeg/ffmpeg @ffmpeg/core-mt @ffmpeg/utilStep 3: Initialize the Multi-Threaded FFmpeg Instance
Import the dependencies and load the multi-threaded core using
toBlobURL to avoid cross-origin and worker-loading
errors:
import { FFmpeg } from '@ffmpeg/ffmpeg';
import { toBlobURL } from '@ffmpeg/util';
const ffmpeg = new FFmpeg();
async function loadMultiThreadedFFmpeg() {
// Verify isolation before attempting to load
if (!crossOriginIsolated) {
throw new Error('COOP/COEP headers are not configured properly. crossOriginIsolated is false.');
}
// Define the base URL for the multi-threaded core assets
const baseURL = 'https://unpkg.com/@ffmpeg/core-mt@0.12.6/dist/esm';
// Load the core, wasm, and worker scripts via Blob URLs
await ffmpeg.load({
coreURL: await toBlobURL(`${baseURL}/ffmpeg-core.js`, 'text/javascript'),
wasmURL: await toBlobURL(`${baseURL}/ffmpeg-core.wasm`, 'application/wasm'),
workerURL: await toBlobURL(`${baseURL}/ffmpeg-core.worker.js`, 'text/javascript'),
});
console.log('Multi-threaded ffmpeg.wasm loaded successfully!');
}
loadMultiThreadedFFmpeg();Step 4: Verify Multi-Threading
Open your browser's Developer Tools and verify the setup:
- In the Console, type
window.crossOriginIsolatedand ensure it returnstrue. - Inspect the Network or Sources tab during FFmpeg execution; you will observe multiple Web Workers being instantiated, executing tasks concurrently across available CPU threads.