akiyoko blog

akiyoko の IT技術系ブログです

Video.js を使って HLS形式の動画をストリーミング再生する

1. はじめに

HLS (HTTP Live Streaming) 形式の動画は、Safari (on Mac) であれば、HTML5 の videoタグですんなり再生することができるのですが、それ以外のブラウザ、例えば Chrome (on Mac) や Chrome (on Windows) でも再生できるようにしたい場合にどうすればよいか?というのが悩みの一つです。

そこでいろいろ調べたところ、Video.js がよいのではないかという結論に至りました(あくまで個人的な意見です)。


http://www.videojs.com/



こちらのブログが大変参考になりました。ありがとうございます!


あと、こちらの公式ドキュメントも参照しました。



 

2. HTMLコード

Video.js を使って HLS形式の動画を再生するための HTMLコードは、以下のようになります。

index.html

<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="utf-8">
  <title>Video.js Test | akiyoko blog</title>
  <link href="css/video-js.min.css" rel="stylesheet">
  <script src="js/video.js"></script>
  <script src="js/videojs-media-sources.js"></script>
  <script src="js/videojs.hls.min.js"></script>
  <script type="text/javascript">
    videojs.options.flash.swf = "js/video-js.swf";
  </script>
</head>
<body>
<video id="test" class="video-js vjs-default-skin vjs-big-play-centered" controls preload="auto" width="640" height="360" data-setup="{}">
  <source src="http://app1-transcoder-out.s3-website-ap-northeast-1.amazonaws.com/HLS/1M/D0002021500_00000/sample.m3u8" type="application/x-mpegURL">
</video>
</body>
</html>


各ファイルは、以下のように配置しています。

/var/www/html/
├── css
│   ├── font
│   │   ├── vjs.eot
│   │   ├── vjs.svg
│   │   ├── vjs.ttf
│   │   └── vjs.woff
│   └── video-js.min.css
├── index.html
└── js
    ├── video-js.swf
    ├── video.js
    ├── videojs-media-sources.js
    └── videojs.hls.min.js


各ライブラリのバージョンは、2015年8月現時点での最新バージョンとなる

video.js 4.12.12
videojs-media-sources 1.0.0
video.js HLS Tech (videojs-contrib-hls) 0.17.6

で検証しています。



HLS形式の動画ファイルは、Amazon Elastic Transcoder で変換したものを「app1-transcoder-out」という名前の S3バケットに以下のように格納して、公開状態にしています。


《 HLS動画ファイル格納用バケット 》

app1-transcoder-out/
 └─HLS/
   └─1M/
     └─D0002021500_00000/
        ├─sample.m3u8
        ├─sample00000.ts
        ├─sample00001.ts
        ├─sample00002.ts
        ├─sample00003.ts
        ├─sample00004.ts
        └─sample00005.ts

参考




 

3. Video.js について

HSL動画を Safari以外の PCブラウザで再生するには、video.js の他に、

  • videojs-contrib-media-sources
  • videojs-contrib-hls (HLS Tech)

の 2つのライブラリが最低限必要になります。



今回は、HLS動画を再生させるために、2. で示したような index.html になっていますが、mp4ファイルの再生をするのであれば、index.html は、

<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="utf-8">
  <title>Video.js Test | akiyoko blog</title>
  <link href="css/video-js.min.css" rel="stylesheet">
  <script src="js/video.js"></script>
</head>
<body>
<video id="test" class="video-js vjs-default-skin vjs-big-play-centered" controls preload="auto" width="640" height="360" data-setup="{}">
  <source src="http://app1-transcoder-in.s3-website-ap-northeast-1.amazonaws.com/MP4/D0002021500_00000/sample.mp4" type="video/mp4">
</video>
</body>
</html>

という感じになります。シンプルですね。





各ライブラリは、Bower を使ってバージョンを調整しました。


ちなみに、↑ の時点の最新バージョン

video.js 4.12.9
videojs-media-sources 1.0.0
video.js HLS Tech (videojs-contrib-hls) 0.17.2

では、Chrome (on Mac) で動作確認したところ、1つ目の tsファイル以降の動画ファイルがロードされない(10秒ごとにスライスしている場合だと10秒以降の動画が見れない)という致命的な不具合があったのですが、現時点の最新バージョン

video.js 4.12.12
videojs-media-sources 1.0.0
video.js HLS Tech (videojs-contrib-hls) 0.17.6

では、その不具合は解消されていました。


なお、Video.js の v5系は、まだ Stable ではなかったので未検証です。

Please Note!

