What You Will Learn

  • How SRT (Secure Reliable Transport) works, and how it differs from RTMP and HLS
  • How to verify that your FFmpeg build includes libsrt support
  • Minimal sender (caller) and receiver (listener) commands
  • When to use each connection mode: caller / listener / rendezvous
  • The meaning of the key parameters pkt_size, latency, and mode, plus tuning guidance
  • How to re-encode for delivery when your source doesn’t match SRT streaming requirements
  • How to handle errors such as “Protocol not found” and “Connection timed out”

Tested with: FFmpeg 6.1 (verified against real FFmpeg)
Supported OS: Windows / macOS / Linux


What Is SRT (vs. RTMP and HLS)

SRT (Secure Reliable Transport) is a low-latency transport protocol developed by Haivision and later open-sourced. Built on top of UDP, it provides packet-loss recovery through ARQ (Automatic Repeat reQuest) and secure transport via AES encryption. Its defining strength is delivering reliable video even over unstable, unpredictable connections like the public internet — without adding the kind of latency that TCP would.

Here is how SRT compares with the other major streaming approaches:

ProtocolTransportLatencyLoss ResiliencePrimary Use
SRTUDP (with ARQ)Low (a few hundred ms and up)HighContribution/relay, field → cloud
RTMPTCPMediumMedium (retransmission adds latency)Ingest to streaming platforms
HLSHTTP (TCP)High (several seconds to tens of seconds)HighLarge-scale delivery to viewers

Because RTMP is TCP-based, packet loss tends to pile up latency through retransmission, and a growing number of platforms are scaling back support for it in recent years. HLS excels at scalable final delivery to viewers, but its latency is high, making it unsuitable for contribution use cases where you need to “bring in” video from the field to a studio or the cloud.

SRT is optimized exactly for this contribution and site-to-site relay role, and its connection modes for traversing firewalls and NAT make it more flexible than RTMP. A common architecture is to receive video over SRT and then convert it to HLS or DASH for delivery to viewers.


Prerequisite: Verifying libsrt Support

To use SRT in FFmpeg, your build must have --enable-libsrt turned on. First, confirm that your local FFmpeg supports the SRT protocol.

ffmpeg -protocols | grep srt

If the output includes srt, you are good to go. If nothing is printed, that build lacks libsrt support.

       srt

What to do if it’s not supported:

  • Linux: Your distribution’s official package may lack support. In many cases, the easiest path is to use a static build that bundles libsrt, such as John Van Sickle’s builds.
  • macOS: Homebrew’s ffmpeg includes libsrt by default (brew install ffmpeg).
  • Windows: The official distribution builds from gyan.dev and BtbN (full / gpl editions) include libsrt.
  • If you build it yourself, install libsrt first, then specify ./configure --enable-libsrt.

If you see Protocol not found when using an SRT URL, it almost certainly means your build lacks libsrt support.


Minimal Send/Receive Commands

SRT typically carries MPEG-TS (-f mpegts). Because SRT transports a byte stream rather than individual media frames, the self-contained MPEG-TS container is the standard choice.

First, start the receiver (listening in listener mode and saving to a file).

ffmpeg -i "srt://0.0.0.0:9000?mode=listener" -c copy received.mp4

0.0.0.0 tells it to listen on all interfaces, and 9000 is an arbitrary UDP port. The receiver must be in a listening state before the sender starts.

Next, send video from the sender (caller).

ffmpeg -re -i input.mp4 -c copy -f mpegts "srt://receiver-host:9000?pkt_size=1316"

Replace receiver-host with the receiver’s hostname or IP address. Here we pass the codecs through unchanged with -c copy and wrap them in an MPEG-TS container with -f mpegts for transmission.

  • -re reads the input at its native frame rate, which is essential for sending a file at real-time speed as if it were a live source. Without it, FFmpeg would read the file as fast as possible, which is not live transmission.
  • pkt_size=1316 is the size of the UDP payload to send (discussed below).

The simplest combination is to leave the mode out of the receiver’s URL and set mode=caller (the default) on the sender. Conversely, you can make the receiver the caller and the sender the listener — any arrangement works as long as one side listens and the other initiates.


Connection Modes (caller / listener / rendezvous)

In SRT, the connection mode decides which side initiates the connection. You specify it with the mode= parameter in the URL.

ModeBehaviorTypical Use
callerConnects out to the peer (the initiating side)A sending PC transmits to a receiving server with a fixed IP
listenerWaits for incoming connections (the receiving side)A receiving server in the cloud waits for connections
rendezvousBoth sides initiate the connection simultaneouslyWhen both sides are behind NAT/firewalls

caller ↔ listener (the most basic): set one side to listener to wait for connections and the other to caller to initiate. The caller side must be able to reach the peer’s global IP/port.

# Receiver (listener)
ffmpeg -i "srt://0.0.0.0:9000?mode=listener" -c copy received.mp4

# Sender (caller, the default when mode is omitted)
ffmpeg -re -i input.mp4 -c copy -f mpegts "srt://receiver-host:9000?pkt_size=1316"

rendezvous: use this when both ends are behind NAT and neither can easily reach the other’s global address directly. Both sides specify the same mode=rendezvous and simultaneously initiate a connection to the peer’s address:port.

# On both sides (host-A / host-B are each the peer's address)
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

Note that when mode is omitted, it is generally treated as caller if a hostname is specified, and as listener if a listening address such as 0.0.0.0 is given. To make intent clear, we recommend writing it explicitly in production.


Key Parameters (pkt_size / latency / mode)

SRT URLs take various parameters as a query string in the form ?key=value&key2=value2.

pkt_size

?pkt_size=1316

