Very Good FFmpeg
How it worksPricingDocsBlog

Published Jun 10, 2026

FFmpeg documentation: thumbnail filter, select filter, and frame extraction commands

How to extract thumbnails from video with FFmpeg using -ss, thumbnail filter, select filter, fps filter, and contact sheets

What are the best FFmpeg commands for extracting video thumbnails?

There is no single best command, because every use case is different. FFmpeg gives you four distinct approaches: fast keyframe seeking with -ss, interval-based extraction with the fps filter, scene-aware frame selection with the select filter, and automatic representative frame picking with the thumbnail filter. This guide covers all four, plus contact sheets and tips for running them in production.

The FFmpeg wiki officially documents these methods, but the documentation is spread across separate pages for seeking, filter graphs, and the wiki itself. This article consolidates everything into one place with real commands, explanations, and production patterns.

TL;DR / Key Takeaways

  • Four core methods: -ss + -frames:v for exact timestamps, fps filter for intervals, select filter for scene detection, thumbnail filter for representative frames.
  • Fastest approach: -ss before -i with select="eq(pict_type\,I)" keyframe selection, grabbing thumbnails in 0.1-0.2 seconds.
  • Most representative single frame: thumbnail=n=100 filter, which analyzes color histograms across a batch of frames.
  • Contact sheets: combine fps + scale + tile filters for a grid of thumbnails.
  • At production scale, run these same FFmpeg commands through a hosted API like Very Good FFmpeg, which handles infrastructure, scaling, and failure recovery.
MethodSpeedAccuracyBest For
-ss + -frames:v 1FastHigh (timestamp)Single poster frame at known timestamp
fps filterMediumMediumRegular interval thumbnails (gallery, timeline)
select=eq(pict_type,I)FastestLow (keyframe only)Quick batch thumbnails where position matters less
thumbnail filterMediumHigh (representative)Best automated poster frame
select=gt(scene,...)SlowHigh (scene aware)Lecture slides, talking head, non-duplicate frames
fps + scale + tileMediumMediumContact sheets and sprite sheets

Background concepts

What is a video thumbnail in FFmpeg?

A video thumbnail is a single still image frame extracted from a video file. Common uses include poster frames for video players, preview images in media libraries, timeline scrub thumbnails, and gallery grids for content review.

The challenge is that video is compressed using inter-frame prediction. Not every frame is stored as a complete image (keyframe). Most frames are delta frames that only store the differences from the previous frame. Extracting a random frame means FFmpeg must decode from the last keyframe forward, which is expensive. Understanding this compression model is essential to choosing the right extraction strategy.

How does FFmpeg handle frame extraction?

FFmpeg decodes video frame-by-frame unless you use keyframe-seeking tricks. Two seeking modes exist.

ModeFlag PositionSpeedAccuracyUse Case
Input seeking (fast)-ss before -iVery fastKeyframe-accurateBulk extraction, timeline previews
Output seeking (accurate)-ss after -iSlowFrame-accurateExact frame extraction, scientific analysis

Key parameters that control frame extraction:

  • -frames:v N stops after N video frames, giving you exact count control.
  • -vsync vfr (variable frame rate) avoids duplicate or padded frames when using filter-based extraction.
  • -qscale:v sets output image quality for JPEG (2-5 is high quality, 15-20 is low).

How do I extract a single thumbnail at a specific timestamp?

Use -ss for input seeking combined with -frames:v 1 to grab exactly one frame at the target time. This is the simplest and most common thumbnail command.

plaintext
ffmpeg -ss 00:01:30 -i input.mp4 -frames:v 1 thumb.png

The -ss flag before -i jumps FFmpeg to the nearest keyframe near 1 minute 30 seconds without decoding the entire video from the start. The -frames:v 1 flag stops processing after it outputs one frame. This makes the command extremely fast even on long videos.

The tradeoff is that input seeking lands at the nearest keyframe, which may be a few frames before or after your exact target. If you need pixel-perfect accuracy at a specific frame, place -ss after -i instead:

plaintext
ffmpeg -i input.mp4 -ss 00:01:30 -frames:v 1 thumb.png

This decodes from the beginning and gives you frame-accurate output, but it is much slower because it processes every frame up to the target.

Add -qscale:v 3 for higher JPEG quality:

