Misskey & Webテクノロジー最前線

ブラウザ上でお手軽動画圧縮

本連載は分散型マイクロブログ用ソフトウェアMisskeyの開発に関する紹介と、関連するWeb技術について解説を行っています。

今回は、Misskey v2025.10.0に含まれる予定の「動画圧縮機能」で採用した、ブラウザ上で動画処理を行えるライブラリMediabunnyを紹介します。

モチベーション

Webサービスにおいては、アップロードされた動画をサーバーにそのまま保存するのではなく、ストレージ節約のため非可逆的に圧縮したり、互換性向上のため再エンコードを行う、というシチュエーションは一般的です。

Misskeyでも動画の投稿が可能なので、サーバーサイドでffmpegを利用してサムネイルの生成を行うなどの処理を行っています。

しかし、サーバーサイドで動画処理を行うのは画像と比べてもはるかに負荷がかかりますし、最終的に圧縮されるとしてもユーザーはオリジナル動画をいちどアップロードする必要があり、帯域を無駄に使います。

そこでMisskeyではMediabunnyを導入し、ユーザーのブラウザ上で動画の圧縮処理を完結させるようにしました。

Misskey(v2025.10.0)における動画圧縮機能

Mediabunny

公式サイトで⁠Complete media toolkit⁠と紹介されているように、JavaScriptで動画・音声ファイルを扱うためのライブラリです。ネイティブのWebCodecs APIを使って実装されており、高速・軽量なことが特徴です。

ECMAScript 2021が動く環境であればサーバー上でも動作しますが、Misskeyではブラウザ上で利用しています。

使い方は驚くほど簡単で、Misskeyに動画圧縮機能を追加するのに、UI部分などを除いたロジック部分のコードはたった50行程度の追加で済みました。

ノート

Misskeyの圧縮機能実装時のプルリクエストはGitHubを参照してください

Mediabunny公式では動画圧縮のデモも用意されているので、実際にファイルを選んで遊んでみてください(ブラウザで完結するタイプのデモなので、もちろん「アップロード」はされません⁠⁠。

なお、Mediabunnyは圧縮以外にも様々な動画・音声処理が可能です。機会があればその他の機能についても検証・紹介したいと思います。

実装

実際にMediabunnyを使用して動画の圧縮を行うコード例を紹介します。

import * as mediabunny from 'mediabunny';

async function compress(source: Blob): Promise<Blob> {
	// 入力を準備
	const input = new mediabunny.Input({
		source: new mediabunny.BlobSource(source),
		formats: mediabunny.ALL_FORMATS,
	});

	// 出力を準備。今回はmp4で出力
	const output = new mediabunny.Output({
		target: new mediabunny.BufferTarget(),
		format: new mediabunny.Mp4OutputFormat(),
	});

	// 変換を行うインスタンス。今回はビットレートのクオリティをLOWにすることで、圧縮を行うように指定
	const conversion = await mediabunny.Conversion.init({
		input,
		output,
		video: {
			bitrate: mediabunny.QUALITY_LOW,
		},
		audio: {
			bitrate: mediabunny.QUALITY_LOW,
		},
	});
	
	// 処理の進捗が更新されたときのコールバック。進捗率は 0.0~1.0 で渡される
	currentConversion.onProgress = p => console.log(`${p * 100}%完了`);

	// 圧縮処理を実行 (注: 時間がかかる場合あり)
	await conversion.execute();

	// 圧縮したデータを返す
	return new Blob([output.target.buffer!], { type: output.format.mimeType });
}

動画データ(Blob)を受け取って、それを圧縮した動画データを返す関数です。見ての通り非常にシンプルに圧縮処理が実装できます。

公式に説明がある通りTree-shakableなので、適切にimportを行えば必要なコードだけをバンドルに含めることもできます。

ノート

元動画の長さや解像度によってはそれなりに時間がかかる場合があるため、実際のプロダクトでは、ユーザーに進捗状況を表示したり、キャンセル機能を実装するのがベターでしょう。

コード例ではビットレートを決め打ちしていましたが、Misskeyではどれくらいの圧縮率で変換を行うかユーザーが設定できるようにしています。

Mediabunnyでは以下のビットレートのプリセットが用意されています。

  • QUALITY_VERY_LOW
  • QUALITY_LOW
  • QUALITY_MEDIUM
  • QUALITY_HIGH
  • QUALITY_VERY_HIGH

Misskey上の圧縮率設定では、高=QUALITY_VERY_LOW、中=QUALITY_MEDIUM、低=QUALITY_VERY_HIGHが選択されるようにしています(デフォルトは中⁠⁠。

元になる動画の内容にもよりますが、それぞれの設定でどれくらい元のファイルサイズから減るかの検証結果も載せておきます。

QUALITY_VERY_LOW 50%前後
QUALITY_MEDIUM 20%前後
QUALITY_VERY_HIGH 10%前後

対応ブラウザ

先進的ですが意外にもカバレッジは広く、主要ブラウザで広くサポートされていますブラウザ対応状況⁠。iOSのSafariであっても動画のみであれば16.4から使えます(完全なサポートは26.0から⁠⁠。

ノート

通常気にする必要はないですが、セキュアコンテキスト(≒HTTPS)でないとWebCodecs APIは動作しないので注意してください。

筆者は非セキュアコンテキストである.localドメインでローカルの開発環境にアクセスして動作確認していたのですが、期待通りに動作せず原因究明に時間を費やしてしまいました…。

まとめ

今回はMediabunnyを使ってブラウザ上で簡単に動画の圧縮を行う実装を紹介しました。WebCodecs APIの登場で、⁠Webはここまでできるようになった」と思えることがまたひとつ増えたのではないでしょうか。

Misskeyでは現在動画の圧縮機能でのみ使用していますが、かなりのポテンシャルを感じたので、今後活用の幅を広げたいと考えています。

おすすめ記事

記事・ニュース一覧