RUNTEQの動画配信基盤-HLSエンコード編-

# はじめに
本記事では動画のアップロードをトリガーとして， MediaConvertのジョブテンプレートからジョブを生成し， HLS形式へと変換するフローを解説します．

# S3バケットの作成
まずはmp4ファイルを格納するバケットと変換されたファイル群を格納するバケットを作成しましょう
(ここではあえてバケットを分けていますが，分けなくても問題ありません．)

# IAMの作成
### MediaConvert用のロール
`AmazonS3FullAccess`, `AmazonAPIGatewayInvokeFullAccess`をアタッチ．
### Lambda用のロール
LambdaからMediaConvertを呼び出すためのカスタムポリシーを作成します．

```json
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "VisualEditor0",
            "Effect": "Allow",
            "Action": [
                "iam:PassRole",
                "mediaconvert:CreateJob"
            ],
            "Resource": "*"
        }
    ]
}
```

上記で作成したポリシーに加え`AmazonS3ReadOnlyAccess`, `AWSLambdaBasicExecutionRole`をアタッチ.

# ジョブテンプレート作成
### 動画の設定
テンプレート名を入力し，出力グループの「追加」からApple HLSを選択．
[![Screenshot from Gyazo](https://gyazo.com/4e146334c9487ac7cb3810a8c7255c9f/raw)](https://gyazo.com/4e146334c9487ac7cb3810a8c7255c9f)
送信先に変換後のファイル群を入れるバケットを指定,　出力の項目の名前修飾子に`_hls`と適当なサフィックスを指定してください．
`Output 1`にてコーデックやフレームレートの設定をしていきます.
[![Screenshot from Gyazo](https://gyazo.com/feec6132fd77fc3ca0679d372418c9f6/raw)](https://gyazo.com/feec6132fd77fc3ca0679d372418c9f6)
ここではフレームレート30, ビットレート5000000としています．解像度はお好みで．

### サムネイルの設定
出力グループの「追加」からファイルグループを選択します．
[![Screenshot from Gyazo](https://gyazo.com/c04fa2c0a3e9e6187f7ab684473ec61c/raw)](https://gyazo.com/c04fa2c0a3e9e6187f7ab684473ec61c)
こちらも送信先に変換後のjpgファイルを入れるバケットを指定し，拡張子は`.jpg`としてください．
`Output 1`にてエンコード設定を行います
[![Screenshot from Gyazo](https://gyazo.com/5a7a9b5392a1620a6f9c572590e34aa6/raw)](https://gyazo.com/5a7a9b5392a1620a6f9c572590e34aa6)
ここではコンテナを使用しないので`NoContainer`を選択します．
サムネイルなので最大キャプチャは1を入力し，Audioの設定は削除しておきましょう．

以上でジョブテンプレートの設定は完了です．

# 動作確認
作成したジョブテンプレートの詳細画面から「ジョブの作成」を選択．
変換対象のmp4ファイルをここで指定します．
[![Screenshot from Gyazo](https://gyazo.com/9b736e0c98185eca3033b21da418250f/raw)](https://gyazo.com/9b736e0c98185eca3033b21da418250f)
次に「設定」にて，先ほど作成したMediaConvert用のIAMロールを指定し， ジョブを作成．

ジョブが完了すると送信先に指定したバケットにエンコードされたファイル群が入っているかと思います．

# Lambda関数の実装
今回はAWSで用されている設計図を元に実装していきます．
[![Screenshot from Gyazo](https://gyazo.com/14bea50bad26f8fe4e819616512b3d8c/raw)](https://gyazo.com/14bea50bad26f8fe4e819616512b3d8c)
### IAMロールの指定
ここで設定するIAMロールは先ほど作成したLambda用のロールを指定してください．
[![Screenshot from Gyazo](https://gyazo.com/59b6b3c5ffc109c07a24145f0ffc0548/raw)](https://gyazo.com/59b6b3c5ffc109c07a24145f0ffc0548)

### S3トリガーの設定
設定は以下の通りになります
`.mp4`のサフィックスが付いているファイルのアップロードをトリガーとします．
入出力のバケットを分けずに行う場合この指定をしておかないと無限ループに陥る可能性が出てくるので要注意．
[![Screenshot from Gyazo](https://gyazo.com/c068585238df168cdbbdac47db65eac9/raw)](https://gyazo.com/c068585238df168cdbbdac47db65eac9)
### 実装！
```python
import json
import urllib.parse
import boto3
import os
 
s3 = boto3.client('s3')
mediaconvert =  boto3.client('mediaconvert', region_name='ap-northeast-1', endpoint_url=os.environ['MEDIACONVERT_ENDPOINT'])
 
def lambda_handler(event, context):

    bucket = event['Records'][0]['s3']['bucket']['name']
    key = urllib.parse.unquote_plus(event['Records'][0]['s3']['object']['key'], encoding='utf-8')

    inputFile = "s3://" + bucket + "/" + key
    outputKey = os.environ['OUTPUT_BUCKET'] + "/" + key.replace(".mp4", "")
 
    try:
        with open("job.json", "r") as jsonfile:
            job_object = json.load(jsonfile)
        job_object["OutputGroups"][0]["OutputGroupSettings"]["HlsGroupSettings"]["Destination"] = outputKey
        job_object["OutputGroups"][1]["OutputGroupSettings"]["FileGroupSettings"]["Destination"] = outputKey
        job_object["Inputs"][0]["FileInput"] = inputFile
 
        response = mediaconvert.create_job(
          JobTemplate=os.environ['JOB_TEMPLATE'],
          Queue=os.environ['QUEUE'],
          Role=os.environ['MEDIACONVERT_ROLE'],
          Settings=job_object
        )
    except Exception as e:
        print(e)
        print('Error getting object {} from bucket {}. Make sure they exist and your bucket is in the same region as this function.'.format(key, bucket))
        raise e
```

```json
{
  "OutputGroups": [
    {
        "Name": "Apple HLS",
        "OutputGroupSettings": {
          "Type": "HLS_GROUP_SETTINGS",
          "HlsGroupSettings": {
            "Destination": ""
        }
      }
    },
    {
      "Name": "File Group",
      "OutputGroupSettings": {
        "Type": "FILE_GROUP_SETTINGS",
        "FileGroupSettings": {
          "Destination": ""
        }
      }
    }
  ],
  "Inputs": [
    {
      "FileInput": ""
    }
  ]
}
```
#### 環境変数について
```
OUTPUT_BUCKET = s3://バケット名
MEDIACONVERT_ENDPOINT = https://xxxx.mediaconvert.ap-northeast-1.amazonaws.com
JOB_TEMPLATE = arn:aws:mediaconvert:ap-northeast-1:xxxxxxxx:jobTemplates/ジョブテンプレート名
QUEUE = arn:aws:mediaconvert:ap-northeast-1:xxxxxxxx:queues/Default
MEDIACONVERT_ROLE = arn:aws:iam::xxxxxxxx:role/MediaConvertのロール
```
# 自動変換の動作確認
対象バケットにmp4ファイルをアップロードし，
Lambda関数が実行され
HLS用のバケットに変換されたファイル群があれば成功です:tada:
[![Screenshot from Gyazo](https://gyazo.com/226b70a69ae84340529ae0e302cd2560/raw)](https://gyazo.com/226b70a69ae84340529ae0e302cd2560)

# さいごに
シンプルにストリーミング配信用の動画エンコードができました．
簡単ですね！

今後はアダプティブビットレートの対応やDRMなどにも挑戦していきたいです．