plaintext
ffmpeg -ss 00:01:30 -i input.mp4 -frames:v 1 -qscale:v 3 thumb.jpg

How do I generate thumbnails at regular intervals?

Use the fps filter to output one frame every N seconds. This is the best approach for timeline preview grids, gallery displays, and video cataloging.

plaintext
ffmpeg -i input.mp4 -vf "fps=1/60,scale=320:-1" thumb%04d.jpg

The fps=1/60 filter produces one frame per 60 seconds of video. The scale=320:-1 resizes output to 320 pixels wide with automatic height to maintain aspect ratio. The output pattern thumb%04d.jpg generates numbered files like thumb0001.jpg, thumb0002.jpg, and so on.

Variations on interval extraction:

StrategyCommandOutput
Every N secondsfps=1/601 frame per 60s
Every N framesfps=1/30 (assuming 30fps)1 frame per 30 frames
Fixed total countN/A (use scripting instead)N thumbnails total
Every 10 seconds at 640x360fps=1/10,scale=640:3601 frame per 10s at 640x360

For a fixed number of thumbnails, you need to calculate the interval from the video duration. Get the duration with ffprobe:

plaintext
ffprobe -v error -show_entries format=duration -of default=noprint_wrappers=1:nokey=1 input.mp4

Then divide by the desired number of thumbnails to get your fps interval denominator.

How do I extract only I-frames (keyframes) for fast thumbnails?

Use the select filter with the picture type expression to grab only I-frames. This is the fastest batch approach for thumbnail extraction.

plaintext
ffmpeg -ss 3 -i input.mp4 -vf "select='eq(pict_type,PICT_TYPE_I)'" -vsync vfr thumb%04d.jpg

The select filter evaluates an expression for every frame. When the expression evaluates to nonzero, the frame is selected. eq(pict_type,PICT_TYPE_I) returns 1 for I-frames (keyframes) and 0 for all other frames. The -vsync vfr flag is critical here because it prevents FFmpeg from duplicating or padding frames to maintain a constant frame rate.

The speed advantage is dramatic. Per the production answer on Super User, each FFmpeg invocation for a 1GB H.264 file takes approximately 0.1-0.2 seconds because input seeking with -ss before -i jumps directly to the nearest keyframe without decoding from the start.

The production-proven pattern for generating N evenly-spaced thumbnails from I-frames works like this:

  1. Get the video duration using ffprobe.
  2. Divide the duration D into N equal segments.
  3. Seek to the midpoint of each segment using -ss before -i.
  4. Grab one I-frame from each midpoint.

In pseudo-code:

plaintext
for X in 1..N:
    T = (X - 0.5) * D / N
    run: ffmpeg -ss <T> -i input.mp4 -vf "select='eq(pict_type,PICT_TYPE_I)'" -vframes 1 output_<X>.jpg

This approach is used in production for user-uploaded content platforms where speed matters more than frame-perfect positioning. As a bonus, you can filter out solid-color frames by checking the output file size, because meaningful frames compress to larger JPEGs than black or blank frames.

How do I pick the most representative frame automatically?

Use the thumbnail filter. It analyzes batches of frames and selects the one most representative of the sequence based on color histogram variance.

plaintext
ffmpeg -i input.mp4 -vf "thumbnail=100,scale=640:360" -frames:v 1 poster.png

The thumbnail=100 filter processes batches of 100 frames. For each batch, it computes the average color histogram across all frames, then picks the frame whose histogram is closest to that average. The result is the single most representative frame from that 100-frame window. The scale=640:360 resizes the output to a web-friendly poster size.

Internally, FFmpeg's thumbnail filter works by accumulating histogram data for N consecutive frames and selecting the one with the minimum color histogram distance from the batch average. The CUDA variant, thumbnail_cuda, provides GPU-accelerated processing for faster batch analysis.

This filter is ideal for automated pipelines where you need one good poster frame from a video and no human curator is available. It excels on approximately uniform content where the average frame is a reasonable representation. Its limitation is highly varied video where no single frame represents the whole content, or videos with long static segments followed by fast action.

How do I detect scene changes and grab only unique frames?

Use the select filter with the scene change expression gt(scene,threshold). This picks frames where the visual difference between consecutive frames exceeds a threshold.

plaintext
ffmpeg -i input.mp4 -vf "select='gt(scene,0.4)'" -vsync vfr scene_%04d.jpg

