How to Split Streams with the FFmpeg Tee Protocol

This guide explains how to use FFmpeg's tee muxer to duplicate and distribute a single audio/video stream across multiple network destinations simultaneously. By routing your output through tee, you can stream to multiple endpoints—such as concurrent RTMP live platforms or UDP network targets—while encoding the source media only once, drastically reducing CPU overhead and memory usage.

The Basic Syntax of the tee Muxer

While commonly discussed as a protocol, FFmpeg implements stream splitting via the tee pseudo-muxer (-f tee). It takes multiple outputs separated by the pipe (|) character within quotes. Each output can specify its own format and options inside brackets [...].

The fundamental command structure is:

ffmpeg -i input.mp4 -c:v libx264 -c:a aac -f tee -map 0:v -map 0:a "[f=flv]rtmp://server1/live/stream1|[f=flv]rtmp://server2/live/stream2"

Splitting to Multiple RTMP Destinations

A common network use case is broadcasting a single live stream to two different ingest servers (such as YouTube and Twitch). Instead of running two separate FFmpeg instances or re-encoding the stream, encode once and write to both targets:

ffmpeg -re -i input.mp4 \
  -c:v libx264 -preset veryfast -b:v 4500k -maxrate 4500k -bufsize 9000k \
  -c:a aac -b:a 160k \
  -flags +global_header \
  -f tee -map 0:v -map 0:a \
  "[f=flv]rtmp://a.rtmp.youtube.com/live2/YOUR_YT_KEY|[f=flv]rtmp://live.twitch.tv/app/YOUR_TWITCH_KEY"

The -flags +global_header flag is recommended when multiplexing to container formats like FLV to ensure headers are properly transmitted to all RTMP endpoints.

Splitting to Heterogeneous Network Protocols (RTMP + UDP/RTP)

You can output to completely different container formats and network transport protocols from the same pipeline:

ffmpeg -re -i input.mp4 \
  -c:v libx264 -c:a aac \
  -f tee -map 0:v -map 0:a \
  "[f=flv]rtmp://live.example.com/app/stream|[f=mpegts]udp://239.255.0.1:1234?pkt_size=1316"

In this example, FFmpeg sends one stream as FLV over RTMP and simultaneously packages the identical bitstream as an MPEG-TS container over UDP multicast.

Preventing Stream Failures with onfail=ignore

By default, if any target in a tee output encounters a network error (such as a disconnected socket or server timeout), the entire FFmpeg process terminates. To keep streaming to the remaining healthy endpoints if one fails, apply onfail=ignore to each output:

ffmpeg -re -i input.mp4 \
  -c:v libx264 -c:a aac \
  -f tee -map 0:v -map 0:a \
  "[f=flv:onfail=ignore]rtmp://primary.live.com/stream|[f=flv:onfail=ignore]rtmp://backup.live.com/stream"

Independent Stream Mapping

The tee muxer allows sending different stream tracks to different network endpoints. For example, if you want one output to receive both video and audio, but a secondary network monitor to receive only the video stream:

ffmpeg -re -i input.mp4 \
  -c:v libx264 -c:a aac \
  -f tee \
  "[select=\'v,a\':f=flv]rtmp://live.example.com/stream|[select=\'v\':f=mpegts]udp://192.168.1.50:5000"

Key Considerations

  • Bandwidth Requirements: The tee muxer duplicates data at the application layer. If you are sending two 5 Mbps streams, your outbound network interface must sustain at least 10 Mbps of upload bandwidth.
  • Escaping Special Characters: If your target URLs contain special characters or colons inside parameters, wrap the URL components in single quotes or escape characters with backslashes (\) according to your shell environment.