About

「100%ローカル」はメディアファイルの話 — WhisperとffmpegをWASMに押し込んだ代償

ブラウザ完結の動画エディタrescriptを実際に動かして確かめたこと

「100%ローカル」という言葉は、メディアファイルが外に出ないという意味だ。何のデータも出ないという意味ではない。そしてローカルで動かす代償は、初回のモデルダウンロードと、サーバー設定が要る SharedArrayBuffer として返ってくる。読み終えれば、「ローカルファースト」のツールを選ぶとき何を確かめるか、似たものを自分で作るとき何を覚悟するかがわかる。

動かしてみたもの

Threadsでrescript(github.com/wassgha/rescript)が共有されていた。「文字起こしのテキストを消すと、動画・音声がその区間だけ切れる、100%ブラウザローカルのエディタ」だ。クローンして実際に動かしてみた(2026-08-24)。

npm install    741 packages / node_modules 1.3GB
起動           Next.js 16、Ready in 273ms
文字起こし     サンプル動画(11.5秒)を正確に文字起こし。話者分離・単語ごとのタイムラインまで

自分で作った3文のサンプルが、誤字なくそのまま出てきた。文字起こしの品質は良かった。

ローカルの中身

サーバーがないのではなく、モデルとffmpegを丸ごとブラウザに押し込んだ構造だ。READMEによると、文字起こしはtransformers.jsでWhisper(baseとsmallのtimestamped版)を動かし、区間の切り出しと書き出しはマルチスレッド版のffmpeg.wasm(WebAssemblyにコンパイルしたffmpeg)が担う。WebGPUがあれば推論に使い、なければWASMにフォールバックする。

Browser tab your video / audio file (stays here) Whispertransformers.js ffmpeg.wasmmulti-threaded needs SharedArrayBuffer WebGPU if present, WASM if not model downloadon first run usage stats, crash reportsON by default (README) COOP / COEP headersfrom the server that hosts the page

代償1 — 動かす条件

READMEはChromium系ブラウザを勧めていて、Web版には SharedArrayBuffer が必要だと書いている。マルチスレッドのffmpegがスレッド間でメモリを共有するのに使うものだ。問題は、これが crossOriginIsolated の状態でしか使えないことだ。そのためには、ページを配信するサーバーがヘッダーを2つ送る必要がある。

Cross-Origin-Opener-Policy: same-origin
Cross-Origin-Embedder-Policy: require-corp

ローカルで処理するためにサーバー設定を触ることになる。require-corp を有効にすると、CORP・CORSヘッダーのない外部の画像やスクリプトが止まるので、既存のサービスに入れるなら外部リソースから点検する。

代償2 — 初回実行

ファイルを読み込んだ直後に「音声モデルをダウンロード中… 4%」と出た。モデルをブラウザに落としてくる。容量とかかる時間はまだ測れていない。サーバーで文字起こしするなら、ユーザーが味わわなくて済む待ち時間だ。

ところでテレメトリは既定でON

READMEによると、匿名の利用統計とクラッシュレポート(Sentryに送られる)が既定でオンになっている。設定 → Privacyでオフにできる。オフにした後にネットワークリクエストが実際に消えるかは、まだ確かめていない。

悪いことだと言いたいのではない。READMEに正直に書いてある。ただ「ローカル」と聞いたら、何がローカルなのかを別に確かめる必要がある、という話だ。

ライセンスもMITではない。PolyForm Noncommercial 1.0.0で、以前のリリースだけがMITのまま残っている。評価・学習は問題ないが、コードを商用サービスに持ち込むのはだめだ。考え方だけ参考にして自分で作るのは関係ない。

「ローカル」を見るときに確かめること

質問 クラウドの文字起こしサービス rescriptのようなブラウザローカル
メディアファイルは出ていくか 出る(アップロード) 出ない
それ以外に出るもの サービス次第 利用統計・クラッシュレポート(既定でON)
初回実行 すぐ使える モデルのダウンロード
サーバー側の要件 なし(他社のサーバー) COOP/COEPヘッダー
処理速度 サーバーの性能 ユーザーの端末・WebGPUの有無

社内の映像のようにファイル自体を外に出せないなら、ローカルが合う。低スペック端末のユーザーが多い、あるいは最初の画面を早く出したいなら、サーバー側のほうがいい。

まだ切り分けられていないことがひとつある。ビデオのプレビューが黒い画面だった(video.readyState = 0)。音声はデコードされて文字起こしもできたので、音声トラックは読めている。合成テスト動画(testsrc2)のせいかアプリの問題かは、実際に撮った映像でもう一度見る必要がある。

ブラウザ内でAIモデルやWASMを動かす機能を検討しているなら、negabaroに相談してほしい。この記事と同じように、まず動かしてどこで詰まるかから一緒に見る。

キーポイント

1

「ローカル」はメディアファイルが出ないという意味。テレメトリ・クラッシュレポートは別に確認

2

マルチスレッドのffmpeg.wasmはSharedArrayBufferが必要で、サーバーがCOOP/COEPヘッダーを送る必要がある

3

初回実行時にモデルのダウンロード待ちが発生する

4

ライセンスを見る。rescriptはPolyForm Noncommercialで商用利用不可

ユースケース

外に出せない動画・音声の文字起こしとカット編集 「ローカルファースト」をうたうツールの導入前点検
← Strudelはビートのスケッチには最強、曲の完成には弱い — そしてlazy importするとエフェクトが静かに消える .blendはWebで開けない — Blender→Webは変換ではなく「GPUが食べられるものだけ残す翻訳」 →