FFmpeg を SRT 有効化した状態でビルドしてみる！

#はじめに
##この記事に書いてあること
以下の内容について、自分の備忘録の意味も込めてまとめています。
コマンドはできるだけコピペで使えるように書いてます。

* FFmpeg を自前でビルドするための環境を構築するためのコマンド
* FFmpeg に SRT プロトコルのサポートを入れた状態で自前ビルドをする方法

#FFmpeg を SRT サポートこみでビルドしてみる
##前提条件
今回は、以下の環境でビルドを行いました。

* Windows 11 Enterprise
* Windows Subsystem for Linux (WSL) 2
* Ubuntu 18.04 LTS (on WSL2)

また、同じ手順を以下の Linux 環境でも試してみてビルドが通ること、ビルドされたバイナリが動くことは確認済みです。

* Ubuntu 20.04 LTS (WSL ではなく、Hyper-V 上の VM として稼働)

たぶん他の環境でも、依存関係のあるライブラリさえインストールできれば同じような手順でいけるんじゃないでしょうか。

##ビルドに使ったコマンド
###まずはビルド用のディレクトリを掘ったり依存関係をセットアップしたり
この辺りはわかる人は好きなようにカスタマイズしちゃっても OK だと思います。

```bash
mkdir git
cd git
sudo apt update
sudo apt install tclsh pkg-config cmake libssl-dev build-essential
#H.264 と H.265 のサポートに必要
sudo apt install libx264-dev libx265-dev nasm
#drawtext フィルタを使うのに必要
sudo apt install libfreetype6-dev
#ffplay をビルドするのに必要
sudo apt install libsdl2-dev libva-dev libvdpau-dev libxcb1-dev libxcb-shm0-dev libxcb-xfixes0-dev
```

###続いて SRT のコマンドラインツールならびにライブラリのビルド
GitHub の SRT のリポジトリから最新のコードをダウンロードしてきてビルドします。

```bash
git clone https://github.com/Haivision/srt.git
cd srt
./configure
make
sudo make install
sudo ldconfig
cd ..
```

###最後に FFmpeg のビルド
FFmpeg のコードリポジトリから最新のスナップショットをダウンロードしてきてビルドします。
./configure をするときに、SRT のサポートを含めるのがポイントです。今回はそれ以外に H.264 と H.265 も入れてみました。
libfreetype をリンクしているのは、drawtext フィルターを使ってテストソースに時刻などの文字を載せるのに使うためです。

```bash
git clone https://git.ffmpeg.org/ffmpeg.git
cd ffmpeg
./configure --enable-libsrt --enable-libx264 --enable-libx265 --enable-libfreetype --enable-gpl
make
sudo make install
```

##セットアップ後の確認
インストール先のパスを確認してみます。
恐らく /usr/local/bin 配下に入っているはずです。

```bash
which ffmpeg
```

対応するプロトコルに srt が入っているか確認します。
下記のコマンドを打って出てきた Input/Output に srt が入っていることを確認しましょう。（srtp と間違えやすいので注意！）

```bash
ffmpeg -protocols
```

ついでなので H.264 と H.265 が扱えるかも見ておきましょう。
下記コマンドの出力で h264 と hevc が入っていることを確認します。

```bash
ffmpeg -codecs
```

これで、FFmpeg で SRT を使って映像伝送を行えるようになりました！

##コマンド例
下記のようなコマンドで、ローカルディレクトリにある動画ファイルを SRT Caller モードで SRT Listener に送ることができます。

```bash
ffmpeg -re -stream_loop -1 -i ./動画ファイル名.mp4 -c:v libx264 -acodec aac -strict -2 -f mpegts "srt://サーバーURL:ポート番号"
```

VLC などから接続しに行くパターンだと、Listener モードで待ち受けをすることになりますが、その場合のコマンドはこんな感じ。

```bash
ffmpeg -re -stream_loop -1 -i ./動画ファイル名.mp4 -c:v libx264 -acodec aac -strict -2 -f mpegts "srt://サーバーURL:ポート番号?mode=listener"
```

