Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

FFMPEG: Extracting 20 images from a video of variable length

I've browsed the internet for this very intensively, but I didn't find what I needed, only variations of it which are not quite the thing I want to use.

I've got several videos in different lengths and I want to extract 20 images out of every video from start to the end, to show the broadest impression of the video.

So one video is 16m 47s long => 1007s in total => I have to make one snapshot of the video every 50 seconds.

So I figured using the -r switch of ffmpeg with the value of 0.019860973 (eq 20/1007) but ffmpeg tells me that the framerate is too small for it...

The only way I figured out to do it would be to write a script which calls ffmpeg with a manipulated -ss switch and using -vframes 1 but this is quite slow and a little bit off for me since ffmpegs numerates the images itself...

like image 578
Vapire Avatar asked Dec 30 '11 12:12

Vapire


People also ask

How do I extract an image from a video using ffmpeg?

You can do this by adding the same argument -vf fps but with different values. You can extract images at a constant time interval by using fractions. For example, -vf fps=1/4 will output an image every 4 seconds. Similarly, -vf fps=2/4 will output 2 images every 4 seconds.

How to extract one frame of a video every n seconds to an image?

The trick is to simply change the frame rate of the output to whatever we want using the -r n option where n is the number of frames per second. 1 frame per second would be -r 1 , one frame every four seconds would be -r 0.25 , one frame every ten seconds would be -r 0.1 and so on.


2 Answers

I was trying to find the answer to this question too. I made use of radri's answer but found that it has a mistake.

ffmpeg -i video.avi -r 0.5 -f image2 output_%05d.jpg

produces a frame every 2 seconds because -r means frame rate. In this case, 0.5 frames a second, or 1 frame every 2 seconds.

With the same logic, if your video is 1007 seconds long and you need only 20 frames, you need a frame every 50.53 seconds. Translated to frame rate, would be 0.01979 frames a second.

So your code should be

ffmpeg -i video.avi -r 0.01979 -f image2 output_%05d.jpg

I hope that helps someone, like it helped me.

like image 97
Terrence Tan Avatar answered Sep 19 '22 08:09

Terrence Tan


I know I'm a bit late to the party, but I figured this might help:

For everyone having the issue where ffmpeg is generating an image for every single frame, here's how I solved it (using blahdiblah's answer):

First, I grabbed the total number of frames in the video:

ffprobe -show_streams <input_file> | grep "^nb_frames" | cut -d '=' -f 2

Then I tried using select to grab the frames:

ffmpeg -i <input_file> -vf "select='not(mod(n,100))'" <output_file>

But, no matter what the mod(n,100) was set to, ffmpeg was spitting out way too many frames. I had to add -vsync 0 to correct it, so my final command looked like this:

ffmpeg -i <input_file> -vsync 0 -vf "select='not(mod(n,100))'" <output_file>

(where 100 is the frame-frequency you'd like to use, for example, every 100th frame)

Hope that saves someone a little trouble!

like image 34
GhostCode Avatar answered Sep 18 '22 08:09

GhostCode