The gt(scene,0.4) expression evaluates the scene change metric for each frame. When the difference between the current frame and the previous frame exceeds 40 percent, the frame is selected. The -vsync vfr flag is required to avoid duplicate frames in the output.

ThresholdBehaviorUse Case
0.1Very sensitive, captures small changesSubtle transitions, slow zooms
0.3Moderate sensitivityStandard cuts, average scene changes
0.4Obvious cuts onlyClean edits, production video
0.015Extremely sensitiveLecture slides with minimal visual change

For lecture slide content with a talking head, combine thumbnail and select filters:

plaintext
ffmpeg -i slide_video.mp4 -vf "thumbnail,select='gt(scene,0.015)'" -vsync vfr -r 1 out%04d.jpg

This command first runs the thumbnail filter to pick representative frames, then runs the select filter with a low scene-change threshold to capture slide transitions while avoiding duplicates. The -frame_pts 1 option can be added to name output files by their presentation timestamp, which helps map thumbnails back to their position in the video.

To exclude black frames from scene-change extraction, use the blackdetect filter beforehand:

plaintext
ffmpeg -i input.mp4 -vf "blackdetect=d=2:pic_th=0.98" -f null -

This outputs the timestamps of black segments, which you can then skip during thumbnail extraction. The blackdetect filter identifies black frames by analyzing duration and blackness percentage.

How do I create a contact sheet (sprite sheet) from a video?

A contact sheet arranges multiple thumbnails into a single grid image. Use the fps filter to pick frames, scale to resize them, and the tile filter to arrange them.

plaintext
ffmpeg -i input.mp4 -vf "fps=1/60,scale=160:90,tile=5x4" contact_sheet.png

The fps=1/60 filter grabs one frame per minute of video. The scale=160:90 resizes each thumbnail to 160x90 pixels. The tile=5x4 filter arranges 20 thumbnails in a grid of 5 columns by 4 rows, producing a single output image.

Steps to create a custom contact sheet:

  1. Determine how many thumbnails you want (grid size).
  2. Calculate the interval: video duration in seconds divided by total thumbnails.
  3. Choose a thumbnail resolution (160x90 is common, 320x180 for larger previews).
  4. Set the tile grid dimensions.
  5. Optionally add padding between frames with tile=5x4:padding=4:margin=2.

Tune the tile filter parameters for spacing:

ParameterPurposeExample
tile=WxHGrid dimensions (columns x rows)tile=5x4 = 20 thumbnails
paddingPixels between framespadding=4 = 4px spacing
marginPixels around the outer bordermargin=2 = 2px outer border

Contact sheets are commonly used for content review, video cataloging, sprite-based AB testing, and media library previews.

Which method should I use for my use case?

The right method depends on your requirements for speed, accuracy, and automation.

MethodBest ForSpeedAccuracyComplexity
-ss + -frames:v 1Single poster frame at known timestampFastHighLow
fps filterRegular interval thumbnailsMediumMediumLow
select=eq(pict_type,I)Fast batch extractionFastestLow (keyframe only)Medium
thumbnail filterBest automated poster frameMediumHigh (within batch)Low
select=gt(scene,...)Scene-aware non-duplicate framesSlowHighMedium
fps+scale+tileContact sheets and sprite sheetsMediumMediumMedium

Quick decision flow:

  • Need one exact frame at a known timestamp? Use -ss before -i + -frames:v 1.
  • Need a batch of thumbnails as fast as possible? Use I-frame selection with select=eq(pict_type,I).
  • Need the best single frame automatically? Use the thumbnail filter.
  • Need a visual timeline for a media library? Use fps filter at regular intervals.
  • Need one thumbnail per scene with no duplicates? Use select=gt(scene,0.4).
  • Need a contact sheet grid? Use fps + scale + tile.

How do I run these commands in production without managing servers?

FFmpeg is powerful, but running it at production scale means provisioning compute instances, managing job queues, handling storage for large input and output files, and dealing with edge case failures. This is where a hosted FFmpeg API like Very Good FFmpeg steps in.

Very Good FFmpeg runs the exact same FFmpeg commands on dedicated high-performance infrastructure. You send your FFmpeg command as a JSON payload, and the API executes it and delivers the output.

