FFmpegをAWS Lambdaで動かす

ffmpegをAWS Lambdaで動かしてみました
何を思ったかRubyのラッパー使ってみました
途中結構躓くことが多かったので面倒でした

# Dockerfile

```dockerfile:Dockerfile
FROM lambci/lambda:build-ruby2.7

RUN gem install bundler -p

WORKDIR /var/task
RUN export TASK=/var/task

RUN mkdir ffmpeg_sources
RUN mkdir ffmpeg_dist
RUN mkdir bin

RUN yum install autoconf automake bzip2 bzip2-devel cmake freetype-devel gcc gcc-c++ git libtool make pkgconfig zlib-devel -y
RUN yum install -y libpng-devel

WORKDIR /var/task/ffmpeg_sources
RUN curl -O -L https://www.nasm.us/pub/nasm/releasebuilds/2.14.02/nasm-2.14.02.tar.bz2
RUN tar xjvf nasm-2.14.02.tar.bz2
WORKDIR nasm-2.14.02
RUN ./autogen.sh
RUN ./configure --prefix="$TASK/ffmpeg_build" --bindir="$TASK/bin"
RUN make
RUN make install
RUN 
WORKDIR /var/task/ffmpeg_sources
RUN curl -O -L https://www.tortall.net/projects/yasm/releases/yasm-1.3.0.tar.gz
RUN tar xzvf yasm-1.3.0.tar.gz
WORKDIR yasm-1.3.0
RUN ./configure --prefix="$TASK/ffmpeg_build" --bindir="$TASK/bin"
RUN make
RUN make install

WORKDIR /var/task/ffmpeg_sources
RUN git clone --depth 1 https://code.videolan.org/videolan/x264.git
WORKDIR x264
RUN PKG_CONFIG_PATH="$TASK/ffmpeg_build/lib/pkgconfig" ./configure --prefix="$TASK/ffmpeg_build" --bindir="$TASK/bin" --enable-static
RUN make
RUN make install


WORKDIR /var/task/ffmpeg_sources
RUN git clone https://bitbucket.org/multicoreware/x265_git.git
WORKDIR /var/task/ffmpeg_sources/x265_git/source
RUN cmake -G "Unix Makefiles" -DCMAKE_INSTALL_PREFIX="$TASK/ffmpeg_build" -DENABLE_SHARED:bool=off .
RUN make
RUN make install

WORKDIR /var/task/ffmpeg_sources
RUN git clone --depth 1 https://github.com/mstorsjo/fdk-aac
WORKDIR fdk-aac
RUN autoreconf -fiv
RUN ./configure --prefix="$TASK/ffmpeg_build" --disable-shared
RUN make
RUN make install

WORKDIR /var/task/ffmpeg_sources
RUN curl -O -L https://downloads.sourceforge.net/project/lame/lame/3.100/lame-3.100.tar.gz
RUN tar xzvf lame-3.100.tar.gz
WORKDIR lame-3.100
RUN ./configure --prefix="$TASK/ffmpeg_build" --bindir="$TASK/bin" --disable-shared --enable-nasm
RUN make
RUN make install

WORKDIR /var/task/ffmpeg_sources
RUN curl -O -L https://archive.mozilla.org/pub/opus/opus-1.3.1.tar.gz
RUN tar xzvf opus-1.3.1.tar.gz
WORKDIR opus-1.3.1
RUN ./configure --prefix="$TASK/ffmpeg_build" --disable-shared
RUN make
RUN make install

WORKDIR /var/task/ffmpeg_sources
RUN git clone --depth 1 https://chromium.googlesource.com/webm/libvpx.git
WORKDIR libvpx
RUN ./configure --prefix="$TASK/ffmpeg_build" --disable-examples --disable-unit-tests --enable-vp9-highbitdepth --as=yasm
RUN make
RUN make install

WORKDIR /var/task/ffmpeg_sources
RUN curl -O -L https://ffmpeg.org/releases/ffmpeg-snapshot.tar.bz2
RUN tar xjvf ffmpeg-snapshot.tar.bz2
WORKDIR ffmpeg
RUN PATH="$TASK/bin:$PATH" PKG_CONFIG_PATH="$TASK/ffmpeg_build/lib/pkgconfig" ./configure \
  --prefix="$TASK/ffmpeg_build" \
  --pkg-config-flags="--static" \
  --extra-cflags="-I$TASK/ffmpeg_build/include" \
  --extra-ldflags="-L$TASK/ffmpeg_build/lib" \
  --extra-libs=-lpthread \
  --extra-libs=-lm \
  --bindir=../../ffmpeg_dist \
  --enable-gpl \
  --enable-libfdk_aac \
  --enable-libfreetype \
  --enable-libmp3lame \
  --enable-libopus \
  --enable-libvpx \
  --enable-libx264 \
  --enable-libx265 \
  --enable-nonfree
RUN make
RUN make install

RUN chmod -R a+x ../../ffmpeg_dist 
RUN mkdir /var/task/dist
RUN cp -r ../../ffmpeg_dist/* /var/task/dist


RUN yum install -y yum-utils rpmdevtools
WORKDIR /tmp
RUN yumdownloader unixODBC.x86_64 libtool-ltdl.x86_64 gnutls.x86_64 \
  bzip2-libs.x86_64 freetype.x86_64 libpng.x86_64
RUN rpmdev-extract *rpm
RUN cp /tmp/*/usr/lib64/* /var/task/dist



WORKDIR /var/task/dist

COPY . .

RUN bundle config set --local path 'vendor/bundle'
RUN bundle install


RUN zip -r dist.zip .

RUN mkdir /var/task/output
CMD cp dist.zip /var/task/output

```

