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リクエストでバイト範囲を指定し、部分的にデータを取得できる仕組み。
おすすめリファレンス・外部リンク
- MDN Web Docs: MediaSource API
- Can I use MediaSource?
- Google Developers: Media Source Extensions for Audio
まとめ
- BlobとMediaSource APIを活用すれば、大容量動画もリアルタイムで分割再生でき、ユーザー体験が大幅に向上します。
- サーバー側はRangeヘッダーへの対応、クライアント側はエラー処理や互換性テストをしっかり行いましょう。
- この記事とサンプルコードを活用し、自社サービスやWebアプリで快適な動画ストリーミング再生を実現しましょう!