Create Low-Latency fMP4 with FFmpeg
This article explains how to generate a fragmented MP4 (fMP4) file optimized for low-latency streaming using FFmpeg. You will learn the essential FFmpeg flags, encoder settings, and command-line examples required to split your MP4 container into real-time playable chunks, reducing playback delay for HLS, DASH, and CMAF workflows.
Understanding fMP4 and Low Latency
Standard MP4 files contain a single metadata block called the
moov atom, which is typically written at the end of the
file. This structure requires players to download the entire metadata
block before playback can begin, making it unsuitable for live or
low-latency streaming.
Fragmented MP4 (fMP4) solves this by dividing the video into a
sequence of very short, self-contained segments (fragments). Each
fragment consists of a track fragment header (moof) and
media data (mdat). This allows the player to start
rendering video as soon as the first tiny fragment is received.
Key FFmpeg Flags for fMP4 Generation
To write an fMP4 file, you must use FFmpeg’s -movflags
option to alter the default behavior of the MP4 muxer. The most
important flags include:
empty_moov: Writes an initial, emptymoovatom at the start of the file without any sample data. This is mandatory for fragmented MP4.frag_keyframe: Forces the muxer to start a new fragment at every video keyframe (I-frame).default_base_moof: Writes the default base media decode time in the track fragment header, which is highly recommended for compatibility with DASH and HLS players.omit_tfhd_offset: Prevents the muxer from writing absolute offsets in track headers, keeping fragment sizes as small as possible.
Optimizing Encoder Settings for Low Latency
Enabling fMP4 is only half the battle. To achieve true low-latency, you must also configure the video encoder to generate frequent keyframes and avoid buffering frames.
- Set a Short GOP (Group of Pictures) Size: Use the
-gflag to force a keyframe at strict intervals (e.g., every 1 or 2 seconds). If your input frame rate is 30 fps, set-g 30or-g 60. - Disable Scene Cut Detection: Set
-sc_threshold 0to prevent the encoder from inserting extra, unexpected keyframes that disrupt fragment uniformity. - Use Low-Latency Tuning: For the
libx264orlibx265encoders, use the-tune zerolatencyflag to disable frame reordering (B-frames) and ensure frames are outputted immediately.
Step-by-Step FFmpeg Command
Below is the optimized FFmpeg command to convert an incoming live RTSP stream, webcam feed, or standard video file into a low-latency fMP4 stream:
ffmpeg -re -i input.mp4 \
-c:v libx264 -preset ultrafast -tune zerolatency \
-g 30 -keyint_min 30 -sc_threshold 0 \
-c:a aac -b:a 128k \
-f mp4 \
-movflags empty_moov+frag_keyframe+default_base_moof+omit_tfhd_offset \
output.mp4Command Breakdown:
-re: Forces FFmpeg to read the input at its native frame rate (essential for simulating live streams).-preset ultrafast: Minimizes encoding CPU time to reduce initial latency.-g 30 -keyint_min 30: Forces a keyframe exactly every 30 frames (1 second at 30 fps).-movflags empty_moov+frag_keyframe+default_base_moof+omit_tfhd_offset: Tells the MP4 muxer to output standard-compliant fMP4 fragments at every keyframe boundary.
How to Verify Your fMP4 File
You can verify if your output file is correctly fragmented using
ffprobe. Run the following command:
ffprobe -v trace output.mp4 2>&1 | grep -E "moof|mdat"If the file is successfully fragmented, the output will show
alternating moof and mdat boxes repeating
throughout the file, confirming that your low-latency fMP4 structure is
intact and ready for chunk-based delivery.