Extract I-Frames in FFmpeg Using the Select Filter
This guide explains how to use FFmpeg's select video
filter to isolate specific video frames based on criteria such as
picture type. By targeting frame properties like I-frames (intra-coded
keyframes), you can efficiently extract scene headers, thumbnails, or
analyze video structure directly from the command line without
re-encoding unnecessary content.
The Basic Syntax for Picture Type Selection
The select filter evaluates an expression for each
frame. If the expression evaluates to a non-zero value, the frame is
kept; if zero, it is discarded.
To filter frames by their slice type, use the pict_type
variable. For example, to target only I-frames, compare
pict_type to PICT_TYPE_I (or simply
I):
ffmpeg -i input.mp4 -vf "select='eq(pict_type\,I)'" -vsync vfr output_%04d.jpgNote: In newer versions of FFmpeg (5.1+), -vsync vfr
is deprecated in favor of -fps_mode vfr.
Why Frame Rate Control Matters
When using the select filter, you must set variable
frame rate mode using -fps_mode vfr (or
-vsync vfr on older builds).
If you omit this flag, FFmpeg defaults to a constant frame rate (CFR) and duplicates remaining frames to fill the gaps left by dropped frames, resulting in duplicate images or an unaltered frame count.
Exporting Selected Frames to a Video File
If your goal is to output a playable video containing only the
selected frames instead of still images, you must reset the presentation
timestamps (PTS) using the setpts filter. Without resetting
timestamps, players will pause during the gaps between frames.
Chain select with setpts:
ffmpeg -i input.mp4 -vf "select='eq(pict_type\,I)',setpts=N/FRAME_RATE/TB" -fps_mode vfr output.mp4setpts=N/FRAME_RATE/TB: Reassigns timestamps sequentially based on the new frame count (N), creating smooth playback at the container's standard frame rate.
Common Criteria Options for
select
The pict_type variable supports all standard frame
types:
- I-Frames:
select='eq(pict_type\,I)' - P-Frames (Predicted):
select='eq(pict_type\,P)' - B-Frames (Bi-directional):
select='eq(pict_type\,B)'
You can also target other conditions alongside or instead of
pict_type:
- Keyframes (Independent of type definition):
select='eq(key\,1)' - Combining conditions (e.g., I-frames with high scene change
score):
select='eq(pict_type\,I)*gt(scene\,0.3)' - Every Nth frame:
select='not(mod(n\,30))'