necotech blog

動画ストリーミングの仕組み

ogv.jsについて調べてた時に、Ajaxでストリーミングとか途中再生ってどうやってるのだろうと思ったので調べてみました。

Rangeヘッダ

ogv.jsのデモをコンソールで見ると、動画のリソースを細切れにして取ってきていることが分かります。リクエストヘッダにRangeで取得バイト数の範囲を指定すると、その分がレスポンスとして返ってくるという仕組みです。(そういえば大昔に2chブラウザを作った時に、Rangeヘッダで差分取得をやったことがあるのを思い出しました。)
ちなみにレスポンスは206 Partial Contentが返ってきて、ヘッダのContent-Rangeには取得した範囲とファイルサイズが書かれています。

HTTP/1.1 206 Partial Content
Accept-Ranges: bytes
Content-Length: 1048576
Content-Range: bytes 0-1048575/26423945
Content-Type: application/ogg
...
レスポンスの例(抜粋)

実装としてはシンプルで、取得したデータのバイト数(seekPosition)を保持し、そこからchunkSizeバイト分のRangeを指定してデータを取ってくる処理をしているだけです。

var range = null;
if (seekPosition || chunkSize) {
  range = 'bytes=' + seekPosition + '-';
}
if (chunkSize) {
  if (bytesTotal) {
    range += Math.min(seekPosition + chunkSize, bytesTotal) - 1;
  } else {
    range += (seekPosition + chunkSize) - 1;
  }
}
if (range !== null) {
  xhr.setRequestHeader('Range', range);
}

あとは、途中再生時や、再生位置とseekPositionが近づいたタイミングでリクエストを投げたりしてます。

Youtubeは?

当たり前のように存在しているので気にしてなかったけど、他の動画サイトはどうなっているの?ということで、Youtubeも同じようにコンソールを見てみると、似たようなことをやっていることが分かります。ただ、HTTPの仕様に基づいてRangeヘッダを送るのではなく、リクエストのURL内で範囲を指定しているようです。(2015/12現在)

https://*.googlevideo.com/videoplayback?*&range=21817352-23222792&*

ogv.jsはライブラリだから一般的なHTTPサーバで使えるように考慮されていて、Youtubeはサービスだから独自実装。当然といえば当然ですね。


ストリーミング専用のプロトコルを使っている訳ではなくて、割とシンプルな方法で実装してるんですね。

続く(かも)

Share on Facebook
Share on LinkedIn
Pocket