hlsでマルチビットレート配信 webプレーヤで速度調整

videojsプレーヤを利用して、ビットレートを調整します。

nginx + rtmp-moduleを利用し、hls variant機能を使ってマルチビットレートでhlsを作成します。

プレーヤは、videojsを利用して、
1.今、受信しているビットレートはどれか?
2.明示的に速度選択をする
3.回線速度に合わせて自動的に速度調整

を実現します。

Web PlayerはVideo.jsを利用します。
http://videojs.com/

HLS配信をnginx rtmp-moduleで行うためには、

           application multi_jp {
                live on;

                on_publish http://localhost/publishauth/auth.php;
                notify_method get;
                on_play http://localhost:8080/on_play;

                hls on;
                hls_path /usr/local/nginx/html/hls/jp;
                hls_nested on;

                hls_variant _lw BANDWIDTH=320000;
                hls_variant _md BANDWIDTH=576000;
                hls_variant _hi BANDWIDTH=2128000;

           }

という設定を行います。

詳しくはこちらをご参照ください

Debian NginxでHLSライブストリーミング 手順まとめ

とりあえず簡単にHLS配信をするためには、jsファイルは準備されているCDNを利用すると楽に始められます。

<link href="http://vjs.zencdn.net/vjs-version/video-js.css" rel="stylesheet">
<script src="http://vjs.zencdn.net/5.16.0/video.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/videojs-contrib-hls/5.1.0/videojs-contrib-hls.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/videojs-contrib-hls/5.1.0/videojs-contrib-hls.min.js"></script>

一から始めたい場合はこちらをご参考にしてください。

video.jsのインストール配信まとめ

npm install --save-dev video.js
npm WARN saveError ENOENT: no such file or directory, open '/home/ubuntu/package.json'
/home/ubuntu
mqw video.js@6.4.0
  tqw babel-runtime@6.26.0
  x tqq core-js@2.5.2
  x mqq regenerator-runtime@0.11.1
  tqw global@4.3.2
  x tqw min-document@2.19.0
  x x mqq dom-walk@0.1.1
  x mqq process@0.5.2
  tqw safe-json-parse@4.0.0
  x mqw rust-result@1.0.0
  x   mqq individual@2.0.0
  tqq tsml@1.0.1
  tqq videojs-font@2.0.0
  tqw videojs-ie8@1.1.2
  x mqq es5-shim@4.5.9
  tqq videojs-vtt.js@0.12.4
  mqw xhr@2.4.0
    tqq is-function@1.0.1
    tqw parse-headers@2.0.1
    x tqq for-each@0.3.2
    x mqq trim@0.0.1
    mqq xtend@4.0.1

npm WARN enoent ENOENT: no such file or directory, open '/home/ubuntu/package.json'
npm WARN ubuntu No description
npm WARN ubuntu No repository field.
npm WARN ubuntu No README data
npm WARN ubuntu No license field.

気になるエラーが見えますが

no such file or directory, open ‘/home/ubuntu/package.json’

これ気にしなくても大丈夫です。なんで?と言われても説明できないのですが、特に支障なく利用できています。

https://github.com/videojs/videojs-contrib-quality-levels

こちらのvideojs-contrib-quality-levelsが肝になります。今回回線速度を判断して受信速度を自動調整するためのモジュールです。明示的に速度を選択する事もできるようになります。

videojs-contrib-hlsバージョン4.1以上を使用すると、HLSソースの品質レベルが自動的に設定されます。なので、videojs-contrib-hlsのバージョンにも気を付けてください。ちなみに、私が利用しているvideojs-contrib-hlsのバージョンは

/**
 * videojs-contrib-hls
 * @version 5.5.3
 * @copyright 2017 Brightcove, Inc
 * @license Apache-2.0
 */

でした。

videojs-contrib-quality-levelsの使い方

git clone https://github.com/videojs/videojs-contrib-quality-levels.git
#npm install --save videojs-contrib-quality-levels
cd videojs-contrib-quality-levels
npm i
npm run build

で、videojs-contrib-quality-levels/dist内に作成された

videojs-contrib-quality-levels.min.js

をvideojsフォルダに放り込みます。(ブラウザからアクセスできる位置に配置)

自分で準備したvideo-js類はこんな感じです。

videojs# ls
video-js.min.css videojs-contrib-hls.min.js videojs-contrib-media-sources.min.js
video.js videojs-contrib-media-sources.js videojs-contrib-quality-levels.min.js

後は、こちらを参考にHTMLを配置すると速度調整用のボタンができる。

Screenshot of github.com

