AWS LambdaとElastic Transcoder

# AWS Lambda
AWS Lambdaはre:Inventで発表されたクラウド上でコードスニペットをイベントドリブンで実行出来るプラットフォームです。
S3 EventNotificationやDynamoDB、Kinesisと連携することが出来ます。例えば、S3にファイルがPUTされたら、そのイベントをトリガーにしてDynamoDBに情報を書き込んだり、AWS SDKを利用して他のAWSサービスを呼び出すことも可能です。現在のところ、LambdaではNode.jsがサポートされています。サードパーティモジュールもnpm_modulesディレクトリも含めてzipでUploadすることで利用することが可能です。
http://aws.amazon.com/lambda/

# Amazon Elastic Transcoder
Amazon Elastic Transcoderは動画や音声を簡単にエンコードが行えるフルマネージドサービスです。リリース時に書いたBlogですが、http://d.conma.me/entry/2013/01/30/002445 に概要をまとめています。
Amazon Elastic Transcoderもリリース後機能追加や性能改善が行われており、SmoothStreamingやSSE対応などが直近で行われた追加です。

# 組み合わせてみる
今回は、AWS Lambdaを簡単に使ってみる例としてS3の特定のバケットに動画がアップロードされたら、S3のEvent NotificationからLambdaを呼び出して、Elastic TranscoderにエンコードJobを登録するというsnippetです。

## Amazon Elastic Transcoderの作成
Amazon Elastic TranscoderのPiplineの作成は割愛します。http://d.conma.me/entry/2013/01/30/002445
に簡単にですが書いてありますのでご参照下さい。

## LambdaへFunctionの登録
```js
var aws = require('aws-sdk');
var s3 = new aws.S3({apiVersion: '2006-03-01'});
var ets = new aws.ElasticTranscoder({apiVersion: '2012-09-25', region: 'us-east-1'});

exports.handler = function(event, context) {
   console.log('Received event:');
   console.log(JSON.stringify(event, null, '  '));
   var bucket = event.Records[0].s3.bucket.name;
   var key = event.Records[0].s3.object.key;
   var pipelineId = key.split('/')[0];
   var presetId = key.split('/')[1];
   var fileName = (key.split('/')[2]).split('.')[0];
   ets.createJob({
     PipelineId: pipelineId,
     OutputKeyPrefix: 'demo/',
     Input: {
       Key: key,
       FrameRate: 'auto',
       Resolution: 'auto',
       AspectRatio: 'auto',
       Interlaced: 'auto',
       Container: 'auto',
     },
     Output: {
       Key: fileName + '.mp4',
       ThumbnailPattern: fileName + '-thumbs-{count}',
       PresetId: presetId,
       Rotate: 'auto'
     }
   }, function(error, data) {
        if(error) {
            console.log(error);
            context.done('error',error);
        } else {
            console.log('Job submitted');
            context.done(null,'');
        }
    });
};
```
このような簡単なsnippetを登録しておきます。
あくまで参考ということで、エラーハンドリングや重複処理が甘い、mp4以外のpresetへ未対応なコードとなっていますが、LambdaをとS3 Notificationを使うイメージを掴んでいただければと思います。

1点だけ注意ですが、functionを作成する際に、Roleを作成します。こちらはLambdaに設定されるIAM Roleですが、標準のままだと

```json
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "logs:*"
      ],
      "Resource": "arn:aws:logs:*:*:*"
    },
    {
      "Effect": "Allow",
      "Action": [
        "s3:GetObject",
        "s3:PutObject"
      ],
      "Resource": [
        "arn:aws:s3:::*"
      ]
    }
  ]
}
```
のようにS3に対する権限のみついているシンプルなものが付与されるため、Elastic TranscoderにJobをSubmit出来る権限をつけます。
IAMの画面からRolesの中に先ほど作成された`lambda_exec_role`(デフォルト名)があるので、それに権限を付与します。もちろん、Lambdaのfunction作成時に一緒に権限を付与してしまう事も可能です。
後から付与する場合は、先ほどのIAM Rolesから選択したRole中の`Attache Role Policy`から`Select Policy Template`内の`Amazon Elastic Transcoder Jobs Submitter`を付与します。
function毎に必要な権限を追加してRoleを作成することをオススメします。

## S3の準備
動画をアップロードする用とエンコード済み動画を格納するバケットをそれぞれ作成しておきます。動画をアップロードするためのバケットのEventsタブで
![S3_Management_Console.png](https://qiita-image-store.s3.amazonaws.com/0/4769/f33efdc0-df9f-60bd-41bd-b7c87999b8da.png)

今回は動画ということで、マルチパートアップロード前提でマルチパートアップロードが完了した場合に通知する`CompleteMultiPartUpload`をEventに指定し、先ほど作成したLambdaのfunctionを呼び出すように設定します。(通常のPutを使う場合はEventで`Put`を指定します)

Invocation roleはIAM Roleで

```json
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Resource": [
        "*"
      ],
      "Action": [
        "lambda:InvokeFunction"
      ]
    }
  ]
}
```
このような権限を設定します。Lambdaの画面からS3にConfigure Event SouceでS3に関連付けると自動的にこのロールを作る事が可能です。

# エンコードしてみる
Elastic TranscoderにはPipline IDと呼ばれる識別子とエンコード動画形式を指定するPreset IDと呼ばれるものがあります。Jobを登録する際はこちら双方のIDが必要になるのですがsnippetに埋め込むのも変更しづらいので、Objectのkey prefixとして指定するようにしてみました。 

形式は
`Pipline ID/preset ID/ファイル名`
この順番でディレクトリを切って、ファイルをアップロードするといい感じにエンコードをしてくれると思います。

# まとめ
今回は簡単にS3とElastic Transcoderが連携出来るのがわかっていただけたと思います。短いコードでS3にアップロードしてエンコードまでがすぐに出来るようになりました。今までだと、S3をポーリングするか別途APIサーバにエンコード要求を送るなどしていたかと思います。この構成にCloud FrontをS3の前面に置くことでCognitoなどもつかうと、EC2インスタンスを一切たてること無く、動画のアップロードからエンコードして、CDN経由で配信まで可能になります。もちろん認証付きです。

また発展系として、DynamoDBに再生数やLike数などを入れて、DynamoDBとSNS Mobile Pushと組み合わせると、動画がアップロードされたりLikeが一定数ついたらPush通知を送るという応用も出来ると思います。

是非、AWS Lambdaで遊んでみてはいかがでしょうか？

こちらは個人の意見で会社とは関係ありません。お約束です。