🌊

動画変換と配信の開発環境を構築

に公開

さて、いろいろテスト用のファイルを作成するにあたり、開発環境の構築を先にやらなければということで、まずは環境構築の手順を一通り載せておこうと思います。前の記事の通り、ネットワーク周りの設定は完了している前提で進めていきます。

サーバ環境の準備

今回は検証用途なので、1台のサーバにすべて入れた物を作っていきます。実際に全部をまとめてしまうと、エンコード中にCPUを使い切り配信に使用するWebサーバが遅くなったりなどの弊害がありますので、本番想定の環境ではちゃんと分離をして設置するようにしてください。

サーバの用意

まずはサーバOSの選定です。
基本的にはDebian派な私ですが、会社のネットワークサーバはAlmalinuxというルールもあるため、今回はAlmalinux 9を使用して構築していきます。仮想環境をVagrantで起動して設定していきますが、Vagrantで配布されているAlmalinuxはそのままではセキュリティ設定が弱いため、必ずルータやファイアウォールの下で使うようにしてください。

ドメインの用意

そしてドメインです。証明書をとるために必要になりますので、適当にドメインレジストラで取得します。無料でやる場合は無料のDynamicDNSサービスなどでもよいかもしれませんが、マイドメインを持っておくと色々便利なのでこの際に取得しても良いかもですね。
私は今回videostream.techというドメインを取りましたのでその前提で手順を書いていきますが、実際に試す場合にはこの部分を自分のドメインに置き換えて読んで下さい。

作業手順

まずはここまで準備したネットワークとサーバ、ドメインがうまく動いているかを確認するために、Webサーバを立てて証明書を設定し、ルータ経由でHTTPSのアクセスができるところまでを確認していきます。

# 初期設定
dnf -y update
dnf -y install yum-utils epel-release

# Webサーバ(nginx)の導入
vi /etc/yum.repos.d/nginx.repo
# https://nginx.org/en/linux_packages.html#RHEL
dnf -y install nginx
vi /etc/nginx/conf.d/default.conf
# 証明書用に server_name を書き換える
systemctl enable nginx
systemctl start nginx

# ファイアウォールでHTTP, HTTPSを許可
firewall-cmd --zone=public --add-service=http --permanent
firewall-cmd --zone=public --add-service=https --permanent
firewall-cmd --reload

# HTTPSの公開準備
dnf -y install certbot python3-certbot-nginx
certbot --nginx -d videostream.tech
systemctl enable certbot-renew.timer

# CORSの設定を追加
vi /etc/nginx/conf.d/default.conf
# この3行を追加
add_header Access-Control-Allow-Origin `*` always;
add_header Access-Control-Allow-Methods 'GET, POST, OPTIONS' always;
add_header Access-Control-Allow-Headers 'X-Requested-With,Accept,Content-Type, Origin' always;
systemctl restart nginx

ここまでで、お手元のブラウザ(サーバ機とは別の端末)からhttps://videostream.tech/などとアクセスしてみましょう。証明書のエラーもなく、nginxのwelcomeページが表示されれば成功です。

今回は自己証明にならなうようにLet's Encrypt様を使用させて頂きました。しかしcertbot有能ですね。ドメインだけ指定すれば証明書ファイルも作成してくれるし、nginx.confもちゃんと書き換えてくれます。テスト環境はスクラップ&ビルドが多いと思うので、こういう手軽さは有難いですね。

ソフトウェアの準備

FFmpegの用意

テスト用のffmpegをビルドします。最新版が欲しいのでソースからインストールしますが、テスト用なので細かいチューニングはおいておいてさくっとビルドします。

# Development Build
dnf -y groupinstall "Development Tools"
dnf config-manager --set-enabled crb
dnf -y install cmake nasm
cd /usr/local/src/

# Library Download
curl -LO https://ffmpeg.org/releases/ffmpeg-7.1.1.tar.xz \
     -LO https://code.videolan.org/videolan/x264/-/archive/master/x264-master.tar.bz2 \
     -LO https://gitlab.com/AOMediaCodec/SVT-AV1/-/archive/v2.3.0/SVT-AV1-v2.3.0.tar.gz \
     -LO https://downloads.xiph.org/releases/opus/opus-1.5.2.tar.gz

