Blobを使った動画のストリーミング再生方法【MediaSource API徹底解説】

Blobを使った動画のストリーミング再生方法【MediaSource API徹底解説】

はじめに|動画ストリーミングの必要性

大容量の動画ファイルを一括で読み込むと、ユーザー側での待ち時間が長くなり、離脱の原因となります。
この課題を解決するのがストリーミング方式(プログレッシブローディング)です。
動画データを小さなチャンクに分割して段階的に読み込むことで、ユーザーはすぐに再生を開始でき、全体の体験も大きく向上します。


仕組みと主な方法

動画ストリーミング

MediaSource APIによるストリーミング再生
MediaSource API を使えば、動画ファイルを細かいセグメントに分割し、ブラウザで動的に追加・再生できます。大容量ファイルでも一括ダウンロード不要、UXが劇的に向上します。

サーバー側のRangeヘッダー対応
バックエンドがRangeリクエストに対応していれば、動画の一部分だけ返せるので、ストリーミング再生に最適です。


実装例:MediaSource API + Blobによる動画ストリーミング

以下は、JavaScriptでMediaSource APIとBlobを使った動画ストリーミング再生のサンプルコードです。

<video id="videoPlayer" controls></video>

<script>
const videoID = "1b7008c6-1951deb2b6d";

// 動画のURLを取得する関数(APIと連携)
async function getVideoUrl(videoID) {
    const response = await fetch(`https://example.com/api/getVideoUrl?id=${videoID}`);
    const data = await response.json();
    return data.videoUrl;
}

// MediaSourceを使って動画をストリーミング再生
async function streamVideo(videoUrl) {
    const video = document.getElementById("videoPlayer");
    const mediaSource = new MediaSource();
    video.src = URL.createObjectURL(mediaSource);

    mediaSource.addEventListener("sourceopen", () => {
        const sourceBuffer = mediaSource.addSourceBuffer('video/mp4; codecs="avc1.64001F, mp4a.40.2"');

        let segmentStart = 0;
        const segmentSize = 10 * 1024 * 1024; // 10MBごとに読み込み

        function loadSegment(startByte, endByte) {
            fetch(videoUrl, {
                headers: { Range: `bytes=${startByte}-${endByte}` }
            })
            .then(response => response.blob())
            .then(blob => {
                const reader = new FileReader();
                reader.onload = () => {
                    sourceBuffer.appendBuffer(new Uint8Array(reader.result));
                };
                reader.readAsArrayBuffer(blob);
            });
        }

        loadSegment(segmentStart, segmentStart + segmentSize);

        sourceBuffer.addEventListener('updateend', () => {
            segmentStart += segmentSize;
            loadSegment(segmentStart, segmentStart + segmentSize);
        });
    });
}

// 再生開始
async function playVideo(videoID) {
    const videoUrl = await getVideoUrl(videoID);
    streamVideo(videoUrl);
}

playVideo(videoID);
</script>

よくある質問(FAQ)

Q1. なぜ動画を分割してストリーミング再生する必要があるのですか?

A. ファイル全体を一括ダウンロードするとユーザーの待ち時間や通信量が増えます。ストリーミングなら必要な部分だけ段階的に取得でき、すぐ再生が始まります。

Q2. MediaSource APIはどのブラウザで使えますか?

A. 最新のChrome、Edge、Firefox、Safariなど主要ブラウザでサポートされています。古い端末や特殊なブラウザでは未対応もあるため、公式対応状況を確認しましょう。

Q3. サーバー側でRangeリクエストに対応していないとどうなる?

A. Rangeに未対応だと部分取得ができず、結局ファイル全体をダウンロードするため、ストリーミングの意味がなくなります。

Q4. コーデックやフォーマットの制限は?

A. 一般的なブラウザはmp4(H.264 + AAC等)に対応。addSourceBufferのMIMEタイプとファイル形式が合っている必要があります。

Q5. 再生が途中で止まる/バッファ切れが起きる場合は?

A. ネットワークやサーバーが遅いとバッファ切れが起きます。セグメントサイズ調整やエラーハンドリング処理が有効です。

Q6. 他にもBlob/MediaSourceの活用例は?

A. 動画だけでなく、音声ストリーミング、ライブ配信、分割ダウンロードによるファイル最適化などにも使えます。


エラー処理・開発時の注意点

  • sourceBuffer.appendBufferでエラーが出る場合
    ファイル形式やコーデックを再確認し、sourceBuffer.updatingの状態管理も重要です。
  • CORS対策
    動画やAPIはCORS(クロスオリジン)対応必須。サーバーで適切なヘッダーを設定しましょう。
  • 非対応端末対策
    古いiOSやAndroid端末は未対応もあるため、Fallbackとして通常の<video>タグやHLS.jsの導入も検討してください。

用語解説

  • MediaSource API
    Webブラウザで動的に音声や動画データをバッファリング&再生するためのAPI。
  • Blob
    大容量データ(動画・音声・画像など)を一時的に扱うためのJavaScriptオブジェクト。
  • Rangeヘッダー
    HTTPリクエストでバイト範囲を指定し、部分的にデータを取得できる仕組み。

おすすめリファレンス・外部リンク


まとめ

  • BlobとMediaSource APIを活用すれば、大容量動画もリアルタイムで分割再生でき、ユーザー体験が大幅に向上します。
  • サーバー側はRangeヘッダーへの対応、クライアント側はエラー処理や互換性テストをしっかり行いましょう。
  • この記事とサンプルコードを活用し、自社サービスやWebアプリで快適な動画ストリーミング再生を実現しましょう!