こんにちは、テリーです。オリンピックで日本人選手が大活躍のニュースが続きました。連日手に汗をかいて見た人も多いのではないでしょうか? NHKやgorin.jpの配信は視聴者も多かったと思いますが、目立った事故もなく楽しませていただきました。

さて、前回の記事では、tcコマンドを使って不安定ネットワークを意図的に作り出す方法を紹介しました。今回は、低遅延映像伝送プロトコルSRTを用いて、不安定ネットワーク上で映像を伝送したときの挙動を確認する方法を紹介します。

環境

本記事の実行環境は下記を使用しています。

  • Mac Intel macOS Big Sur 11.5.2
  • Visual Studio Code 1.59.0
  • Docker Desktop 3.5.2
  • Ubuntu 20.04.2 LTS
  • SRT 1.4.3
  • FFmpeg 4.4

SRTのインストールとビルド

前編の記事と同じ手順で、Dockerコンテナを2つ立ち上げます。名前はsrt1, srt2で、IPアドレスは172.17.0.2, 172.17.0.3とします。
立ち上げたらそれぞれのコンテナ内のターミナルで下記のコマンドを打ち、srtのコードをGitHubから取得し、ビルドします。次に、SRTに対応しているFFmpgのバイナリをダウンロードしてインストールします。

apt update
apt install -y tclsh pkg-config cmake libssl-dev build-essential iputils-ping net-tools dnsutils
git clone https://github.com/Haivision/srt -b v1.4.3 --depth 1
cd srt
./configure
make
make install

cd /tmp
wget https://johnvansickle.com/ffmpeg/releases/ffmpeg-release-amd64-static.tar.xz
tar -xvf /tmp/ffmpeg-release-amd64-static.tar.xz ffmpeg-4.4-amd64-static/ffmpeg
cp /tmp/ffmpeg-4.4-amd64-static/ffmpeg /usr/bin

サンプル映像の準備

なにかしら動きと音声のある映像をお好みで用意します。ここではサンプル映像として、BigBuckBunnyの動画を使用します。ファイル名は BigBuckBunny.mp4 とします。
srt1のターミナルで下記のコマンドを実行します。

wget http://commondatastorage.googleapis.com/gtv-videos-bucket/sample/BigBuckBunny.mp4

srt-live-transmitで送信

Dockerコンテナのsrt1を送信側、srt2を受信側として、下記のコマンドをそれぞれ実行し、疎通を確認します。

srt1(送信側)

srt-live-transmit udp://:1234 srt://172.17.0.3:4201 -v

srt2(受信側)

srt-live-transmit srt://:4201 file://con -v

“SRT target connected”、”Accepted SRT source connection”と表示されれば成功です。映像データは流れていませんが、srt1からsrt2にSRT接続が完了しています。

この状態で、srt1(送信側)にもうひとつターミナルを開き、下記のコマンドを実行します。

ffmpeg -re -i BigBuckBunny.mp4 -pix_fmt yuv420p -c:v libx264 -b:v 1000k -g 30 -keyint_min 120 -profile:v baseline -preset veryfast -f mpegts "udp://127.0.0.1:1234?pkt_size=1316"

すると、srt2の画面に大量の文字が表示され、映像データのようなものが送受信されていることが確認できます。確認できたら、ffmpegのコマンドを実行しているターミナルでキーボードの「q」を押し、送信を停止します。

次にsrt2(受信側)でファイルに保存します。srt2のターミナルで実行中のsrt-live-transmitコマンドを「Cmd+C」を押して停止します。その後、下記のコマンドを実行し、さらにsrt1では上記ffmpegコマンドを再度実行します。

srt-live-transmit srt://:4201 file://con -v | ffmpeg -i pipe:0 -c:v copy -c:a copy -y a.ts

10秒程度様子を見て、srt1,srt2のターミナルでそれぞれ「Cmd+C」を押してコマンドを停止します。その後ホストコンピュータのMacでsrt2にマウントしたフォルダ上のa.tsを再生し、受信した映像が送信した映像とほぼ同じように再生されることを確認します。

ホストコンピュータで受信して再生

これまではDockerコンテナのsrt2で受信・保存してから再生確認しましたが、srt1から送信したデータを、ホストコンピュータのMacで直接受信しながら再生してみましょう。srt2のコンテナはもう使用しないので閉じてください。

