この記事の対象
- ngx_http_hls_moduleを試してみたい方
- HLSに興味があるのでとりあえず試して見たい方
- 自分なりに調べたまとめという内容ですので、ただシンプルにHLSの動作を確認してみたいという方は以下のページを参考にし、本内容は読まなくて良いです。
- HLS(HTTP Live Streaming)で動画を配信・再生してみよう | YAZ技術ブログ
- 動画をストリーミング配信する方法 | IT SKILL MAP
- ffmpeg を使い、HTTP Live Streaming(HLS)をファイルに保存し、保存したファイルからストリーミングを行う方法について - Qiita
- HTTP Live Streamingを試してみた - UUUM攻殻機動隊(エンジニアブログ)
- HTTP Live Streaming 動画配信のやり方 (実践) | ビズバレーブログ
- ffmpeg で mp4 をiPhone用のストリーミング(HLS)に対応させる。 - それマグで!
- ffmpegでUSBカメラの映像をHLSでライブストリーミングする
- 自分なりに調べたまとめという内容ですので、ただシンプルにHLSの動作を確認してみたいという方は以下のページを参考にし、本内容は読まなくて良いです。
動画配信技術、HLSについて詳しく知りたい方は以下のリンクなどを参考にし、本内容は読まなくて良いです
- HTTP Live Streaming - Wikipedia
- フロントエンドエンジニアのための動画ストリーミング技術基礎 | ygoto3.com
- nginxでストリーミングサーバを立ててライブ配信する。 - Qiita
- HLSについて知っていることを話します
- ライブ動画配信プロトコル(HTTP Live Streaming, HLS)の概要図解メモ(AbemaTV/FRESH!)
- 動画配信技術 その1 - HTTP Live Streaming(HLS) - Akamai Japan Blog
- HLSとは - Qiita
- オンデマンド動画配信を支える技術 - わかる!HLS編 - Qiita
※本記事で解説している内容もほとんど↑のリンクに書いてある内容から記載しています
本記事の要約
- HTTP Live Streaming(HLS)を使うと何が嬉しいか
- 「動画配信って動画全て読み込んでからの再生だと動きが遅いなあ」
- 「HTTP Live Streaming(HLS)を使えば読み込んだ部分から再生し、再生しながら次の部分を読み込むということが可能だよ」
- 「すごい!HLS便利!」
- ngx_http_hls_moduleを使うと何が嬉しいのか
- 「でもHLSで再生するには、
hoge.mp4
ファイルから.m3u8
ファイルと複数.ts
ファイルに変換する一手間があるな」 - 「ngx_http_hls_moduleを使えば
hoge.mp4
を変換しなくても、URLでhttp://hogexxx.com/hoge.mp4.m3u8
とリクエストを送ったらサーバがよしなに解釈してくれるよ」 - 「すごい!まじかよ!超便利!!!」
- 「でもHLSで再生するには、
ストリーミングとは
ストリーミング (英語: 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" ファイルをもとにしている。
ただのテキストファイルで実際のメディアファイルへのパスが記載されている
あとで実際に作成しますが、自分が作ったのはこのような感じになりました
#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) は、符号化方式を使ってデータのエンコード(符号化)とデコード(復号)を双方向にできる装置やソフトウェアなどのこと。 また、そのためのアルゴリズムを指す用語としても使われている。
コーデックには、データ圧縮機能を使ってデータを圧縮・伸張するソフトウェアや、音声や動画などのデータを別の形式に変換する装置およびソフトウェアが含まれる。
コーデックについて自分が分かりやすかったページ
- コーデックとは? 動画を扱うなら知っておきたい基礎知識|ネットワークビデオレコーダー(NVR)
- 動画形式の「コンテナ」と「コーデック」についての説明|「分かりそう」で「分からない」でも「分かった」気になれるIT用語辞典
ブラウザ対応状況
2019/01/02現在
chromeなどの主要なブラウザでは対応されていませんので、
Media Source Extensions(Media Source Extensions - Wikipedia)を利用するとchromeなどでもHLS再生できるようです
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
使用する動画
mp4の動画をダウンロードする
(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
にアクセスしたら再生ができる!
chromeから再生できるようにする
$ sudo touch /usr/share/nginx/html/live-stream.html
- https://github.com/video-dev/hls.js/ のREADMEのGetting Startedからコードをコピペし編集
<!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
ファイルを一定間隔で取得しているのも確認できました
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/;
+ }
$ 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
動画へのパスを編集
- hls.loadSource('http://192.168.33.10/video/playlist.m3u8');
+ hls.loadSource('http://192.168.33.10/hls/BigBuckBunny_320x180.mp4.m3u8');
ブラウザでアクセスすると、先ほどと同じように再生されました
この時http://192.168.33.10/hls/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
(省略)
クエリストリングのstart
とend
が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
参考
- Instructions | NGINX
- NGINX Plusでできることまとめ - Qiita
- html5 - Http Media Streaming Server - Stack Overflow
- CompilationGuide/Centos – FFmpeg
- CentOS7にffmpegのインストール - うま味がない
- CentOS7にffmpegをyumインストール - Qiita
- [小ネタ] Video.jsのvideojs-contrib-hlsを使ってHLS形式のライブ配信を再生する最低限度の設定 | DevelopersIO
- bash - How to put a line comment for a multi-line command - Stack Overflow
- javascript - How to handle "Uncaught (in promise) DOMException: play() failed because the user didn't interact with the document first." on Desktop with Chrome 66? - Stack Overflow
- Disable html5 video autoplay - Stack Overflow