緑色が、現在受信している速度。


赤色は無効にしている速度。

映像ソースには .m3u8を設定するのが重要です。こちらのm3u8は、nginx.confで設定した受けたストリーム名になります。

nginx.confの設定部分はここ

         application live {
            live on;
            record off;
            on_publish http://localhost/publishauth/auth.php;
            notify_method get;

            deny play all;
            hls on;
            hls_path /usr/local/nginx/html/hls;

            hls_type live;

            hls_variant _lw BANDWIDTH=320000;
            hls_variant _md BANDWIDTH=576000;
            hls_variant _hi BANDWIDTH=2128000;

         }

です。streamという名前は、エンコーダ側で設定したストリーム名になります。エンコーダから3本のストリーム

stream_hi

stream_md

stream_lw

を受け、それぞれhls_variant設定して、BANDWIDTH設定してあります。hls_variant設定の詳細はこちらに記載があります。

variantは標準からわずかに異なるもの。異形といった意味という意味で、上記nginx.confで、hls variantを追加登録している事になります。_から後ろ、(_hi,_md,_lw)は接尾辞という扱いになります。

そこでできるstream.m3u8(接尾辞より前)には、追加されたhls_variantの.m3u8ファイルが示されます。

/usr/local/nginx/html/hls# cat stream.m3u8
#EXTM3U
#EXT-X-VERSION:3
#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=320000
stream_lw.m3u8
#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=576000
stream_md.m3u8
#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=2128000
stream_hi.m3u8

このstream.m3u8ファイルを映像ソースとして設定する事で、videojs-contrib-quality-levelsが判断し、自動的にBANDWIDTHを認識表示・再生します。

<!doctype html>
<html>
<head>
  <meta charset="utf-8">
  <title>videojs-contrib-quality-levels Demo</title>
  <link href="../videojs/video-js.css" rel="stylesheet">
  <style>
    button.enabled {
      background: SkyBlue;
    }
    button.selected {
      background: SpringGreen;
    }
    button.disabled {
      background: red;
    }
  </style>
</head>
<body>
  <div id="fixture">
  </div>
  <div id="quality-levels">
    <h2>映像受信速度:</h2>
  </div>
  <script src="../videojs/video.js"></script>
  <script src="../videojs/videojs-contrib-hls.js"></script>
  <script src="../videojs/videojs-contrib-quality-levels.min.js"></script>
  <script>
    function createQualityButton(qualityLevel, parent) {
      var button = document.createElement('button');
      var classes = button.classList;
      if (qualityLevel.enabled) {
        classes.add('enabled');
      } else {
        classes.add('disabled');
      }
      button.innerHTML = qualityLevel.id + ': ' + qualityLevel.bitrate + ' kbps';
      button.id = 'quality-level-' + qualityLevel.id;
      button.onclick = function() {
        var old = qualityLevel.enabled;
        qualityLevel.enabled = !old;
        button.classList.toggle('enabled');
        button.classList.toggle('disabled');
      }
      parent.appendChild(button);
    }
    function createPlayer(callback) {
      var video = document.createElement('video');
      video.id = 'videojs-contrib-quality-levels-player';
      video.className = 'video-js vjs-default-skin';
      video.setAttribute('controls', true);
      video.setAttribute('height', 720);
      video.setAttribute('width', 1280);
      document.querySelector('#fixture').appendChild(video);
      var options = {
        autoplay: true,
        qualityLevels: {}
      };
      var url = 'http://video.hanako.jp/hls/stream.m3u8';
      var type = 'application/x-mpegURL';
      try {
        window.player = videojs(video.id, options);
        window.player.src({
          src: url,
          type: type
        });
        callback(window.player);
      } catch(err) {
        console.log("caught an error trying to create and add src to player:", err);
      }
    }
    function setup(player) {
      player.ready(function() {
        var qualityLevels = player.qualityLevels();
        var container = document.getElementById('quality-levels');
        qualityLevels.on('addqualitylevel', function(event) {
          createQualityButton(event.qualityLevel, container);
        });
        qualityLevels.on('change', function(event) {
          for (var i = 0; i < qualityLevels.length; i++) {
            var level = qualityLevels[i];
            var button = document.getElementById('quality-level-' + level.id);
            button.classList.remove('selected');
          }
          var selected = qualityLevels[event.selectedIndex];
          var button = document.getElementById('quality-level-' + selected.id);
          button.classList.add('selected');
        })
      });
    }
    (function(window, videojs) {
      createPlayer(setup);
    })(window, window.videojs);
  </script>
</body>
</html>

 

関連コンテンツ