簡単に作れる動画配信

ちょっと時間が余ったので前からやってみたかった自分で撮った動画をWEBにアップして見れるようなサーバを作成してみました！

小さい環境でもできるのにはびっくりしました！

##■環境
Public CloudではAzureを利用していますがAWSでも以下のスペックを持っていれば可能です

【WEB配信サーバ】

| 項目 | 値 |
|:-:|:-:|
|Public Cloud|Azure VM|
|OS|CentOS 7.4|
|Hostname|WHSMINI|
|Disk|31GB|
|Size(CPU/Memory:Money)|1vCPU,3.5GB,￥8711   |
|Network|Public(動的)|
|NSGRule1|1935(Allow,Inbound,Any,Any)|
|NSGRule2|80(Allow,Inbound,Any,Any)|
|NSGRule2|22(Allow,Inbound,Any,Any)|


##**■シナリオ**
こんな感じのシナリオになります

【１】．｢ストリーミングサーバ｣にSSH設定(root)
【２】．関連パッケージインストール
【３】．[nginx-rtmp-module] [nginx(ソースコード)]のダウンロード
【４】．[nginx(ソースコード)]のmake
【５】．[nginx.config]の編集
【６】．[nginx]サービス設定、起動確認
【７】．動画ファイルアップデートと変換
【８】．[html]ファイル編集
【９】．ストリーミングサイト 稼働確認

##**■覚えておいたほうがいいこと**

<Font Color="Red">ストリーミング　：</Font>
　サイズの大きなファイルをパケットにしてダウンロードと再生を同時に行う配信方法。パケットデータはメモリーに蓄積され、再生が終わると消滅します

<Font Color="Red">ライブ配信　：</Font>
　いわゆる[生放送]。リアルタイムで配信するため、[早送り]とかはできません。[会議の中継]等で利用される。
　今回の記事ではやらないけど稼働確認は取れてるのでいつか書くかもしれないです。

<Font Color="Red">オンデマンド配信　：</Font>
　録画放送。あらかじめサーバにアップした動画ファイルを再生します。ライブと違い[早送り]等可能です。スマホやPCで撮った動画をアップするのはこっちの配信方式になります。今回はこちらをやります。

##**■オンデマンド配信サーバの構築方法**
ここから本番です！思った以上に簡単でした！

###**<Font Color="Red">【１】．｢ストリーミングサーバ｣にSSH設定(root)</Font></Font>**
<HR>
　｢ストリーミングサーバ｣にrootでログインするためAZVMに設定を入れます。理由はいちいち[sudo]とか[su]が面倒だからです。

**（１） rootパスワード設定**
 ⇒　このままやればできます。

```ruby:コマンド
[user@WHSMINI ~]$ sudo passwd root
[user@WHSMINI ~]$ su
[root@WHSMINI user]# vi /etc/ssh/sshd_config
```

```ruby:/etc/ssh/sshd_config
# PermitRootLogin yes
PermitRootLogin yes
```

###**<Font Color="Red">【２】．関連パッケージインストール</Font>**
<HR>
　以降の作業で必要となるパッケージをすべてこのタイミングでインストールします。
<HR>

**（１）関連パッケージおよび動画変換パッケージのインストール**
 ⇒　以下を実行します。

```ruby:コマンド(root)
yum install -y wget gcc pcre-devel openssl openssl-devel git
yum install -y epel-release
rpm --import http://li.nux.ro/download/nux/RPM-GPG-KEY-nux.ro
rpm -Uvh http://li.nux.ro/download/nux/dextop/el7/x86_64/nux-dextop-release-0-1.el7.nux.noarch.rpm
```

###**<Font Color="Red">【３】．[nginx-rtmp-module] [nginx(ソースコード)]のダウンロード</Font>**
<HR>
　[RTMP(Real-Time Message Protocol)] は音声や動画などをストリーミング再生するためのプロトコルです。流れとしては動画ファイルを分割してクライアント側のFlushPlayerで分割したファイルを再度つなぎ合わせ再生を行っています。
<HR>


**（１）nginx-rtmp-moduleのダウンロード**
 ⇒　Gitからモジュールをダウンロードしてきます。

