ffmpegvideo-processingthumbnailscli

How to Extract Frames from Video with FFmpeg

·Javid Jamae·6 min read
How to Extract Frames from Video with FFmpeg

Extracting frames from video is one of the most common FFmpeg operations, and one of the most confusing. The flags aren't intuitive, the output naming is easy to get wrong, and quality control requires knowing which JPEG encoder settings FFmpeg actually respects.

This guide covers the patterns developers actually need: single frame at a timestamp, periodic extraction, keyframe-only extraction, quality control, and scaled thumbnails. Every command was tested against a real 640x360 H.264 MP4, and the actual file sizes are included so you know what to expect.

Extract a Single Frame at a Specific Timestamp

The most common case. Grab one frame from a specific point in the video.

ffmpeg -ss 00:00:05 -i input.mp4 -frames:v 1 frame.jpg

Two things matter here.

**Put -ss before -i.** This tells FFmpeg to seek before decoding, which is dramatically faster on long videos. If you put -ss after -i, FFmpeg decodes every frame from the start up to your timestamp. On a 2-hour file, that's the difference between milliseconds and minutes.

-frames:v 1 limits output to one frame.** Without it, FFmpeg extracts every frame from that timestamp onward. Thousands of JPEGs filling your disk.

The timestamp accepts HH:MM:SS.ms or raw seconds:

ffmpeg -ss 90.5 -i input.mp4 -frames:v 1 frame.jpg

Output: a single 23KB JPEG at the video's native resolution.

Extract Frames at Regular Intervals

To grab one frame per second across the entire video:

ffmpeg -i input.mp4 -vf "fps=1" frame_%03d.jpg

The fps filter value controls the interval:

  • fps=0.5 gives one frame every 2 seconds
  • fps=0.1 gives one frame every 10 seconds
  • fps=5 gives five frames per second

The %03d in the output filename is a C-style format specifier. FFmpeg increments it per frame: frame_001.jpg, frame_002.jpg, and so on. Use %04d if you expect more than 999 frames.

On a 13-second test video at fps=1, this produced 14 frames ranging from 23KB to 38KB each. Total extraction time: under 1 second.

Extract Only Keyframes

If you don't need every frame and just want the visually significant ones, extract keyframes (I-frames). These are fully encoded frames that mark scene changes or major visual shifts.

ffmpeg -i input.mp4 -vf "select='eq(pict_type,I)'" -vsync vfr keyframe_%03d.jpg

-vsync vfr is critical.** Without it, FFmpeg duplicates frames to maintain constant frame rate, and you get hundreds of identical images instead of just the keyframes.

On the same 13-second video, this produced 2 keyframes instead of 14. Much less disk usage, and the frames tend to be the ones you'd pick manually.

Generate Scaled Thumbnails

For thumbnail grids or preview strips, combine extraction with the scale filter:

ffmpeg -i input.mp4 -vf "fps=1,scale=320:180" -q:v 2 thumb_%03d.jpg

This chains two filters: fps=1 for the extraction interval, and scale=320:180 for the output dimensions. Filter order matters. fps first reduces the frame count, then scale resizes only those frames. Reversing works but wastes CPU.

**The -q:v flag controls JPEG quality.** Range is 2 (highest) to 31 (lowest). Default is around 8-10. For thumbnails displayed at small sizes, -q:v 5 balances quality and file size well.

At 320x180 with -q:v 2, thumbnails were 9-12KB each. At native 640x360 resolution, the same quality setting produced 36-38KB files.

To auto-calculate one dimension and preserve aspect ratio:

ffmpeg -i input.mp4 -vf "fps=1,scale=320:-1" thumb_%03d.jpg

scale=320:-1 sets width to 320 and calculates height automatically. Use -2 instead of -1 if the codec requires even dimensions.

Common Pitfalls

**Wrong -ss placement.** Putting -ss after -i decodes from the start. On long videos, this turns a millisecond operation into a multi-minute wait. Always put -ss before -i.

**Missing -frames:v 1 for single frames.** Without it, you get every frame from the seek point to the end. On a 1080p video, that's tens of thousands of files.

**Forgetting -vsync vfr with select.** Keyframe extraction without -vsync vfr produces duplicated frames. Hundreds of output files that are mostly identical.

Wrong format specifier. frame_%d.jpg works but produces frame_1.jpg, frame_2.jpg without padding. Sorting breaks after 9. Use %03d or %04d.

Output directory doesn't exist. FFmpeg won't create directories. ffmpeg -i input.mp4 output/frame_%03d.jpg fails if output/ doesn't exist. Create it first with mkdir -p output.

FAQ

Can I extract frames as PNG instead of JPEG?

Yes. Change the extension to .png. FFmpeg picks the encoder from the file extension. PNG is lossless but much larger. The same frame that was 23KB as JPEG was 269KB as PNG. About 11x bigger.

ffmpeg -ss 5 -i input.mp4 -frames:v 1 frame.png

How do I extract every Nth frame instead of every Nth second?

Use the select filter with a modulo expression:

ffmpeg -i input.mp4 -vf "select='not(mod(n,30))'" -vsync vfr every_30th_%03d.jpg

This grabs every 30th frame. For a 30fps video, that's roughly one per second, but frame-count-based instead of time-based.

What's the fastest way to extract a single frame?

Put -ss before -i and add -frames:v 1. FFmpeg seeks to the nearest keyframe, decodes forward to your timestamp, outputs one frame, and exits. On a 2GB file, this typically completes in under 100ms.

How do I extract frames from a specific time range?

Combine -ss (start) with -t (duration):

ffmpeg -ss 00:01:00 -i input.mp4 -t 10 -vf "fps=1" range_%03d.jpg

This extracts one frame per second from the 1:00 to 1:10 mark.

Is JPEG or PNG better for extracted frames?

JPEG for most cases. It's 10x smaller (23KB vs 269KB for the same 640x360 frame) and good enough for thumbnails, preview images, and visual inspection. Use PNG only when you need lossless pixel data for machine learning training sets or when frames feed into another image processing pipeline.

If you're building a video processing pipeline and need transcoding, format conversion, or watermarking alongside frame extraction, FFmpeg Micro handles the heavy lifting through a simple API. One HTTP call handles the transcode, so you can keep your local FFmpeg work focused on frame extraction. Grab a free API key at ffmpeg-micro.com.

*Last verified: 2026-05-16 against FFmpeg 3.3.3*

About Javid Jamae

Founder & CEO at FFmpeg Micro

Javid is a software engineer, author, and entrepreneur with over 25 years of professional software development experience across enterprise, startup, and consulting environments. He founded FFmpeg Micro to make video processing accessible to developers through a simple, automation-first REST API.

Software EngineeringVideo ProcessingFFmpegCloud ArchitectureAPI DesignAutomation

Ready to process videos at scale?

Start using FFmpeg Micro's simple API today. No infrastructure required.

Get Started Free