The master branch is now the development branch for 5.0 and should be considered unstable until the first 5.0 release. If you're looking for the most recent stable release, please refer to the stable branch.


https://github.com/videojs/video.js#please-note




 

4. 動作確認

4.1. Nginx で index.html を公開

Amazon EC2インスタンスを起動して、Nginx で index.html を公開してみます。


ローカル(Mac)のファイル構成は以下のようになっていると仮定します。

/Users/akiyoko/github/videojs-sample
├── Gruntfile.js
├── README.md
├── bower.json
├── bower_components
・
・
├── dist
│   ├── css
│   │   ├── font
│   │   │   ├── vjs.eot
│   │   │   ├── vjs.svg
│   │   │   ├── vjs.ttf
│   │   │   └── vjs.woff
│   │   └── video-js.min.css
│   └── js
│       ├── video-js.swf
│       ├── video.js
│       ├── videojs-media-sources.js
│       └── videojs.hls.min.js
├── node_modules
・
・
└── package.json

参考
GitHub - akiyoko/videojs-sample






以下、公開までの手順です。

EC2インスタンスの Elastic IP は「52.68.xxx.xxx」とします。


《 on Mac 》

$ ssh -i ~/Downloads/T1-key.pem ubuntu@52.68.xxx.xxx


《 on EC2 》

$ sudo -i

### Nginx をインストール
# apt-get install -y nginx
# nginx -v
nginx version: nginx/1.4.6 (Ubuntu)

# vi /etc/nginx/conf.d/default.conf
server {
    listen 80;
    location / {
        root /var/www/html;
        index index.html;
    }
}
# service nginx reload

# mkdir -p /var/www/html/


《 on Mac 》

### ローカルからファイルを転送
$ scp -i ~/Downloads/T1-key.pem -r /Users/akiyoko/github/videojs-sample/dist ubuntu@52.68.xxx.xxx:/home/ubuntu/


《 on EC2 》

# mv /home/ubuntu/dist/* /var/www/html/
# vi /var/www/html/index.html
---
<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="utf-8">
  <title>Video.js Test | akiyoko blog</title>
  <link href="css/video-js.min.css" rel="stylesheet">
  <script src="js/video.js"></script>
  <script src="js/videojs-media-sources.js"></script>
  <script src="js/videojs.hls.min.js"></script>
  <script type="text/javascript">
    videojs.options.flash.swf = "js/video-js.swf";
  </script>
</head>
<body>
<video id="test" class="video-js vjs-default-skin vjs-big-play-centered" controls preload="auto" width="640" height="360" data-setup="{}">
  <source src="http://app1-transcoder-out.s3-website-ap-northeast-1.amazonaws.com/HLS/1M/D0002021500_00000/sample.m3u8" type="application/x-mpegURL">
</video>
</body>
</html>
---


 

4.2. S3 の設定

以降、HLS動画ファイルの公開設定(Amazon S3 側の設定)を見ていきます。
設定が必要になるのは、

  • Permissions (Bucket Policy)
  • Permissions (CORS Configuration)
  • Static Website Hosting

ですが、今回はあくまで動画が見れればよい(動作確認が目的)ということで、セキュリティのことは全く考慮していません。


4.2.1. Bucket Policy 設定

動作検証ということで、「app1-transcoder-out」バケットの Bucket Policy を誰にでも見えるような設定にしておきます。

{
  "Id": "Policy1434989802960",
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "Stmt1434989800735",
      "Action": [
        "s3:GetObject"
      ],
      "Effect": "Allow",
      "Resource": "arn:aws:s3:::app1-transcoder-out/*",
      "Principal": "*"
    }
  ]
}

f:id:akiyoko:20150627175504p:plain

 

4.2.2. Static Website Hosting 設定

今回は手っ取り早く、S3 の Endpoint URL を使って S3オブジェクトへのパスを指定したかったので、Webサイトホスティングの設定をしていきます。


「Enable website hosting」にチェック、「Index Document」を「index.html」に設定します(「Index Document」は必須項目なので、「index.html」はダミーの値です)。

f:id:akiyoko:20150627180241p:plain


 

4.2.3. CORS Configuration 設定

ここまでの設定で、index.html 上で動画を再生しようとすると、クロスオリジン問題が発生して、以下のようなエラーがブラウザの JavaScriptコンソールに吐かれます。

f:id:akiyoko:20150811004935p:plain

