hls.jsで実装する動画ストリーミングの分かりやすい解説

Icon JavaScript

ホストした動画をストリーミング配信する簡単な方法はないか…と探して行きついたのが、HLS(とライブラリであるhls.js)です。

なぜ調べていたかと言うと、長編動画を配信するのにクラウド上にファイルを配置したり社内で共有したりする方法だと、どうしてもダウンロードの動作になり、動画が数百MBや数GBだと待ち時間が相当長くなります。
他い良い方法はないか…と探したのがきっかけです。

YouTubeは便利ですが、誰でも見られる場所に置きたくない場合は恐らく使えません。

ですが、hls.jsを使うとWebサーバーさえあれば動画ストリーミングが簡単に実現できます。

今回、HLSの概念的な説明と、hls.jsでの実装の方法を、初めて知る人向けに分かりやすく記事にしてみました。

丁寧に解説したつもりですが、既にご存知の箇所があれば飛ばして読んでもらっても大丈夫です。

最初は、基礎的な概念から説明しています。

ストリーミングとプログレッシブダウンロードの違い

わざわざhls.jsを使わずとも、ブラウザが単体のmp4を読込む時はダウンロードしながら再生しているのだし、hls.jsなんてライブラリ必要?と考えるかもしれませんが、実はあれはストリーミングではなく、プログレッシブダウンロードという動作です。

そもそもストリーミングとは

おさらい的に、、、ですが、そもそもストリーミングとは、

  • 動画ファイル全体を配信せず、特定の部分だけを配信する
  • ファイルをダウンロードしないのでクライアント側に情報が残らない

一般的にはこういう理解でしょう(間違っていないはず)。

IT用語といえばココのe-wordさんのページで分かりやすく解説されています。
ストリーミング 【 streaming 】 – IT用語辞典 e-words

プログレッシブダウンロードとの違い

単純にvideoタグだけを使用してHTMLファイル内に動画ファイルを貼り付けた場合は、プログレッシブダウンロード (Progressive download)の動作をします。

プログレッシブダウンロードはファイル全体がダウンロードできていなくても再生が可能ですが(その際にファイル先頭にあるメタデータを参照する)、データを最初から連続的に読む動作になります。
なので、再生位置を後にずらすなどするとその場所までのデータをダウンロードしないと再生できず、遅延が発生しやすくなります。
対して、ストリーミングは「現在再生している箇所だけ」を受信し、再生箇所の部分以外は取得しません(なのでライブ配信に向くわけですね)ので、オンデマンド配信ならストリーミングが向きます。

再生位置変更しても待ち時間を少なくしたり、ライブやオンデマンドでの配信をするなら、単純にHTMLに<video>タグを入れるだけでは無理があるようです。

ですが、ストリーミング配信用に新規にサーバーを立てるのは相当な手間です。
で、簡単にストリーミング配信できる技術というものがあり、それがHLSです。

参考リンク
Progressive Download versus Streaming (Brightcove Inc, 2009/3/31)
Progressive download (Wikipedia)
What Is Progressive Download? (NGINX)

HLS (HTTP Live Streaming)の概略

HLSは、Appleが開発した動画ストリーミングの技術です。

HLSの特徴

Appleのサイトで解説されていますが、以下の特徴があります。

  • Appacheなど通常のWebサーバがあれば実現可能(他にサーバーを立てなくて良い)
  • 有線・無線の速度など通信環境に合わせて動的にビットレートを最適化する– アダプティブビットレートストリーミング (Adaptive bit rate streaming)
  • ライブ配信・オンデマンド配信にに対応
  • 暗号化と認証に対応
  • iOSやmacOSなどApple製品は標準で対応

ApacheやNGINXなど、普段使用しているWebサーバーがあれば実装できる点が大きなメリットですね。
あと、HLSに限りませんが、動画をCDN上に配置すればサーバーへの負荷は軽くなりそうです。

ブラウザのHLS対応状況

注意点としては、Apple製品のOS(というかSafari?)は標準で対応していますが、Windowsはブラウザにより対応状況が違ってきます。

Windows 10のEdgeはHLSをサポートしていますが、Chrome、Firefox、Internet Explorer 11はネイティブサポートしていません(つまり、ブラウザ単体で再生ができません)。

ですが、hls.jsをクライアントとして実装すれば、ChromeやFirefoxでも再生が可能になります。

このページでAppleがHLSのサンプルを用意してくれているので、実際再生可能かどうかを確認することができます。

HLSの具体的な実装方法の概略

① 動画ファイルをHLS形式に変換

2種類のファイルを用意します。

  1. プレイリストファイル (.m3u8)
  2. 分割された動画ファイル (.ts)

プレイリストの実体はテキストファイルです。
MP4などの元動画を、ffmpegなどのツールで変換します(ちなみにffmpegはフリーです)。
本家のAppleがHLS用のツールを公開していますが、macOS専用のコンソールアプリです。

② サーバー上に配置

WebサーバーもしくはCDNなどに①で作成したファイルを配置します。

③ 配信

HTMLファイル中に、

<video src="https://.../xxx.m3u8" ></video>

と単純にm3u8を指定すれば、SafariとEdgeはそれで再生可能になります。
ChromeやFirefoxは再生できませんので、hls.jsを使うなどする必要があります。

参考サイト
HTTP Live Streaming – Overview (Apple)
Simplified Adaptive Video Streaming: Announcing support for HLS and DASH in Windows 10 (Microsoft Windows Blog, 2015/1/29)

