お久しぶりです。streampackのfadoです。花粉の季節到来に最近猛威を振るっている新型コロナウィルスに加えて、外出する気力が奪われていきますよね。オリンピックの年ですし早く収束してくれることを祈ります!さて、今回はFFmpeg
というツールを使ってストリームを画像に変換する流れを紹介したいと思います。本記事で少しでもみなさんの参考になれたら嬉しいです!
注意事項
- 検証はAWS環境で行ったものとなります。
- 検証環境のOSは
Amazon Linux
にしました。 - 入力ファイルは
rtsp
ストリーミングと想定しています。 - Wowza Media Systems社が無料で提供する
rtsp
ストリームのサンプルを使用しています。- rtsp://wowzaec2demo.streamlock.net/vod/mp4:BigBuckBunny_115k.mov
作業の目的
rtsp
ストリームをFFmpeg
を用いて画像(jpgファイル)に変換- 出力されたjpgファイルをほぼオンザフライで
S3
に同期させます
AWSリソース
- EC2
- インスタンスタイプ: t2.small
- OS: Amazon Linux
- HDD: 30GiB
- S3
EC2にアタッチするIAMロールやセキュリティグループの設定等は省略させていただきます。
検証環境の準備
1.jpg画像用フォルダーを作成
$ mkdir -p ~/images/test1
2.FFmpegのインストールとセットアップ。
- 自分でビルドする必要のない
FFmpeg Static Builds
を利用します。
$ wget https://johnvansickle.com/ffmpeg/builds/ffmpeg-git-amd64-static.tar.xz $ tar xvfJ ffmpeg-git-amd64-static.tar.xz $ sudo cp -av ffmpeg-git-20200211-amd64-static/ffmpeg /usr/local/bin/ $ sudo cp -av ffmpeg-git-20200211-amd64-static/ffprobe /usr/local/bin/ $ which {ffmpeg,ffprobe} /usr/local/bin/ffmpeg /usr/local/bin/ffprobe
$ ffmpeg -version ffmpeg version N-51730-gf15007afa9-static https://johnvansickle.com/ffmpeg/ Copyright (c) 2000-2020 the FFmpeg developers built with gcc 8 (Debian 8.3.0-6) configuration: --enable-gpl --enable-version3 --enable-static --disable-debug --disable-ffplay --disable-indev=sndio --disable-outdev=sndio --cc=gcc --enable-fontconfig --enable-frei0r --enable-gnutls --enable-gmp --enable-libgme --enable-gray --enable-libaom --enable-libfribidi --enable-libass --enable-libvmaf --enable-libfreetype --enable-libmp3lame --enable-libopencore-amrnb --enable-libopencore-amrwb --enable-libopenjpeg --enable-librubberband --enable-libsoxr --enable-libspeex --enable-libsrt --enable-libvorbis --enable-libopus --enable-libtheora --enable-libvidstab --enable-libvo-amrwbenc --enable-libvpx --enable-libwebp --enable-libx264 --enable-libx265 --enable-libxml2 --enable-libdav1d --enable-libxvid --enable-libzvbi --enable-libzimg libavutil 56. 39.100 / 56. 39.100 libavcodec 58. 68.102 / 58. 68.102 libavformat 58. 38.100 / 58. 38.100 libavdevice 58. 9.103 / 58. 9.103 libavfilter 7. 75.100 / 7. 75.100 libswscale 5. 6.100 / 5. 6.100 libswresample 3. 6.100 / 3. 6.100 libpostproc 55. 6.100 / 55. 6.100
3.incronのインストール
incron
はEPELレポジトリからインストールしますのでまずEPELリポジトリを有効にする必要があります。
$ sudo yum-config-manager --enable epel $ sudo yum -y install incron
- バージョンを確認
$ incrond -V incrond 0.5.9
- 自動起動を設定し、サービスを起動
$ sudo chkconfig incrond on $ sudo /etc/init.d/incrond start
作業の手順
1.S3に同期させるためのスクリプトの作成
- ソースのjpgファイルが削除されたらターゲットのjpgファイルも削除されるように
--delete
オプションを付けます。 BUCKET
名は適切なものに書き換えてください。
aws-synctoS3.sh
#!/bin/bash /usr/bin/aws s3 sync /home/ec2-user/images/test1 s3://BUCKET名/images/test1 --delete
- 実行権限を付与
$ chmod +x ~/aws-synctoS3.sh
2.incrontabの設定
incrontab -e
で設定- 設定後、
incrontab -d
でテーブルをreload - どんなタイプが設定可能か
incrontab -t
で確認可能 - incronのログは
/var/log/cron
に出力されます
$ incrontab -l /home/ec2-user/images/test1 IN_MODIFY,IN_CREATE,IN_DELETE,IN_ONESHOT,IN_NO_LOOP /home/ec2-user/aws-synctoS3.sh
・IN_MODIFY
ファイルが上書きされた場合でもトリガーされる
・IN_ONESHOT
イベントを一回のみ監視する
・IN_NO_LOOP
イベントが完了するまで監視をしない
- 問題ないかログを確認しましょう。
$ sudo tail -f /var/log/cron Feb 21 01:23:09 ip-10-16-10-61 incrond[2727]: ready to process filesystem events Feb 21 01:49:01 ip-10-16-10-61 CROND[2776]: (root) CMD (/sbin/start --quiet update-motd) Feb 21 01:53:52 ip-10-16-10-61 incrond[2727]: table for user ec2-user created, loading Feb 21 01:55:31 ip-10-16-10-61 incrond[2727]: table for user ec2-user changed, reloading
3.バックグラウンドでFFmpegコマンドの実行
$ ffmpeg -rtsp_transport tcp -i rtsp://wowzaec2demo.streamlock.net/vod/mp4:BigBuckBunny_115k.mov -f image2 -s 1920x1080 -r 15 /home/ec2-user/images/test1/image-%08d.jpg < /dev/null > /dev/null 2>&1 &
- パラメーターの説明
-rtsp_transport rtspのトランスポートプロトコルを指定。udpでパケロスが生じた場合の回避策としてtcpに指定 -i 入力ファイルもしくはストリームを指定 -f フォーマットを指定。FFmpegは賢いのでこのパラメーターは省略しても問題ない -s 解像度を指定 (wxh) -r 出力ファイルのフレームレートを指定 %08d 出力のファイル名に8桁の数字で順番をつける < /dev/null > /dev/null 2>&1 & FFmpegをバックグラウンドで起動させ、FFmpegの標準出力と標準出力エラーを/dev/nullにリダイレクトする
jobs
コマンドでバックグラウンドで動いているプロセスを確認できます。
$ jobs [1]+ 実行中 ffmpeg -rtsp_transport tcp -i rtsp://wowzaec2demo.streamlock.net/vod/mp4:BigBuckBunny_115k.mov -f image2 -s 1920x1080 -r 15 /home/ec2-user/images/test1/image-%08d.jpg < /dev/null > /dev/null 2>&1 &
4.指定したフォルダーにjpgファイルができたことを確認
$ ls ~/images/test1/image-0000* | head /home/ec2-user/images/test1/image-00000001.jpg /home/ec2-user/images/test1/image-00000002.jpg /home/ec2-user/images/test1/image-00000003.jpg /home/ec2-user/images/test1/image-00000004.jpg
5.incronがトリガーされたことを確認
$ sudo tail -f /var/log/cron Feb 21 03:14:48 ip-10-16-10-61 incrond[2727]: (ec2-user) CMD (/home/ec2-user/aws-synctoS3.sh) Feb 21 03:14:49 ip-10-16-10-61 incrond[2727]: (ec2-user) CMD (/home/ec2-user/aws-synctoS3.sh) Feb 21 03:14:51 ip-10-16-10-61 incrond[2727]: (ec2-user) CMD (/home/ec2-user/aws-synctoS3.sh)
6.出力されたjpgファイルがS3に問題なく同期されたことを確認
結果
FFmpeg
を使ってrtspストリームを15fps
でjpg画像に変換することができました。出力されたjpgファイルをincron
を用いてS3
に同期させることもできましたので本記事の目的は達成できたかと思います。今回は15fps
を指定しましたので仕組み上、1秒に15回S3
に同期されることになります。注意すべき点はFFmpeg
の処理よりもincron
プロセスの方が高負荷であることです。30fps
や60fps
に変換したい場合や2つ以上のストリームの画像変換を試したい場合、jpgではなくpngで出力させたい場合などインスタンスタイプを変更しながら検証する必要が出てきます。
私が検証した環境ではt2.small
でFFmpeg
とincron
と同時に走らせて15fps
ならCPU使用率が約80%
、ロードアベレージが1.5
を超えた結果となりました。ギリギリですね。
感想
FFmpeg
はとても万能で動画や音声処理をするには欠かせないツールです。仕事でも動画変換をしたり動画配信したりでFFmpeg
を使う機会がたくさんあります。使いこなせていない機能もまだまだあります。FFmpeg
とはもっともっと仲良くなりたいなと考えている今日この頃の私です。実はAmazon Linux 2
での検証もしてみたのですがAmazon Linux 2
のEPELで採用されているincron
のバージョンが新しくなり、IN_NO_LOOP
がデフォルトとなったり、IN_ONESHOT
は今回と違う動きを見せたりで少し苦戦していましたが再チャレンジし、いずれか報告できたらいいなと思っています。
参考文献
https://www.ffmpeg.org/
https://ffmpeg.org/ffmpeg-formats.html#image2-2
https://en.wikibooks.org/wiki/FFMPEG_An_Intermediate_Guide/image_sequence
https://linux.die.net/man/5/incrontab