AWS Lambda(Node.js) + ffmpeg でエンコード
動画のサイズや形式を変更したり、音楽だけ抜き出したりするのに”Amazon Elastic Transcoder”を使用している方は多いと思います。
このサービスは驚異のマシンパワーでガンガンエンコードしてくれるため非常に便利なのですが、利用料金もガンガンかかってきます。
今回は料金を抑えるためにAWS Lambda上でエンコードする方法をお伝えします。
使用するものは次の4つです。
・AWS Lambda…今回はNode.jsを使用しますがAWS SDKとLinuxコマンドを叩くだけなので何でもOKです。
・Amazon S3…今回はエンコード元、先ファイルを置くのに使用します。
・ffmpeg
・動画ファイル…今回はMP4を使用しますが、MP3などffmpegが対応していれば何でもOKです。
ffmpegについてはアマゾンも推奨しているツールになってます。
ffmpegの用意
公式サイトからLinux用のffmpegをダウンロードします
x86_64buildをダウンロードします。
ひとまず適当なフォルダへ解凍しておきます。
S3の用意
適当な場所へエンコードしたいMP4ファイルをアップロードしてください。
Lambdaの用意
Lambda関数をNode.jsで作成してください。
ソースは上書きしてしまうので、空のLambdaでも何かのテンプレートを使用しても、どっちでも大丈夫です。
次にソースをLambdaの中身のソースを作ります。下記の構成でファイルを配置してください。
フォルダ
├index.js
└bin
└ffmpeg
ffmpegはダウンロードして解凍したファイル1つだけを持ってきてください。
他のフォルダやindex.jsは新規作成してください。
index.jsに次のソースを貼り付けます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 | 'use strict'; const fs = require('fs'); const aws = require('aws-sdk'); var s3 = new aws.S3(); let execSync = require('child_process').execSync; const getObject = function(bucket, key, resolve, preserve) { let params = { Bucket: bucket, Key: key }; s3.getObject(params, function(error, data) { try { if (error) { preserve(error); } else { resolve(data); } } catch(e) { preserve(e); } }); }; const putObject = function(body, bucket, key, resolve, preserve) { let params = { Body: body, Bucket: bucket, Key: key }; s3.putObject(params, function(error, data) { try { if (error) { preserve(error); } else { resolve(data); } } catch(e) { preserve(e); } }); }; exports.handler = (event, context, callback) => { try { getObject('<バケット名>', '<パス名>/src.mp4', function(srcData) { fs.writeFileSync('/tmp/srcData.mp4', srcData.Body); process.env.PATH += ':/var/task/bin'; execSync('ffmpeg -i /tmp/srcData.mp4 -vf scale=320:240 /tmp/destData.mp4'); var fileStream = fs.createReadStream('/tmp/destData.mp4'); fileStream.on('error', function(error) { callback(JSON.stringify(error)); }); putObject(fileStream, '<バケット名>', '<パス名>/desc.mp4', function(data) { callback(null, 'OK'); }, function(error) { callback(JSON.stringify(error)); }); }, function(error) { callback(JSON.stringify(error)); }); } catch(e) { callback(JSON.stringify(e)); } }; |
<バケット名>、<パス名>の部分は上で用意したS3のファイルの物に置き換えてください。
ブログの関係で”>”も全角になっていますので、半角にしておいてください。
フォルダの中身だけをzipにしてS3へアップロードします(index.js等を入れたフォルダは含めないでください)。
また、パスやファイル名に日本語は含めないでください。
Lambdaで実行
“コードエントリタイプ”を”Amazon S3からのファイルのアップロード”へ
“S3リンクのURL”へアップロードしたファイルのURLを入力して保存します。
テストを押して実行してみましょう。
パラメータを入力する画面が出てきますが、パラメータは使わないので適当で大丈夫です。
これで上手くいけばいいのですが、デフォルトのLambdaは3秒を越えると強制終了してしまいます。
ffmpegの処理は重いので3秒以内というのは難しいところがあり、次のようなエラーになることが多いです。
Lambdaの下の方にタイムアウトを変更する項目があるので、伸ばして再実施してみてください。
正常に終わればS3に変換後MP4ファイルができています。
ダウンロードして再生してみましょう。
変換したことにより動画のサイズが縮んでいることが確認できます。
今回は動画のサイズを変えてみましたが、MP3に変換して音声だけにしたり、再生速度を変えたり、とffmpegのオプションを変更してやるだけでできます。
メディアを扱ったサービスを展開している方は是非取り入れてみてください。