Skip to content

ブラウザ動画再生の原理:videoタグからMSE、EME、WebCodecsまで

ChromeがM3U8を再生できないのはなぜ?HLSがMP4より遅いのはなぜ?BilibiliはどうやってFLVを再生している?Netflixのビデオはなぜ海賊版にされない?答えはブラウザ動画再生技術にあります。このガイドでは、基本的なvideoタグからMSE、EME、WebCodecsまでをカバーします。

ブラウザ動画再生の進化

ブラウザ動画は三世代を経てきました:

第1世代:HTML5 videoタグ(2010年以前)

最もシンプルな形式:

html
<video src="video.mp4" controls></video>

ブラウザネイティブサポート、MP4/WebM単一ファイルを直接再生。制限:

  • 「完全なファイル」のみ、ストリーミングなし
  • ブラウザネイティブコーデックのみ(H.264、VP8/9)
  • 暗号化コンテンツなし
  • ライブ配信なし

Flashプラグインがこれらのギャップを埋めていましたが、Flashは終了しました。

第2世代:MSE + EME(2013年〜現在)

Media Source Extensions(MSE)がストリーミング再生を解決:

javascript
const video = document.querySelector('video');
const mediaSource = new MediaSource();
video.src = URL.createObjectURL(mediaSource);

mediaSource.addEventListener('sourceopen', () => {
  const sourceBuffer = mediaSource.addSourceBuffer('video/mp4; codecs="avc1.42E01E, mp4a.40.2"');
  
  // セグメントデータを動的に追加
  fetch('chunk-1.m4s')
    .then(res => res.arrayBuffer())
    .then(data => sourceBuffer.appendBuffer(data));
});

Encrypted Media Extensions(EME)がDRM暗号化を解決、Netflixなどがブラウザで著作権コンテンツを再生可能に。

第3世代:WebCodecs(2021年〜現在)

WebCodecs APIがJSでブラウザのハードウェアコーデックを直接呼び出し可能に、videoタグの制限を突破:

javascript
// ビデオフレームをデコード
const decoder = new VideoDecoder({
  output: (frame) => {
    // 生のVideoFrameを取得、エフェクト適用可能
    canvas.getContext('2d').drawImage(frame, 0, 0);
    frame.close();
  },
  error: (e) => console.error(e),
});

decoder.configure({
  codec: 'avc1.42E01E',
  hardwareAcceleration: 'prefer-hardware',
});

// エンコードデータを供給
decoder.decode(new EncodedVideoChunk({
  type: 'key',
  timestamp: 0,
  data: h264Data,
}));

WebCodecsは画面録画、配信、ビデオエフェクト、カスタムプレーヤーを可能にします。

MSE:ストリーミング再生のコア

MSEはモダンウェブビデオの基盤です。すべての主要プレーヤーライブラリ(hls.js、dash.js、flv.js、Shaka Player)がこれに基づいて構築されています。

MSEの仕組み

  1. MediaSourceオブジェクト作成:JSが仮想「メディアソース」を作成
  2. videoタグにバインドURL.createObjectURL()でblob URLを生成、video.srcに割り当て
  3. SourceBuffer作成:各ストリーム(ビデオ、オーディオ)に独立したバッファ
  4. セグメントデータ追加:JSがセグメントをダウンロード、ArrayBufferに変換、sourceBuffer.appendBuffer()を呼び出し
  5. ブラウザがデコードして再生:videoタグがSourceBufferからデータを取得、デコードしてレンダリング

MSEの制限

  • fMP4またはWebM必須:ネイティブMSEはTSセグメントをサポートしません — hls.jsがTSをfMP4に変換してからMSEに供給
  • コーデックを事前宣言必須:SourceBuffer作成時にコーデックを指定、途中で変更不可
  • メモリ管理:追加したデータを手動で削除してメモリ解放
  • 厳密な順序:タイムスタンプ順に追加必須、そうでなければエラー

MSEコーデックサポート

コーデックChromeFirefoxSafariEdge
H.264 (avc1)
H.265 (hevc)🟡🟡
VP9✅ (iOS 14+)
AV1✅ (85+)✅ (68+)✅ (16.4+)
AAC
Opus✅ (部分)