# x264 build
tar jxf x264-master.tar.bz2
cd x264-master
./configure --disable-opencl --enable-shared && make -j && make install
cd ..

# AV1 build
tar zxf SVT-AV1-v2.3.0.tar.gz
cd SVT-AV1-v2.3.0/Build
cmake .. -G"Unix Makefiles" -DCMAKE_BUILD_TYPE=Release && make -j && make install
cd ../..

# Opus build
tar zxf opus-1.5.2.tar.gz
cd opus-1.5.2
./configure && make -j && make install
cd ..

export PKG_CONFIG_PATH="/usr/local/lib/pkgconfig:/usr/local/lib64/pkgconfig"

# FFmpeg build
tar xf ffmpeg-7.1.1.tar.xz
cd ffmpeg-7.1.1
./configure --enable-gpl --enable-version3 --enable-shared --enable-openssl --enable-libx264 --enable-libsvtav1 --enable-libopus
make -j && make install

echo "/usr/local/lib" > /etc/ld.so.conf.d/ffmpeg.conf
echo "/usr/local/lib64" >> /etc/ld.so.conf.d/ffmpeg.conf
ldconfig

とりあえずこれでffmpeg 7.1.1がビルドされました。ffmpegだけでなくx264などもバージョンが違うとちょっと動きが違ったりするので、動作確認をする際には必ずバージョンを合わせておきましょう。パッケージでインストールされるffmpegもそういう意味では怖いので、事業継続性を考える場合はなるべくバージョンを指定してダウンロードしたソースを自分でコンパイルする方が良いかと思います。

動作確認

動画ファイルを普通にエンコードしてみて再生できるかを確認してみます。
元ファイルには有名なBig Buck Bunnyのファイルを利用させてもらいます。このファイルも動画エンジニアの人はいったい何万回見たことだろうか…。

標準エンコード

cd /home/vagrant
curl -LO https://download.blender.org/peach/bigbuckbunny_movies/big_buck_bunny_1080p_stereo.avi

cd /usr/share/nginx/html
mkdir 1_normal
cd 1_normal
ffmpeg -i /home/vagrant/big_buck_bunny_1080p_stereo.avi \
  -filter_complex "[0:v]split=3[v1][v2][v3]; \
                   [v1]scale=w=640:h=360[v1out]; \
                   [v2]scale=w=426:h=240[v2out]; \
                   [v3]scale=w=256:h=144[v3out]" \
  -map "[v1out]" -map a -c:v:0 libx264 -b:v:0 600k -c:a:0 aac -b:a:0 96k \
  -map "[v2out]" -map a -c:v:1 libx264 -b:v:1 300k -c:a:1 aac -b:a:1 64k \
  -map "[v3out]" -map a -c:v:2 libx264 -b:v:2 150k -c:a:2 aac -b:a:2 48k \
  -f hls \
  -var_stream_map "v:0,a:0 v:1,a:1 v:2,a:2" \
  -master_pl_name master.m3u8 \
  -hls_time 10 -hls_list_size 0 \
  -hls_segment_filename "v%v/segment_%03d.ts" \
  v%v/playlist.m3u8

Adaptive BitrateのみでスタンダードなHLSを作成。あまりいろんな機能をつけると将来的に再生できない場合にどこが悪かったのかがわかりにくくなりますが、ABRぐらいはまあ基本機能かなと。テストなので画質は低めでやっています。そもそも再生できるかどうかの検証なので。

再生確認

これでhls.jsなどで再生してみましょう。1_normalというディレクトリを作成して出力したので、このパスのmaster.m3u8を指定します。この後は同じように[テスト番号]_[テスト概要]のようなフォルダを作り、その部分を変えて行けば再生確認が簡単にできますね。
とりあえず再生に問題があった場合は、1番に戻ってくることでプレイヤー側の問題でないことが確認できます。何もしていないものがちゃんと再生できることを確認するのは検証の第一歩ですしね。

暗号化エンコード

ついでにAES-128で暗号化されたストリームも作っておきましょうか。

cd /usr/share/nginx/html
mkdir 1_aes
cd 1_aes