```ruby:コマンド(root)
mkdir /Storeaming
git clone https://github.com/arut/nginx-rtmp-module.git
```

**（２）[nginx]ソースコードダウンロード**
　⇒　落としてきた[RTMP]を使用するためソースコードからMakeします
　　　以下で使用する[nginx]のソースコードは以下のサイトから確認しています
　　　http://nginx.org/en/download.html

```ruby:コマンド(root)
cd /Storeaming
wget http://nginx.org/download/nginx-1.12.2.tar.gz
tar zxf nginx-1.12.2.tar.gz
rm -rf nginx-1.12.2.tar.gz
```

###**<Font Color="Red">【４】．[nginx(ソースコード)]のmake</Font>**
<HR>
 [--add-module]を先ほど落とした[nginx-rtmp-module]のパスにします。
<HR>

**（１）configure**
 ⇒　MakeFileを作成し実行する

```ruby:コマンド(root)
cd /Storeaming/nginx-1.12.2/
./configure --add-module=/Storeaming/nginx-rtmp-module
make
make install
```

###**<Font Color="Red">【５】．[nginx.config]の編集</Font>**

<HR>
　[nginx.config]の設定ファイルを編集し[nginx]で[rtmp]を使えるようにします。以下の内容をファイルの最終行に追加します。またこの時点で動画を格納するディレクトリに関しても作成します。
<HR>

**（１）画像ファイルの格納ディレクトリ作成とConfig設定**
 ⇒　MakeFileを作成し実行する

```ruby:コマンド(root)
mkdir /usr/local/nginx/html/movie
chown nobody /usr/local/nginx/html/movie
vi /usr/local/nginx/conf/nginx.conf
```

```ruby:/usr/local/nginx/conf/nginx.conf
rtmp {
    server {
        # Rtmp Port
        listen 1935;
        access_log logs/rtmp_access.log;
         application livet {
            live on;
            wait_video on;
            # IP を絞る場合以下の設定を有効化
            # allow publish 192.168.1.0/24;
            # deny publixh all;
            hls on;
            hls_path /usr/local/nginx/html/test2;
            hls_fragment 5s;
        }
        ####VOD In Add ########
        application vod {
           play /usr/local/nginx/html/movie; // 動画を格納するディレクトリを指定する
        #######################
        }
    }
}
```

###**<Font Color="Red">【６】．[nginx]サービス設定、起動確認</Font>**
<HR>
　このままでは[systemctl]でのサービス起動はできない為、起動スクリプトを作成します。以下の内容をコピーで問題ありません。
<HR>

**（１）サービス起動スクリプト作成**

```ruby:コマンド(root)
vi /usr/lib/systemd/system/nginx.service
```

```ruby:/usr/lib/systemd/system/nginx.service
[Unit]
Description=nginx - high performance web server
Documentation=http://nginx.org/en/docs/
After=network.target remote-fs.target nss-lookup.target
[Service]
Type=forking
ExecStartPre=/usr/local/nginx/sbin/nginx -t -c /usr/local/nginx/conf/nginx.conf
ExecStart=/usr/local/nginx/sbin/nginx -c /usr/local/nginx/conf/nginx.conf
ExecReload=/bin/kill -s HUP $MAINPID
ExecStop=/bin/kill -s TERM $MAINPID
PrivateTmp=true
[Install]
WantedBy=multi-user.target
```

**（２）サービス起動設定**

```ruby:コマンド(root)
systemctl enable nginx
systemctl start nginx
```
**（３）nginx 起動確認**

作業端末（インターネットに接続できる環境）より以下に接続

``http://<｢ストリーミングサーバ｣のPublicIP>``

###**<Font Color="Red">【７】．動画ファイルアップデートと変換</Font>**
<HR>
　スマホで撮った動画をサーバに格納してファイル形式をMP4からm3u8に変換します。
<HR>

**（１）動画アップロード**

　アップロード自体は[WinSCP]で構いません。ただし格納先は【５．[nginx.config]編集】で作成した動画格納ディレクトリになります

![vod2.png](https://qiita-image-store.s3.amazonaws.com/0/150678/05a0ef7b-7f37-fc6c-8cef-14e6ba80cf2d.png)

**（２）動画ファイルを変換**
　ここでは格納した動画ファイルをHLSに変換します。変換コマンドは通常Centosに入っていませんので別途インストールする必要があります

```ruby:コマンド(root)
yum install -y ffmpeg
cd /usr/local/nginx/html/movie/
```

```ruby:コマンド(root)
# HLS 変換コマンド
#<動画ファイル2>　：格納した動画ファイルから拡張子を抜いてください
ffmpeg -re -i 180320_100150.mp4<動画ファイル> -vcodec libx264 -vprofile baseline -acodec copy -ar 44100 -ac 1 -f segment -segment_format mpegts -segment_time 10 -segment_list 180320_100150<動画ファイル2>.m3u8 180320_100150<動画ファイル2>-%03d.ts
```


```ruby:コマンド実行前と実行後
#実行前
[root@WHSMINI movie]# ls /usr/local/nginx/html/movie
180320_100150.mp4
#実行後
[root@WHSMINI movie]# ls /usr/local/nginx/html/movie
180320_100150-000.ts  180320_100150-001.ts  180320_100150-002.ts  180320_100150.m3u8  180320_100150.mp4
[root@WHSMINI movie]#
```

###**<Font Color="Red">【８】．[html]ファイル編集</Font>**
<HR>
 ここでは起動させるhtmlファイルを編集します。
<HR>

**（１）Topページの作成**
作成内容はWEB動画を配信させるページへのリンクページです。index.htmlを書き換えます。
また次回以降を見据えて「Live配信用のWEBページへのリンク」も作成しておきます。

```ruby:コマンド(root)
rm -rf /usr/local/nginx/html/index.html
vi /usr/local/nginx/html/index.html
```

```ruby:index.html
<DOCTYPE html>
<html lang="en" class="">
<body>
<p>This Is Web Storeaming StartPage!!</p>
<hr>
<a href="live.html">Live</a><br/>
<a href="vod.html">Video On Demand</a>
</body>
```

![vod.png](https://qiita-image-store.s3.amazonaws.com/0/150678/13918c17-ecff-b8b5-b923-5aac581c5c7e.png)

**（２） [Video On Demand]ページの作成**

こちらが[Video On Demand]用のWEBページです。

```ruby:コマンド(root)
vi /usr/local/nginx/html/vod.html
```

```ruby:vod.html
<DOCTYPE html>
<html lang="en" class="">
<head>
    <title>ONDEMAND</title>
    <link href="//vjs.zencdn.net/5.11/video-js.min.css" rel="stylesheet">
    <script src="//cdn.jsdelivr.net/hls.js/latest/hls.min.js"></script>

</head>
<body>
<p> Video On Demand </p>
<video id="video" class="video-js vjs-default-skin" width="640" height="480" controls>
<script type="text/javascript">
    // 変換した動画ファイルを指定します。
    var source = '/movie/180320_100150.m3u8';
    var ua = navigator.userAgent;
　　// スマホからのアクセスか、それ以外のアクセスかを判断
    if (ua.indexOf('iPhone') > 0 || ua.indexOf('iPad') > 0 || ua.indexOf('Android') > 0) {
        // iOS
        document.write('<source src=' + source + ' type="application/x-mpegURL">');
        document.write('</video>');

    }else{
        // OTHER
        document.write('</video>');
        if(Hls.isSupported()) {
            var video = document.getElementById('video');
            var hls = new Hls();
            hls.loadSource(source);
            hls.attachMedia(video);
            hls.on(Hls.Events.MANIFEST_PARSED,function() {
                video.pause();
            });
        }
    }
</script>
</body>
</html>
```

###**<Font Color="Red">【９】．ストリーミングサイト 稼働確認</Font>**
<HR>
　上記で設定は終わりました。後は先ほど確認したページからリンクをたどり動画が再生できるかを確認することになります。

注意：下記画像ではあえて動画を見せないようにしています。
<HR>

【TOPページ】
![vod3.png](https://qiita-image-store.s3.amazonaws.com/0/150678/b3e7f0ab-25b4-6392-8b65-cb4a7fb62777.png)

【動画再生ページ】
![vod4.png](https://qiita-image-store.s3.amazonaws.com/0/150678/8bf4ee14-871b-f3b9-b937-4cb9e48f5221.png)

##**<Font Color="Red">【補足】．同じページに複数の動画を載せたい場合</Font>**
<HR>
　よくある動画サイトの様に複数の動画を同じサイトに表示させる方法になります。基本的には動画アップして変換してHTMLに追加といった形です
<HR>

**１．動画格納**

```ruby:コマンド(root)
mkdir /usr/local/nginx/html/movie2
chown nobody /usr/local/nginx/html/movie2
```

<Font Color="Red">２．動画ファイル変換</Font>

```ruby:コマンド(root)
ffmpeg -re -i <動画ファイル> -vcodec libx264 -vprofile baseline -acodec copy -ar 44100 -ac 1 -f segment -segment_format mpegts -segment_time 10 -segment_list <動画ファイル>.m3u8 <動画ファイル>-%03d.ts
```

**３．動画HTMLの編集**
```ruby:コマンド(root)
vi /usr/local/nginx/html/vod.html
```

```ruby:追加コード
<DOCTYPE html>
<html lang="en" class="">
<head>
    <title>ONDEMAND</title>
    <link href="//vjs.zencdn.net/5.11/video-js.min.css" rel="stylesheet">
    <script src="//cdn.jsdelivr.net/hls.js/latest/hls.min.js"></script>

</head>
<body>
<p> Video On Demand </p>
<video id="video" class="video-js vjs-default-skin" width="640" height="480" controls>
<script type="text/javascript">
    var source = '/movie/x180320_100150.m3u8';
    var ua = navigator.userAgent;
    if (ua.indexOf('iPhone') > 0 || ua.indexOf('iPad') > 0 || ua.indexOf('Android') > 0) {
        // iOS
        document.write('<source src=' + source + ' type="application/x-mpegURL">');
        document.write('</video>');

    }else{
        // OTHER
        document.write('</video>');
        if(Hls.isSupported()) {
            var video = document.getElementById('video');
            var hls = new Hls();
            hls.loadSource(source);
            hls.attachMedia(video);
            hls.on(Hls.Events.MANIFEST_PARSED,function() {
                video.pause();
            });
        }
    }
</script>

///////////////以下の部分を追加する///////////////
//　・変数が上記と変わっていることを注意する事
////////////////////////////////////////////////
<p> Video On Demand Vol 2 </p>
<video id="videoid2" class="video-js vjs-default-skin" width="640" height="480" controls>
<script type="text/javascript">
    var source2 = '/movie2/x180327_135730.m3u8';
    var ua = navigator.userAgent;
    if (ua.indexOf('iPhone') > 0 || ua.indexOf('iPad') > 0 || ua.indexOf('Android') > 0) {
        // iOS
        document.write('<source src=' + source2 + ' type="application/x-mpegURL">');
        document.write('</video>');

    }else{
        // OTHER
        document.write('</video>');
        if(Hls.isSupported()) {
            var video2 = document.getElementById('videoid2');
            var hls2 = new Hls();
            hls2.loadSource(source2);
            hls2.attachMedia(video2);
            hls2.on(Hls.Events.MANIFEST_PARSED,function() {
                video.pause();
            });
        }
    }
</script>
////////////////////////////////////////////////////////////
</body>
</html>
```

**４．確認結果**
　下記の様に動画ファイルが二つ表示されます。
※動画ファイルはあえて表示されないようにしています。

![01.png](https://qiita-image-store.s3.amazonaws.com/0/150678/2d147b13-ac13-1943-8130-f4e93f929fda.png)

<HR>

##**■最後に**

　今回のは動画を格納するタイプ（ビデオオンデマンド）での動画配信を行っています。動画配信サイトは「高スペックじゃないと動かない」と思っていたのですが、軽い動画なら動くんだなと思いました。次回はLive配信（生放送）について書いていこうかと思います！