Amazon S3に動画をアップロードしたらAWS Lambdaでサムネイルを作成してAmazon S3に保存する方法

Amazon S3に動画をアップロードしたらAWS Lambdaでサムネイルを作成してAmazon S3に保存する仕組みを作ったのでその備忘録です。

実行ロールを作成

AWS LambdaでAmazon S3のファイルを取得したりアップロードしたり出来るようにAWSLambdaExecute ポリシーを設定します。

  1. IAM コンソールの [Roles] ページを開きます。
  2. [ロールの作成] を選択します。
  3. 次の流れでロールを作成します。
    • [信頼されたエンティティの種類を選択] – [AWS サービス]。
    • [このロールを使用するサービスを選択] – [Lambda]。
    • 次のステップをクリック。
    • [Attach アクセス権限ポリシー] – [AWSLambdaExecute]。
    • 次のステップ:タグ
    • 次のステップ:確認
    • [ロール名] – [lambda-s3-role]。
    • ロールの作成

     

関数を作成

AWS Lambdaの関数を作成します。

基本的な情報で以下の情報を入力・選択して下さい。

  • [関数名] – [createThunbnail]
  • [ランタイム] – [Node.js 8.10]
  • [アクセス権限] – [既存のロールを使用する] – [lambda-s3-role]

トリガーの追加

S3トリガーを追加して下さい。

FFmpegの静的ビルドをダウンロード

動画のサムネイルを作成するためFFmpegを使います。

FFmpegの静的ビルドをAWS Lambdaにアップロードする必要があるのですが、このファイルの容量が大きいため関数コード一式はAmazon S3にアップロードしてそこからAWS Lambdaにアップロードします。

FFmpegの静的ビルドは以下のページから「ffmpeg-git-amd64-static.tar.xz」をダウンロードして下さい。

https://johnvansickle.com/ffmpeg/

ダウンロードした圧縮ファイルを解凍するといろいろファイルが入っていますが、今回はffmpegのみ使用します。

関数コード作成

動画ファイル(mp4)がuploadsディレクトリにアップロードされたら、動画のサムネイルをthumbnailsディレクトリにアップロードする関数コードを作成します。

以下のようにindex.jsを作成して下さい。

'use strict'

const fs = require('fs');
const aws = require('aws-sdk');

let path = require('path');
let util = require('util');

let s3 = new aws.S3();
let execSync = require('child_process').execSync;

let i = 1;

const getObject = (bucket, key, resolve) => {
    let params = {
        Bucket: bucket,
        Key: key
    };
    
    s3.getObject(params, function(error, data) {
        try {
            if(error) {
                console.log(error);
            } else {
                resolve(data);
            }
        } catch(e) {
            console.log(e)
        }
    });
};

const putObject = (body, bucket, key, resolve) => {
    let params = {
        Body: body,
        Bucket: bucket,
        Key: key
    };
    
    s3.putObject(params, function(error, data) {
        try {
            if (error) {
                console.log(error);
            } else {
                resolve(data);
            }
        } catch(e) {
            console.log(e);
        }
    });
};

exports.handler = (event, context, callback) => {
    let bucket_name = "バケット名";
    
    let srcKey = decodeURIComponent(event.Records[0].s3.object.key.replace(/\+/g, " "));
    let name = path.basename(srcKey, path.extname(srcKey));
    
    try {
        getObject(bucket_name, 'uploads/' + name + '.mp4', function(srcData) {
           fs.writeFileSync('/tmp/srcData.mp4', srcData.Body);
           
           process.env.PATH += ':/var/task/bin';
           
           execSync('ffmpeg -i /tmp/srcData.mp4 -vframes 1 -filter:v fps=fps=1:round=down /tmp/%d.jpg');
           
           let files = fs.readdirSync('/tmp');
           
           for (let i = 1; i < files.lenght; i++) {
               let fileStream = fs.createReadStream('/tmp/' + i + '.jpg');
               putObject(fileStream, bucket_name, 'thumbnails/' + name + i + '.jpg', function(date) {
                   callback(null, 'OK');
               })
               
           }
        });
        
    } catch(e) {
        callback(JSON.stringify(e));
    }
    
};

バケット名の部分は作成したバケット名に変更して下さい。

ファイル一式をAmazon S3にアップロード

ffmpegとindex.jsを以下のように配置して圧縮して下さい。

├ index.js
└bin
└ ffmpeg

zip -r lambda.zip .

圧縮ファイルをAmazon S3にアップロードして下さい。

Amazon S3からAWS Lambdaに関数コードをアップロード

関数の設定の「関数コード」で関数コードをアップロードして下さい。

  • [コードエントリタイプ] – [Amazon S3 からのファイルのアップロード]
  • [Amazon S3のリンクURL] – lambda.zipのパスをコピペ

設定できたら保存して下さい。

以上で完成です。

Amazon S3に動画をアップロードしてみる

Amazon S3にuploadsディレクトリを作成してその中に動画(mp4)をアップロードして見て下さい。

暫く待つとthumbnailsディレクトリが作成され、その中に動画の一部を切り取った画像が保存されます。

もし画像がされなかった場合は権限設定を見直すか、関数設定ページの「基本設定」でメモリとタイムアウトを調整してみて下さい。

タイムアウトがデフォルトでは3秒なので重い動画だとタイムアウトされる場合があります。

お気軽にコメントをどうぞ

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください