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 の影響で実際の倍率は変動します。

主要な技術特性

  1. 線形メモリArrayBuffer を線形メモリとし、JS と Wasm が同一バッファを共有してゼロコピー転送
  2. GC 停止なし:Wasm に GC はなく、長時間計算が中断されにくい
  3. サンドボックス:明示的に import した関数とメモリのみアクセス可能
  4. ストリーミングコンパイル:ダウンロード中にコンパイル可能

実例 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 倍遅いですが、アップロード不要・インストール不要という利点で十分なトレードオフです。

技術的課題

  1. SharedArrayBuffer:マルチスレッド版は Cross-Origin-Isolation が必要。CDN によっては未対応
  2. メモリ:大きな動画では Wasm 線形メモリが数百 MB に—OOM に注意
  3. 初回読み込み: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 モジュールは遅延読み込みで、他ツールページの速度に影響しません。


今後の展望

  1. Wasm GC:標準化が進み、Java/Kotlin/Go が直接 Wasm をターゲットに
  2. Wasm Components:モジュール化され npm のように再利用可能に
  3. WASI:サーバー側でも Wasm を動かす System Interface
  4. Threads + SIMD:マルチスレッドとベクトル命令でネイティブに近づく

WebAssembly はブラウザ計算の境界を塗り替えています。ToolsKu は Wasm を深掘りし、インストール不要・アップロード不要・プライバシー保護のまま、デスクトップ級の能力をブラウザへ届け続けます。

ブラウザローカルツールを無料で試す →

#WebAssembly#FFmpeg#Rust#性能#WASM