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.mp4

Parameter Breakdown

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.mp4

Trade-offs of Using Intra-Refresh

While intra-refresh is highly effective for smoothing out network traffic, it comes with minor trade-offs:

  1. 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 60 is used at 30 fps).
  2. 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.