From f510610ea1797977b9e5568e6d2d7687b217d9f0 Mon Sep 17 00:00:00 2001 From: zack34567 Date: Sat, 23 May 2026 10:40:21 +0530 Subject: [PATCH] feat: add COOP/COEP headers and enable FFmpeg.wasm multi-threading --- CONTRIBUTING.md | 13 +++++++++++++ public/_headers | 3 +++ src/lib/ffmpeg.ts | 20 +++++++++++++++----- vercel.json | 10 +++++++++- 4 files changed, 40 insertions(+), 6 deletions(-) create mode 100644 public/_headers diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index af91ea2c..2b0ab463 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -419,3 +419,16 @@ We expect all contributors to follow our Code of Conduct to create a safe, welco - **Constructive feedback is encouraged.** Thank you for making Reframe better! 🎬 + +## Cross-Origin Isolation & GitHub Pages + +This project uses `Cross-Origin-Opener-Policy` and `Cross-Origin-Embedder-Policy` +headers to enable cross-origin isolation, which allows FFmpeg.wasm to run in +multi-threaded mode for significantly faster video exports. + +**GitHub Pages does not support custom HTTP headers.** +If you are deploying to GitHub Pages, cross-origin isolation cannot be enabled +and FFmpeg will automatically fall back to single-threaded mode. + +For full multi-threading support, deploy to **Vercel**, **Netlify**, or +**Cloudflare Pages** where custom headers are supported. diff --git a/public/_headers b/public/_headers new file mode 100644 index 00000000..c3720e51 --- /dev/null +++ b/public/_headers @@ -0,0 +1,3 @@ +/* + Cross-Origin-Opener-Policy: same-origin + Cross-Origin-Embedder-Policy: require-corp diff --git a/src/lib/ffmpeg.ts b/src/lib/ffmpeg.ts index ef9f6157..79b737d2 100644 --- a/src/lib/ffmpeg.ts +++ b/src/lib/ffmpeg.ts @@ -1,5 +1,5 @@ import { FFmpeg } from "@ffmpeg/ffmpeg"; -import { fetchFile } from "@ffmpeg/util"; +import { fetchFile, toBlobURL } from "@ffmpeg/util"; import { EditRecipe, ExportResult, BackgroundMusicOptions, ImageOverlayOptions } from "./types"; import { getPresetById } from "./presets"; import { simd } from "wasm-feature-detect"; @@ -57,10 +57,20 @@ export async function loadFFmpeg( try { ffmpeg.on("progress", handleProgress); - // Secure engine load using verified runtime checksum hashes from main + const isIsolated = typeof self !== "undefined" && self.crossOriginIsolated; + const baseURL = isIsolated + ? "https://unpkg.com/@ffmpeg/core-mt@0.12.6/dist/esm" + : "https://unpkg.com/@ffmpeg/core@0.12.6/dist/esm"; + await ffmpeg.load({ - coreURL: await fetchWithIntegrity(`${CORE_BASE_URL}/ffmpeg-core.js`, "text/javascript"), - wasmURL: await fetchWithIntegrity(`${CORE_BASE_URL}/ffmpeg-core.wasm`, "application/wasm"), + coreURL: await toBlobURL(`${baseURL}/ffmpeg-core.js`, "text/javascript"), + wasmURL: await toBlobURL(`${baseURL}/ffmpeg-core.wasm`, "application/wasm"), + ...(isIsolated && { + workerURL: await toBlobURL( + `${baseURL}/ffmpeg-core.worker.js`, + "text/javascript" + ), + }), }, { signal }); onProgress?.(100); @@ -477,4 +487,4 @@ export async function exportVideo( export function formatBytes(bytes: number): string { if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`; return `${(bytes / (1024 * 1024)).toFixed(1)} MB`; -} \ No newline at end of file +} diff --git a/vercel.json b/vercel.json index 9b847292..60c58b0b 100644 --- a/vercel.json +++ b/vercel.json @@ -21,8 +21,16 @@ { "key": "Strict-Transport-Security", "value": "max-age=31536000; includeSubDomains" + }, + { + "key": "Cross-Origin-Opener-Policy", + "value": "same-origin" + }, + { + "key": "Cross-Origin-Embedder-Policy", + "value": "require-corp" } ] } ] -} \ No newline at end of file +}