FFmpeg Tee Muxer: Transcode and Copy Streams

This guide explains how to configure FFmpeg's tee muxer to output a stream-copied feed to one target while simultaneously transcoding it for another. Because the tee muxer operates at the muxer level after encoding has already taken place, you cannot transcode directly inside the tee slave definition. Instead, you must map the source streams multiple times, set up both the copy and transcode operations in the main FFmpeg pipeline, and then use the tee muxer's select option to direct the respective streams to each destination.

The Configuration Command

ffmpeg -i input.mp4 \
  -map 0:v -c:v:0 copy \
  -map 0:v -c:v:1 libx264 -preset veryfast -b:v:1 3000k \
  -map 0:a -c:a copy \
  -f tee "[select=\'v:0,a:0\']backup.mp4|[select=\'v:1,a:0\':f=flv]rtmp://live.example.com/app/stream"

Breakdown of the Pipeline

1. Stream Mapping and Codec Setup

  • -map 0:v -c:v:0 copy: Takes the video stream from the first input (0:v) and assigns it to output video stream index 0 (v:0) without re-encoding (copy).
  • -map 0:v -c:v:1 libx264 -preset veryfast -b:v:1 3000k: Maps the same input video stream a second time to output video stream index 1 (v:1) and transcodes it using the libx264 encoder.
  • -map 0:a -c:a copy: Maps the input audio stream to be copied directly without re-encoding. If transcoding audio is also required for the second output, map 0:a twice with distinct codec configurations in the same manner as the video.

2. The tee Muxer Configuration

The -f tee argument accepts pipe-separated (|) slave definitions wrapped in brackets:

  • Destination 1 (Stream Copy): [select=\'v:0,a:0\']backup.mp4 selects the stream-copied video (v:0) and the copied audio (a:0) and packages them into a local file. The file container is inferred from the .mp4 extension.
  • Destination 2 (Transcoded Stream): [select=\'v:1,a:0\':f=flv]rtmp://live.example.com/app/stream selects the transcoded video (v:1) along with the copied audio (a:0). Since RTMP targets do not use file extensions to determine the format, the container format is explicitly specified using :f=flv.

Escaping and Options

  • Quoting select values: Commas and colons inside tee target parameters must be properly escaped. In standard Bash shells, wrap the entire slave block in quotes and escape the internal parameter quotes: [select=\'v:0,a:0\'].
  • Handling Connection Drops: For network destinations, append :onfail=ignore to the bracketed options (for example, [select=\'v:1,a:0\':f=flv:onfail=ignore]). This ensures that network failure on the transcoded live stream does not terminate the local file recording.