Pulling Still Frames Out of a Video — and Why They Look Softer Than the Video Did
Published 8/10/2026 · 12 min read · File tools
Daniel Okonkwo — Front-end developer and tech writer at OneKitly
Web performance · File formats
Checked against 4 sources
The frame extractor runs ffmpeg inside your browser and builds one of three commands. One frame: -ss <seconds> -i <file> -frames:v 1 -q:v 2. The seek sits before the input, so ffmpeg jumps to the nearest earlier keyframe and decodes forward to your timestamp. A fixed number of frames: -i <file> -vf fps=<count divided by duration> -frames:v <count>, which spreads them evenly over the whole clip. One frame every N seconds: -i <file> -vf fps=<1 divided by N> -frames:v <count>. JPG is written with -q:v 2, the second-best rung of the MJPEG scale that runs from 2 to 31; PNG carries no quality flag at all, because it is lossless. Whichever mode you choose, the tool stops at 60 frames and says so on screen before it starts. Two things to know before you trust the picture. First, a frame is not a photograph. Video stores a complete image only at keyframes, typically one every one to ten seconds, and rebuilds everything in between from lists of differences. Extract a frame from the middle of that run and you get the decoder's reconstruction, which is softer and blockier than a still shot at the same resolution; keyframes are the exception and are genuinely sharp. Second, the width buttons are ceilings rather than targets. They become scale=w='min(W,iw)':h=-2, so a button means at most this wide: ask for less than the source and you get it, ask for more and the frame comes back at its own size. A 1080x1920 portrait clip asked for 1280 returns 1080x1920, untouched, because enlarging a frame invents nothing and only makes the file bigger.
Three commands hide behind three buttons: one frame at a timestamp, a fixed number spread across the clip, or one every N seconds. Here are the exact arguments, the 60-frame ceiling and the reason a frame from the middle of a compressed clip can never be as sharp as a keyframe.
Three buttons, three different ffmpeg commands
The interface offers a number of frames, an interval, or a single moment, and each one assembles a different command. "A number of frames" divides the count you typed by the clip's duration and hands the result to the fps filter: ask for 12 frames from a 6-second clip and the filter becomes fps=2.000000, with -frames:v 12 to stop it there. "At a regular interval" inverts your interval instead — one frame every 5 seconds is fps=0.200000 — and computes the count from the duration. "One frame" skips the filter entirely and uses -ss before the input with -frames:v 1.
That last placement matters more than it looks. Putting -ss before -i lets ffmpeg jump straight to a seek point instead of decoding the whole file up to your timestamp, which is the difference between a fraction of a second and a long wait on a large clip. Old advice says an input seek is only keyframe-accurate; that stopped being true years ago, and this build seeks accurately by default when it is transcoding, decoding the short stretch between the seek point and your timestamp and throwing it away. The frame you see on the preview slider is the frame you get.
A frame is not a photograph
Every modern video codec stores complete pictures only now and then. Those are keyframes, and everything between them is written as instructions: this block moved four pixels left, that region is the same as before, this patch changed by these small amounts. A one-hour recording at 30 frames per second holds 108,000 frames but perhaps only a few thousand complete pictures. When you ask for the frame at 47.3 seconds, the decoder finds the last keyframe before it and replays every instruction since to rebuild what should be on screen.
The reconstruction is faithful enough to watch and disappointing to freeze. Because the encoder spent its bits on what changes, a static background that has not been refreshed for two seconds is carrying two seconds of accumulated approximation. Motion blur that reads as movement at 30 frames per second reads as a smear when you stop on it. And any block the encoder decided nobody would look at closely — dark areas, out-of-focus areas, fast pans — is exactly where the quantiser saved room. That is why a frame grabbed from a heavily compressed clip looks softer than a photograph of the same scene at the same pixel count, even though both are the same size on disk terms.
Keyframes are the exception, and they are worth hunting for. If the clip matters — a licence plate, a face, a scoreboard — extract several frames around the moment rather than one. In a run of ten consecutive frames one will usually be a keyframe or close to one, and it will be visibly cleaner than its neighbours. The interval and count modes make that easy: they never let you nominate a keyframe directly, but a dense enough sample will land on one.
The width buttons are ceilings, not targets
Four buttons offer Original, 640, 1280 and 1920. Pick one and the filter chain gains scale=w='min(W,iw)':h=-2, which caps the width at that number and lets ffmpeg compute a height that keeps the shape, rounded to the nearest even number. The cap is the important word. On a 1920x1080 clip the 1280 button gives 1280x720, exactly as you would expect. On a 1080x1920 portrait clip the same button gives 1080x1920 — the source, untouched — because 1280 is wider than the clip is and the tool takes the smaller of the two.
That cap is worth having because enlarging a frame gains nothing. Upscaling cannot invent detail; it interpolates, so the image becomes larger and heavier without becoming sharper — softer, in fact, because the interpolation smooths over what little detail survived the video compression. Without the cap the buttons read as targets, and a portrait clip asked for 1920 came back at 1920x3414: more than three times the pixels of the source, every one of them guessed. If you want a bigger picture than the clip holds, the answer is not here — it is a source recorded at a higher resolution.
Sixty frames — and the ceiling means two different things
The tool will not produce more than 60 frames in one run, and it says so before you start: ask for 500 and the line under the mode buttons updates to 60 and adds a warning. That much is honest. What the warning does not say is that the ceiling behaves differently in the two batch modes, and the difference decides whether you get a survey of the whole video or only its opening.
In count mode the sampling rate is derived from the duration: 60 frames out of a twenty-minute recording becomes fps=0.050000, so the frames land every twenty seconds from beginning to end. In interval mode the rate is derived from your interval and the count is only a stop signal: one frame per second on that same twenty-minute recording becomes fps=1.000000 with -frames:v 60, and ffmpeg stops after sixty seconds of footage. You get the first minute of the video, sixty times, and nothing from the remaining nineteen. The on-screen figure is truthful about how many files you will get; it says nothing about where in the video they come from. If you want coverage, use count mode.
One more thing the interface gets wrong about itself. The note under the buttons says every frame is a separate download and that there is no archive to bundle them into. There is: the Download all button collects the frames into images-video.zip whenever there is more than one, and asks the browser once. The individual Download buttons under each thumbnail are there for when you want two frames out of sixty, not because the tool cannot zip.
What the frames are actually for
Three uses cover almost everything people extract frames for. A contact sheet: twelve to twenty-four frames spread over the whole clip, printed small, is the fastest way to find where something happens in an hour of footage without scrubbing. Count mode with the width on 640 is built for this. A thumbnail: platforms judge a video by its first still, and the automatic choice is almost always worse than one you pick. Use the single-frame mode, drag the slider until the preview shows the frame you want, and extract at Original width. And evidence: a moment you need to show someone who will not watch a video.
For that third use, choose PNG and leave the width alone. A JPG at -q:v 2 is very good, but it is a second lossy generation on top of the video's own compression, and anyone examining the image closely will be looking at artefacts from two encoders instead of one. PNG stores exactly what the decoder produced, files are five to fifteen times larger, and nothing is added. The picture will still be a reconstruction rather than a photograph — no format fixes that — but at least the reconstruction is the only approximation in it.
| Width button | From 1080×1920 (phone, portrait) | From 1920×1080 (landscape) | From 3840×2160 |
|---|---|---|---|
| Original | 1080×1920 unchanged | 1920×1080 unchanged | 3840×2160 unchanged |
| 640 px | 640×1138 — 65 % fewer pixels | 640×360 — 89 % fewer pixels | 640×360 — 97 % fewer pixels |
| 1280 px | 1080×1920 unchanged — capped | 1280×720 — 56 % fewer pixels | 1280×720 — 89 % fewer pixels |
| 1920 px | 1080×1920 unchanged — capped | 1920×1080 unchanged | 1920×1080 — 75 % fewer pixels |
Frequently asked questions
- Should I choose JPG or PNG?
- JPG for anything you are going to look at, share or paste into a document: the tool writes it at -q:v 2, which is the second-best setting on a scale that runs from 2 to 31, and the artefacts it adds are far smaller than the ones already in the video. PNG for anything that will be examined, zoomed into or argued about, because it adds nothing at all — it stores the decoder's output byte for byte. Expect PNG files five to fifteen times the size of the equivalent JPG. There is no quality slider for either: the JPG level is fixed in the code and PNG has no level to set.
- Why is my extracted frame blurrier than the video looked?
- Because motion hides compression and stillness exposes it. Playing at 30 frames per second, your eye integrates thirty approximations a second and reads the result as a sharp scene; stop on one of them and the approximation is all there is. On top of that, the frame you picked is probably not a keyframe, so it is a reconstruction built from a chain of difference instructions. Try extracting a short burst around the same moment and comparing: one of them will be noticeably cleaner, and that one is at or near a keyframe.
- Can I get every single frame of the video?
- Not in one run: the ceiling is 60 frames, which is a little over two seconds of 25 fps footage. That ceiling is not arbitrary — sixty full-resolution stills already run to tens or hundreds of megabytes held in browser memory at once, and a browser tab has far less room than a desktop program. If you genuinely need every frame of a short passage, trim the clip to the seconds you care about first, then run the interval mode with an interval equal to one frame duration — one divided by the clip's frame rate, so 0.04 for a 25 fps clip. Asking for a shorter interval than that does not get you more: the fps filter has no extra frames to give and simply repeats the ones it has. You will still stop at sixty, but they will be sixty consecutive frames rather than a sample.
- Is my video uploaded anywhere?
- No. The decoder is ffmpeg compiled to WebAssembly and served from this site itself rather than from a content delivery network, and it runs inside the tab. Your file is read into the page's own memory, processed there, and the resulting frames are handed back as downloads. Nothing leaves the machine, which is also why a long clip takes real time: a single browser thread is doing work that a desktop machine would spread across every core it has.
- Why does one frame per second give me only the start of a long video?
- Because the interval mode fixes the sampling rate and then stops at the 60-frame ceiling. One frame per second means fps=1.000000, and -frames:v 60 halts ffmpeg after the sixtieth output frame, which is sixty seconds into the source. Everything after the first minute is never reached. The count mode does not behave this way: it derives the rate from the total duration, so 60 frames from a two-hour recording become fps=0.008333 and land two minutes apart from start to finish. Use count mode whenever you want to see the whole video, and interval mode only for the opening or for a clip you have already trimmed.
Articles you may find interesting
All guides →Related tools
These four tools run ffmpeg in your browser: nothing is uploaded, and nothing here depends on a server staying up. The behaviour described was read out of each component's source and then confirmed by executing the same argument arrays against the very ffmpeg build the site ships, so it is true of the version live today and not of ffmpeg in general. Sizes and loudness figures came from short synthetic test files; your own footage will give different numbers on the same commands. Where a tool's on-screen wording and its code disagree, this article follows the code.
Sources
Spotted a mistake in this article?