AWS Lambdaでタイムラプス動画を作る

特定のS3バケットへ定期的にアップロードされる画像を元にして、タイムラプス動画（要はスライドショー）が作りたくて試してみた。
https://github.com/sparkgene/lambda_image_to_video

[![ffmpeg generated video](http://img.youtube.com/vi/EDiJmv_5R28/1.jpg)](http://www.youtube.com/watch?v=EDiJmv_5R28)

## Lambda functionで動画編集するには
AWS LambdaにはImageMagickは入ってるけど、動画を編集したい場合は[ffmpeg](https://www.ffmpeg.org/)が必要になってきます。

Pythonの場合[MoviePy](http://zulko.github.io/moviepy/)という素晴らしいpython moduleがあり、これは実行時にffmpegをダウンロードしてくれるので、Mac上で試す場合でもffmpegを入れてなくても実行時に環境を整えてくれる。（ただし、依存するライブラリは事前に入れておく必要があるけど）

### MoviePyの自動ダウンロード
先に書いたようにMoviePyが呼ばれた時に自動でダウンロードてくれるのだが、実際にやってみると正しく動いてくれない。
ソースを追ってみると、ダウンロード先がlambda functionが権限を持たないディレクトリであるために、失敗する事がわかった。
https://github.com/imageio/imageio/blob/master/imageio/core/util.py#L408-L410

```
userDir = '/var/tmp'
```
この部分を

```
userDir = '/tmp'
```
に書き換えてあげれば、ダウンロードは正しく行われるが、毎回同じ環境で動くわけではないので、最悪の場合lambda functionが実行されるたびにダウンロードが行われてしまうので、現実的ではない。

### zipに含める
ffmpegのバイナリサイズがそれなりなので、zipファイルがそれなりのサイズとなってしまうが、この方法が無駄がないと思われる。ただし、実際に環境を整えようとしたら、だいぶ苦労した。

moviepyがnumpyを利用しているため、numpy関連の静的ファイルも必要になってきます。
ビルド方法やビルド済みのライブラリがこちらで公開されているので、今回はそれを利用します。
https://github.com/vitolimandibhrata/aws-lambda-numpy

また、ffmpegはこちらで公開されている各環境向けのバイナリを利用します。
https://github.com/imageio/imageio-binaries

zipに含める場合でも、Lambdaの場合は配置されるディレクトリでは実行権限がつけられないので、一旦`/tmp`に移動してから実行権限をつけて、MoviePyが参照するffmpegのバイナリを示す環境変数に移動したファイルのパスを指定してあげる必要がある。
https://github.com/sparkgene/lambda_image_to_video/blob/master/lambda_function.py#L23-L26

## ffmpegが使えるPythonのLambda Functionを作成する

AWS Lambdaと同じ環境でビルドする必要があるので、Amazon LinuxのEC2インスタンスを用意します。

最新の状態にする

```
sudo yum -y update
sudo yum install -y git
sudo yum -y install gcc-c++
```

リポジトリをcloneする

```
git clone https://github.com/sparkgene/lambda_image_to_video.git
```

ビルド済みのnumpyのリポジトリをcloneする

```
git clone https://github.com/vitolimandibhrata/aws-lambda-numpy.git
```

ライブラリとnumpyをコピー

```
cp -R aws-lambda-numpy/lib lambda_image_to_video/
cp -R aws-lambda-numpy/numpy lambda_image_to_video/
```

freeimageのバイナリをダウンロード

```
wget https://github.com/imageio/imageio-binaries/raw/master/freeimage/libfreeimage-3.16.0-linux64.so -O lambda_image_to_video/lib/libfreeimage.so
```

ffmpegのバイナリをダウンロード

```
wget https://github.com/imageio/imageio-binaries/raw/master/ffmpeg/ffmpeg.linux64 -O lambda_image_to_video/ffmpeg.linux64
```

lambda functionの修正

```
cd lambda_image_to_video
vi lambda_function.py

image_bucket = "" # 変換元の画像ファイルが格納されているバケット
video_bucket = "" # 変換後の動画を含めるバケット
```

このラムダファンクションは`image_bucket`に`yyyy/mm/dd/hoge-0001.jpg` のようなキーで画像が保存されていることを想定しています。（0001.jpgの部分は連番ではなくてもいいですが、ソートしてから動画を作成するので、ソート時に正しい順番に並ぶようにネーミングしてください）
動画は`video_bucket`に`yyyy/mm/yyyymmdd.mp4`というキーで出力します。
動画は1fpsで生成されるので、利用する画像数＝動画の秒数となります。

moviepyのインストール

```
pip install -r requirements.txt -t ./
```

zipファイルに固める

```
zip -r func.zip . -x *.git*
```

## Lambda FunctionのRole
Roleは以下のポリシーを持つRoleを作成します。

```
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "logs:CreateLogGroup",
                "logs:CreateLogStream",
                "logs:PutLogEvents"
            ],
            "Resource": "arn:aws:logs:*:*:*"
        },
        {
            "Sid": "Stmt1234567890",
            "Effect": "Allow",
            "Action": [
                "s3:GetObject",
                "s3:GetObjectAcl",
                "s3:ListBucket",
                "s3:PutObject",
                "s3:PutObjectAcl"
            ],
            "Resource": [
                "arn:aws:s3:::image-input",
                "arn:aws:s3:::image-input/*",
                "arn:aws:s3:::video-output",
                "arn:aws:s3:::video-output/*"
            ]
        }
    ]
}
```

動画を生成するのでメモリはある程度余裕をもたせた設定にするのが良さそう。
画像20枚ぐらいで動画を作った時は以下のように、200M近くメモリを消費しました。また、処理時間も画像の枚数に比例するので、メモリとタイムアウトの設定は実際の利用状況をみて設定するのが良さそうです。

```
REPORT RequestId: 1c8d6fcf-21d4b17b5ec2	Duration: 33316.13 ms	Billed Duration: 33400 ms Memory Size: 256 MB	Max Memory Used: 195 MB
```


## 参考にしたサイト

http://stackoverflow.com/questions/34749806/using-moviepy-scipy-and-numpy-in-amazon-lambda

https://github.com/vitolimandibhrata/aws-lambda-numpy

https://github.com/imageio/imageio-binaries