UDPストリーミングとは
UDP(User Datagram Protocol)は、データを送る方式(トランスポートプロトコル)のひとつです。TCPと違い、送る前に相手と接続を確立しません(コネクションレス)。接続の手続きも再送もしないぶん処理が軽く、少ない遅延で映像を送れます。FFmpegは udp:// で、このUDPに直接対応しています。
ただしUDPには、途中で失われたパケット(パケットロス)を取り戻す仕組みがありません。SRTや、TCPを使うRTMPと違い、消えたパケットは送り直されません。ネットワークでパケットが落ちれば、そのぶん映像が乱れます。
向いている用途と向いていない用途は、次のとおりです。
| 向いている用途 | 向いていない用途 |
|---|---|
| 管理されたLAN内の伝送 | インターネット越しの配信 |
| スイッチ直結など低ロス環境 | 無線・モバイルなどロスが多い経路 |
| 超低遅延が必要な現場(中継・モニタリング) | ロス耐性・信頼性が必須の配信 |
UDPで送るときの入れ物(コンテナ)には、配信に向いたMPEG-TS(MPEG Transport Stream)を使います。FFmpegでは -f mpegts で指定します。MPEG-TSは188バイト固定長のパケットでできていて、途中から受信を始めても読み取れます(自己同期)。そのため、ライブの伝送に向いています。
ユニキャスト送受信
ユニキャストは、1つの送信元から1つの受信先へ送る、1対1の伝送です。送り先として、受信側のIPアドレスとポート番号を指定します。
送信(再エンコードなし)
入力がすでに配信に向いたコーデック(H.264 + AAC)なら、再エンコードせずにそのまま流すのがいちばん軽い方法です。
ffmpeg -re -i input.mp4 -c copy -f mpegts "udp://192.168.1.50:1234"
-re:ファイルを本来の速さ(フレームレートどおり)で読み込みます。付けないとFFmpegはできるだけ速くファイルを送ってしまい、ライブの伝送になりません。リアルタイム配信では必須です。-c copy:再エンコードせず、そのままコピーします。CPUの負荷が低く、画質も落ちません。-f mpegts:コンテナをMPEG-TSにします。udp://192.168.1.50:1234:送り先(受信する側)のIPアドレスとポート番号です。
受信して保存
受信側では 0.0.0.0 を指定して待ち受け、届いた映像をファイルに保存できます。
ffmpeg -i "udp://0.0.0.0:1234" -c copy received.mp4
0.0.0.0 は、このマシンのすべてのネットワークインターフェースで、指定したポートを受信するという意味です。-c copy なので、再エンコードせずにそのまま received.mp4 に書き出します。
受信して再生(ffplay)
保存せずに映像を見るだけなら、ffplay で再生できます。
ffplay "udp://0.0.0.0:1234"
送信側と受信側を別々のマシンで(または同じマシンの別のターミナルで)起動すると、LANでの低遅延の伝送をすぐに試せます。
マルチキャスト配信
マルチキャストを使うと、1回の送信で複数の受信者に同時に届けられます。送信側はネットワークに1本のストリームを流すだけです。対応したスイッチやルーターが、受け取りたい受信者の分だけ複製して届けます。受信者が増えても、送信側の帯域は増えません。
マルチキャストには、専用のIPアドレスの範囲を使います。よく使うのは 239.0.0.0/8(管理スコープ。組織の中で使うために予約された範囲)です。インターネット上のアドレスとぶつからないので、LAN内の配信に安心して使えます。
マルチキャスト送信
ffmpeg -re -i input.mp4 -c copy -f mpegts "udp://239.0.0.1:1234?pkt_size=1316"
ユニキャストとの違いは、宛先がマルチキャストアドレス(239.0.0.1)になっている点です。pkt_size=1316 は、1回に送るパケットの大きさです。ポート番号(1234)は、用途に合わせて変えてかまいません。
マルチキャスト受信
受信側は、送信側と同じマルチキャストアドレスを指定します。
ffplay "udp://239.0.0.1:1234"
同じアドレスを指定した受信者は、複数台あっても全員が同じストリームを受け取れます。デジタルサイネージや教室での一斉配信のように、同じ映像をたくさんの端末に届けたいときに便利です。
マルチキャストが届くかどうかは、ルーターやスイッチの設定(IGMPへの対応など)で決まります。家庭用ルーターや一部のスイッチは、マルチキャストを通さないことがあります。届かないときは、ネットワーク機器の設定を確認してください。
主要パラメータ(pkt_size・fifo_size・overrun_nonfatal)
UDPの設定は、URLの後ろに ?key=value&... の形で付けます。
pkt_size
pkt_size は、UDPで1回に送るパケットのバイト数です。MPEG-TSのパケットは188バイト固定なので、その整数倍にするのが基本です。
188 バイト × 7 = 1316 バイト
pkt_size=1316 は、MPEG-TSのパケットちょうど7個分です。一般的なイーサネットのMTU(1回に送れるパケットの最大サイズ。1500バイト)にも収まるので、パケットが途中で分割される(IPフラグメンテーション)のを避けられます。UDPでMPEG-TSを流すときの推奨値です。
ffmpeg -re -i input.mp4 -c copy -f mpegts "udp://192.168.1.50:1234?pkt_size=1316"
fifo_size と overrun_nonfatal
受信側は、届いたパケットをいったん内部のバッファ(FIFOバッファ。リングバッファとも呼びます)にためてから処理します。送る速さが速いときや、受信側の処理が一時的に追いつかないときは、このバッファがあふれることがあります。
fifo_size:受信バッファの大きさです。大きくすると、一時的にどっと届いたデータを受け止められます。単位はパケットの数で、既定値より大きくすると途切れにくくなります。overrun_nonfatal=1:バッファがあふれても(オーバーラン)、エラーで止まらずに受信を続けます。多少データが欠けても、受信を止めたくないときに使います。
両方を使った受信コマンドです。
ffmpeg -i "udp://0.0.0.0:1234?overrun_nonfatal=1&fifo_size=1000000" -c copy received.mp4
fifo_size=1000000 で大きめのバッファを用意し、overrun_nonfatal=1 であふれても止まらないようにしています。「Circular buffer overrun」と出て受信が止まるときは、この2つで安定させます。
再エンコードして送出する
入力のビットレートが大きすぎる、コーデックが対応していない、といった場合は、送るときに再エンコードします。次の例は、遅延を抑え、映像のビットレートを 2Mbps 前後に抑える設定です。
ffmpeg -re -i input.mp4 -c:v libx264 -preset veryfast -b:v 2000k -maxrate 2000k -bufsize 4000k -pix_fmt yuv420p -g 60 -c:a aac -b:a 128k -f mpegts "udp://192.168.1.50:1234?pkt_size=1316"
各オプションの意味:
| オプション | 意味 |
|---|---|
-c:v libx264 |
映像をH.264にエンコード |
-preset veryfast |
エンコード速度優先(ライブで遅延を抑える) |
-b:v 2000k |
映像ビットレート目標 2Mbps |
-maxrate 2000k / -bufsize 4000k |
2Mbpsを長く超えないようにする。キーフレームなどで一瞬超えることはあり、単純な映像では下がる |
-pix_fmt yuv420p |
互換性の高いピクセルフォーマット |
-g 60 |
キーフレームの間隔を最大60フレームにする(受信開始点を増やす) |
-c:a aac -b:a 128k |
音声をAAC 128kbpsにエンコード |
-f mpegts |
MPEG-TSコンテナで送出 |
-maxrate と -bufsize を付けると、映像のビットレートが2Mbpsを長く超えることはなくなります。ただし、パケットの送り方までは平らになりません。FFmpegはフレームができるとすぐに送るので、キーフレームは2Mbpsを大きく超える勢いで一度に送られます。音声やMPEG-TSのデータも上乗せされるので、ネットワークの帯域には余裕を残してください。-g 60 でキーフレームを定期的に入れておくと、受信側が途中からつないでも、すぐに映像が出ます。
RTMP・SRTとの使い分け
ライブ伝送のプロトコルは、用途に合わせて選びます。
| プロトコル | トランスポート | ロス回復 | 主な用途 |
|---|---|---|---|
| UDP | UDP | 無し | LAN内の超低遅延伝送・モニタリング |
| SRT | UDP + 再送 | 有り(ARQ) | 不安定な回線・インターネット越しの低遅延配信 |
| RTMP | TCP | 有り(TCP) | 配信プラットフォームへの入稿(YouTube/Twitch等) |
選び方の目安:
- UDP:自分たちで管理している閉じたLANで、とにかく遅延を小さくしたいとき。スイッチに直結するような、パケットがほとんど落ちない環境が前提です。インターネット越しや、ロスの多い経路には向きません。
- SRT:インターネット越しでも、遅延を小さく保ちたいとき。UDPをもとにしていますが、独自の再送(ARQ)で失われたパケットを取り戻せます。
- RTMP:配信サービスに映像を送るとき。多くのサービスが受け付けていて、TCPを使うので確実に届きます。
よくあるエラーと対処
受信できない
次の順に確認します。
- ポート番号:送信側と受信側で同じポート(例:
1234)を指定しているか。 - ファイアウォール:受信側のファイアウォールが、そのUDPポートを止めていないか。Windowsや、Linux(ufw/firewalld)で受信ポートを開けます。
- マルチキャスト:ルーターやスイッチがマルチキャスト(IGMP)を転送しない設定だと届きません。同じスイッチにつないだ機器どうしで試す、ネットワーク機器のマルチキャスト設定を確認する、といった方法で原因を絞り込みます。
映像が乱れる
ブロックノイズや音飛びが出るなら、パケットが落ちている可能性が高いです。UDPは落ちたパケットを取り戻せないので、ネットワークの側で対処します。
- 帯域に余裕を持たせる(
-maxrateを下げてビットレートを抑える、有線でつなぐ)。 - 経路の混雑(輻輳)を解消する。
- どうしてもパケットが落ちる経路なら、失われたパケットを取り戻せるSRTへの切り替えを考えます。
Circular buffer overrun
受信側のバッファがあふれたことを示すエラーです。受信の処理が、届くデータの量に追いつかないときに出て、overrun_nonfatal=1 を付けていなければ、そこで受信が止まります。
ffmpeg -i "udp://0.0.0.0:1234?overrun_nonfatal=1&fifo_size=1000000" -c copy received.mp4
fifo_size を大きくしてバッファを増やし、overrun_nonfatal=1 であふれても止まらないようにします。
遅延が大きい
fifo_size は受け止められる量の上限なので、大きくしただけでは遅延は増えません。遅延が増えるのは、受信側の処理が追いつかず、バッファにデータがたまったときです。遅延をいちばん小さくしたいなら、再エンコードの -preset を速いものにし、受信側の処理が遅れないようにします。
関連記事
よくある質問
UDPとSRTはどちらを使うべき?
管理されたLANで、パケットがほとんど落ちないなら、軽くて遅延がとても小さいUDPを選びます。インターネット越しや無線のように、パケットが落ちる経路では、落ちたパケットを取り戻せる(ARQ)SRTが向いています。
pkt_size はなぜ 1316 なのか?
MPEG-TSのパケットは188バイト固定で、イーサネットのMTU(1500バイト)に収まるのは7個分(188×7=1316)までだからです。FFmpegの既定の1472バイトもMTUには収まりますが、188の倍数ではないので、TSのパケットが2つのUDPパケットにまたがります。UDPでMPEG-TSを流すときの定番の値です。
マルチキャストアドレスはどの範囲を使えばいい?
LAN内で使うなら 239.0.0.0/8(管理スコープ)が安全です。組織の中で使うために予約されていて、インターネット上のアドレスとぶつかりません。受信側が送信側と同じアドレスとポートを指定すれば、複数台で同時に同じストリームを受け取れます。
-re を付け忘れるとどうなる?
FFmpegがファイルをできるだけ速く送ってしまい、受信側がリアルタイムで処理しきれなくなります。ファイルをライブのように流すときは、本来の速さで読み込む -re が必須です。