Edited at

HTTP Live Streaming (HLS)の基本とngx_http_hls_moduleについて調べて試してみた


この記事の対象

動画配信技術、HLSについて詳しく知りたい方は以下のリンクなどを参考にし、本内容は読まなくて良いです

※本記事で解説している内容もほとんど↑のリンクに書いてある内容から記載しています


本記事の要約


  • HTTP Live Streaming(HLS)を使うと何が嬉しいか


    1. 「動画配信って動画全て読み込んでからの再生だと動きが遅いなあ」

    2. 「HTTP Live Streaming(HLS)を使えば読み込んだ部分から再生し、再生しながら次の部分を読み込むということが可能だよ」

    3. 「すごい!HLS便利!」



  • ngx_http_hls_moduleを使うと何が嬉しいのか


    1. 「でもHLSで再生するには、hoge.mp4ファイルから.m3u8ファイルと複数.tsファイルに変換する一手間があるな」

    2. 「ngx_http_hls_moduleを使えばhoge.mp4を変換しなくても、URLでhttp://hogexxx.com/hoge.mp4.m3u8とリクエストを送ったらサーバがよしなに解釈してくれるよ」

    3. 「すごい!まじかよ!超便利!!!」





ストリーミングとは


ストリーミング (英語: streaming) とは、主に音声や動画などのマルチメディアファイルを転送・再生するダウンロード方式の一種である。

通常、ファイルはダウンロード完了後に開く動作が行われるが、動画のようなサイズの大きいファイルを再生する際にはダウンロードに非常に時間がかかってしまい、特にライブ配信では大きな支障が出る。そこで、ファイルをダウンロードしながら、同時に再生をすることにより、ユーザーの待ち時間が大幅に短縮される。この方式を大まかに「ストリーミング」と称することが多い。



HTTP Live Streaming (HLS)とは


アップルによるHTTPベースのストリーミング・プロトコル。IETF標準化を目指して仕様が公開されており、多くのサーバーやクライアントが対応している。また、いくらかのブラウザ(Safari、Androidなど)でも直接再生することができる。Flash Playerも再生に対応している。また、hls.jsなどのスクリプトを使うことで、HTML5のMedia Source Extensions(英語版) APIに対応しているブラウザでも再生することができる。




  • HTTPを使うので通常のwebサーバで通信できる

  • プレイリスト(.m3u8ファイル)とセグメントファイル(動画を数秒ごとに分割したMPEG-2 TS形式のファイル)の2種類で構成されている


  • .m3u8ファイルをまず読み込み、そこに記載されている動画ファイルへのパスを次々読み込んで行くという流れで動画配信を行う


プレイリスト(.m3u8ファイル)


.m3u8ファイルとは


M3Uファイルは、一つ、または複数のメディアファイルのパスをプレーンテキスト(テキストファイル)で記述したものである。このファイルを、".m3u"または".m3u8"の拡張子で保存する。 M3UファイルのエンコードはWindows-1252の場合が多いものの、CP932に対応しているものも存在する。エンコードがUTF-8であることを明示するとき、拡張子M3U8を使用する。

