191

There are many tutorials and stuff showing how to extract multiple screenshots from a video using ffmpeg. You set -r and you can even start a certain amount in.

But I just want 1 screenshot at, say 01:23:45 in. Or 1 screenshot at 86% in.

This is all possible with ffmpegthumbnailer but it's another dependency I don't want to depend on. I want to be able to do it with ffmpeg.

Ciro Santilli OurBigBook.com
  • 347,512
  • 102
  • 1,199
  • 985
Peter Bengtsson
  • 7,235
  • 8
  • 44
  • 53

2 Answers2

339

Use the -ss option:

ffmpeg -ss 01:23:45 -i input -frames:v 1 -q:v 2 output.jpg
  • For JPEG output use -q:v to control output quality. Full range is a linear scale of 1-31 where a lower value results in a higher quality. 2-5 is a good range to try.

  • The select filter provides an alternative method for more complex needs such as selecting only certain frame types, or 1 per 100, etc.

  • Placing -ss before the input will be faster. See FFmpeg Wiki: Seeking and this excerpt from the ffmpeg cli tool documentation:

-ss position (input/output)

When used as an input option (before -i), seeks in this input file to position. Note the in most formats it is not possible to seek exactly, so ffmpeg will seek to the closest seek point before position. When transcoding and -accurate_seek is enabled (the default), this extra segment between the seek point and position will be decoded and discarded. When doing stream copy or when -noaccurate_seek is used, it will be preserved.

When used as an output option (before an output filename), decodes but discards input until the timestamps reach position.

position may be either in seconds or in hh:mm:ss[.xxx] form.

Ryan Romanchuk
  • 10,819
  • 6
  • 37
  • 41
llogan
  • 121,796
  • 28
  • 232
  • 243
  • 7
    This is MUCH faster. Thank you so much. Putting the -ss first makes a huge difference. – Peter Bengtsson Dec 21 '14 at 18:40
  • is there any way to get the n-th frame after the specified time? – dorien Sep 20 '17 at 05:00
  • @GuntherPiez I don't see any mention anywhere about possible artifacts. – Stefan Reich Aug 19 '19 at 15:06
  • 7
    Note that `vframes` is obsolete in (at least) version 4.2.2. Per manual "[`vframes`] is an obsolete alias for '`-frames:v`', which you should use instead." – Synexis Mar 02 '20 at 08:30
  • Works perfect and fast. – Smeterlink Jul 28 '20 at 23:39
  • My video is 15 seconds 15.000 Millis But when I try to get the 15.000 it gives me error but if I try to get 14.800 its ok. What can be the problem with latest frame? – Kyryl Zotov Apr 30 '21 at 12:14
  • Thank you very much, works as expected with ffmpeg version 4.2.2 – Prabath Aug 29 '22 at 15:53
  • 1
    Note that if there is warning `The specified filename 'output.jpg' does not contain an image sequence pattern or a pattern is invalid.\nUse a pattern such as %03d for an image sequence or use the -update opt on (with -frames:v 1 if needed) to write a single image.`, you can put `-update 1` between `-frames:v 1` and `output.jpg` – http8086 Nov 24 '22 at 06:52
66

FFmpeg can do this by seeking to the given timestamp and extracting exactly one frame as an image, see for instance:

ffmpeg -i input_file.mp4 -ss 01:23:45 -frames:v 1 output.jpg

Let's explain the options:

-i input file           the path to the input file
-ss 01:23:45            seek the position to the specified timestamp
-frames:v 1             only handle one video frame
output.jpg              output filename, should have a well-known extension

The -ss parameter accepts a value in the form HH:MM:SS[.xxx] or as a number in seconds. If you need a percentage, you need to compute the video duration beforehand.

FFmpegEnthusiast
  • 193
  • 1
  • 10
SirDarius
  • 41,440
  • 8
  • 86
  • 100
  • Seems to work as expected. I'm currently benchmarking if this is the same speed as using ffmpegthumbnailer. – Peter Bengtsson Dec 19 '14 at 18:12
  • Yeah, this approach is super slow. See http://www.peterbe.com/plog/fastest-way-to-take-screencaps-out-of-videos – Peter Bengtsson Dec 19 '14 at 20:02
  • 16
    try using the -ss option before -i since it will skip the decoding part of the pipeline. This might speedup the process. – SirDarius Dec 19 '14 at 20:07
  • 2
    Is there any way to output as PNG to the stream instead of a file? – Nicke Manarin Nov 12 '19 at 13:40
  • 7
    @NickeManarin Yes.. `ffmpeg -ss 01:23:45 -i video.mp4 -c:v png -frames:v 1 image.jpg`. Notice that I also put the `-ss` "seek" option ***before*** the input file on the command line, as others have recommended. – Glenn Slayden Nov 16 '19 at 04:37
  • @GlennSlayden Hmm, your example will output 1 frame to 1 file, not multiple frames to the output stream. – Nicke Manarin Nov 16 '19 at 21:19
  • @NickeManarin Oops, sorry, I misread that you just wanted a PNG instead of JPG version of what's shown in this answer. To output entire file as PNG to `stdout`, use this: `ffmpeg -i video.mp4 -c:v png -f image2pipe -` (notice the bare hyphen at the end). I believe `-f rawvideo -` might work instead of `image2pipe` also. – Glenn Slayden Nov 17 '19 at 02:31