hls.js、dash.js、flv.jsの仕組み

hls.js:非SafariブラウザでHLS再生

hls.jsは典型的なMSEアプリケーション:

  1. M3U8ダウンロード:fetchがM3U8ファイルをリクエスト
  2. M3U8解析:JSがテキスト形式を解析、セグメントURLを抽出
  3. TSセグメントダウンロード:順次に各.tsファイルをフェッチ
  4. TS → fMP4変換:MPEG-TSコンテナをfMP4に変換(重要ステップ、MSEはTSを受け付けない)
  5. MSEに追加sourceBuffer.appendBuffer()を呼び出してvideoに供給
  6. アダプティブビットレート:ダウンロード速度とバッファを監視、M3U8品質を切り替え

プロセス全体は開発者に透過です。hls.jsをインポート後、数行で:

javascript
if (Hls.isSupported()) {
  const hls = new Hls();
  hls.loadSource('https://example.com/stream.m3u8');
  hls.attachMedia(video);
}

詳細はHLS.js完全ガイド をご覧ください。

dash.js:ブラウザでMPEG-DASH再生

dash.jsはhls.jsと似た動作、違い:

  • M3U8(テキスト)ではなくMPD(XML)を解析
  • セグメントは通常TSではなくfMP4 — コンテナ変換不要
  • fMP4を直接MSEに追加

flv.js:ブラウザでFLV再生

Bilibiliのオープンソースflv.jsはChromeでFLVストリームを再生:

  1. FLVコンテナヘッダーを解析
  2. FLVからAACオーディオとH.264ビデオストリームを抽出
  3. fMP4に再パッケージ
  4. MSEに追加して再生

詳細はflv.js RTMP/FLVプレイヤーガイド をご覧ください。

EME:DRM暗号化再生

Netflix、Disney+のビデオが海賊版にされないのはEME(Encrypted Media Extensions) + DRMシステムのおかげです。

EMEワークフロー

  1. ブラウザが暗号化コンテンツをリクエスト:ビデオセグメントは暗号化、直接デコード不可
  2. JSがEME APIを呼び出しMediaKeySystemAccess.createMediaKeys()でDRMセッション作成
  3. ライセンスリクエスト生成:ブラウザがDRMライセンスサーバーに復号キーをリクエスト
  4. サーバーがユーザーを検証:Cookie、Tokenなどでユーザー権限を確認
  5. キー配信:サーバーが暗号化キーを返却
  6. ブラウザが内部で復号:セキュアエリア(CDM、Content Decryption Module)で
  7. デコードして再生:復号データがデコーダーに、通常再生

三大DRMシステム

DRMベンダーブラウザサポート使用ケース
WidevineGoogleChrome、Firefox、Edge、Androidウェブデフォルト
PlayReadyMicrosoftEdge、IE、XboxWindowsエコシステム
FairPlayAppleSafari、iOSAppleエコシステム

商用プラットフォームは三つのDRMすべてをサポートする必要があります。オープンソース参考:Shaka PlayerのDRM実装。

WebCodecs:ブラウザ動画処理の新時代

WebCodecsはJSがエンコード/デコードを直接制御可能に、videoタグの制限を突破。

WebCodecsでできること

  1. 画面録画と共有:画面フレームをキャプチャ、H.264/VP9にエンコード、ストリーミングまたは保存
  2. ビデオエフェクト:ビデオフレームをCanvasにデコード、フィルター適用、再エンコード
  3. 低遅延再生:カスタムプレーヤー、videoタグのオーバーヘッドを回避
  4. ビデオトランスコード:ブラウザでトランスコード、サーバー不要
  5. AIビデオ処理:ビデオフレームをTensorFlow.jsに供給して認識

画面録画配信の例

javascript
// 画面をキャプチャ
const stream = await navigator.mediaDevices.getDisplayMedia({ video: true });

// WebCodecsでエンコード
const track = stream.getVideoTracks()[0];
const processor = new MediaStreamTrackProcessor({ track });
const reader = processor.readable.getReader();