openssl rand 16 > aes.key
cat <<EOF | tee aes.keyinfo
/aes.key
https://videostream.tech/aes.key
0123456789abcdef0123456789abcdef
EOF
mv aes.key /usr/share/nginx/html/

ffmpeg -i /home/vagrant/big_buck_bunny_1080p_stereo.avi \
  -filter_complex "[0:v]split=3[v1][v2][v3]; \
                   [v1]scale=w=640:h=360[v1out]; \
                   [v2]scale=w=426:h=240[v2out]; \
                   [v3]scale=w=256:h=144[v3out]" \
  -map "[v1out]" -map a -c:v:0 libx264 -b:v:0 600k -c:a:0 aac -b:a:0 96k \
  -map "[v2out]" -map a -c:v:1 libx264 -b:v:1 300k -c:a:1 aac -b:a:1 64k \
  -map "[v3out]" -map a -c:v:2 libx264 -b:v:2 150k -c:a:2 aac -b:a:2 48k \
  -f hls \
  -var_stream_map "v:0,a:0 v:1,a:1 v:2,a:2" \
  -master_pl_name master.m3u8 \
  -hls_time 10 -hls_list_size 0 \
  -hls_key_info_file aes.keyinfo \
  -hls_segment_filename "v%v/segment_%03d.ts" \
  v%v/playlist.m3u8

暗号化を行う場合は、keyとkeyinfoを作成し、-hls_key_info_fileで指定するだけです。
aes.keyinfoでは適当な32文字のIV(初期ベクトル)を設定していますが、これは省略しても構いません。ただEXT-X-KEYタグにIVを指定できるという挙動を明確に確認するためにあえて設定しています。

こちらも再生してみると、普通に再生されるかと思います。ただ開発者ツールなどを見ていると、playlist.m3u8の後にaes.keyへのアクセスが確認できると思います。また.tsファイルをダウンロードしてきて動画プレイヤーで再生しようとしてもエラーになってしまいます。

CMAFエンコード

もう一つ、スタンダードなエンコードとして、CMAF(Common Media Application Format)のものも作っておきます。これは簡単に言うと、これまでの古いファイル形式(MPEG2-TS)から新しいファイル形式(MP4)に変わったものみたいな認識で大丈夫です。新機能の中にはこのCMAF形式であることが前提の機能もありますので、ここで基準となるストリームを作っておきます。

cd /usr/share/nginx/html
mkdir 1_cmaf
cd 1_cmaf
ffmpeg -i /home/vagrant/big_buck_bunny_1080p_stereo.avi \
  -filter_complex "[0:v]split=3[v1][v2][v3]; \
                   [v1]scale=w=640:h=360[v1out]; \
                   [v2]scale=w=426:h=240[v2out]; \
                   [v3]scale=w=256:h=144[v3out]" \
  -map "[v1out]" -map a -c:v:0 libsvtav1 -b:v:0 600k -c:a:0 libopus -b:a:0 96k \
  -map "[v2out]" -map a -c:v:1 libsvtav1 -b:v:1 300k -c:a:1 libopus -b:a:1 64k \
  -map "[v3out]" -map a -c:v:2 libsvtav1 -b:v:2 150k -c:a:2 libopus -b:a:2 48k \
  -f hls \
  -var_stream_map "v:0,a:0 v:1,a:1 v:2,a:2" \
  -master_pl_name master.m3u8 \
  -hls_time 10 -hls_list_size 0 \
  -hls_segment_type fmp4 \
  -hls_flags +independent_segments \
  -hls_fmp4_init_filename "init.mp4" \
  -hls_segment_filename "v%v/segment_%03d.m4s" \
  v%v/playlist.m3u8

こちらは主にfmp4(fragmented MP4)関連のオプションが追加されています。本来はもうちょっとチューニングが必要ですが、いったんは再生確認までなのでお手軽に用意してみます。
またコーデックをAV1とOpusに変更していますので、現在では再生できる環境が限られています。

完了

ここまでで環境構築はいったん完了。
次からはいろんな条件でエンコードし、新しいHLS規格のストリームを作成していきます。


https://voice.stream.co.jp/

Discussion