FFmpeg Intra-Refresh: Prevent H.264 I-Frame Spikes
This article explains how to configure the intra-refresh option in H.264 encoding using FFmpeg to eliminate bitrate spikes caused by keyframes (I-frames). You will learn the specific command-line parameters required to enable this feature, how it distributes intra-coded data across multiple frames, and the benefits and trade-offs it brings to low-latency live streaming.
The Problem with I-Frame Spikes
In standard H.264 video encoding, the encoder periodically inserts an Instantaneous Decoder Refresh (IDR) frame, commonly known as an I-frame or keyframe. Because I-frames contain complete image data without referring to other frames, they are significantly larger than P-frames (predictive) and B-frames (bi-directional).
In bandwidth-constrained or low-latency streaming environments, these massive I-frames cause sudden, dramatic spikes in bitrate. These spikes can saturate network buffers, leading to packet loss, frame drops, and playback stutter.
How Intra-Refresh Works
Intra-refresh (also called Periodic Intra-Refresh or PIR) eliminates these spikes by eliminating traditional, full-frame I-frames entirely after the very first frame.
Instead of sending a whole keyframe at once, the encoder refreshes the video by inserting a moving column or block of intra-coded macroblocks across a sequence of consecutive P-frames. Over a set number of frames—determined by the Group of Pictures (GOP) size—the entire screen is refreshed. This spreads the data size of a single I-frame evenly over multiple frames, resulting in a highly consistent, flat bitrate.
FFmpeg Command for H.264 Intra-Refresh
To enable intra-refresh in FFmpeg using the standard
libx264 encoder, you must use the
-intra-refresh 1 flag and define your GOP size with the
-g option.
Here is the recommended FFmpeg command:
ffmpeg -i input.mp4 -c:v libx264 -intra-refresh 1 -g 60 -keyint_min 60 -b:v 2M000k -bufsize 2M output.mp4Parameter Breakdown
-c:v libx264: Specifies the H.264 encoder.-intra-refresh 1: Enables the periodic intra-refresh feature.-g 60: Sets the GOP (Group of Pictures) size. In intra-refresh mode, this number defines how many frames it takes to complete one full refresh cycle of the screen. For example, at 30 frames per second, a GOP of 60 means the screen fully refreshes every 2 seconds.-keyint_min 60: Prevents the encoder from automatically creating IDR frames earlier than the specified GOP size.-b:v 2Mand-bufsize 2M: Sets the target bitrate and buffer size to enforce strict constant bitrate (CBR) control, maximizing the benefits of the flattened bitrate.
Alternatively, you can pass this option directly to the x264 encoder
library using the -x264-params flag:
ffmpeg -i input.mp4 -c:v libx264 -x264-params intra-refresh=1 -g 60 output.mp4Trade-offs of Using Intra-Refresh
While intra-refresh is highly effective for smoothing out network traffic, it comes with minor trade-offs:
- Seeking/Fast-Forwarding: Because there are no
complete keyframes, if a viewer joins a live stream or seeks to a new
timestamp mid-way, they will experience a brief moment of visual tearing
or “smearing” until the refresh cycle completes (e.g., up to 2 seconds
if
-g 60is used at 30 fps). - Slightly Lower Compression Efficiency: Overall compression efficiency may be slightly lower compared to standard GOP structures, meaning you might need a marginally higher bitrate to achieve the exact same visual quality.