それぞれのエントリには以下のような記述をする。


  • 絶対パス(例: C:\My Music\Heavysets.mp3

  • 相対パス(例: Heavysets.mp3)

  • URL
    M3Uファイルにはコメントを含むことができ、#以降がコメントとみなされる。

M3Uフォーマットの一般的な使用方法として、単一のエントリにURLを記述することがあげられる。このファイルのおかげで、ストリーミングへのアクセス、ウェブサイトからのダウンロード、インターネットラジオの視聴が容易になる。

iOSのHTTP Live Streamingフォーマットは"M3U" and "M3U8" ファイルをもとにしている。


ただのテキストファイルで実際のメディアファイルへのパスが記載されている

あとで実際に作成しますが、自分が作ったのはこのような感じになりました


playlist.m3u8

#EXTM3U

#EXT-X-VERSION:3
#EXT-X-MEDIA-SEQUENCE:0
#EXT-X-ALLOW-CACHE:YES
#EXT-X-TARGETDURATION:13
#EXTINF:10.500000,
segment-000.ts
#EXTINF:1.458333,
segment-001.ts
#EXTINF:3.875000,
segment-002.ts
#EXTINF:7.291667,
segment-003.ts
#EXTINF:10.416667,
(省略)

このplaylistを元に、.tsファイルを順番に取得しつつ再生していきます


セグメントファイル(分割したMPEG-2 TS形式のファイル)


  • 拡張子.ts

  • 一つの配信に対して.tsファイルが大量にできる

  • 映像コーデックはH.264、音声コーデックはAAC を使うのが一般的なようです


コーデックとは


コーデック (Codec) は、符号化方式を使ってデータのエンコード(符号化)とデコード(復号)を双方向にできる装置やソフトウェアなどのこと。 また、そのためのアルゴリズムを指す用語としても使われている。

コーデックには、データ圧縮機能を使ってデータを圧縮・伸張するソフトウェアや、音声や動画などのデータを別の形式に変換する装置およびソフトウェアが含まれる。


コーデックについて自分が分かりやすかったページ


ブラウザ対応状況

https://caniuse.com/#search=hls

2019/01/02現在

HTTP Live Streaming(HSL) ブラウザ対応状況

chromeなどの主要なブラウザでは対応されていませんので、

Media Source Extensions(Media Source Extensions - Wikipedia)を利用するとchromeなどでもHLS再生できるようです

https://caniuse.com/#search=mse

Media Source Extensions(MSE) ブラウザ対応状況

MSEで再生するのに一番簡単にはhls.jsを使うと良いようです

https://github.com/video-dev/hls.js/


HLSを試して見る


確認Version

VagrantでCentOSの環境を作成して確認しています


  • macOS High Sierra

  • VirtualBox 5.2.22

  • Vagrant 2.2.2

  • CentOS 7

  • nginx/1.15.7 (nginx-plus-r17)

  • ffmpeg version N-92867-g86555a2


使用する動画

Big Buck Bunny ≫ Download

mp4の動画をダウンロードする

Big Buck Bunny

(c) copyright 2008, Blender Foundation / www.bigbuckbunny.org


ffmpegでmp4を変換


  • nginxのrootにmp4ファイルを置く

$ cd /usr/share/nginx/html

$ ls *.mp4
BigBuckBunny_320x180.mp4


  • ffmpeg実行 ※バッククォート内の文字はコメントなのでなくてもOK

$ ffmpeg \

-i BigBuckBunny_320x180.mp4 `# 入力ファイル` \
-map 0 \
-f segment \
-vcodec libx264 `# 映像コーデックを指定` \
-acodec libfdk_aac `# 音声コーデックを指定` \
-segment_list video/playlist.m3u8 `# プレイリスト名` \
-segment_time 5 `# 5秒ずつぐらいに分割される` \
video/segment-%03d.ts `# .tsファイル名 segment-000.ts 〜 segment-999.ts になる`

※↑こちらが詳しいです。 https://www.slideshare.net/moriyoshi/hls-46107808/14


  • プレイリストファイルとセグメントファイルが作成される

プレイリストファイルとセグメントファイル


再生


  • この状態でSafariからvideo/playlist.m3u8にアクセスしたら再生ができる!

Safariから`video/playlist.m3u8`にアクセス


chromeから再生できるようにする

$ sudo touch /usr/share/nginx/html/live-stream.html


live-stream.html

<!DOCTYPE html>

<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<script src="https://cdn.jsdelivr.net/npm/hls.js@latest"></script>
<!-- Or if you want a more recent canary version -->
<!-- <script src="https://cdn.jsdelivr.net/npm/hls.js@canary"></script> -->
<video id="video" controls preload="none"></video>
<script>
var video = document.getElementById('video');
if(Hls.isSupported()) {
var hls = new Hls();
hls.loadSource('http://192.168.33.10/video/playlist.m3u8');
hls.attachMedia(video);
hls.on(Hls.Events.MANIFEST_PARSED,function() {
video.play();
});
}
</script>
</body>
</html>


  • chromeで再生でき、.tsファイルを一定間隔で取得しているのも確認できました

hls.jsを使ってchromeから再生


ngx_http_hls_module

商用版のNGINX Plusで利用できます


ngx_http_hls_moduleとは


The ngx_http_hls_module module provides HTTP Live Streaming (HLS) server-side support for MP4 and MOV media files. Such files typically have the .mp4, .m4v, .m4a, .mov, or .qt filename extensions. The module supports H.264 video codec, AAC and MP3 audio codecs.


Google翻訳↓


ngx_http_hls_moduleモジュールは、MP4およびMOVメディアファイルに対するHTTP Live Streaming(HLS)サーバー側のサポートを提供します。 このようなファイルは通常、.mp4、.m4v、.m4a、.mov、または.qtのファイル名拡張子を持ちます。 このモジュールは、H.264ビデオコーデック、AACおよびMP3オーディオコーデックをサポートしています。


先ほどHLSを試した時は以下のように実行しました



  • .mp4ファイルを用意 -> ffmpegで変換 -> .m3u8ファイルを読み込んで再生

ngx_http_hls_moduleを使うことで



  • .mp4ファイルを用意 -> URLでhoge.mp4.m3u8などとリクエストするとHLSとして読み込める

↑のように.mp4から変換することなくHLSで再生することが可能です


ngx_http_hls_moduleの設定

sudo vi /etc/nginx/conf.d/default.conf

公式を参考にして設定追加

+    location /hls/ {

+ hls;
+ hls_fragment 5s;
+ hls_buffers 10 10m;
+ hls_mp4_buffer_size 1m;
+ hls_mp4_max_buffer_size 5m;
+ root /var/video/;
+ }

default.conf

$ sudo systemctl restart nginx # nginx再起動

$ sudo mkdir -p /var/video/hls
$ sudo cp BigBuckBunny_320x180.mp4 /var/video/hls/BigBuckBunny_320x180.mp4 # confファイルのrootに設定したパスに動画をコピー


再生

sudo vi /usr/share/nginx/html/live-stream.html

動画へのパスを編集


/usr/share/nginx/html/live-stream.html

-       hls.loadSource('http://192.168.33.10/video/playlist.m3u8');

+ hls.loadSource('http://192.168.33.10/hls/BigBuckBunny_320x180.mp4.m3u8');

ブラウザでアクセスすると、先ほどと同じように再生されました

ブラウザでngx_http_hls_moduleを使用してHLSで配信

この時http://192.168.33.10/hls/BigBuckBunny_320x180.mp4.m3u8は以下のようなレスポンスを返します


BigBuckBunny_320x180.mp4.m3u8

#EXTM3U

#EXT-X-VERSION:3
#EXT-X-TARGETDURATION:5
#EXT-X-PLAYLIST-TYPE:VOD

#EXTINF:5.000,
BigBuckBunny_320x180.mp4.ts?start=0.000&end=5.000
#EXTINF:5.000,
BigBuckBunny_320x180.mp4.ts?start=5.000&end=10.000
#EXTINF:5.000,
BigBuckBunny_320x180.mp4.ts?start=10.000&end=15.000
#EXTINF:5.000,
BigBuckBunny_320x180.mp4.ts?start=15.000&end=20.000
#EXTINF:5.000,
BigBuckBunny_320x180.mp4.ts?start=20.000&end=25.000
(省略)


クエリストリングのstartendが5秒おきに設定されます。これで5秒おきに動画を分割したのと同じように扱ってくれます。

confファイルの設定を変えれば5秒以外にも設定できます

     location /hls/ {

  hls;
  hls_fragment 5s; # <- ここの設定を変える
  hls_buffers 10 10m;
  hls_mp4_buffer_size 1m;
  hls_mp4_max_buffer_size 5m;
  root /var/video/;
  }

confファイルの設定を変えなくても、http://192.168.33.10/hls/BigBuckBunny_320x180.mp4.m3u8?len=10としても動画を分割する間隔の秒数を指定できる


その他パラメータ


  • start

動画の開始位置を秒数で指定できる


  • end

動画の終了位置を秒数で指定できる


  • offset

動画の再生を指定秒数からにする

なので、以下のようなパラメータでリクエストを送ると

http://192.168.33.10/hls/BigBuckBunny_320x180.mp4.m3u8?offset=5&start=3&end=20

元の動画の3秒〜20秒までを切り取った17秒間の動画として扱い、

その17秒間の動画の5秒目から再生されるという動きになります

パラメータ送信


詳しく知りたい方は公式を参照

最後まで読んでいただいてありがとうございましたm(_ _)m


参考