WebAssembly がブラウザ計算を変える:FFmpeg.wasm から OxiPNG まで
技术架构(更新: 2026年5月15日)
ブラウザ計算の限界
長い間、ブラウザで動くのは JavaScript だけでした。計算負荷の高い処理では、その天井ははっきりしています。
- 動画トランスコード:1080p 変換は数十億回の演算
- 画像圧縮:PNG 可逆最適化は DEFLATE + エントロピー符号化
- OCR:Tesseract は LSTM ニューラルネット推論
- 暗号:RSA/SM2 などの公開鍵演算は大整数演算
これらを純 JavaScript で実装すると、ネイティブ比で 10〜100 倍遅いことが多いです。
WebAssembly:ブラウザの「第二のエンジン」
基本概念
WebAssembly(Wasm)は低レベルのバイナリ命令形式で、スタック型 VM 向けのコンパイル先として設計されています。
C/C++/Rust/Zig ソース
↓ コンパイル
Wasm バイナリ (.wasm)
↓ ブラウザにダウンロード
Wasm ランタイムがデコード&実行
↓ サンドボックス内
ネイティブに近い実行速度
性能比較
| ベンチマーク | JavaScript | WebAssembly | 倍率 |
|---|---|---|---|
| Fibonacci(45) | 8.2s | 1.1s | 7.5x |
| ガウシアンぼかし | 320ms | 45ms | 7.1x |
| PDF 解析 | 580ms | 95ms | 6.1x |
| 正規表現エンジン | 210ms | 38ms | 5.5x |
Chrome 120、M2 MacBook Pro で計測。メモリレイアウトや GC の影響で実際の倍率は変動します。
主要な技術特性
- 線形メモリ:
ArrayBufferを線形メモリとし、JS と Wasm が同一バッファを共有してゼロコピー転送 - GC 停止なし:Wasm に GC はなく、長時間計算が中断されにくい
- サンドボックス:明示的に import した関数とメモリのみアクセス可能
- ストリーミングコンパイル:ダウンロード中にコンパイル可能
実例 1:FFmpeg.wasm による動画変換
ToolsKu の動画ツール(形式変換・トリム・圧縮・GIF 化)はすべて FFmpeg.wasm ベースです。
アーキテクチャ
ユーザーが動画を選択
↓
FileReader で ArrayBuffer に読み込み
↓
ffmpeg.writeFile('input.mp4', arrayBuffer) ← Wasm 仮想 FS に書き込み
↓
ffmpeg.exec('-i input.mp4 -c:v libx264 output.mp4') ← 変換実行
↓
ffmpeg.readFile('output.mp4') ← 結果を読み取り
↓
Blob → URL.createObjectURL → ダウンロード
コアコード
import { FFmpeg } from '@ffmpeg/ffmpeg';
import { toBlobURL } from '@ffmpeg/util';
const ffmpeg = new FFmpeg();
// Wasm コアを CDN からストリーミング読み込み
const baseURL = 'https://unpkg.com/@ffmpeg/core@0.12.6/dist/esm';
await ffmpeg.load({
coreURL: await toBlobURL(`${baseURL}/ffmpeg-core.js`, 'text/javascript'),
wasmURL: await toBlobURL(`${baseURL}/ffmpeg-core.wasm`, 'application/wasm'),
});
// 入力ファイルを書き込み
await ffmpeg.writeFile('input.mp4', await fetchFile(file));
// トランスコード
await ffmpeg.exec(['-i', 'input.mp4', '-c:v', 'libx264', '-preset', 'fast', 'output.mp4']);
// 出力を読み取り
const data = await ffmpeg.readFile('output.mp4');
性能
| 操作 | 入力サイズ | 所要時間 | デスクトップ FFmpeg 比 |
|---|---|---|---|
| MP4 → WebM | 50MB | ~45s | ~8s (5.6x) |
| トリム | 50MB | ~12s | ~3s (4x) |
| GIF 化 | 10MB | ~25s | ~4s (6.3x) |
| 音声抽出 | 50MB | ~8s | ~2s (4x) |
ブラウザ Wasm はデスクトップ比 4〜6 倍遅いですが、アップロード不要・インストール不要という利点で十分なトレードオフです。
技術的課題
- SharedArrayBuffer:マルチスレッド版は
Cross-Origin-Isolationが必要。CDN によっては未対応 - メモリ:大きな動画では Wasm 線形メモリが数百 MB に—OOM に注意
- 初回読み込み:ffmpeg-core.wasm は約 30MB。初回は遅い(以降はブラウザキャッシュ)
実例 2:OxiPNG による PNG 可逆圧縮
ToolsKu の PNG 圧縮は Rust 製の高性能オプティマイザ OxiPNG を Wasm で実行しています。
Rust + Wasm を選ぶ理由
- ゼロコスト抽象化:Rust の所有権 + Wasm の線形メモリで GC オーバーヘッドなし
- 小さいバイナリ:Rust → Wasm はランタイム不要(Go の Wasm は約 8MB の runtime が必要)
- メモリ安全:コンパイル時にリークやバッファオーバーフローを防止
@jsquash/oxipng の統合
import { oxipng } from '@jsquash/oxipng';
// PNG を ArrayBuffer で読み込み
const inputBuffer = await file.arrayBuffer();
// 可逆最適化(OxiPNG Wasm 内で実行)
const outputBuffer = await oxipng(inputBuffer, {
level: 2, // 最適化レベル 0-6
interlace: false,
});
// outputBuffer が最適化後の PNG
const blob = new Blob([outputBuffer], { type: 'image/png' });
圧縮効果
| 画像種別 | 元サイズ | 最適化後 | 削減率 | 時間 |
|---|---|---|---|---|
| スクリーンショット (1920x1080) | 2.1 MB | 1.5 MB | 29% | 0.3s |
| UI アイコン (256x256) | 45 KB | 28 KB | 38% | 0.05s |
| 写真 (PNG) | 5.2 MB | 4.1 MB | 21% | 0.8s |
| アルファ付き | 800 KB | 520 KB | 35% | 0.15s |
Wasm の限界と対策
限界 1:DOM アクセス不可
Wasm は DOM を直接操作できません。JS 経由が必須です。
Wasm 計算 → JS グルー → DOM 更新
対策:計算集約部分は Wasm、UI は JavaScript に分担。
限界 2:初回読み込み
大きな Wasm(ffmpeg-core.wasm 約 30MB)は初回が遅い。
対策:
- ストリーミングコンパイルでダウンロードと並行
- 動画ツールページでのみ FFmpeg Wasm を遅延読み込み
Cache-Controlを長く—Wasm は安定しており 1 年キャッシュも妥当
限界 3:デバッグの難しさ
Wasm バイナリはそのままでは読みにくい。
対策:
- 開発時に DWARF デバッグ情報
- Chrome DevTools の Wasm デバッグ
- コアは Rust/C で単体テスト、Wasm は薄いグルーに留める
ToolsKu の Wasm スタック
| 機能 | Wasm ライブラリ | 言語 | Wasm サイズ | 性能 |
|---|---|---|---|---|
| 動画変換 | FFmpeg.wasm | C | ~30MB | デスクトップの約 1/5 |
| PNG 圧縮 | OxiPNG | Rust | ~1.2MB | デスクトップに近い |
| OCR | Tesseract.js | C++ | ~2.5MB | 実用可能 |
| PDF 描画 | pdfjs-dist | C++ (ビルド済) | ~2MB | スムーズ |
すべての Wasm モジュールは遅延読み込みで、他ツールページの速度に影響しません。
今後の展望
- Wasm GC:標準化が進み、Java/Kotlin/Go が直接 Wasm をターゲットに
- Wasm Components:モジュール化され npm のように再利用可能に
- WASI:サーバー側でも Wasm を動かす System Interface
- Threads + SIMD:マルチスレッドとベクトル命令でネイティブに近づく
WebAssembly はブラウザ計算の境界を塗り替えています。ToolsKu は Wasm を深掘りし、インストール不要・アップロード不要・プライバシー保護のまま、デスクトップ級の能力をブラウザへ届け続けます。
ブラウザローカルツールを無料で試す →
#WebAssembly#FFmpeg#Rust#性能#WASM