#まとめ
比較的簡単に FFmpeg で SRT をサポートさせることができました！
パブリック インターネット経由での映像伝送における注目株プロトコルだと思うので、是非試してみてください！（何しろ無料ですし！）

#補足情報
##もうちょっと真面目にやればよかったと思っていること
SRT と FFmpeg のそれぞれで、ビルドをする前に checkout コマンドを打って、ビルドする対象のバージョンを明示的に指定しておけばよかったかもしれないです。（特に FFmpeg は最新のブランチだとバージョン番号がなんかわかりにくい）

たぶんこんな感じのコマンドですね。

```bash
#SRT は 2022/02/02 時点の最新の安定リリースが v1.4.4 なのでそのブランチに切り替え
git checkout -b v1.4.4 v1.4.4

#FFmpeg は 2022/02/02 時点の最新の安定リリースが v5.0 なのでそのブランチに切り替え
git checkout -b n5.0 n5.0
```

##そもそも何をやりたかったのか
SRT を使った映像伝送の実験を行うにあたり、映像ソースを FFmpeg で生成し SRT の Listener に流し込む必要がありました。

##何が当初うまくいかなかったのか
WSL 2 上で動作する Ubuntu 18.04 に apt でインストールできる FFmpeg は SRT のサポートが入っていなかったため、自分で SRT を含めた形で FFmpeg をビルドする必要に迫られました。

##SRTとは何か？
Haivision 社が中心となり、OSS として開発が進んでいる映像伝送プロトコルです。

https://www.haivision.com/products/srt-secure-reliable-transport/

プロトコル名の SRT とは Secure Reliable Transport の略で、その名の通り、不安定なパブリック インターネット回線においても、安全に確実にデータを伝送することを目標にして設計・実装がなされています。このプロトコルを使うことで、下記のメリットを享受し、パブリック インターネット回線で安全に確実に映像を届けることができるようになります。

* End to End の AES 128/256 bit 暗号化により、映像は VPN や閉域網を使わずとも通信経路上で保護されます
* UDP をベースにしたプロトコルによって、低遅延での映像伝送が可能です
* 自動再送要求 (ARQ) と、前方誤り訂正 (FEC) の働きにより、パケットロスやジッターの多い環境、帯域幅の変動のある環境でも可能な限り最高の品質で映像を送り届けることが可能です
* オープンソースで開発が進められており、Mozilla PublicLicenceを使用してGitHubで入手できる無料のオープンソースコードベースを使用して誰でも実装可能です

#よくあるエラー
##protocol not found
以下のようなコマンドで FFmpeg で srt を扱おうとすると "protocol not found" のエラーが出る場合には？

```bash
ffmpeg -re -i source.mp4 -c copy -f mpegts srt://127.0.0.1:5000
```

これ、apt とかでいれた SRT サポートなしバージョンの FFmpeg が使われているときにはエラーになります。
この記事を最初から読んで、是非 SRT 対応したバージョンの FFmpeg を自分でビルドしてみてください。

##SRT で送られた映像や音声が乱れる
経験上以下のいずれかに起因している場合が多い印象です。（あくまで個人の感想です）

###そもそもエンコード時の CPU 負荷が高すぎて、リアルタイムエンコードが出来ていない
FFmpeg のエンコードプリセットを見直しましょう。映像が送れるかどうかの実験程度なら、preset ultrafast とかで良い気がします。あと、コーデックも要検討です。HEVC は低いビットレートで高画質な映像を送れますが、その分 CPU にかかる負荷は高めです。

###バッファが足りない
SRT では受け取った映像をある程度バッファリングしますが、そのバッファ長を手動で入力するようなトランスコーダーもあります。受け側のバッファの設定や回線の遅延のパラメーターをチューニングするとよいでしょう。

###帯域が細い
良い回線を契約しましょう。筆者は NURO 光を使ってますが、すいているときなら 800Mbps 程度出ていて大満足です。