FFmpeg Tee Muxer: Stream to RTMP and Save Locally

This guide explains how to use the FFmpeg tee muxer to split a single media stream into multiple outputs simultaneously. By leveraging this method, you can broadcast a live stream to an RTMP destination (such as YouTube, Twitch, or a custom media server) while archiving the identical raw or encoded video to a local disk file in one single, resource-efficient FFmpeg process.

The Basic Command

To stream to RTMP and save to a local MP4 file without re-encoding twice, use the following syntax:

ffmpeg -re -i input.mp4 -c:v libx264 -preset veryfast -b:v 3000k -maxrate 3000k -bufsize 6000k \
-c:a aac -b:a 128k -f tee -map 0:v -map 0:a \
"[f=flv]rtmp://your-rtmp-server/live/streamkey|[f=mp4]local_backup.mp4"

If your source input is already encoded in an RTMP-compatible format (H.264 video and AAC audio), you can pass through the streams without re-encoding to save CPU power:

ffmpeg -re -i input.mp4 -c copy -f tee -map 0:v -map 0:a \
"[f=flv]rtmp://your-rtmp-server/live/streamkey|[f=mp4]local_backup.mp4"

Command Breakdown

  • -re: Reads the input at its native frame rate. This is required when streaming from a pre-recorded file to simulate a real-time live broadcast. If using a capture device (like a webcam or capture card), omit this flag.
  • -c:v and -c:a: Specifies the video and audio codecs. Encoding happens once before passing the data to the muxer, ensuring duplicate encoding work is avoided.
  • -f tee: Activates the tee muxer, which allows writing identical packets to multiple outputs.
  • -map 0:v -map 0:a: Explicitly maps all video and audio streams to the outputs. The tee muxer requires explicit stream mapping to ensure tracks are properly routed to each sub-destination.
  • "[f=flv]rtmp://...|[f=mp4]output.mp4": The core of the tee muxer. Individual outputs are separated by a pipe (|) character, and parameters for each output are wrapped in square brackets:
    • [f=flv]: Forces the FLV container format required by RTMP ingest servers.
    • [f=mp4]: Defines the container format for the local file output.

Preventing Stream Drops with onfail=ignore

By default, if one output in the tee muxer fails (such as a temporary network disconnection to your RTMP server), the entire FFmpeg process terminates, killing your local recording. To keep the local recording running even if the RTMP connection drops, add the onfail=ignore flag to the RTMP destination:

ffmpeg -re -i input.mp4 -c copy -f tee -map 0:v -map 0:a \
"[f=flv:onfail=ignore]rtmp://your-rtmp-server/live/streamkey|[f=mp4]local_backup.mp4"

Handling MP4 File Finalization

Standard MP4 files store their metadata index (the moov atom) at the end of the file when FFmpeg safely closes. If an unexpected power outage or crash occurs, the MP4 recording may become corrupted. You can mitigate this by passing the movflags=faststart or movflags=frag_keyframe option directly to the MP4 output inside the tee string:

ffmpeg -re -i input.mp4 -c:v libx264 -c:a aac -f tee -map 0:v -map 0:a \
"[f=flv:onfail=ignore]rtmp://your-rtmp-server/live/streamkey|[f=mp4:movflags=frag_keyframe+empty_moov]local_backup.mp4"

Alternatively, you can save the local file using the Matroska container (.mkv), which is inherently resilient to crashes and does not require complex finalization flags:

ffmpeg -re -i input.mp4 -c copy -f tee -map 0:v -map 0:a \
"[f=flv:onfail=ignore]rtmp://your-rtmp-server/live/streamkey|[f=matroska]local_backup.mkv"