ffmpeg extract frames: practical commands for videographers
By Lance Coleman · October 14, 2026
Use FFmpeg to extract frames by timestamp, interval, scene cut, or frame number, with practical advice on image quality, speed, and delivery prep.
Start with the command you actually need
To extract one high-quality JPEG at 12.5 seconds:
ffmpeg -ss 00:00:12.500 -i "master.mp4" -frames:v 1 -q:v 2 -update 1 "still.jpg"
-ss 00:00:12.500seeks to the requested position.-i "master.mp4"specifies the input. Replace this with your MOV or MP4 path.-frames:v 1limits the output to one video frame.-q:v 2sets high JPEG quality. Lower values mean higher quality.-update 1tells the image writer to use one filename rather than expect a numbered sequence."still.jpg"sets the output name and, through its extension, the image format.
For client selects, extract a small set of candidates first. Exporting every frame of a wedding film usually creates a sorting problem rather than solving one.
Install FFmpeg and check the master
FFmpeg is a free command-line tool. These examples use macOS Terminal syntax, which also works in most Linux shells.
Check whether it is installed:
ffmpeg -version
On a Mac with Homebrew already installed:
brew install ffmpeg
Work from the highest-quality finished master available, not a downloaded social copy. Inspect its first video stream with FFprobe, included with typical FFmpeg installations:
ffprobe -v error -select_streams v:0 -show_entries stream=codec_name,width,height,r_frame_rate,avg_frame_rate,pix_fmt,color_space,color_transfer,color_primaries -of default=noprint_wrappers=1 "master.mp4"
-v errorhides routine logging.-select_streams v:0selects the first video stream.-show_entries stream=...requests the listed technical fields.-of default=noprint_wrappers=1prints simple key-value lines without section wrappers.
Check dimensions, frame rates, and color metadata. Missing color tags are not proof that the source is SDR. For a graphical alternative, see how to extract stills from a video on Mac.
Extract the first frame or a frame at a timestamp
First frame as PNG
ffmpeg -i "master.mov" -frames:v 1 -update 1 "first-frame.png"
Without -ss, decoding starts at the beginning. The .png extension selects PNG output. There is no JPEG quality setting because PNG uses lossless compression.
This extracts the first frame, not the first useful picture. A master beginning with black, a slate, or a fade will produce exactly that.
Seek quickly to a specific moment
ffmpeg -ss 00:01:23.400 -i "master.mov" -frames:v 1 -update 1 "hero.png"
Putting -ss before -i enables input seeking. For ordinary seekable files, FFmpeg typically jumps to a preceding seek point, then decodes and discards frames until the requested position. Default accurate seeking means this is not simply a keyframe grab.
You may also see:
ffmpeg -i "master.mov" -ss 00:01:23.400 -frames:v 1 -update 1 "hero.png"
Here, FFmpeg decodes from the beginning and discards frames before the target. It can be much slower deep into a long event recording. Try this placement if a file behaves unexpectedly with input seeking.
These timestamps are playback positions, not embedded production timecode. 00:01:23.400 means 83.4 seconds, not an editor's hours:minutes:seconds:frames notation. A requested instant between frames cannot create a new exposure.
Extract every frame without adding duplicates
mkdir -p "frames"
ffmpeg -i "master.mp4" -fps_mode passthrough -q:v 2 "frames/frame_%06d.jpg"
mkdir -pcreates the destination folder if needed.-fps_mode passthroughavoids output frame duplication or dropping for frame-rate synchronization.%06dcreates a six-digit sequence:frame_000001.jpg,frame_000002.jpg, and so on.
For PNGs:
mkdir -p "frames-png"
ffmpeg -i "master.mp4" -fps_mode passthrough "frames-png/frame_%06d.png"
A three-minute master at exactly 24 fps contains 4,320 frames. Use the video frame calculator before starting a large extraction, and test a short section to estimate disk usage.
Sequence numbers describe output order, not source timestamps. They start at 1 by default. Add -start_number 0 before the output path if you need zero-based filenames.
Older tutorials use -vsync 0. Modern FFmpeg uses the per-output -fps_mode passthrough option instead.
Extract frames at regular intervals
For a first-pass review, one frame every few seconds is often enough to locate promising shots.
mkdir -p "review"
ffmpeg -i "master.mp4" -vf "fps=1/5" -q:v 2 "review/pick_%04d.jpg"
-vfintroduces a video filter chain.fps=1/5outputs one frame every five seconds.%04dgives four-digit numbering.
Change only the filter expression for other sampling rates:
| Goal | Filter |
|---|---|
| One frame per second | fps=1 |
| Two frames per second | fps=2 |
| One frame every ten seconds | fps=1/10 |
| One frame per minute | fps=1/60 |
The fps filter samples onto a regular output timeline. It can drop or duplicate frames to achieve that rate. It does not select the sharpest image within each interval, and output numbering is not a timestamp record.
Select every Nth decoded frame
mkdir -p "every-48"
ffmpeg -i "master.mp4" -vf "select='not(mod(n,48))'" -fps_mode passthrough -q:v 2 "every-48/pick_%04d.jpg"
n is the zero-based decoded frame index. mod(n,48) calculates the remainder after division by 48; not(...) selects indices 0, 48, 96, and so on.
At exactly 24 fps, that is every two seconds. With variable-frame-rate footage, the time gaps can differ. Use fps for time-based sampling and select for frame-count-based sampling.
Extract a short burst around the best moment
A useful expression can sit between your interval samples. Instead of exporting the entire master, pull a three-second burst:
mkdir -p "burst"
ffmpeg -ss 00:00:42 -i "master.mp4" -t 3 -fps_mode passthrough -q:v 2 "burst/frame_%04d.jpg"
-t 3, placed after the input, limits the output duration to three seconds. At a constant 24 fps, expect roughly 72 candidates.
For a wedding kiss, inspect the approach and reaction as well as the contact. For performance footage, check eye direction, mouth shape, and microphone position. For products, look for readable labels and clean reflections.
Select an exact decoded frame number
ffmpeg -i "master.mp4" -vf "select='eq(n,240)'" -fps_mode passthrough -frames:v 1 -update 1 "frame-240.png"
eq(n,240) selects frame index 240, the 241st decoded frame. At exactly 24 fps with a zero-based timeline, it starts at ten seconds.
This command decodes from the beginning. Do not prepend an input seek and assume n still refers to the original full-file frame index. For fractional rates such as 24000/1001, avoid rounding the frame rate to 24 when calculating positions.
Extract scene-change candidates and retain timing clues
Scene detection is useful for a brand montage or music video where evenly spaced samples miss short shots:
mkdir -p "scenes"
ffmpeg -i "master.mp4" -vf "select='gt(scene,0.30)',showinfo" -fps_mode passthrough -q:v 2 "scenes/scene_%04d.jpg" 2> "scenes/extraction.log"
sceneis FFmpeg's scene-change score.gt(scene,0.30)selects frames whose score exceeds 0.30.- Lower thresholds generally select more candidates; higher thresholds select fewer.
showinfologs information about selected frames, includingpts_timein seconds.2>redirects diagnostic output into a log file, so normal progress messages also go there.
Because showinfo follows select, its zero-based frame counter follows the selected sequence. Keep the log alongside the numbered images if you need to revisit moments. Presentation timestamps are not automatically your NLE's embedded timecode, especially with unusual source offsets.
This is change detection, not a quality ranking. Flash photography, strobes, and whip pans can trigger it. Dissolves may not. The first frame after a cut can be blurred or awkward, and the opening shot may not produce a detection. Use these images as navigation points, then extract nearby bursts.
Build a contact sheet before opening hundreds of files
This creates one sheet from the first 25 ten-second samples:
ffmpeg -i "master.mp4" -vf "fps=1/10,scale=320:-1,tile=5x5" -frames:v 1 -q:v 2 -update 1 "contact-sheet.jpg"
- Commas connect filters in processing order.
scale=320:-1makes each thumbnail 320 pixels wide and calculates its height proportionally.tile=5x5arranges 25 thumbnails in five columns and five rows.-frames:v 1writes one completed sheet.
This is a browsing aid, not a delivery still. It has no timestamp labels. Keep the sampling interval noted, then return to the master for full-resolution candidates. Short videos may leave unused cells.
Choose quality settings that match the job
JPEG versus PNG
| Format | Best use | Main trade-off |
|---|---|---|
JPEG with -q:v 2 | Review, web, routine client selects | Lossy compression, smaller files |
| PNG | Retouching handoff, graphics-heavy frames | Larger files, often slower export |
For FFmpeg's JPEG encoder, the commonly used quality range is 2 to 31, with lower values producing higher quality. -q:v 2 does not mean 2 percent quality. It is a sensible starting point, not a guarantee of a particular file size.
PNG avoids additional lossy image compression. It cannot recover detail lost in the video master, remove motion blur, or turn a frame into a higher-resolution photograph.
Source dimensions, HDR, and interlacing
Without a scaling filter, extraction generally preserves decoded frame dimensions, although rotation metadata can affect orientation. Anamorphic sources may need aspect-ratio correction for square-pixel stills.
HDR deserves a separate check. PQ or HLG video exported directly to an ordinary JPEG can look wrong because it needs an intentional SDR tone-mapping and color-conversion workflow. When matching an approved SDR delivery, extract from that approved SDR master if available. PNG alone does not solve HDR conversion.
For genuinely interlaced material, a filter such as bwdif can remove combing before image export. Do not deinterlace progressive footage by default.
Keep full-resolution selects separate from social versions. Use the social media size cheat sheet when preparing crops, and check faces, hands, logos, and caption space rather than blindly center-cropping.
Make extraction faster without sacrificing the wrong thing
The fastest useful workflow exports fewer, better-targeted images.
- Seek before the input for isolated moments. Avoid decoding a long recording from the beginning for each still.
- Use small JPEGs for browsing. Add
scale=640:-1after your sampling filter, then re-extract approved moments at full size. - Write to a fast local disk. Thousands of small files can make storage the bottleneck.
- Test hardware decoding before committing. Moving decoded frames back to system memory for image encoding can offset its benefits.
An fps filter reduces image-writing work, but it generally does not eliminate decoding of intervening compressed frames. Likewise, -c copy cannot turn H.264 video packets into JPEGs or PNGs. Frame extraction requires decoding.
Common fixes:
- Missing folder: create it before running FFmpeg.
- Unexpected duplicates: use
-fps_mode passthroughfor all-frame orselectextraction. Remove unintended output-rsettings. - Wrong video stream: add
-map 0:v:0after the input to select its first video stream explicitly. - Filename pattern problems: use
%04din macOS Terminal. Windows batch files require%%04d. - Overwrite prompts: use a fresh folder, or add
-yonly when overwriting is intentional.
Where ShotBatch fits
FFmpeg is a strong free choice for repeatable extraction commands, scripted batches, and precise technical control. Exporting a still from your NLE is also reasonable when you only need one or two images.
ShotBatch fits the broader delivery workflow. It is a native Mac app that starts with a finished MOV or MP4 master already on your Mac. A review pass reads scene cuts, sharpness, faces, motion, lyrics, and audio energy to surface candidates the editor approves.
Its white-label exports include named source-resolution stills, social crops, contact sheets, and JSON and CSV manifests with source timestamps. ShotBatch never uploads footage. Its export includes a self-hosted share folder with a passcode option; you choose the host.
Pricing is one-time: Lite is $39 and Pro is $129, with no subscription and a 14-day money-back guarantee.
FAQ
What is the simplest FFmpeg command to extract one frame?
Use ffmpeg -i "master.mp4" -frames:v 1 -update 1 "still.png". Add -ss 00:00:10 before -i to request a frame at ten seconds instead of the beginning.
How do I extract one frame every second?
Use ffmpeg -i "master.mp4" -vf "fps=1" -q:v 2 "frame_%04d.jpg". Change fps=1 to fps=1/5 for one frame every five seconds.
Can FFmpeg automatically find the sharpest frame?
Not with the interval or scene-detection commands here. They select by timing or visual change, not sharpness. Inspect neighboring frames at full size before approving a still.
Why is my extracted PNG still blurry?
PNG preserves the decoded image without additional lossy compression, but the source may contain motion blur, missed focus, or compression damage. Try adjacent frames or a better master. Upscaling does not restore missing detail.
Related guides
How to get a still from a video without losing quality
Learn how to get a still from a video at full resolution, choose sharp frames between blinks, and avoid motion blur, soft screenshots, and HDR issues.
How to extract frames from video and pick the sharpest stills
Extract every video frame with FFmpeg, save individual stills with VLC, and learn a practical workflow for choosing sharp, usable images from your edit.
How to convert MP4 to JPG on Mac at full resolution
Convert MP4 to JPG on Mac with screenshots, FFmpeg, or batch export. Keep source resolution, choose sharp frames, and avoid unnecessary quality loss.