AWS で爆速エンコード -準備編-
こんにちは。みなさんは録画をする人でしょうか。
序
このブログを読みに来るようなオタクの皆さんの場合、日々増え続ける 15Mbps の MPEG-TS との戦いを往々にして繰り広げているものと思います。
我が家の録画サーバーも録画済データが 1TB に迫り、いよいよ真面目にエンコードをしていかないと先行きが不安です。
しかしながらエンコードにはCPUパワーとなおも多大な時間を要します。
試しにウチの録画管理に使っている LIVA (Bay-Trail-M Celeron N2807) で x264 によるエンコードを試してみたところ、30分の動画を処理するのに8時間強を要しました。未エンコード件数は400件近くあり、不眠不休で頑張らせても100日ほどかかることになりますね。
とてもじゃないけどやってらんないので、Amazon パワーでぶん殴っていくことを考えました。
アメイゾンパワー
AWS の EC2 には GPU を積んだインスタンスとして g2 シリーズというものがあります。
g2 は NVIDIA GRID K520 が利用可能であり、これを利用して NVENC を通じたハードウェアエンコードが可能です。
というわけで AWS にエンコードをやってもらう仕組みを作ってみました。
流れとしては、S3 にデータをぶっ込む → イベントを受けて Lambda が EC2 インスタンスを起動 → EC2 がエンコードしてデータを S3 に吐いて自動でシャットダウン ということになります。
こういうどうでもいい絵を一回作ってみたかった。この記事はこれで満足です。以下余談となります
今回は準備編として、AWS EC2 上でハードウェアエンコードできるようになるまでを書きます。
EC2 の下準備
やっていくため、大ざっぱに以下のものを用意していきます。
- nvidia ディスプレイドライバー (367.57)
- CUDA Toolkit (エンコードのみなら不要ですが、デコードやスケーリングも GPU に任せたいなら必要です)
- nvenc に対応した ffmpeg 3.3
AWS Marketplace では NVIDIA によりドライバーインストール済みの AMI イメージが公開されていますが、ドライバーのバージョンが古く(352.99) ffmpeg 3.3 が正常に動かなかった && アップデートも上手くいかなかったため、結局素の RHEL 7 AMI でやりました。
EC2 インスタンスを生やす
キリがないんでサクッと言うと S3 を読み書きできる IAM ロール を持った RHEL 7 の g2.2xlarge インスタンスをシュッと立てた。
なお GPU インスタンスは us-east-1 がちょっと安い。
お約束
$ sudo yum -y update
$ sudo yum -y groupinstall "Development Tools"
ディスプレイドライバーのインストール
このへんから結構手こずったのでマジメに書いておきます。
ちなみに本来であれば NVENCODE/DECODE API を使う場合 nvidia ドライバー >= 378.13 が必要らしいんですが、GRID K520 向けには 367.57 までしか提供されていません。
375.10 という beta 版もあるっぽいですがインストールしても使えませんでした。
ダウンロードします。
$ wget http://us.download.nvidia.com/XFree86/Linux-x86_64/367.57/NVIDIA-Linux-x86_64-367.57.run
RHEL の場合、もともと入っている nouveau ドライバが邪魔なので無効化します。
/etc/default/grub
を編集し、GRUB_CMDLINE_LINUX
に rd.driver.blacklist=nouveau nouveau.modeset=0
を加えます。
この段階で一度インストーラーを起動し、nouveau を無効化するファイルをシステムに加えます。
$ chmod +x NVIDIA-Linux-x86_64-367.57.run
$ sudo ./NVIDIA-Linux-x86_64-367.57.run
nouveau 無効化云々に Yes みたいな感じで答えると一旦インストーラーが終了するので、システムを再起動します。
再起動後、DKMS のビルドに必要なパッケージを入れたのち再びインストーラーを起動します。
$ sudo kernel-devel kernel-headers dkms
$ sudo ./NVIDIA-Linux-x86_64-367.57.run
nvidia-smi
あたりで確認して入ってるようなら大丈夫です。
CUDA のインストール
ダウンロードします。
$ wget https://developer.nvidia.com/compute/cuda/8.0/Prod2/local_installers/cuda_8.0.61_375.26_linux-run
あとは起動するだけですが、 Display Driver はインストールせず(古いので)、CUDAのみをインストールします。
したらば /etc/ld.so.conf
に /usr/local/cuda/lib64
を書いて ldconfig
しておく。
ffmpeg のビルド
この辺はサクッと。 3.3 ともなれば ./configure
時になにも書かずともデフォルトで cuvid/nvenc が有効になります。よかったですね。 以下では一応やっています。libnppはデフォルト無効のようです。
ところで素の RHEL 7 には bzip2 が入っていなくて驚いた。
$ sudo yum install autoconf automake bzip2 cmake freetype-devel gcc gcc-c++ git libtool make mercurial nasm pkgconfig zlib-devel $ wget http://ffmpeg.org/releases/ffmpeg-3.3.tar.bz2 $ tar xvf ffmpeg-3.3.tar.bz2 $ cd ffmpeg-3.3 $ ./configure --enable-cuda --enable-cuvid --enable-nvenc --enable-libnpp --enable-gpl --enable-nonfree --extra-cflags=-I/usr/local/cuda/include/ --extra-ldflags=-L/usr/local/cuda/lib64/ $ make $ sudo make install
こうして ffmpeg ができた、
$ ffmpeg -decoders | grep cuvid ffmpeg version 3.3 Copyright (c) 2000-2017 the FFmpeg developers built with gcc 4.8.5 (GCC) 20150623 (Red Hat 4.8.5-11) configuration: --enable-cuda --enable-cuvid --enable-nvenc --enable-libnpp --enable-gpl --enable-nonfree --enable-libfdk-aac --extra-cflags=-I/usr/local/cuda/include/ --extra-ldflags=-L/usr/local/cuda/lib64/ libavutil 55. 58.100 / 55. 58.100 libavcodec 57. 89.100 / 57. 89.100 libavformat 57. 71.100 / 57. 71.100 libavdevice 57. 6.100 / 57. 6.100 libavfilter 6. 82.100 / 6. 82.100 libswscale 4. 6.100 / 4. 6.100 libswresample 2. 7.100 / 2. 7.100 libpostproc 54. 5.100 / 54. 5.100 V..... h264_cuvid Nvidia CUVID H264 decoder (codec h264) V..... hevc_cuvid Nvidia CUVID HEVC decoder (codec hevc) V..... mjpeg_cuvid Nvidia CUVID MJPEG decoder (codec mjpeg) V..... mpeg1_cuvid Nvidia CUVID MPEG1VIDEO decoder (codec mpeg1video) V..... mpeg2_cuvid Nvidia CUVID MPEG2VIDEO decoder (codec mpeg2video) V..... mpeg4_cuvid Nvidia CUVID MPEG4 decoder (codec mpeg4) V..... vc1_cuvid Nvidia CUVID VC1 decoder (codec vc1) V..... vp8_cuvid Nvidia CUVID VP8 decoder (codec vp8) V..... vp9_cuvid Nvidia CUVID VP9 decoder (codec vp9) $ ffmpeg -encoders | grep nvenc ffmpeg version 3.3 Copyright (c) 2000-2017 the FFmpeg developers ... V..... h264_nvenc NVIDIA NVENC H.264 encoder (codec h264) V..... nvenc NVIDIA NVENC H.264 encoder (codec h264) V..... nvenc_h264 NVIDIA NVENC H.264 encoder (codec h264) V..... nvenc_hevc NVIDIA NVENC hevc encoder (codec hevc) V..... hevc_nvenc NVIDIA NVENC hevc encoder (codec hevc)
これは後で fdk_aac も加えたやつです。
使い方
このように
$ ffmpeg -c:v mpeg2_cuvid -i input.m2ts -c:v h264_nvenc output.mp4
とすると、cuvid でデコードして、nvenc でエンコードすることができます。CPU は殆ど使いません。
今の僕の設定はこうです、
$ ffmpeg -c:v mpeg2_cuvid -deint adaptive -i "input.m2ts" -c:v h264_nvenc -vf hwupload_cuda,scale_npp=-1:720 -preset slow -rc vbr -cq 10 -b:v 2M -minrate 500k -maxrate 5M "output.mp4"
cuvid でデコードすると同時にそのまま GPU でデインターレース、720p にスケーリングして 2Mbps でエンコード、です。
ぶっちゃけ画質は微妙で、1Mbps では相当アラが目立ちます。この辺は職人が緻密にパラメーターを調整してエンコードした動画には勝てませんね……
その分速度は爆速で、30分の 1440x1080/60i MPEG-2 の 地デジ動画を 100fps ちょっと、9分でエンコードしてしまいます。ぶっちゃけ S3 への転送より速い。
長くなったので続きは別記事にします。次は S3 と Lambda とアレするやつ書きます。