
什麼是 FFmpeg.wasm?
FFmpeg.wasm 是將知名的開源影音處理工具 FFmpeg 透過 Emscripten 編譯為 WebAssembly 的版本。它讓瀏覽器能夠在不依賴後端伺服器的情況下,直接在用戶端執行複雜的影片解碼、轉碼、合併等操作。
專案連結:github.com/ffmpegwasm/ffmpeg.wasm
傳統架構 vs FFmpeg.wasm 架構
傳統架構(後端轉碼):
用戶 → 上傳影片 → 伺服器 FFmpeg → 輸出 → 用戶下載
問題:伺服器 CPU 資源消耗大、頻寬成本高、隱私疑慮
FFmpeg.wasm 架構:
用戶 → 瀏覽器內 FFmpeg.wasm → 輸出 Blob → 用戶下載
優點:零伺服器消耗、隱私保障、離線可用
技術核心:WebAssembly 是什麼?
WebAssembly(Wasm)是一種低層級的二進位格式,設計目標是讓編譯語言(C、C++、Rust 等)的程式碼在瀏覽器中接近原生速度執行。
FFmpeg 的原始碼是 C 語言,Emscripten 工具鏈可以將 C 程式碼編譯成 .wasm 二進位模組,配合 JavaScript 膠水程式碼(ffmpeg-core.js)在瀏覽器環境運行。
FFmpeg.wasm 的兩種執行模式
單執行緒模式(Single-threaded)
import { FFmpeg } from '@ffmpeg/ffmpeg';
import { toBlobURL } from '@ffmpeg/util';
const ffmpeg = new FFmpeg();
await ffmpeg.load({
coreURL: await toBlobURL(
'https://unpkg.com/@ffmpeg/[email protected]/dist/esm/ffmpeg-core.js',
'text/javascript'
),
wasmURL: await toBlobURL(
'https://unpkg.com/@ffmpeg/[email protected]/dist/esm/ffmpeg-core.wasm',
'application/wasm'
),
});
- 不需要
SharedArrayBuffer - 不需要 特殊 HTTP Header(COOP/COEP)
- 所有操作在單一 JS 執行緒(Worker)中進行
- 適合大多數靜態網站部署(Cloudflare Pages、GitHub Pages 等)
多執行緒模式(Multi-threaded)
await ffmpeg.load({
coreURL: 'ffmpeg-core-mt.js', // 多執行緒版 core
wasmURL: 'ffmpeg-core-mt.wasm',
workerURL: 'ffmpeg-core-mt.worker.js',
});
- 使用
SharedArrayBuffer在多個 Web Worker 之間共享記憶體 - 需要伺服器設定以下 HTTP Headers:
Cross-Origin-Opener-Policy: same-origin
Cross-Origin-Embedder-Policy: require-corp
- 速度顯著提升(可利用多核心 CPU)
- 但設定較為複雜,部分 CDN 不支援
虛擬檔案系統(Emscripten FS)
FFmpeg.wasm 沒有直接存取本地磁碟的能力。它使用 Emscripten 的虛擬檔案系統(VFS) 模擬磁碟操作:
// 將 ArrayBuffer 寫入虛擬 FS
await ffmpeg.writeFile('input.ts', new Uint8Array(buffer));
// 執行 FFmpeg 命令(在虛擬 FS 中操作)
await ffmpeg.exec(['-i', 'input.ts', '-c', 'copy', 'output.mp4']);
// 讀取輸出
const data = await ffmpeg.readFile('output.mp4');
// 清理釋放記憶體(重要!)
await ffmpeg.deleteFile('input.ts');
await ffmpeg.deleteFile('output.mp4');
關鍵: 虛擬 FS 中的資料存在於 JavaScript 堆(Heap)中,必須在使用完畢後手動刪除,否則會佔用瀏覽器記憶體直到頁面關閉。
記憶體限制與最佳實踐
這是 FFmpeg.wasm 最大的先天限制:
| 項目 | 限制 |
|---|---|
| JS Heap 上限 | 約 1-2 GB(依瀏覽器和 OS 而定) |
| Wasm 記憶體模型 | 32-bit 定址,單一模組上限 4 GB |
| 實際可用 | 通常 500 MB - 1.5 GB |
建議的使用場景
- ✅ 720p 以下,30 分鐘以內的影片
- ✅ 主要是 concat(片段合併),非重新編碼
- ✅ 公開串流的技術研究與測試
- ❌ 4K/1080p 長片(記憶體不足)
- ❌ 複雜的濾鏡和重新編碼(速度過慢)
記憶體管理最佳實踐
// 1. 分批下載,避免同時持有所有 ArrayBuffer
const BATCH = 5;
for (let i = 0; i < segments.length; i += BATCH) {
const batch = await downloadBatch(segments.slice(i, i + BATCH));
// 立即寫入 VFS,可回收 JS 側的 ArrayBuffer
for (const [idx, buf] of batch.entries()) {
await ffmpeg.writeFile(`seg${i + idx}.ts`, new Uint8Array(buf));
}
}
// 2. 執行完成後立即清理 VFS
await ffmpeg.deleteFile('output.mp4');
與後端 API 的比較
| 面向 | FFmpeg.wasm | 後端 API |
|---|---|---|
| 伺服器成本 | 零 | 高(CPU 密集) |
| 隱私性 | 100%(本地處理) | 需信任伺服器 |
| 處理速度 | 慢(單核 Wasm) | 快(多核 + GPU) |
| 大檔案支援 | 受瀏覽器記憶體限制 | 幾乎無限制 |
| 部署複雜度 | 極簡(靜態資源) | 需要伺服器維護 |
| 最適場景 | 小型轉換、研究工具 | 生產環境大批量處理 |
實際應用:本站實作方式
本站的 HLS 研究工具 採用以下組合:
- @ffmpeg/ffmpeg 0.12.x(單執行緒,無需 COOP/COEP)
- @ffmpeg/core 0.12.x(對應的 Wasm Core)
- 透過 unpkg CDN 動態載入,首次載入約 15-30 秒(Wasm 模組約 30MB)
- 執行
ffmpeg -f concat -safe 0 -i concat.txt -c copy output.mp4完成 TS 合併
延伸閱讀
想立即測試您的 M3U8 連結嗎?
🚀 立即測試 M3U8 線上播放器