サーバレスアーキテクチャな動画変換 〜 “Easy Video Transcoding in AWS”を読んでみた&やってみた

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

はじめに

清水です。久しぶりに動画ネタです。

海外のブログでAWSでのサーバレスな動画トランスコードを題材にしたエントリを見つけましたのでご紹介、かつ実際にやってみました。

A Cloud Guruでのサーバレスな動画トランスコードの紹介

今回読んでみたページはこちらです。

Easy video Transcoding in AWS

ブログの元となっているA Cloud Guruというサイトはクラウド(AWS)についての学習サイトというようで、動画を見ながら学習できることをアピールポイントとしています。

そして動画配信という観点からみた特徴として、世界中から生徒がくること、その生徒のインターネット接続環境はスピード、デバイスなどバラバラであることを挙げています。また配信している動画としては、50本以上の動画による講義、動画の長さは2分から20分とバラバラ、という特徴があり、配信環境としては以下となっているそうです。

  • S3バケットに動画ファイルを格納
  • S3をオリジンとしてCloudFrontで動画ファイルを配信
  • 認証済みユーザにCluodFrontのsigned URLを発行して限定配信

エントリで扱っているサーバレスアーキテクチャに移行する以前では、HandBrakeというMac用のトランスコードソフトで手動でトランスコードを行っていたようです。 1つのコンテンツでも、トランスコード後の動画ファイル数はフォーマットや解像度の違いで数種類になっていたと想像できます。手動でやるには大変で、また人為的ミスが発生しやすい作業です。この問題を解決するため(またA Cloud Guruではサーバレスアーキテクチャを積極的に採用していることもあり)、動画変換部分をサーバレスアーキテクチャで自動化しています。

自動化の方法としては、Elastic TranscoderとS3、Lambdaを使用しています(具体的な方法は下の「やってみた」でご紹介します)。 また動画は720p, webm, HLS v3といった各種フォーマット/解像度への変換の他、サムネイル画像の生成、ウォーターマークの付与なども自動で行っているとのことです。

やってみた

ということで、もとのブログのエントリにアーキテクチャと、さらには設定例まで書いてあります!これはやってみずにはいられません。

仕組みとしては以下になります。

  1. S3へファイルをアップロード
  2. S3のファイルアップロードイベントでLamdaを呼び出し
  3. LambdaファンクションでElastic TranscoderのジョブをAWS SDKで実行
  4. Elastic TransocderジョブでS3へアップロードされたファイルを入力としてトランスコード実行
  5. トランスコードの結果、変換された動画ファイル、サムネイル画像がS3バケットに出力

EVT201604-010

では、もとのブログのエントリにならいElastic Transcoder、Lambda、S3の設定を行ってみます。

Elastic Transcoder

Elastic Transcoderの要素としては以下の3つがあります。

  1. プリセット
  2. パイプライン
  3. ジョブ

今回、1.のプリセット(変換フォーマット等の指定)についてはデフォルトで設定済みのもの(System preset)を使用します。

そして3.のジョブ(実際のトランスコーディング処理)についてはLambdaからJavaScript SDKで実行します。 なのでまずは2.のパイプラインを作成します。

パイプラインはManagement ConsoleのElatic Transcoder画面から作成できますが、入力・出力用のS3バケットが必要になるので事前に作成しておきます。

バケットの準備ができたら、Management ConsoleのElastic Transcoderの画面から[Create New Pipeline]をクリックして、パイプラインを作成画面に進みます。

EVT201604-001

パイプライン名、入出力のバケット、さらにサムネイル画像用の出力バケットを入力します。 IAM Roleについては"Create console default role"を選択して、Management Consoleから作成するのがお手軽です。 (これを選択すると、Elastic_Transcoder_Default_Role というロールができます。)

なお、今回は省略していますが、Elastic Transcoderは処理完了時にSNSで通知を行なうことができます。 もとのエントリでは特に On Error Event については通知をしておいた方が良い、としています。

Lambda

次にLambdaの設定をします。こちらもManagement ConsoleのLambda画面を開いて、[Create a Lambda function]をクリックして進めます。 Select blueprintの項目はSkipしてConfigure functionの項目で、Function Name、Descriptionを入力します。Runtimeは Node.js 4.3 を選択します。

EVT201604-002

そして、もとのエントリから必要な箇所を変更した以下のコードを貼り付けます。

'use strict';

var AWS = require('aws-sdk');
var s3 = new AWS.S3({
    apiVersion: '2012-09-25'
});

var eltr = new AWS.ElasticTranscoder({
    apiVersion: '2012-09-25',
    region: 'ap-northeast-1'
});

