AWS MediaConvertとS3/CloudFrontで作るストリーミングサーバ～その１～

#はじめに
AWSにはメディアサービスと呼ばれる、リアルタイムにライブ配信したり、動画をVOD方式で配信したりするための仕組みが充実してます。これらのシステムを使ってビジネス上のコンテンツデリバリーシステムを構築している方々もたくさんいます。私は"見る側"として、いろんな配信サービスを利用してますが、インフラエンジニアとして、そこにはどんなサーバやストレージがあって、どのように組み合わさって動いてるのか興味がありました。OSSのffmpegやnginxなどを利用して勉強し始めていたところだったんですが、並行して、AWSのサービスを使って配信プラットフォームの仕組みを勉強していきます。
というのもAWSは、公式の学習用コンテンツが豊富にそろっていますし、すでに基盤があるわけなので、サーバやストレージを組み上げなくても、配信技術そのものを把握するのに早いかなと思いました。多角的に理解を深めるためにもOSSを使った勉強もしていきたいですが。。。

今後数回にわたって、AWSのサービスをセットアップする際に気になったことなどをメモしていきます。あくまでメモなので、いろいろとご指摘などありましたら、よろしくお願いします。
#1.やりたいこと(VOD)
まずはVOD形式の配信サービスを構築してみたいと思っています。ざっくりイメージにするとこんな感じです。
<img width="610" alt="streaming02.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/531509/94a77f9e-bb5e-73b3-0f28-adf7fd1a086d.png">

このフローをAWSのサービスに当てはめるとこんな感じです。

| Step       |       手順 |    AWSで使うサービス   |
|:-----------------|:------------------|:------------------|
| 1           |元のファイルをストレージにアップロード    |   S3        |
| 2          | H.264やHEVCなどの符号化処理 |       MediaConvert       |
| 3          |HLSやMPEG-DASHなどへのパッケージング | MediaConvert       |
| 4          |Webサーバにアップロード | S3 |
| 5          |エッジサーバでキャッシュ| CloudFront|
| 6          |パソコンやスマホのブラウザで視聴| - |

