Extract A Single Image From A Video Using FFMPEG

Update: Still using this 8 years later, but in the form of a quick script, which is useful if you are doing it more than once.

Update 2: DHM points out the way this was written no longer works in modern versions of ffmpeg. Instead of -t 1, use -vframes 1

Dead handy, this:

ffmpeg -ss 0.5 -i inputfile.mp4 -vframes 1 -s 480x300 -f image2 imagefile.jpg

The various options:

  • -vframes 1: limit to 1 frame extracted
  • -ss 0.5: point of movie to extract from (ie seek to 0.5 seconds; you can also use HH:MM:SS.ZZZZ sexagesimal format)
  • -s 480x300: frame size of image to output (image resized to fit dimensions)
  • -f image2: forces format

I use this to generate preview stills for jwplayer to use. Dead handy!

Edit: Thanks to DieBagger who pointed out it is much faster to place the seek argument before the input file, and Matthias his point about the seek time.

18 thoughts on “Extract A Single Image From A Video Using FFMPEG”

  1. Thx man,

    one suggestion though: if you put the -ss in front of -i, ffmpeg will seek to the given position much faster…

  2. time ffmpeg -i wrong-way-fixed.mp4 -ss 125 \
     -t 1 -s 480x300 -f image2 /dev/null
    real    0m1.151s
    user    0m1.110s
    sys     0m0.030s
    time ffmpeg -ss 125 -i wrong-way-fixed.mp4 -t 1 \
    -s 480x300 -f image2 /dev/null
    real    0m0.050s
    user    0m0.040s
    sys     0m0.010s

    Well, there’s a quite clear difference there! It would be good to know exactly why it works this way though.

  3. Putting the -ss before the -i is faster (and less precise) because ffmpeg does not decode the video to find the frame. I think this has something to do with keyframes. Because of this I have found it to be problematic with some videos that will produce a gray frame, whereas putting the -ss after the -i will work fine (though of course much slower).

  4. i extracted the frames but they were not of good quality, pixels are getting scattered.
    So if any one have any idea for the good solution plz suggest me and my querry is->

    ffmpeg -i input.mp4 -r 25 -s 1280*720 -f image2 frame_%d.jpg

  5. You can use -ss both before and after the -i. The -ss before will skip to the nearest keyframe before the specified time. What you can do (and possibly use a simple wrapper script to generate this) is

    T=3456 # total seconds to skip
    ffmpeg -ss $((T-20)) -i file.mp4 -ss 20 … out.mp4

    Quite possibly adding -ss 0 after the -i file.mp4 also improves things. Certainly if I extract a 10 second segment using

    ffmpeg -ss 1234 -i file.mp4 -t 10 … out.mp4

    the output file (sometimes) isn’t quite right (for example the length isn’t exactly 10 seconds).

  6. Matthias: True- you can specify the time in either hh:mm:ss.micro (sexagesimal format!); or as a simple number, which is interpreted as seconds. I will update the post to point this out. Thanks 🙂

  7. Doesn’t work in 2020. That’s with ffmpeg 4.2.2-1. It produced this error.
    [image2 @ 0x559704154fc0] Could not get frame filename number 2 from pattern ‘imagefile.jpg’.
    Use ‘-frames:v 1’ for a single image, or ‘-update’ option, or use a pattern such as %03d within the filename.
    av_interleaved_write_frame(): Invalid argument

  8. @DHM: Quite correct! Good catch.

    I hadn’t noticed this as I was using it in a script] which uses -vframes 1.

    I’ll update this post. Cheers for the heads-up 🙂

    …seems I had actually updated the explanation to use vframes 1 already, just not the example. Sorted now!

Tell us what's on your mind