plaintext
curl -X POST https://verygoodffmpeg.com/api/ffmpeg \
  -H "Authorization: Bearer $API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "input_files": {
      "input.mp4": "https://your-bucket.s3.amazonaws.com/input.mp4"
    },
    "output_files": ["thumb.jpg"],
    "ffmpeg_commands": [
      "-i {{input.mp4}} -ss 00:01:30 -frames:v 1 -qscale:v 3 {{thumb.jpg}}"
    ]
  }'

This API approach has several advantages over running FFmpeg yourself:

Usage-based pricing without monthly minimums. You pay per GB processed, with volume discounts that kick in automatically. No monthly subscription floor. If you process 1 GB, you pay for 1 GB.

High-performance dedicated hardware. CPU jobs run on 16 dedicated 5+ GHz vCPUs with 32 GB DDR5 RAM and NVMe storage. GPU jobs run on demand with Nvidia RTX 4090, A5000, and other Nvidia chips.

No artificial time limits. Each job can run up to 6 hours. This compares favorably to alternatives like AWS Lambda (15 minutes), Cloud Run (60 minutes), or Rendi Pro (10 minutes on standard tiers).

High concurrency. 100 requests per second rate limit after an initial prepaid balance. No limit on concurrent running jobs.

Developer tooling. Official TypeScript SDK (@verygoodffmpeg/sdk), Python SDK (very-good-ffmpeg), an MCP server, and Make.com integration are all available.

Production features. Realtime logs in the dashboard let you watch every job as it runs. When a command fails, the AI auto-diagnosis feature analyzes the FFmpeg output and tells you exactly what went wrong. Command chaining lets you run thumbnail extraction, transcoding, and audio extraction in a single request.

FeatureVery Good FFmpegRendi ProRenderIO GrowthAWS Lambda
PricingPer GB, no minimumSubscription + GBSubscription + commandsPer request + storage
Max job runtime6 hours10 minutes5 minutes15 minutes
CPU per job16 dedicated 5+ GHz vCPUsShared poolCloudflare Workers1-6 vCPUs (burst)
GPU on demandYes (Nvidia RTX/A-series)Upon requestNoNo
Realtime logsYesNoNoVia CloudWatch
Auto-diagnosisYesNoNoNo
SDKsTypeScript + PythonNoNoAWS SDK (generic)
Rate limit100 req/sN/AN/AAccount-level

For a production pipeline that needs to generate thousands of video thumbnails daily, a hosted FFmpeg API eliminates the operational burden while giving you the same FFmpeg commands you already know.

FAQ

What is the difference between -ss before -i and after -i?

-ss before -i enables input seeking, which jumps to the nearest keyframe without decoding the full video. It is fast but keyframe-accurate. -ss after -i enables output seeking, which decodes from the start and is frame-accurate but much slower.

Why do I get fewer thumbnails than expected with the fps filter?

The fps filter outputs at most one frame per interval. If your video is shorter than the interval multiplied by the frame count, you get fewer outputs. It also only outputs frames that exist in the decoded stream, so a very short or corrupt video can produce fewer frames than expected.

What does -vsync vfr do and why do I need it?

-vsync vfr sets variable frame rate output. Without it, FFmpeg duplicates or drops frames to maintain a constant output frame rate, which can produce duplicate or padded frames when using filter-based extraction. With -vsync vfr, only the frames that pass through the filter graph are written to output.

How do I avoid black or solid-color thumbnails?

Filter out small output files, because solid-color frames compress to very small JPEGs. Check the file size after extraction and discard any thumbnail below a threshold (e.g., 2 KB). You can also use blackdetect to identify black segments and skip them during extraction.

Can I extract thumbnails from an online video URL without downloading first?

FFmpeg can read from URLs using protocols like HTTP, HTTPS, and HLS. You can pass a URL as input: ffmpeg -ss 10 -i https://example.com/video.mp4 -frames:v 1 thumb.png. However, seek operations on remote files are limited because FFmpeg must download and decode from the start unless the server supports byte-range seeking.

Does Very Good FFmpeg support GPU-accelerated thumbnail extraction?

Yes. Set machine: "nvidia" on the request to route the job to an Nvidia GPU worker. The thumbnail_cuda filter provides GPU-accelerated thumbnail extraction. One important caveat is that FFmpeg uses CPU code paths by default, so a GPU instance only runs faster when your command uses GPU decoders, encoders, and filters.