できる限りAWSの解説も加えながら、スマホやパソコンで動画を視聴することをゴールに、環境を構築していきます。
# 2.ソースファイル配置用のS3バケットの作成
S3(Amazon Simple Storage Service)は、Amazonのクラウド型オブジェクトストレージサービスで、ファイルをオブジェクトとして格納します。NFSなどの共有ファイルサービスのようにディレクトリ構造での格納ではなく、バケットと呼ぶスペース(コンテナ)でオブジェクトを管理します。公式サイトによるとS3に書き込まれたデータは、複数のAZ(アベイラビリティゾーン）やデバイスに冗長的に書き込まれるので耐障害性が高いというのも特徴の一つです。オブジェクトストレージに関する投稿は、OpenStack swiftを題材にいつか書きたいなぁ。

またS3は単にファイルを保管・管理するだけでなく、静的なwebサイトとしても動作します。この辺りはコンテンツ公開用のWebサーバを立ち上げるところで説明します。

今回の環境を構築する上で、S3に2つのバケットを作る必要があります。

- MediaConvertへ元の動画ファイルを渡すためのソースとなるバケット
- MediaConvertでエンコード/パッケージ処理されて出来上がったファイルの格納先となるバケット

バケット自体は簡単に作れます。
AWSのコンソールで、サービスの中からS3を選択します。
`+バケットを作成する`ボタンをクリックします。そうすると`バケットの作成`のウインドウが表示されます。

##名前とリージョン
元の動画ファイルを配置するバケットを`video-input-01`という名前で作成しました。

| 設定項目 | 設定値|
|:-:|:-:|
| バケット名  | video-input-01  |
|  リージョン | アジアパシフィック(東京)  |
|既存のバケットから設定をコピー  | 空欄 |

##オプションの設定
こちらはすべてデフォルト値で進めました。

##ブロックパブリックアクセス（バケット設定）
バケットに対するアクセス権に関する設定ですね。デフォルト値の☑パブリックアクセスをすべてブロックの状態のまま進めます。

##バケットの作成
設定したことに間違いがないか確認してから、`バケットを作成`をクリックします。これで、入力ソース用のビデオアップロード先ができました。

#3.ファイル書き出し用のS3バケットの作成
続いて同じ手順で、MediaConvertのアウトプットを格納するためのバケットを作ります。
こちらのバケット名は`video-output-01`にしました。今度はブロックパブリックアクセスは公開する設定にします。


結果として以下の2つのバケットがコンソール上に現れます。

| バケット名| アクセス権|リージョン |
|:--|:--|:--|
| video-input-01  |パケットとオブジェクトは非公開   | アジアパシフィック(東京)  |
| video-output-01  |公開   |  アジアパシフィック(東京) |

この2つのバケットだけ用意しておけばよいのですが、出力先のvideo-output-01には、`dash01`という名前で1つフォルダを作成しました。

#4.動画ファイルの準備
##動画ファイルの入手
作成した`video-input-01`にmovieファイルを置きます。今回は検証用ということで、Big Buck Bunnyの動画ファイルを使おうと思います。

- Big Buck Bunny, Sunflower version

Big Buck Bunny
Copyright (C) 2008 Blender Foundation | peach.blender.org
Some Rights Reserved. Creative Commons Attribution 3.0 license.
http://www.bigbuckbunny.org/

ダウンロードサイトにはいろいろなバージョンのファイルがあるのですが、今回はStandard 2DのFull HD(1920x1080) 30fps　H.264/AC-3のファイルにしました。
このファイルをBig Buck Bunnyの公式ダウンロードページからいったん手元の作業用PCにダウンロードします。
オーディオコーディングがAC-3というのが、1つ忘れてはならないポイントです。後で解説します。

## 動画ファイルのアップロード
movieファイルのダウンロードが完了したら、そのファイルをS3のvideo-input-01に上げます。

- AWSコンソールでS3のコンソールを開きます。
- バケットの一覧が表示されているので、`video-input-01`を選択します。
- `アップロード`ボタンがあるのでクリックし、アップロードしたいファイルを選択し、`アップロード`ボタンをクリックします。

これでアップロードは完了です。

# 5.MediaConvertの符号化とパッケージングの設定
##IAMロールの用意
MediaConvertを使った処理に入る前に、`IAMロール`を設定します。IAMロールとはAWSの異なるサービス間を、セキュリティを担保しながら連携させるためのルール(ポリシー)の集まりのようなものです。
今回はS3とMediaConvertの2つのサービスを連動させるので、その間のアクセス権限を確保するための`IAMロール`を用意します。

- AWSコンソールのサービスから`セキュリティ、ID、およびコンプライアンス`にある`IAM`をクリックします。
- ダッシュボードから`アクセス管理>ロール`をクリックします。
- `ロールの作成`をクリックします。
- `信頼されたエンティティの種類を選択`し、`MediaConvert`をクリックします。すると`ユースケースの選択`に`MediaConvert Allows MediaConvert service to call S3 APIs and API Gateway on your behalf.`と表示されるので、`次のステップ：アクセス権限`をクリックします。
- ロールに該当するポリシーが下記のように表示されますので、内容を確認して`次のステップ：タグ`をクリックします。

| ポリシー名 | 次として使用 | 説明 |
|:-:|:-:|:-:|
| AmazonAPIGatewayInvokeFullAccess  |Permissions policy(1)   |Provides full access to invoke APIs in Amazon API Gateway   |
| AmazonS3FullAccess  |Permissions policy(1)   |Provides full access to all backets via the AWS Management Console   |

- タグの追加については何も入力せず、`次のステップ：確認`に進みます。
- ここではロール名を指定します。私は`MediaConvert-01`と名付けました。
- 最後に`ロールの作成`をクリックしてIAMロールの用意は完了です。

##MediaConvertでジョブをつくる
MediaConvertでエンコードしたりパッケージする処理はジョブという単位で行われます。
それでは先ほどアップロードしたビデオを処理するジョブを作ってみましょう。

- AWSコンソールのサービスから`メディアサービス`にある`MediaConvert`をクリックします。
- 画面右上にある`ジョブの作成`から`今すぐ始める`をクリックします。

###入力の設定

ジョブの作成画面が表示されます。まずは入力1でソースのmovieファイルを指定します。

- `入力1`にオブジェクトのパスを入力します。直接ではなくても`参照`ボタンを使えば、バケットとその中のファイルをプルダウン形式で選択できます。私の例では下記のように選択しました。

| 項目 | 設定 |
|:--|:--|
|バケット   |video-input-01   |
|ファイル   |bbb_sunflower_1080p_30fps_normal.mp4   |
結果として、パスは`s3://video-input-01/bbb_sunflower_1080p_30fps_normal.mp4`となりました。

この画面には、他にも`ビデオセレクタ`、`オーディオセレクタ`など設定がたくさんあります。詳細は別途検証したいと思います。今回はこれらの設定はデフォルトのまま進めます。

###出力グループの設定(DASH-ISO)
出力グループを設定します。この設定は、いわゆる`パッケージャ`の設定になるところだと思います。
ここでは1つだけ出力グループを作ってみます。HLSやCMAFなどありますが、今回は`DASH-ISO`で作成します。

- 画面左にある`出力グループ`で`追加`ボタンをクリックします。
- リストの中から`DASH-ISO`を選択します。
 

DASH ISOグループは、以下の通り設定しました。

| 設定項目 | 設定値 | 備考 |
|:--|:--|:--|
|カスタムグループ名   |type-n-dash   |   |
| 送信先  | s3://video-output-01/dash01/  |S3上の出力先   |
| サーバー側の暗号化  | なし  |デフォルト値   |
| アクセスコントロール  | パブリック読み取り  |誰でも視聴できるように   |
| セグメント制御  |  セグメント化されたファイル | セグメントファイルを分割して作成※1  |
| フラグメントの長さ(秒) |2   |デフォルト値※2   |
| セグメントの長さ(秒）  | 30  | デフォルト値※2  |
| HbbTVのコンプライアンス  | なし  |デフォルト値   |
|セグメントタイムラインを表現に書き込む|チェックなし|デフォルト値|
|MPDマニフェストプロファイル|メイン|セグメント化されたファイルの場合、メインのみ|

DRM暗号化は【Pro】用設定なのでoffのままです。

####【設定していて理解できなかったこと】
※1:セグメントの制御の項目で`単一ファイル`を選ぶと、1個のセグメントファイルだけが作成される。しかしこの単一ファイルで生成すると、どんな利点があるのかよく分からない。。。
※2:セグメントは分割された動画ファイル(.mp4)のことだと思ってて、その長さが30秒になるように生成されるという意味だと思うんだけど、その場合、ここで言うフラグメントの長さとはいったい何の長さなのかよく分からない。。。

###出力設定(Output1)
動画や音声に関するエンコードの設定をします。出力欄にある`Output 1`をクリックします。
ここでも細かくいろいろなことが設定できます。いやいや細かすぎて私には理解しながら入力するのは今のままでは無理です...。
なので、今回は全体としてはデフォルト値を使って一部分だけ設定を変えてます。

まず名前修飾子に、`bbb-dash_$Number$`と入力しました。

【動画】
ビデオコーデックは`MPEG-4 AVC(H.264)`を採用しました。というかそれ以外はすべて【Pro】用設定でした。
解像度を`640x360`、ビットレートを`1.5m`に設定して、あとはそのままです。

【オーディオ１】
こちらは動画に比べわかりやすい設定値になってます。
オーディオコーデックを`Advanced Audio Coding`にして、ビットレートは`96.0`、サンプルレートは`48.0`です。これらはすべてデフォルト値です。

オーディオはAACでエンコードさせたかったです。ソースがAC-3なのでそのままパススルーされてしまうと、AC-3のコーデックが搭載されていないWindows環境では音が聞こえないからです。出力設定にはプリセットが用意されているのですが、そのプリセットを選択するとオーディオがエンコードされませんでした。選んだプリセットが悪かっただけなのだろうか...。一応全プリセットを確認したつもりなんですが。

###IAMロールの設定
このジョブに、先の工程で作ったIAMロールを割り当てます
画面左にある`ジョブの設定`にある`設定`をクリックすると`IAMロール`を指定する箇所があるので、プルダウンメニューから`MediaConvert-01`を選びます。

以上で、ジョブの作成は完了です。

#4.ジョブの実行
画面下にある`作成`ボタンをクリックすると、ジョブが生成されて同時に実行されます。ジョブのステータスがCOMPLETEに変わるまで待ちます。

#5.動画の視聴確認
送信先に設定したS3に、作成されたマニフェスト(.mpd)と、セグメントファイル(.mp4)が生成されているか確認します。S3サービスを開き、送信先のバケット/フォルダに移動します(私の場合、video-output-01/dash01)。1つのマニフェストとずらっとセグメントファイルが作られていることがわかります。

ブラウザからストリーミング再生して動画/音声が正しく視聴できるか確認してみましょう。とくにwebサーバを別途用意することなく、簡単にインターネットを介した視聴確認ができます。

##ファイルのアクセス権の変更
まずはこれらのファイルのアクセス権を変更します。S3のコンソール上でvideo-output-01/dash01を開き、すべてのファイルを選択して`アクション`から`公開する`を選びます。

##テスト視聴
ブラウザからマニフェストにアクセスできれば、順次セグメントファイルを読み込むので、このマニフェストのURLを知る必要があります。S3上でマニフェストを開くと、ここに`オブジェクトURL`が表示されているので、このパスをコピーします。

私はMicrosoft Edgeで視聴確認しました。URLバーに先ほどのオブジェクトURLをペーストして、S3にアクセスすると、問題なく視聴できました。


#おわりに
今回は、MediaConvertの使い方の基本をなぞってみました。エンコーダのオプションなど、かなり手抜きになってすみません。素人なのでまずは基本フローを抑えることに重点を置きました。次回は S3 + CloudFrontを利用した公開用Web環境の設定をやってみたいと思います。

#参考にしたページ
http://blog.serverworks.co.jp/tech/2020/01/16/mediaconvert/
https://qiita.com/montama/items/90bb8a3973d101be4690
https://docs.aws.amazon.com/ja_jp/AmazonS3/latest/gsg/GetStartedWithS3.html
https://docs.aws.amazon.com/ja_jp/mediaconvert/latest/ug/what-is.html