pkt_size=1316 is the payload size (in bytes) of a single packet to send. MPEG-TS packets are 188 bytes, and seven times that (188 × 7 = 1316) is this value. 1316 bytes fits within a standard Ethernet MTU (1500 bytes) even after adding IP/UDP/SRT headers, so it avoids IP fragmentation while sending efficiently, which is why it is widely recommended for SRT/UDP transmission. When sending MPEG-TS over SRT, attaching pkt_size=1316 is generally all you need.

latency

?latency=200

latency= is the SRT receiver buffer in milliseconds (the grace period during which the receiver waits for packet retransmission). When the link drops packets, SRT fills the gaps with ARQ (retransmission) within this buffer window.

  • Increasing the value gives more chances for retransmission, making the video less likely to break up even over lossy, unstable links. In exchange, end-to-end latency increases.
  • Decreasing the value reduces latency but lowers loss resilience.
  • The default is roughly around 120 ms. As a rule of thumb, set it to about 3–4× the RTT (round-trip time) and adjust according to link quality.

An example that explicitly sets the buffer for an unstable link:

ffmpeg -re -i input.mp4 -c copy -f mpegts "srt://receiver-host:9000?pkt_size=1316&latency=200"

When listing multiple parameters, join them with &.

mode

As described above, this decides the connection roles (caller / listener / rendezvous). If the caller and listener sides are mismatched, the connection will not be established, so configure the pair so they don’t conflict.


Re-Encoding for Delivery

-c copy is the lightest option because it passes the source codecs through unchanged, but you should re-encode when the input’s codec or GOP structure doesn’t match the delivery requirements. For example, the receiver may expect H.264 + AAC MPEG-TS, or you may want a consistent keyframe interval.

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"

What each option does:

OptionRole
-c:v libx264Re-encode video to H.264 (broadly playable)
-preset veryfastA low-latency, low-CPU preset suited to live transmission
-b:v 4000k / -maxrate 4000k / -bufsize 8000kPins the bitrate to 4 Mbps and caps momentary peaks
-pix_fmt yuv420pStandardizes on a highly compatible pixel format
-g 60Inserts a keyframe every 60 frames (a 2-second interval at 30 fps)
-c:a aac -b:a 128kRe-encodes audio to AAC at 128 kbps

By setting -maxrate and -bufsize to cap the bitrate ceiling, you prevent loss caused by peaks that exceed the link bandwidth. Inserting periodic keyframes with -g 60 speeds up recovery when the receiver reconnects. If your CPU is short on headroom, -preset ultrafast lowers the load further, though at the cost of compression efficiency.


Common Errors and Fixes

Protocol not found

This occurs when FFmpeg is built without libsrt support. Check with ffmpeg -protocols | grep srt, and if nothing appears, switch to a build that bundles libsrt (Homebrew, the full editions from gyan.dev/BtbN, a static build, etc.).

Can’t Connect (Fails to Establish Before Timeout)

The three most common causes are:

  • Port not open: SRT uses UDP. Allow UDP inbound on the relevant port (e.g., 9000) in the receiver’s firewall/security group. Opening only TCP will not work.
  • Mode mismatch: one side must be caller and the other listener. With both as caller or both as listener, the connection will never be established.
  • Startup order: put the listener side into a listening state first, then start the caller side.

Video Breaks Up Due to Packet Loss

If you see block noise or video dropouts, the retransmission buffer is insufficient for the link’s packet loss. You can improve it by increasing latency.

ffmpeg -re -i input.mp4 -c copy -f mpegts "srt://receiver-host:9000?pkt_size=1316&latency=500"

If that still doesn’t help, the bitrate may be too high for the link bandwidth. Use re-encoded delivery and lower -maxrate to leave more headroom in the link.

Connection timed out

This tends to happen when both ends are behind NAT and the caller cannot reach the listener directly. In that case, setting both sides to mode=rendezvous and attempting simultaneous connections from both ends can sometimes punch through.

ffmpeg -re -i input.mp4 -c copy -f mpegts "srt://peer-host:9000?mode=rendezvous&pkt_size=1316"

In environments where even that doesn’t work, the reliable approach is to stand up a relay server with a global IP (such as a VPS) as the listener and have both ends connect to it as callers.


FAQ

Should I choose SRT or RTMP?

SRT has the edge for contribution use cases — bringing video in from the field or a remote site to a studio or the cloud — as well as for unstable links and situations where low latency matters. On the other hand, RTMP is still often the standard for ingest into streaming platforms (such as YouTube Live), so use RTMP in those cases. A common architecture combines the two: SRT for field → cloud, and RTMP for cloud → platform.

What value should I set for latency?

Use about 3–4× the link’s RTT (round-trip time) as a guideline. For stable links such as within a LAN, the default of around 120 ms is plenty, but over mobile networks or long-distance internet paths, increasing it to roughly 200–1000 ms improves loss resilience. Since latency and stability are a trade-off, the practical approach is to find the smallest value at which the video doesn’t break up on your actual link.

Can I encrypt the stream?

Yes — SRT supports AES encryption, which you enable by adding passphrase= and pbkeylen= (16/24/32) to the URL. You must specify the same passphrase on both the sender and the receiver. For transmission over the internet, setting a passphrase is recommended.

I want to deliver received SRT to viewers

SRT is fundamentally a transport (contribution/relay) protocol. To reach many viewers, the standard practice is to segment the received MPEG-TS into HLS or DASH for delivery. See the related articles for the HLS conversion procedure.



Tested with: ffmpeg 6.1.1 / Ubuntu 24.04 (verified against real FFmpeg)
Primary sources: ffmpeg.org/ffmpeg-protocols.html#srt / trac.ffmpeg.org/wiki/StreamingGuide / srtalliance.org