const encoder = new VideoEncoder({
  output: (chunk, meta) => {
    // エンコードされたH.264データをWebSocket/WebRTCで送信
    sendChunk(chunk);
  },
  error: (e) => console.error(e),
});

encoder.configure({
  codec: 'avc1.42E01E',
  width: 1920,
  height: 1080,
  bitrate: 4_000_000,
  framerate: 30,
});

while (true) {
  const { done, value: frame } = await reader.read();
  if (done) break;
  encoder.encode(frame, { keyFrame: false });
  frame.close();
}

動画再生カクつきの根本原因

原理を理解すればカクつきの原因を特定しやすくなります:

1. ネットワークボトルネック

  • ダウンロード速度 < ビデオビットレート:バッファが枯渇、カクつき不可避
  • 診断video.bufferedでバッファ長を確認、2秒未満は危険
  • 解決策:ビットレートを下げる、ABRで低品質に切り替え、CDNアクセラレーション

2. デコードボトルネック

  • CPU/GPU使用率高:デコード速度が再生に追いつかない
  • 診断:Chrome DevTools Performanceパネル
  • 解決策:ハードウェアデコード、解像度を下げる、フレームレートを下げる

3. MSEバッファ管理

  • SourceBuffer満杯:追加失敗、再生中断
  • 診断sourceBuffer.updateendイベントを監視、sourceBuffer.bufferedを確認
  • 解決策:定期的にsourceBuffer.remove()で再生済みコンテンツをクリーンアップ

4. メインスレッドブロック

  • JS実行がビデオレンダリングをブロック:大きな計算、長いタスクがメインスレッドをブロック
  • 診断:PerformanceパネルでLong Tasksを確認
  • 解決策:計算をWeb Workerに移動、requestIdleCallback使用

5. GCポーズ

  • 大きなArrayBufferがGCをトリガー:セグメント追加で大量のメモリ割り当て
  • 診断:PerformanceパネルのMemoryビュー
  • 解決策:ArrayBufferを再利用、セグメントサイズを制御

ブラウザ動画技術の境界

ウェブ動画再生で何ができるか?

機能videoタグMSEWebCodecs
MP4単一ファイル再生
HLSストリーム再生✅ (hls.js)
DASHストリーム再生✅ (dash.js)
DRMコンテンツ再生✅ (EME)
リアルタイム画面配信
ビデオフレームエフェクト
カスタムコーデック
ハードウェアアクセラレーテッドデコード

MP4ネイティブ vs HLS再生

HLSがMP4より遅いのはなぜ?原理から:

次元MP4ネイティブHLS (hls.js)
起動リクエスト1(直接MP4)2(M3U8 + 最初のセグメント)
起動遅延ほぼ0(プログレッシブ)2-10秒(セグメント待ち)
バッファ戦略ブラウザ内部JS手動MSE管理
メインスレッドオーバーヘッド最小大(解析、再マルチプレクス)
ABRサポート
ライブサポート
暗号化サポート✅ (DRM)

シンプルなシナリオではMP4ネイティブが最速で最も安定。複雑なシナリオ(ライブ、ABR、DRM)ではMSEソリューションが必要。

まとめ

ブラウザ動画はシンプルなvideoタグからMSE+EME+WebCodecsへ進化し、デスクトッププレーヤーができるほぼすべてのことが可能になりました。

  • videoタグ:ローカルMP4/WebM再生、最もシンプル
  • MSE:ストリーミング再生のコア、hls.js/dash.js/flv.jsの基盤
  • EME:DRM暗号化再生、Netflix/Disney+が使用
  • WebCodecs:直接コーデック制御、画面録画、配信、エフェクトの新時代

この技術スタックを理解すれば、再生問題の原因を特定し、製品の技術選定で落とし穴を避けることができます。

クイックリファレンス:

  • videoタグ:MP4単一ファイル再生
  • MSE:ストリーミングのコア、hls.js/dash.js/flv.jsの基盤
  • EME:DRM暗号化再生
  • WebCodecs:ブラウザコーデック制御の新時代
  • 再生カクつき:ネットワーク/デコード/MSEバッファ/メインスレッド/GC — 五つの原因

参考文献

最終更新: