HLSを使って動画をストリーミング配信する

## 3つの映像配信方式

- **ストリーミング**
  音声や動画ファイルを細かく分割（セグメント）して配信する仕組みです。
  データを受信しながら再生を行うことができます。
  ファイルを分割して配信しているので、動画の途中部分を開始地点としたデータの受信（再生）もできます。
  受信したデータは視聴者側にファイルとして保存されないことが特徴です。
  YouTubeなどの動画配信や、Spotifyなどの音楽配信もこれに分類されます。

- **プログレッシブダウンロード**
  疑似ストリーミングとも呼ばれ、この方式もデータを受信しながら再生を行うことができます。
  ただし、ストリーミングと異なり、動画の途中部分から受信を開始するといったことができません。
  受信したデータはキャッシュファイルとして保存されます。
  `<video src="sample.mp4"></video>`といった記述では、この方式でデータを受信します。

- **ダウンロード**
  前述2つとは異なり、ファイル自体を全て受信してから再生する仕組みです。
  受信したデータは視聴者側にファイルとして保存されます。


## HLSって？
- HTTP Live Streamingの略で、Appleが開発した動画ストリーミングのプロトコルです。  
  現在主流な規格のひとつで、HuluやAbemaTV、Tverなどのサービスで使われています。
- HTTPプロトコルを使用しており、HTTPSによる暗号化にも対応しています。
- Webサーバがあればストリーミング配信ができるので、ストリーミング専用サーバを立てる必要がありません。
- アダプティブストリーミング（後述）にも対応しています。
- SafariとMicrosoft Edgeはネイティブサポートしています。  
  その他のモダンブラウザは[hls.js](https://github.com/video-dev/hls.js/)というライブラリを導入することで対応できます。


## 作業の流れ

1. HLS用の動画データを生成
2. hls.jsを使って実装
3. HTMLファイルと動画ファイルをサーバーにアップロード


## 実装

### HLS用の動画データを生成
FFmpegというツールででHLS用に変換します。

1. **FFmpegのインストール**
    HomebrewでFFmpegをインストールします。

    ```
    brew install ffmpeg
    ```

1. **FFmpegを使ってHLS用に動画を変換**
    各オプションを設定します。

    ```
    ffmpeg -i [変換元のファイル] -c:a [オーディオのエンコード指定] -f [出力ファイルのフォーマット] -hls_playlist_type [ストリーミング設定] -hls_time [分割する秒数] -g [動画のフレーム数] -hls_segment_filename [出力ファイルの名称]
    ```

    さらにアダプティブストリーミングにも対応させます。
    アダプティブストリーミングとは視聴側の通信環境に応じて、ビットレート（画質）を自動的に変更する仕組みです。
    いくつかのビットレートでHLS動画を用意しておくことで、最適なビットレートでストリーミング配信してくれます。

    ビットレートはFFmpegでの変換時に`-b:v`オプションで指定できます。
    今回は1Mbpsと10Mbpsの2つのビットレートでHLS動画を生成します。

    ```
    // 1Mbpsの動画を生成
    ffmpeg -i sample.mp4 -b:v 1M -c:a copy -f hls -hls_playlist_type vod -hls_time 5 -g 24 -hls_segment_filename "sample-1m%3d.ts" sample-1m.m3u8

    // 10Mbpsの動画を生成
    ffmpeg -i sample.mp4 -b:v 10M -c:a copy -f hls -hls_playlist_type vod -hls_time 5 -g 24 -hls_segment_filename "sample-10m%3d.ts" sample-10m.m3u8
    ```

    コマンドを実行するとインデックスファイル（.m3u8）とメディアセグメントファイル（.ts）が生成されます。
    こちらの2種類のファイルがHLSに必要なデータになります。

1. **すべての動画をまとめたインデックスファイルを作成**
    生成した動画をビットレートごとにフォルダにまとめます。

    ```
    video
    ├── 10m
    │   ├── sample-10m.m3u8
    │   ├── sample-10m000.ts
    │   ├── sample-10m001.ts
    │   └── ...
    └── 1m
       ├── sample-1m.m3u8
       ├── sample-1m000.ts
       ├── sample-1m001.ts
       └── ...
    ```

    続いて、各ビットレートへの参照を記述したマスタインデックスファイル`master.m3u8`を作成します。
    `master.m3u8`の中身は以下になります。

    ```:master.m3u8
    #EXTM3U
    #EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=1000000
    1m/sample-1m.m3u8
    #EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=10000000
    10m/sample-10m.m3u8
    ```

    実際のページでは`<video>`でマスタインデックスファイルを読み込みます。


### hls.jsを使って実装

1. [hls.js](https://github.com/video-dev/hls.js/)をインストールします。

    ```
    npm install hls.js
    ```

1. HTMLとJavaScriptでコードを記述します。

    ```html:HTML
    <video id="video" controls>
    ```

    ```JavaScript:JavaScript
    import Hls from 'hls.js';

    const video = document.querySelector('#video');
    const videoSrc = 'video/master.m3u8';

    if ( Hls.isSupported() ) {
      const hls = new Hls();
      hls.loadSource(videoSrc);
      hls.attachMedia(video);
    } else if ( video.canPlayType('application/vnd.apple.mpegurl') ) {  // ネイティブサポートブラウザ用
      video.src = videoSrc;
    }
    ```


### HTMLファイルと動画ファイルをサーバーにアップロード
今回はNetlifyにアップロードして確認します。

**実装例**
[https://elated-ritchie-9409d8.netlify.app/](https://elated-ritchie-9409d8.netlify.app/)


## 参考URL

- [ストリーミング（streaming）とは - IT用語辞典 e-Words](https://e-words.jp/w/%E3%82%B9%E3%83%88%E3%83%AA%E3%83%BC%E3%83%9F%E3%83%B3%E3%82%B0.html)
- [HTTP Live Streaming (HLS) - Apple Developer](https://developer.apple.com/streaming/)
- [hls.jsで実装する動画ストリーミングの分かりやすい解説](https://mat0401.info/blog/brief-hlsjs1/)