XMLHttpRequest cannot load http://app1-transcoder-out.s3-website-ap-northeast-1.amazonaws.com/HLS/1M/D0002021500_00000/sample.m3u8. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://52.68.xxx.xxx' is therefore not allowed access.
VIDEOJS: ERROR: (CODE:2 MEDIA_ERR_NETWORK) HLS playlist request error at URL: http://app1-transcoder-out.s3-website-ap-northeast-1.amazonaws.com/HLS/1M/D0002021500_00000/sample.m3u8


Video.js が Ajax通信で HLS動画ファイル取得する際、Video.js と動画ファイルが別ホストに置かれている場合には、クロスサイトリクエストフォージェリ(CSRF)対策として「同一制限元ポリシー(Same Origin Policy)」に引っ掛かってしまうのです。

制約の内容 ― 同一生成元ポリシー(Same Origin Policy)

以下の3条件がすべて満たされている場合のみ、XMLHttpRequest によるデータ送信 & 受信が行えます。 それ以外は基本的に通信が拒否されます。

  • スキーム(http / https)が同じ
  • ホスト(サーバー名、IPアドレス)が同じ
  • ポートが同じ


Ajax クロスドメインリクエスト 制約」より



要するに、信頼できるサーバ(リソース)を除いて、Webページが置かれたドメイン以外への HTTPリクエストができなくなるという制約があるのです。


この制約を回避するには、S3のバケット側に CORS の設定をすればよいです。


CORS については、この記事が一番分かりやすかったです。


そこで、「app1-transcoder-out」バケットに、以下のような CORS Configuration の設定を行いました。もちろん、セキュリティの考慮はしていませんので、ご注意を。

<CORSConfiguration>
    <CORSRule>
        <AllowedOrigin>*</AllowedOrigin>
        <AllowedMethod>GET</AllowedMethod>
        <MaxAgeSeconds>3000</MaxAgeSeconds>
        <AllowedHeader>Authorization</AllowedHeader>
    </CORSRule>
</CORSConfiguration>

f:id:akiyoko:20150627190037p:plain




なお、クロスオリジン問題が発生するのは、動画のファイル形式が HLS の場合だけで、mp4ファイルの場合には CORSの設定は不要です。おそらく、HLSの場合とでは通信形式が違うのでしょう。




4.3. 動作確認結果

手元の環境で動作確認をしてみました。

Nexus 5 (Android 5.1.1) の Firefox 39.0 でのみ「No compatible source was found for video.」というエラーが表示されて再生ができませんでしたが、その他は正常に再生することができました。

デバイス OS Browser 結果
PC OSX 10.9.5 Safari 7.1.7 OK
PC OSX 10.9.5 Chrome 44.0 OK
PC OSX 10.9.5 Firefox 39.0 OK
PC Windows 7 Internet Exploer 11.0 OK
PC Windows 7 Chrome 44.0 OK
PC Windows 7 Firefox 39.0 OK
iPhone 5 iOS 8.4 Safari 8.0 OK
iPhone 5 iOS 8.4 Chrome 44.0 OK
Nexus 5 Android 5.1.1 Chrome 44.0 OK
Nexus 5 Android 5.1.1 Firefox 39.0 NG(下記参照)


Firefox 39.0 (on Nexus 5)
f:id:akiyoko:20150811011155p:plain


参考
ユーザーエージェント一覧(iPhone、iPad、Mac) - fragment.database.





 

5. その他の疑問・気になること

  • source が 2つあって、1つ目が見つからないときは?

 → type が同じ場合はエラー(type が別々であれば、2つ目が見つかればOK ( *1 ))

  • 以下のスクリプトを省略した場合は?
<script type="text/javascript">
  videojs.options.flash.swf = "js/video-js.swf";
</script>

 → HLS の場合は、外部CDN ( *2 ) から video-js.swf をダウンロードする挙動になる
 → mp4 の場合は、videojs-swf.js はダウンロードしない

  • Firefox で再生すると、Firebugで以下のワーニングが出てしまう。
"application/x-mpegURL" で指定された "type" 属性はサポートされていません。メディア http://app1-transcoder-out.s3-website-ap-northeast-1.amazonaws.com/HLS/1M/D0002021500_00000/sample.m3u8 を読み込めませんでした。
リソース候補の読み込みがすべて失敗しました。メディアの再生を中止します。

 

6. まとめ

Video.js を使えば、デバイスや OS(Windows・Mac・Android・iOS)を問わず、主要なものであればほとんど全てのブラウザで HLS形式の動画を再生することができます。

現時点では、Video.js はバージョン4(4系)からバージョン5(5系)への過渡期となっており、まだ 5系は安定版とはなっていないようですが、コミュニティの開発は精力的に進められているようなので、もうしばらくすると 5系の安定版がリリースされるものと思われます。