Keyframe interval tuning for HLS: GOP discipline and segment alignment
Configure keyframe interval (GOP) so HLS segment boundaries are clean and rendition switches are seamless. Closed GOPs, scene-cut handling, and the keyint math for any framerate.
When to use this
You tune keyframe intervals when streaming via HLS or DASH — segment boundaries must align with keyframes (IDR frames in H.264 / IRAP frames in HEVC), or players can't cleanly switch renditions and start playback positions are imprecise. The standard pattern: closed GOP every 2 seconds, segment length matching GOP duration. Without explicit keyframe control, FFmpeg's default (250 frames or scene-cut detection) produces irregular GOP boundaries that break HLS segment alignment.
Command variants
ffmpeg -i input.mp4 \
-c:v libx264 -preset medium -crf 22 \
-x264opts "keyint=60:min-keyint=60:no-scenecut" \
-c:a copy \
output.mp4GOP every 60 frames (2s at 30fps). The standard HLS pattern.
ffmpeg -i input.mp4 \
-c:v libx264 -preset medium -crf 22 \
-x264opts "keyint=96:min-keyint=96:no-scenecut" \
-c:a copy \
output.mp4GOP every 96 frames (4s at 24fps). Common for film-rate content.
ffmpeg -i input.mp4 \
-c:v libx265 -preset medium -crf 23 -tag:v hvc1 \
-x265-params "keyint=60:min-keyint=60:no-scenecut" \
-c:a copy \
output.mp4libx265 uses x265-params instead of x264opts. Same logic.
ffmpeg -i input.mp4 \
-c:v libx264 -preset medium -crf 22 \
-g 60 -keyint_min 60 -sc_threshold 0 \
-c:a copy \
output.mp4-g, -keyint_min, -sc_threshold work across most codecs (H.264/HEVC/VP9). Less precise than codec-specific opts.
What each parameter does
keyint=NMaximum keyframe interval in frames. N=60 at 30fps = 2-second segments.
min-keyint=NMinimum keyframe interval. Setting equal to keyint prevents the encoder from inserting keyframes earlier than expected.
no-scenecutDisables scene-change keyframes. Without this, scene changes insert extra keyframes that don't align with segment boundaries — breaking HLS rendition switches.
-g (FFmpeg generic)Generic GOP size flag. Equivalent to keyint for most codecs. Less precise than codec-specific options.
-sc_threshold 0FFmpeg generic flag to disable scene-cut detection. Equivalent to no-scenecut in x264opts.
What this outputs
Encoded video with predictable, segment-aligned keyframe intervals. Segment lengths match GOP duration: 2-second segments need keyint=60 at 30fps; 4-second segments need keyint=120. Players can switch renditions cleanly at every segment boundary, and start-playback latency is bounded by segment length.
Pitfalls
- Default scene-cut detection inserts extra keyframes: the encoder makes "smart" decisions that ruin HLS segment alignment. Always disable with no-scenecut.
- Keyint vs framerate mismatch: keyint=60 at 24fps = 2.5s GOPs, not 2s. Calculate keyint = framerate × segment_seconds explicitly.
- min-keyint must equal keyint for closed GOPs: leaving min-keyint at the default (1) lets the encoder insert keyframes at any time, defeating segment alignment.
- NVENC GOP control is different: use -g and -force_key_frames for hardware encoders. The x264opts/x265-params syntax doesn't apply.
- Variable framerate sources break GOP math: if framerate changes mid-stream, fixed keyint produces irregular segment timing. Use -force_key_frames "expr:gte(t,n_forced*2)" for time-based instead of frame-based keyframes.
- Audio segment alignment: HLS audio segments should also align with video segment boundaries. This usually happens automatically with AAC, but manual verification is wise for production.
At production scale
Keyframe interval choice has compute implications at scale: shorter GOPs (1s) increase encoded file size by 5-15% because more keyframes mean less inter-frame prediction. 2-second GOPs are the production sweet spot for HLS; 4-second GOPs save file size at the cost of slightly longer rendition switch time. At >1M assets/month, the file-size delta from GOP choice translates to meaningful storage and CDN egress costs — pick the longest GOP that meets your latency requirements.
MpegFlow exposes GOP discipline as a per-stage parameter in the DAG manifest, with sensible defaults that produce HLS-compatible output without manual configuration. The audit log records the actual keyint produced (verified post-encode), so segment-alignment bugs are caught before delivery.