この記事でわかること
- SRT(Secure Reliable Transport)の仕組みと、RTMP・HLSとの違い
- FFmpegがlibsrt対応でビルドされているかの確認方法
- 最小の送信側(caller)・受信側(listener)コマンド
- 接続モード
caller/listener/rendezvousの使い分け - 主要パラメータ
pkt_size・latency・modeの意味と調整指針 - 素材がSRT配信要件に合わない場合の再エンコード送出
- 「Protocol not found」「Connection timed out」などのトラブル対処
テスト済みバージョン: FFmpeg 6.1(検証スクリプトで実 FFmpeg 実行確認)
対象 OS: Windows / macOS / Linux
SRTとは(RTMP・HLSとの違い)
SRT(Secure Reliable Transport)は、Haivisionが開発しオープンソース化した低遅延伝送プロトコルです。UDPをベースにしながら、ARQ(Automatic Repeat reQuest)によるパケットロス回復と、AES暗号化によるセキュアな伝送を実現しています。インターネットのような品質が安定しない回線でも、TCPほど遅延を増やさずに信頼性の高い映像伝送ができるのが最大の特徴です。
主要なストリーミング手段との違いを整理すると次のようになります。
| プロトコル | トランスポート | 遅延 | ロス耐性 | 主な用途 |
|---|---|---|---|---|
| SRT | UDP(ARQ付き) | 低(数百ms〜) | 高 | 中継・コントリビューション、現場→クラウド |
| RTMP | TCP | 中 | 中(再送で遅延増) | 配信プラットフォームへの入力 |
| HLS | HTTP(TCP) | 高(数秒〜数十秒) | 高 | 視聴者への大規模配信 |
RTMPはTCPベースのため、パケットロスが起きると再送による遅延が積み上がりやすく、近年はサポートを縮小するプラットフォームも増えています。HLSは視聴者へのスケーラブルな最終配信に強い一方、遅延が大きく、撮影現場からスタジオ・クラウドへ映像を「持ち込む」コントリビューション用途には向きません。
SRTはこの「持ち込み(コントリビューション)」や拠点間中継に最適化されており、ファイアウォール/NAT越えのための接続モードを備えている点でもRTMPより柔軟です。視聴者への配信はSRTで受けた映像をHLSやDASHに変換して行う、という組み合わせが一般的です。
前提:libsrt対応の確認
FFmpegでSRTを使うには、ビルド時に --enable-libsrt が有効になっている必要があります。まずは手元のFFmpegがSRTプロトコルに対応しているか確認しましょう。
ffmpeg -protocols | grep srt
出力に srt が含まれていれば対応済みです。何も表示されない場合、そのビルドはlibsrt非対応です。
srt
非対応の場合の対処:
- Linux: ディストリビューションの公式パッケージは非対応のことがあります。多くの場合、staticビルドやジョンヴァンシッカ氏のbuildsなどlibsrt同梱のビルドを使うのが手軽です。
- macOS: Homebrewの
ffmpegは標準でlibsrtを含みます(brew install ffmpeg)。 - Windows: gyan.dev や BtbN の公式配布ビルド(full / gpl版)はlibsrtを含みます。
- 自分でビルドする場合は、先に
libsrtをインストールしてから./configure --enable-libsrtを指定します。
SRT URLを使ったときに
Protocol not foundと表示されたら、ほぼ確実にビルドがlibsrt非対応です。
最小の送受信コマンド
SRTはMPEG-TS(-f mpegts)を運ぶのが一般的です。SRTは個々のメディアフレームではなくバイトストリームを運ぶため、自己完結したコンテナであるMPEG-TSが標準的に使われます。
まず受信側(listenerモードで待ち受け、ファイルに保存)を起動します。
ffmpeg -i "srt://0.0.0.0:9000?mode=listener" -c copy received.mp4
0.0.0.0 は全インターフェースで待ち受ける指定、9000 は任意のUDPポートです。受信側が先に待ち受け状態になっている必要があります。
次に送信側(caller)から映像を送ります。
ffmpeg -re -i input.mp4 -c copy -f mpegts "srt://receiver-host:9000?pkt_size=1316"
receiver-host は受信側のホスト名またはIPアドレスに置き換えます。ここでは -c copy でコーデックをそのまま流し、-f mpegts でMPEG-TSコンテナに包んで送出しています。
-reは入力をネイティブのフレームレートで読み込む指定で、ファイルをライブのように等速で送出するために必須です。これがないとファイルを一気に読み込んでしまい、ライブ送出になりません。pkt_size=1316は送出するUDPペイロードのサイズ(後述)。
受信側ではURLにモードを書かず、送信側で mode=caller(既定)にする組み合わせが最もシンプルです。逆に、受信側をcaller、送信側をlistenerにすることもできます(どちらかが待ち受け、もう一方が発信する関係であれば成立します)。
接続モード(caller / listener / rendezvous)
SRTでは「どちらが接続を開始するか」を接続モードで決めます。URLの mode= パラメータで指定します。
| モード | 動作 | 典型的な使い方 |
|---|---|---|
caller | 相手へ接続しに行く(発信側) | 送信PCが、固定IPの受信サーバーへ送る |
listener | 接続を待ち受ける(受信側) | クラウド上の受信サーバーが待機する |
rendezvous | 双方が同時に接続を開始する | 両側がNAT/ファイアウォール内にある場合 |
caller ↔ listener(最も基本):片方を listener にして待ち受け、もう片方を caller にして発信します。発信側からは相手のグローバルIP/ポートに到達できる必要があります。
# 受信側(listener)
ffmpeg -i "srt://0.0.0.0:9000?mode=listener" -c copy received.mp4
# 送信側(caller、mode省略時の既定)
ffmpeg -re -i input.mp4 -c copy -f mpegts "srt://receiver-host:9000?pkt_size=1316"
rendezvous:両端がNATの内側にいて、どちらも相手のグローバルアドレスへ直接到達しづらいケースで使います。双方が同じ mode=rendezvous を指定し、同時に相手のアドレス:ポートへ接続を開始します。
# 両側で(host-A / host-B はそれぞれ相手のアドレス)
ffmpeg -re -i input.mp4 -c copy -f mpegts "srt://host-B:9000?mode=rendezvous&pkt_size=1316"
ffmpeg -i "srt://host-A:9000?mode=rendezvous" -c copy received.mp4
なお mode を省略した場合、ホスト名が指定されていれば caller、0.0.0.0 のような待ち受けアドレスであれば listener として扱われるのが一般的です。意図を明確にするため、運用では明示的に書くことをおすすめします。
主要パラメータ(pkt_size・latency・mode)
SRTのURLにはクエリ文字列として各種パラメータを ?key=value&key2=value2 の形式で付与します。
pkt_size
?pkt_size=1316
pkt_size=1316 は送出する1パケットのペイロードサイズ(バイト)です。MPEG-TSのパケットは188バイトで、その7倍(188 × 7 = 1316)がこの値です。1316バイトは標準的なイーサネットMTU(1500バイト)にIP/UDP/SRTヘッダを加えても収まり、IPフラグメンテーションを避けつつ効率よく送れるため、SRT/UDP送出で広く推奨されています。MPEG-TSをSRTで送る場合は基本的に pkt_size=1316 を付けておけば問題ありません。
latency
?latency=200
latency= はミリ秒単位のSRTレシーバーバッファ(受信側がパケットの再送を待つための猶予時間)です。回線でパケットロスが起きたとき、SRTはこのバッファ時間の範囲内でARQ(再送)によって欠損を埋めます。
- 値を大きくすると再送のチャンスが増え、ロスの多い不安定な回線でも映像が破綻しにくくなります。その代わりエンドツーエンドの遅延が増えます。
- 値を小さくすると遅延は減りますが、ロス耐性は下がります。
- 既定値はおおむね120ms前後です。RTT(往復遅延)の3〜4倍程度を目安に、回線品質に応じて調整します。
不安定な回線向けにバッファを明示する例:
ffmpeg -re -i input.mp4 -c copy -f mpegts "srt://receiver-host:9000?pkt_size=1316&latency=200"
複数のパラメータを並べるときは & で連結します。
mode
前述のとおり接続の主従を決めます(caller / listener / rendezvous)。caller側とlistener側で食い違うと接続が確立しないため、ペアで矛盾しないように設定します。
再エンコードして送出する
-c copy は素材のコーデックをそのまま流すため最も軽量ですが、入力のコーデックやGOP構造が配信要件に合わない場合は再エンコードします。たとえば受信側がH.264 + AACのMPEG-TSを前提にしている、あるいはキーフレーム間隔を一定にしたい、といったケースです。
ffmpeg -re -i input.mp4 -c:v libx264 -preset veryfast -b:v 4000k -maxrate 4000k -bufsize 8000k -pix_fmt yuv420p -g 60 -c:a aac -b:a 128k -f mpegts "srt://receiver-host:9000?pkt_size=1316"
各オプションの意味:
| オプション | 役割 |
|---|---|
-c:v libx264 | 映像をH.264で再エンコード(広く再生可能) |
-preset veryfast | ライブ送出向けに低遅延・低CPU負荷のプリセット |
-b:v 4000k / -maxrate 4000k / -bufsize 8000k | ビットレートを4Mbpsに固定し、瞬間的なピークも抑える |
-pix_fmt yuv420p | 互換性の高いピクセルフォーマットに統一 |
-g 60 | 60フレームごとにキーフレームを挿入(30fpsで2秒間隔) |
-c:a aac -b:a 128k | 音声をAAC 128kbpsで再エンコード |
-maxrate と -bufsize を設定してビットレートの上限を抑えることで、回線帯域を超えるピークによるロスを防ぎます。-g 60 で定期的にキーフレームを入れておくと、受信側で再接続したときの復帰が速くなります。CPUに余裕がなければ -preset ultrafast でさらに負荷を下げられますが、画質効率は落ちます。
よくあるエラーと対処
Protocol not found
FFmpegがlibsrt非対応でビルドされている場合に発生します。ffmpeg -protocols | grep srt で確認し、何も出なければlibsrt同梱のビルド(Homebrew、gyan.dev/BtbNのfull版、staticビルドなど)に入れ替えてください。
接続できない(タイムアウト前に確立しない)
最も多い原因は次の3つです。
- ポートが開いていない: SRTはUDPを使います。受信側のファイアウォール/セキュリティグループで該当ポート(例: 9000)のUDP受信を許可してください。TCPだけ開けても通りません。
- mode不一致: 一方が
caller、もう一方がlistenerになっている必要があります。両方caller、または両方listenerだと永遠に確立しません。 - 起動順: listener側を先に待ち受け状態にしてから、caller側を起動します。
パケットロスで映像が乱れる
ブロックノイズや映像の途切れが出る場合、回線のパケットロスに対して再送バッファが足りていません。latency を増やして改善できます。
ffmpeg -re -i input.mp4 -c copy -f mpegts "srt://receiver-host:9000?pkt_size=1316&latency=500"
それでも改善しない場合は、回線帯域に対してビットレートが高すぎる可能性があります。再エンコード送出で -maxrate を下げて帯域に余裕を持たせてください。
Connection timed out
両端がそれぞれNATの内側にあり、caller→listenerの直接到達ができないと発生しがちです。この場合は双方を mode=rendezvous にして、両側から同時接続を試みると越えられることがあります。
ffmpeg -re -i input.mp4 -c copy -f mpegts "srt://peer-host:9000?mode=rendezvous&pkt_size=1316"
それでも越えられない環境では、グローバルIPを持つ中継サーバー(VPSなど)をlistenerとして立て、両端をそこへcallerで接続させる構成が確実です。
よくある質問
SRTとRTMP、どちらを選ぶべき?
撮影現場やリモート拠点からスタジオ・クラウドへ映像を持ち込む(コントリビューション)用途、回線が不安定な環境、低遅延が重要な場面ではSRTが有利です。一方、配信プラットフォーム(YouTube Live等)への入力としてはまだRTMPが標準のことも多いため、その場合はRTMPを使います。両者を組み合わせ、現場→クラウドはSRT、クラウド→プラットフォームはRTMP、という構成もよくあります。
latencyはどのくらいに設定すればいい?
回線のRTT(往復遅延)の3〜4倍を目安にします。LAN内など安定した回線なら既定の120ms前後で十分ですが、モバイル回線や長距離のインターネット経由では200〜1000ms程度に増やすとロス耐性が上がります。遅延と安定性はトレードオフなので、実際の回線で映像が破綻しない最小値を探るのが実用的です。
暗号化はできる?
SRTはAESによる暗号化に対応しており、URLに passphrase= と pbkeylen=(16/24/32)を付けることで有効化できます。送信側と受信側で同じパスフレーズを指定する必要があります。インターネット越しの伝送ではパスフレーズの設定を推奨します。
受信したSRTを視聴者向けに配信したい
SRTはあくまで伝送(持ち込み・中継)に適したプロトコルです。多数の視聴者へ届けるには、受信したMPEG-TSをHLSやDASHにセグメント化して配信するのが定石です。HLS化の手順は関連記事を参照してください。
関連リソース
よく使うオプション・フィルタ・コーデック設定をまとめた PDF チートシートです。手元に置いておくと調べる時間を短縮できます。
関連記事
- HLSセグメント生成 — Webストリーミング用セグメントとプレイリストの作成
- DASHセグメント生成 — MPEG-DASH配信用の出力作成
- RTMPストリーミング — ライブ配信プラットフォームへの送出
- 動画の圧縮 — CRFとビットレート目標値
- NVENCハードウェアエンコード — GPUによる高速変換
テスト環境: ffmpeg 6.1.1 / Ubuntu 24.04(検証スクリプトで実行確認)
一次ソース: ffmpeg.org/ffmpeg-protocols.html#srt / trac.ffmpeg.org/wiki/StreamingGuide / srtalliance.org