exports.handler = function(event, context) {
    console.log('Executing Elastic Transcoder Orchestrator');
    var bucket = event.Records[0].s3.bucket.name;
    var key = event.Records[0].s3.object.key;
    var pipelineId = '1459942387665-6x17nn';
    if (bucket !== 'input-easyvideotranscodinginaws') {
        context.fail('Incorrect Video Input Bucket');
        return;
    }
    var srcKey =  decodeURIComponent(event.Records[0].s3.object.key.replace(/\+/g, " ")); //the object may have spaces
    var newKey = key.split('.')[0];
    var params = {
        PipelineId: pipelineId,
        OutputKeyPrefix: newKey + '/',
        Input: {
            Key: srcKey,
            FrameRate: 'auto',
            Resolution: 'auto',
            AspectRatio: 'auto',
            Interlaced: 'auto',
            Container: 'auto'
        },
        Outputs: [{
            Key: 'mp4-' + newKey + '.mp4',
            ThumbnailPattern: 'thumbs-' + newKey + '-{count}',
            PresetId: '1351620000001-000010', //Generic 720p
            Watermarks: [{
                InputKey: 'watermarks/cmlogo.png',
                PresetWatermarkId: 'BottomRight'
            }],
        },{
            Key: 'webm-' + newKey + '.webm',
            ThumbnailPattern: '',
            PresetId: '1351620000001-100240', //Webm 720p
            Watermarks: [{
                InputKey: 'watermarks/cmlogo.png',
                PresetWatermarkId: 'BottomRight'
            }],
        },{
            Key: 'hls-' + newKey + '.ts',
            ThumbnailPattern: '',
            PresetId: '1351620000001-200010', //HLS v3 2mb/s
            Watermarks: [{
                InputKey: 'watermarks/cmlogo.png',
                PresetWatermarkId: 'BottomRight'
            }],
        }]
    };

    console.log('Starting Job');
    eltr.createJob(params, function(err, data){
        if (err){
            console.log(err);
        } else {
            console.log(data);
        }
        context.succeed('Job well done');
    });
};

変更内容ですが、環境に依存するものを変更しています。 具体的には、

  • 10行目: region: 任意のリージョンに変更
  • 17行目: pipelineId: 先ほど作成したElastic TranscoderのパイプラインID
  • 18行目: バケット名: 先ほど作成した入力用のバケット
  • 40, 48, 56行目: InputKeyのウォータマーク画像へのパス(ウォータマークはinputバケットに入れておきます)

Lambda function handler and roleの部分は、Handlerについてはデフォルトの"index.handler"のまま設定します。

EVT201604-003

Roleについてですが、Management Consoleで提示されるRoleだとLambda内でElastic TranscoderのAWS SDKを実行するには権限が足りません。Create new roleの「 * Basic execution role」を選択して以下のようにしました。

  • IAMロール: 新しいIAMロール作成
  • ロール名: lambda_elastictranscoder_exec_role

ポリシードキュメントを表示して、Elastic Transcoderまわりの権限を追加します。

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "logs:CreateLogGroup",
                "logs:CreateLogStream",
                "logs:PutLogEvents"
            ],
            "Resource": "arn:aws:logs:*:*:*"
        },
        {
            "Effect": "Allow",
            "Action": [
                "elastictranscoder:Read*",
                "elastictranscoder:List*",
                "elastictranscoder:*Job",
                "elastictranscoder:*Preset"
            ],
            "Resource": [
                "arn:aws:elastictranscoder:*:*:*"
            ]
        }
    ]
}

Advanced settingsについてはデフォルトのまま、Nextで次画面に進み、functionを作成します。

S3

S3については、ファイルがアップロードされたらイベントを発生させ、先ほど作成したLambdaファンクションを呼び出すように設定します。

入力用バケットの「プロパティ」 > 「イベント」の項目から

  • 名前: 適切に(今回はEasyVideoTranscoindgInAWSとしました)
  • イベントはObjectCreated(All)を選択
  • プレフィックス、サフィックスは適宜設定(今回は設定していません)
  • 送信先としてLambda関数を指定
  • Lambda関数の欄でLambda関数名、またはARNを入力

これらの設定を行ない、保存します。

EVT201604-007

動作確認

それでは実際に入力用バケットに動画ファイルをアップロードしてみます。

しばらくすると、出力用バケットに入力ファイル名と同名のディレクトリが作成され、その下に、hls, mp4, webmから始まるそれぞれの形式の動画ファイル、さらにthmbsから始まるサムネイル画像ファイルが生成されました! EVT201604-008

まとめ

A Cloud Guru のブログエントリ Easy video Transcoding in AWS を読んでみて、そこで紹介されていたサーバレスアーキテクチャな動画変換をやってみました。

個人的にElastic Transcoder以外、LambdaやLambdaとS3の連携部分はほぼ初めて触る部分だったのですが、予想以上に簡単にできたという印象です。もとのブログエントリに手順、さらにはLambdaのコードまで書いてあったことが大きく、実際にゼロから構築する際にはコードを書く必要があります。ですがコードを書いてしまえば容易にサーバレスな動画変換システムが構築できます。改めて、だいぶ手軽にサーバレスアーキテクチャを実現する環境が整っていることを感じた次第です。