MacにsrtをインストールするにはHomeBrew(パッケージマネージャー)を使います。HomeBrewをインストールした後、Macのターミナルを開き、下記のコマンドを実行してください。

brew install srt

インストールが終わったら、Macのターミナルで下記のコマンドを実行します。SRTで受信待機し、届いたパケットをffplayで再生します。

srt-live-transmit srt://:4201 file://con -v | ffplay -

送信側のsrt1では、下記のコマンドを実行します。前述のsrt-live-transmitコマンドを使用しても同じ挙動となりますが、ffmpegがsrtに対応している場合は、下記のように出力先に”srt://”で始まるURLを指定することで、エンコードしたパケットがSRTで送信されます。宛先のホスト名として、Dockerホストを指定します。Dockerコンテナ上では、ホストコンピュータとしてhost.docker.internalという名前が定義されています。

ffmpeg -re -i BigBuckBunny.mp4 -pix_fmt yuv420p -c:v libx264 -b:v 1000k -g 30 -keyint_min 120 -profile:v baseline -preset veryfast -f mpegts "srt://host.docker.internal:4201?pkt_size=1316"

ffmpegコマンドを実行すると、ffplayのウインドウが表示され、映像が確認できるようになります。

tcコマンドで不安定にして送受信し再生

前編の記事で紹介したtcコマンドを元に、ネットワークを不安定にしてみましょう。下記のコマンドをsrt1のターミナルで実行してください。ホストコンピュータ宛のポート4201のパケットに制限を加えています。

# 設定をすべて削除
tc qdisc del dev eth0 root
# パケットを3種類(1:1, 1:2, 1:3)に分類する仕組みを導入
tc qdisc add dev eth0 root handle 1: prio
# IP host.docker.internal UDPポート4201 宛のパケットを1:1に分類
tc filter add dev eth0 protocol ip parent 1: prio 1 u32 match ip dst `dig host.docker.internal +short`/32 match ip dport 4201 0xffff flowid 1:1

# 1:1に分類したパケットに遅延・帯域制限等を設定
tc qdisc add dev eth0 parent 1:1 handle 10: netem delay 200ms 50ms loss 1%

その後、前節と同じ下記のコマンドで映像を送受信し、tcコマンドの前後で違いを確認します。

Mac(受信側)

srt-live-transmit srt://:4201 file://con -v | ffplay -

srt1(送信側)

ffmpeg -re -i BigBuckBunny.mp4 -pix_fmt yuv420p -c:v libx264 -b:v 1000k -g 30 -keyint_min 120 -profile:v baseline -preset veryfast -f mpegts "srt://host.docker.internal:4201?pkt_size=1316"

tcコマンドで制限を加えた後は、絵が崩れたり、音がバリっと破裂音がしたり、途切れたりがたびたび発生しますが、それでもなんとか再生しようとします。これはSRTがネットワークのゆらぎを吸収しているからです。確認できたら「q」キーを押して停止します。

SRTを使わずに送受信し再生

tcコマンドによる制限が加わった状態で、SRTを使わずに生UDPでパケットを送受信したものを再生すると、SRTの役割がよくわかります。下記のコマンドを実行して再生すると、ほぼ見るに堪えない状況が続きます。

Mac(受信側)

ffplay udp://127.0.0.1:4201

srt1(送信側)

ffmpeg -re -i BigBuckBunny.mp4 -pix_fmt yuv420p -c:v libx264 -b:v 1000k -g 30 -keyint_min 120 -profile:v baseline -preset veryfast -f mpegts "udp://host.docker.internal:4201?pkt_size=1316"

まとめ

SRTを使用した映像伝送と、ローカル環境でネットワークのゆらぎを再現して、トランスポートプロトコルの挙動を確認する方法を紹介しました。srt-live-transmitコマンドにはたくさんのオプションパラメータがありますので、最適なオプションを試行錯誤することにも使用できます。最大許容する遅延時間を先に定め、ネットワークのゆらぎ幅を仮定し、オプションを調整していくとよいでしょう。WebTransportなどさらに新しいトランスポートプロトコルにも本記事で述べた手順は応用できると思います。ぜひ挑戦してみてください。