Azure Blob Storageから取得した動画の、Javascriptからシークできなかった話
サーバが206 Patial Contentに対応し、ストリーミング配信されるようになるため
2018/9時点では、Azure Storage ExplorerやAzureポータルではx-ms-versionの変更はできないので、C#にてBlobのプロパティを編集する必要がある
Windows Azure Blob StorageをProgressive Downloadに最適化させる設定 | メディア with Microsoft
※ 記載時点で2018-03-28が最新:Versioning for the Azure Storage Services | Microsoft Docs
認証するためのアクセス名、アクセスキーはAzure portalの当該ストレージアカウントの設定 > アクセスキーを指定する。アクセスキーは2種類あるが、どちらを指定してもよい
やりたかったこと
Azure Blob Storageから動画を引っ張ってきて、数fpsごとの静止画に対して手作業を行いたかった。そこで、ブラウザから簡単に作業できるよう、html+javascriptでページを作成
実装したこと
- 上記htmlにvideoタグを埋め込み、videoタグのsrcにBlob上の動画のURLを指定
- videoのメタデータが読み込まれたら(onloadedmetadataイベントが発火したら)フレームを指定するUIを表示
- 上記UIにて何フレーム目を表示するか指定すると、対応するフレームの静止画を表示。具体的には、video.currentTimeを指定後、canvasにdrawImage(video, 0, 0)する
発生した問題
動画を初回ロードしたとき、video.currentTimeの値をセットしてもvideo.currentTimeが常に0だった
- videoタグにcontrols属性を付けている場合、再生、一時停止、シーク操作ともにOK。また、ここで再生している限りではvideo.currentTimeが再生位置に更新されていた
- 2回目以降にロードしたときは、video.currentTimeを設定できた
- しかし、30秒以上の動画では設定できず
- Google Chrome(69.0.3497.100)で同現象が確認された。一方Safariバージョン12.0 (13606.2.11)では問題なくcurrentTimeを設定できた
試行錯誤したこと
- 状況:video.play() → video.currentTimeが所定の時刻に来るまでループ
- 仮説:video.stop()すればいけるのでは?
- 結果:ループ部分が無限ループになり、ブラウザがハングアップ
調査した内容
- video.currentTimeを設定できるときと設定できないときで何が違うのか調査
- ChromeのデベロッパーツールのNetworkで、動画がどう読み込まれているかをチェック
- サーバのレスポンスについて、NG時は200 OK, OK時は206 Partial Content(disk cache)が帰ってきていた
- そこで、常に206 Partial Contentが帰るようにすれば設定できるようになるのでは?と判断
- Azure Blob Storageに対し、x-ms-versionを2011-08-18以降に設定することで問題解消
なぜこれで改善されるか
StackOverflowで回答されている通り、Google Chromeの仕様上サーバがByte rangeリクエストに対応できていないとサーバからのストリーミングができない。この時、ブラウザ側でvideo.currentTimeが無効化される
x-ms-version = 2011-08-18にてAzure Blob Storageはストリーミングに対応(206 Partial Responseが返るようになる)。これによりChromeでもvideo.currentTimeを設定できるようになった