上のDockerfileと一緒のディレクトリにlambda_functionをおいて

```bash
docker build . -t lambda_ruby_ffmpeg
docker run -v "{PWD}":/var/task/output  lambda_ruby_ffmpeg
```
でstreamio-ffmpegが使えます

[github](https://github.com/misogihagi/lambda_ruby_ffmpeg.git)の方にも上げておいたのでlambda_function.rbを編集してdocker上でビルドして走らせるだけでデプロイパッケージのzipが出てくると思います。
ただrequireはbundleに依存するので

```ruby

require 'bundler'
Bundler.require
```
は忘れないでください。
それとバイナリにパスは通っていないはずなのでカレントディレクトリ(/var/task)にパスを通してください

# 躓いたところ

以下文体崩壊

## --pathが古い

```bash

bundle install --path vendor/bundle
```
を実行したら--pathが古いといわれた。AWSの公式サンプルにも乗っていたのにそれでいいのかAmazon

```bash:fix
RUN bundle config set --local path 'vendor/bundle'
```

## ffmprobeの実行権限がないと言われた
windowsでzipファイルの作業してたらはまった。Lambdaのコンテナ上で圧縮しないと
実行権限の付与も忘れずに
RUN chmod -R a+x ../../ffmpeg_dist 

## x265のリポジトリがない
MercurialというGitに似たものがあったらしい(無知)。
[これ](https://trac.ffmpeg.org/wiki/CompilationGuide/Centos)を見ればわかる通りffmpegの公式のビルド手順にもx265のビルドにはMercurialを使うように書かれているが、
[公式(かどうかはわからないが)](https://bitbucket.org/multicoreware/x265_git/wiki/Home)のx265のビルド方法を見てみると **gitを使っていた**。
Mercurialからgitに乗り換えるという歴史的な瞬間に立ち会ってしまった。
考えてみればGitもBitKeeperに触発それて作られているわけでほかにも分散型バージョン管理システムがあっても不思議じゃない。
AWSにせよなんにせよクラウドサービスの多くがgithubフレンドリーな姿勢になるほどGitはデファクトスタンダードになっているが、その一方で他の分散型バージョン管理システムのシェアを奪っているんだなあと寂寥感に苛まれた。
そして苦労して入れたところでおそらく使われない。
ffmpegで必要なライブラリ、例えばLameとかもgitで管理されているわけではなくsourceforgeで進められていて、tarボールをcurlするような形になっていて常に最新のバージョンをとってこられるよう指定できない。そう考えたらgitもMercurialもいい感じなのになあ。


## * .so. * エラー
「2021年までにモバイルトラフィックの80％は動画で占められます」
https://media.kaizenplatform.com/n/n51e413c8087c
これほどまでに動画は我々の世界に身近になったけれど、動画を再生するまでに何があるのか知っている人はほとんどいない
ffmpegはビルドすると30MBほどになる巨大なプログラムだが、動かすにはまだ足りない。


<details><summary>これらの</summary><div>
START RequestId: effdb447-3a9a-4fa4-832e-e7359370d9d0 Version: $LATEST
ffprobe: error while loading shared libraries: libfreetype.so.6: cannot open shared object file: No such file or directory
END RequestId: effdb447-3a9a-4fa4-832e-e7359370d9d0
REPORT RequestId: effdb447-3a9a-4fa4-832e-e7359370d9d0	Duration: 2249.69 ms	Billed Duration: 2300 ms	Memory Size: 128 MB	Max Memory Used: 113 MB	Init Duration: 724.21 ms	
RequestId: effdb447-3a9a-4fa4-832e-e7359370d9d0 Error: Runtime exited with error: exit status 127
Runtime.ExitError


START RequestId: 51a2ee5f-3cfc-4647-a1cf-58096076e7b6 Version: $LATEST
ffprobe: error while loading shared libraries: libbz2.so.1: cannot open shared object file: No such file or directory
END RequestId: 51a2ee5f-3cfc-4647-a1cf-58096076e7b6
REPORT RequestId: 51a2ee5f-3cfc-4647-a1cf-58096076e7b6	Duration: 2024.82 ms	Billed Duration: 2100 ms	Memory Size: 128 MB	Max Memory Used: 111 MB	Init Duration: 748.18 ms	
RequestId: 51a2ee5f-3cfc-4647-a1cf-58096076e7b6 Error: Runtime exited with error: exit status 127
Runtime.ExitError


START RequestId: 47eaba0a-f985-4103-a452-935a78e4e6e1 Version: $LATEST
ffprobe: error while loading shared libraries: libpng15.so.15: cannot open shared object file: No such file or directory
END RequestId: 47eaba0a-f985-4103-a452-935a78e4e6e1
REPORT RequestId: 47eaba0a-f985-4103-a452-935a78e4e6e1	Duration: 2530.37 ms	Billed Duration: 2600 ms	Memory Size: 128 MB	Max Memory Used: 128 MB	Init Duration: 887.27 ms	
RequestId: 47eaba0a-f985-4103-a452-935a78e4e6e1 Error: Runtime exited with error: exit status 127
Runtime.ExitError



</div></details>


エラーメッセージは実行しようとしたときに必要になった共通ライブラリ。lambdaで実行するにはこれらを含めなければならなかった。
つくづく動画をデジタル信号に変えるのはあらゆる処理が必要なのだなと感じた。