S3に配置した動画をMediaLiveでスケジュール組んで配信してみる

この記事は [NewsPicks Advent Calendar 2019](https://qiita.com/advent-calendar/2019/newspicks) の8日目の記事です。

# はじめに

こんにちは、NewsPicksでサーバーサイドエンジニアをしている@d-kumoです。

NewsPicksというとオリジナル記事等の文字ベースのコンテンツをイメージされる方も多いかと思いますが、動画コンテンツにも力を入れており、今では週に4回配信することもあります。
今後増えていく動画コンテンツをより安定的に配信するため、最近はいろんな配信技術に触れる機会も増えてきました。

そんな中で、今回はAWSが提供しているライブ配信サービス[AWS Elemental MediaLive](https://aws.amazon.com/jp/medialive/)を使った配信構成を試してみたのでご紹介したいと思います。

※NewsPicksの動画配信構成については、以下の記事で解説しています。ご興味のある方はご覧ください。
https://qiita.com/kirihata/items/c027c7561eead3b1dced

# MediaLiveとは

[AWS Elemental MediaLive](https://aws.amazon.com/jp/medialive/)とは、入力された動画データをリアルタイムにエンコードして出力してくれるサービスです。
入力として使える動画データは、撮影中のカメラ等から転送されてきたものはもちろんのこと、S3に配置されているmp4ファイルを使うこともできます。

ただ、このサービスはエンコードしてくれるだけなので、動画配信は他のサービスと連携して行う必要があります。
例えば、[AWS Elemental MediaStore](https://aws.amazon.com/jp/mediastore/)というメディア向けにチューニングされたストレージサービスをMediaLiveの出力先に指定し、そこでエンコードされたコンテンツを保存、配信するような形です。

# やりたいこと

既に収録済みである動画を配信します。

具体的には以下の通りです。

- 配信構成は、MediaLive→MediaStore(冗長性は考えない)
- 入力は、S3にアップロードしたmp4ファイル
- 配信スケジュールは以下
 - 2019/12/8 21:45から予告映像を配信する(ループ再生)
 - 2019/12/8 22:00になったら本編映像を配信する
 - 本編終了後、配信が終了した旨の映像を配信する(ループ再生)

# ざっくりやること

やりたいことを実現するため、以下の設定をします。

- S3に動画ファイルを配置
- MediaStoreでコンテナ作成
- MediaLiveでInput作成
- MediaLiveでChannel作成
- MediaLiveでスケジュール設定

# やってみる

## S3に動画ファイルを配置

**S3の適当なパスに配信したいmp4ファイルを配置します。**

今回は、予告動画、本編動画、終了後動画の3本を配置しています。

<img width="1305" alt="スクリーンショット 2019-12-05 18.15.04.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/319840/231f279d-56a3-2ca2-b7c0-548ccb7ac043.png">


## MediaStoreでコンテナ作成

**MediaLiveからの配信を受けるコンテナを作成します。**

### コンテナ作成

`Create container`からコンテナを作成します。

<img width="704" alt="スクリーンショット 2019-12-05 17.48.00.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/319840/f9b02a86-b4f6-4af1-a0bd-8f92faf2fa53.png">

### Container policyを設定

[公式ドキュメント](https://docs.aws.amazon.com/ja_jp/mediastore/latest/ug/policies-examples.html)を参考にポリシーを設定してアクセスできるようにします。

HTTPS通信であれば誰でもアクセスを許可するのであれば、以下の通りです。
`<region>`、`<owner acct number>`、`<container name>`には適当なものを入れてください。

```
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "PublicReadOverHttps",
      "Effect": "Allow",
      "Action": ["mediastore:GetObject", "mediastore:DescribeObject"],
      "Principal": "*",
      "Resource": "arn:aws:mediastore:<region>:<owner acct number>:container/<container name>/*",
      "Condition": {
        "Bool": {
            "aws:SecureTransport": "true"
        }
      }
    }
  ]
}
```

## MediaLiveのInput作成

**MediaLiveへの入力として、S3に配置したmp4ファイルを設定します。**

`Create input`でinput作成画面を開きます。

<img width="742" alt="スクリーンショット 2019-12-05 18.33.06.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/319840/fc0bfbdb-f273-b70c-45bb-5c1bd96bfeb0.png">


Inputの名前、入力するファイル形式(今回はmp4)を入力します。

<img width="777" alt="スクリーンショット 2019-12-05 18.05.50.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/319840/139b8570-bd7d-1e88-768b-841111e226f0.png">

ソースのパスを指定して`Create`
(`Input source A`だけ入力すれば大丈夫です。)

<img width="759" alt="スクリーンショット 2019-12-05 18.22.22.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/319840/b62cc326-4a64-5d69-76d4-45938b9b8085.png">


配信する3つの動画ファイルについて、それぞれ作成します。


## MediaLiveのChannel作成

**配信チャンネルを作成します。**(これが中々大変です。。)

`Create channel`でChannel作成画面を開きます。

<img width="708" alt="スクリーンショット 2019-12-05 18.42.37.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/319840/307c02fb-9986-2d92-81cd-b3d5c64c58fe.png">

### Channel and input details

#### General info

Channel名とIAMロールを設定します。

<img width="776" alt="スクリーンショット 2019-12-05 21.41.31.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/319840/ae3dd843-ab85-84be-8e14-a5b14e9511f3.png">


#### Channel template

既存のテンプレートである`Live event`(HLSの方)を設定します。

<img width="775" alt="スクリーンショット 2019-12-05 21.42.06.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/319840/d2dfe2e5-6fcc-3422-6a2b-bd9d0bf8ba10.png">

すると、Output groupsにHLS形式の出力設定が追加されます。


#### Channel class

ここは`SINGLE_PIPELINE`を設定します。

デフォルト設定である`STANDARD`を使うと、Multi-AZで構成される2つのパイプラインを使用した冗長構成になりますが、Multi-AZ構成でない場合や検証の場合等には、`SINGLE_PIPELINE`を使った方が安価に使えます。

<img width="772" alt="スクリーンショット 2019-12-05 21.42.25.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/319840/e17672cd-868f-c984-b1c9-1ea4fcc81543.png">

### Input Attachments

`ADD`を押して、プルダウンからChannelに紐づけるinputを選択し、`Confirm`を押します。


<img width="781" alt="スクリーンショット 2019-12-05 21.54.53.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/319840/85ef7fe0-dd7a-e231-b63d-2aae242f067a.png">

今回のケースだと、予告動画と終了後動画はループ再生させたいので、作成したInput Attachmentsを選択して`Source End Behavior`を`LOOP`に変更します。

<img width="1111" alt="スクリーンショット 2019-12-05 22.53.56.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/319840/cfcf0326-f1cf-d7a3-8c5a-37dda8df438c.png">


### Output groups

作成したMediaStoreのコンテナを、配信先に設定します。

#### URL

ここのURLには、MediaStoreのコンテナに記載されている`Data endpoint`を記載しますが、httpsを**mediastoresslに置き換える必要がある**ので、ご注意ください。

配信先にしたいMediaStoreのEndpointが下記のような場合、

```
https://XXXXXXXXXXXXXX.data.mediastore.ap-northeast-1.amazonaws.com/<path>/<basename>
```

URLには以下のように設定します。

```
mediastoressl://XXXXXXXXXXXXXX.data.mediastore.ap-northeast-1.amazonaws.com/<path>/<basename>
```

`<path>`にはコンテナ以下のパス、`<basename>`には設定したいマニフェストファイル名を入れます。
(OutputにName Modifierを設定した場合は、`<basename>`にName Modifierを結合した名前がマニフェストファイル名になります)


#### CDN Settings

今回はMediaStoreを配信先に指定しているので、`Hls media store`を設定してください。

<img width="794" alt="output.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/319840/fa8da5b9-167f-8923-04f6-891dd1019c82.png">


出力される映像の画角やビットレート、コーデック等についてはOutputごとに設定できるので、その辺りを調整する場合はそちらで行ってください。

### Create Channel

ここまで設定が終わったら、`Create channel`を押します。

## Schedule設定

最後に、配信スケジュールを作成します。

ChannelのScheduleタブを開き、`Create`します。

<img width="1105" alt="スクリーンショット 2019-12-05 23.26.25.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/319840/017f3573-ac42-b5ee-2933-3e171df0d6db.png">


### 2019/12/8 22:00になったら本編に切り替える

Action nameに適当な名前を入力します。
Start typeを`Fixed`に指定し、Date、Timeを2019/12/8 13:00に設定します。(Timeは**UTC**なので注意)
次に、Action typeを`Input Switch`に、Input attachmentで本編である`main`を設定し、`Create`します。

<img width="763" alt="スクリーンショット 2019-12-05 23.35.33.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/319840/ab472735-9cd5-fb91-dd4d-27fddc638da8.png">

これで、2019/12/8 22:00(JST)になったら本編に切り替わるようになります。


### 本編が終了したら終了後動画に切り替える

Action nameに適当な名前を入力後、こちらではStart typeを`Follow`に指定します。
Reference action nameに上記で作成したスケジュール名を指定し、Follow pointを`END`に設定します。
Action typeは`input Switch`で、Input attachmentは`finished`を設定し、`Create`します。

<img width="760" alt="スクリーンショット 2019-12-05 23.36.00.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/319840/08c38525-0d3e-cedf-d58d-b2cac9936480.png">

この設定で、本編が終了したら終了後動画に切り替わるようになります。

### 設定完了

上記の設定ができたら、Scheduleタブにはこのように表示されます。

<img width="1097" alt="スクリーンショット 2019-12-05 23.36.25.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/319840/dd04c876-503e-2722-085f-558f0a35c838.png">

### 【注意】ChannelがRUNNINGじゃないとスケジュール機能は動作しない

若干ハマったポイントなんですが、スケジュール機能はChannelがRUNNING状態になっていないと動作しません。

設定したスケジュール日時になる前に必ず**RUNNING**にしておきましょう。
(Scheduleを設定したから時間通り動くでしょとか思っていたら動きませんでした)

本当はChannelの起動もMediaLive内でできたらいいなとか思っているのですが、そのような機能はなさそう。
そこも自動化したければ、Lambda等と連携する必要がありそうです。


# おわりに

これで全ての設定が完了です。お疲れ様でした。
Channelを`Start`させれば予告動画が配信され、スケジュール設定した時刻になれば本編が流れます。

今回はMediaLiveを使ってスケジュールした時間に予告→本編→終了後と切り替わる配信を試してみました。
ちょっとChannelの設定を作るのは大変ですが、これだけでスケジュール管理された動画配信ができるのはすごいですよね。

とはいえ、この操作を毎度コンソールから行うのは手間がかかり過ぎてしまうので、現実的にはSDKを使って自動で設定が作られるようにすべきだろうなとは思います。


## 参考記事

https://qiita.com/khagi/items/ff8120c498a7d45338b1
https://dev.classmethod.jp/cloud/aws/aws-elemental-medialive-programming-using-mp4-input-and-switch-input/
https://qiita.com/ryotax/items/60f7ec699cfaec62a8be