How do I choose the right scene change threshold?

Start with 0.4 for standard video content with clean cuts. Lower it to 0.3 for more sensitivity, and all the way to 0.015 for lecture slides or presentations where visual changes are subtle. Test with a short segment of your video and adjust until you capture the transitions you need without duplicates.

Can I run multiple thumbnail commands in a single API request?

Yes. Pass an array of FFmpeg commands to run them sequentially on the same instance. One request can generate multiple thumbnail sizes, extract frames at different timestamps, or combine thumbnail extraction with transcoding.

What is the maximum video duration I can process with Very Good FFmpeg?

Each job can run up to 6 hours. This covers long videos, feature-length films, and batch processing of multiple files in a single request.

What happens if my FFmpeg command fails on Very Good FFmpeg?

The auto-diagnosis feature analyzes the FFmpeg stderr output and provides a plain-English explanation of the failure. Common issues like invalid flags, missing codecs, or incorrect filter syntax are detected and reported automatically.

References

  • FFmpeg wiki: Create a thumbnail image every X seconds of the video. https://trac.ffmpeg.org/wiki/Create%20a%20thumbnail%20image%20every%20X%20seconds%20of%20the%20video
  • FFmpeg filter documentation: select and aselect. https://ffmpeg.org/ffmpeg-filters.html#select_002c-aselect
  • FFmpeg filter documentation: thumbnail. https://ffmpeg.org/ffmpeg-filters.html#thumbnail
  • FFmpeg filter documentation: tile. https://ffmpeg.org/ffmpeg-filters.html#tile
  • FFmpeg seeking documentation. https://ffmpeg.org/ffmpeg-utils.html#toc-Seeking
  • FFmpeg wiki: scene detection. https://trac.ffmpeg.org/wiki/Scenes
  • Super User: Meaningful thumbnails for a video using FFmpeg. https://superuser.com/questions/538112/meaningful-thumbnails-for-a-video-using-ffmpeg
  • Super User: Efficient thumbnail generation using keyframe seeking. https://superuser.com/a/821680
  • Super User: Combining thumbnail and select filters for slide content. https://superuser.com/a/1822672
  • OTTVerse: Creating video contact sheets with FFmpeg. https://ottverse.com/ffmpeg-extract-thumbnails-from-video-contact-sheet/
  • BannerBear: How to generate video thumbnails with FFmpeg. https://www.bannerbear.com/blog/how-to-generate-video-thumbnails-with-ffmpeg/
  • Very Good FFmpeg documentation. https://verygoodffmpeg.com/docs

Related reading

  • Jun 10, 2026

    Hosted FFmpeg REST API: 2026 Pricing and Comparison Guide

    Compare the top hosted FFmpeg REST APIs for video transcoding in 2026. Transparent pricing, hidden costs, and use-case recommendations across Mux, Bitmovin, AWS, Coconut, Rendi, FetchMedia, and Very Good FFmpeg.

  • Jun 10, 2026

    FFmpeg Extract Audio From Video: Command for WAV, MP3, AAC With Codec, Channel, and Sample Rate Control

    Extract audio from video with ffmpeg using exact commands for wav mono 16khz, high-quality mp3, and aac stream copy. Covers -ac, -ar, -acodec flags and scaling with a hosted FFmpeg API.

  • Jun 10, 2026

    FFmpeg Formats Documentation: MP4, Matroska (MKV), WebM, and MOV Explained

    How to convert between video containers with FFmpeg, lose zero quality with stream copy, and when to re-encode

  • Jun 10, 2026

    api.video Pricing, Video API Transcoding Docs 2026

    Compare api.video pricing for video API transcoding, docs, and how a full-stack video platform differs from a hosted FFmpeg API like Very Good FFmpeg.

Very Good FFmpegChecking status...
Product
  • How it works
  • Pricing
  • Comparison
  • FAQ
  • Blog
Developers
  • Documentation
  • API Reference
  • MCP Server
  • TypeScript SDK
  • Python SDK
Company
  • Contact
  • Sign in
  • Sign up
  • Terms
  • Privacy
As Seen On
  • G2
  • Product Hunt
  • GitHub
  • PyPI
  • NPM
  • Smithery
  • MCP.so
  • AlternativeTo
  • Make
© 2026 Very Good FFmpeg