hls.jsとは

hls.jsは、HLSクライアントの実装となるJavaScriptライブラリです。
(要するにこれがあればHLSがChromeやIE11で再生できる)。

HTML5のvideo(videoタグ)と、HTML5のJavaScriptライブラリとしてW3Cが標準化したMedia Source Extensionsを使用しています。

hls.jsは、twitterやTEDのサイトでも利用されているそうです。
あと、余談ですが、video.jsなどのJavaScriptのプレイヤーにも搭載されているのだとか。
実績豊富のようですね。

hls.jsの実装方法

①ファイルを用意する (FFmpegで作成)

Appleが公開するツールを使ってもよいのですが、今回は、Windows環境でも使用可能なFFmpegを使用したいと思います(macOS, Linuxにも対応)。

FFmpegのインストール

DownloadページのWindowsロゴをクリックし、「Windows builds by Zeronoe」をクリックします。

FFmpeg Install
FFmpegのDownloadページ

ダウンロードページに飛ぶので、適切な選択肢を選びます。
Versionは最新のものを、あとはArchitectureを自分のプラットフォームに合わせたものを選択するだけでよいでしょう。
「Download Build」をクリックすると、zipファイルがダウンロードされます。

FFmpeg Install
FFmpegダウンロードページ

後は、ダウンロードされたZIPファイルを解凍し、適当なフォルダに配置ます。
これで、インストールは完了。

動画ファイルを変換する

FFmpegを使って動画をHLSのファイル形式に変換します。

動画が手元にない場合は、Pixtabayで無料で入手できます。
今回は、PixtabayMuhammad Faiz Rasidさんの素材を使用させて頂きました。

コマンドプロンプトで、以下のようなオプションで実行します。
(ffmpeg.exeはパスを通しているものとし、カレントディレクトリにNature.mp4があるものとします)

ffmpeg -i Nature.mp4 -c:v copy -c:a copy -f hls -hls_time 1 -hls_playlist_type vod -hls_segment_filename "Nature%03d.ts" Nature.m3u8
FFmpeg command
オプションの解説

-i
入力元のファイルを指定します(今回の場合はNature.mp4)。

-c:v
-cオプションはエンコーダーの指定で、コーデックを指定します(入力元ファイルの前で使うとデコーダーの指定になる)。
-c:vはビデオのエンコードを意味します。
入力・出力ともmp4でコーデックを変換する必要はないので、その場合、copyを指定すると再エンコードを実施せずに済み、処理を無駄に増やしません。

-c:a
オーディオのコーデック指定です。
上と同様、copyで大丈夫です。

-f
出力ファイルのフォーマットを指定します。
hlsを指定します。

-his_time
ファイル分割の際の長さを秒単位で指定します。
省略した場合、2秒がデフォルト値になります。

-hls_playlist_type
EVENTまたはVODを指定します。
ライブ配信の場合はEVENT、オンデマンドならVODを指定するようです。
(※ライブ配信の場合、サーバー側でプレイリストファイルの行追加が行われるので、その場合はEVENTを指定する)
今回は、VODで問題ありません。

-hls_segment_filename
分割するファイル(.ts)の名称を指定します。
%03dは、3桁の連番が入ることを意味します。

最後に、プレイリストファイル名(Nature.m3u8)を指定します。

実行すると、以下のようなメッセージが出力され、

FFmpeg command

ファイルが出力されます。

HLS Files

これで、動画の変換は完成です。

参考
ffmpeg Documentation (All)
Video on Demand Playlist Construction (Apple)

②サーバー上に配置する

Webサーバー上なりCDNのサーバー上なりに配置します。
ここは、大丈夫ですよね。

Webサーバーに配置する時は他サイトからの直リンクを防ぎたいので(わざわざしてくる人は少数でしょうが)、必要に応じて.htaccessを作成します。
以下、作成例です。
動画ファイルと同じディレクトリに置いて下さい。

SetEnvIf Referer "^https://[ドメイン名]\.jp" ref001
order deny,allow
deny from all
allow from env=ref001

③表示用ページを作成する

his.jsのGitHubページに、親切に実装例が公開されています。
HTMLファイルに以下のscriptとvideoを入れ込みます。

<script src="https://cdn.jsdelivr.net/npm/hls.js@latest"></script>
<video id="video" controls width="640" height="360"></video>
<script>
  var video = document.getElementById('video');
  var videoSrc = 'https://[動画の配置先]/sample.m3u8';
  if (Hls.isSupported()) {
    var hls = new Hls();
    hls.loadSource(videoSrc);
    hls.attachMedia(video);
  }
  else if (video.canPlayType('application/vnd.apple.mpegurl')) {
    video.src = videoSrc;
  }
</script>

補足ですが、videoタグのcontrols width=”640″ height=”360″で、動画の表示サイズを調整しています。
if (Hls.isSupported())の部分は、ブラウザがHLSをネイティブサポートしていればブラウザの機能で再生し、そうでなければhls.jsスクリプトで再生する、という分岐です。

var videoSrc にプレイリスト(m3u8)のURLをセットしましょう。

上手くできれば、以下のように動画が表示されるはずです。
video.play();があるといきなり再生されるので、その辺りの箇所は省きました。

再生位置をずらしてもスムーズに再生できますね。

というように、hls.jsを使うと動画ストリーミングの実装が簡単にできます。

 

以上です。
終わり。

 

参考リンク
hls.js (GitHub)
Media Source Extensions (W3C)
FFmpeg
Pixtabay