If you want 1/10 of what you have now (when you use -r 1) then use
-r 0.1
It will get 1 frame every 10 seconds instead of 1 frame every 1 second.
ffmpeg -i out1.avi -r 0.1 -f image2 image-%3d.jpeg
EDIT:
If you really what every 10th frame from video then you can use select with modulo 10
ffmpeg -i out1.mp4 -vf "select=not(mod(n\,10))" -vsync vfr image_%03d.jpg
but it may gives more images than before.
If video has 25fps then -r 1 gives image every 25th frame. And if video has 60fps then gives image every 60th frame. So it gives less images then this code which get image every 10th frame.
I'm trying to extract a frame every 10 seconds or 300 frames from a video but I keep getting errors
What is I frame extraction option every 10 sec?
video - Fastest way to extract frames using ffmpeg? - Stack Overflow
framerate - Extract the frame (in image format) at exactly every minute (or second) from a video (by ffmpeg) - Video Production Stack Exchange
How do I get one frame every N seconds?
Can I extract frames as JPG instead of PNG?
What's the difference between extracting frames and making a thumbnail?
It's very simple with ffmpeg, and it can output one frame every N seconds without extra scripting. To export as an image sequence just use myimage_%04d.png or similar as the output. The %0xd bit is converted to a zero-padded integer x digits long - the example I gave gets output as
myimage_0000.png,myimage_0001.png,myimage_0002.pngetc..
You can use lots of still image formats, png, jpeg, tga, whatever (see ffmpeg -formats for a full list).
Ok so now we know how to export the movie as a sequence of images, but say we don't want to export every single frame?
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.
So to put it all together, this is how it would look to save one frame of input.mov every four seconds to output_0000.png, output_0001.png etc.:
ffmpeg -i input.mov -r 0.25 output_%04d.png
Note that the -r 0.25 option goes after the -i input.mov part, because it's controlling the frame rate of the output. If you put it before the input it would treat the input file as if it had the specified frame rate.
Change the %xd to however many digits you need, e.g. if the command would create more than 10,000 frames change the %04d to %05d. This also works for input files that are image sequence. Read more here.
Windows users:
On the command line use %
example: ffmpeg -i inputFile.mp4 -r 1 outputFile_%02d.png
In CMD and BAT Scripts use %%
example: ffmpeg -i inputFile.mp4 -r 1 outputFile %%02d.png
So double %% in scripts, and single % on the interactive command line. Getting it wrong in either situation will generate an error.
Edit Worth checking out the discussion of file types in the comments below. There are advantages and disadvantages with each:
- jpeg much smaller file sizes, lossy, only 8-bit colour, no alpha.
- png lossless, large files, slow. 8-bit colour supports alpha.
- tiff lossless, even larger files, fast, supports up to 16 colour and alpha.
To specify the file format, just use the required extension in the output file, e.g. myimage_%04d.jpg, myimage_%04d.png or myimage_%04d.tiff
mplayer -vo jpeg -sstep 5 file.avi
will save a frame as a jpeg file every 5 seconds.
However, it will not stop at the end of the file, it will continue producing copies of the last frame. To avoid this, find the duration of the video in seconds, using another player, or with mplayer:
mplayer -vo null -ao null -frames 0 -identify file.avi
and look for a line like "ID_LENGTH=147.00".
Subtract 2 from the length, and use this value for the -endposoption. For example, for a 147 second video:
mplayer -vo jpeg -sstep 5 -endpos 145 file.avi
I think this is the correct line for it:
ffmpeg -i "G:\Series\[RH] Perritos bonitos Tai [Dual Audio] [BDRip] [1080p]" -vf fps=1/10 %04d.png
But now I keep getting:
Error opening input: Permission denied
I tried running CMD as an administrator, as a normal user and adding "G:" before the line, it didn't worked.
I already tried 3 easier programs to do this but all failed, now I have to use lines of code, please help.
Hello
I am trying to extract I frame every 10 sec for 24 fps video source.
Is it correct?
ffmpeg -i myvideo.mp4 -vf fps=1/600 img%03d.jpg
When it ran it, it looks like does not matched my video player timeframe.
Please correct me if I have worng.
Thanks
If the JPEG encoding step is too performance intensive, you could always store the frames uncompressed as BMP images:
ffmpeg -i file.mpg -r 1/1 $filename%03d.bmp
This also has the advantage of not incurring more quality loss through quantization by transcoding to JPEG. (PNG is also lossless but tends to take much longer than JPEG to encode.)
Came across this question, so here's a quick comparison. Compare these two different ways to extract one frame per minute from a video 38m07s long:
time ffmpeg -i input.mp4 -filter:v fps=fps=1/60 ffmpeg_%0d.bmp
1m36.029s
This takes long because ffmpeg parses the entire video file to get the desired frames.
time for i in {0..39} ; do ffmpeg -accurate_seek -ss `echo $i*60.0 | bc` -i input.mp4 -frames:v 1 period_down_$i.bmp ; done
0m4.689s
This is about 20 times faster. We use fast seeking to go to the desired time index and extract a frame, then call ffmpeg several times for every time index. Note that -accurate_seek is the default
, and make sure you add -ss before the input video -i option.
Note that it's better to use -filter:v -fps=fps=... instead of -r as the latter may be inaccurate. Although the ticket is marked as fixed, I still did experience some issues, so better play it safe.
This is a generalized version of the select filter to pick 8 frames every 5 seconds.
ffmpeg -i in.mp4 -vf "select='if(not(floor(mod(t,5)))*lt(ld(1),1),st(1,1)+st(2,n)+st(3,t));if(eq(ld(1),1)*lt(n,ld(2)+8),1,if(trunc(t-ld(3)),st(1,0)))'" -vsync 0 out%d.png
This will work for videos with any frame-rate, constant or variable.
Change the 5 in mod(t,5) for the interval, in seconds. And the 8 in ld(2)+8 for the number of frames to select.
You can use the select filter to select frames that match an expression. If the expression evaluates to a nonzero number or true, it'll select those frames. For example, if your filter is -vf select="between(n\, 0\, 7)", it'd select the first eight frames. The frame number is n, and it starts at zero.
Combining this with the mod (modulo) operator, you can select the first eight frames of every group of, say, 24 frames, so every second for a video of 24 fps:
ffmpeg -i input.mp4 -vf "select=between(mod(n\, 24)\, 0\, 7), setpts=N/24/TB" output.mp4
The setpts filter is needed to adjust the timestamps of the frames so that you don't have gaps in your video.
To get the first eight frames every five seconds, multiply the 24 by 5:
ffmpeg -i input.mp4 -vf "select=between(mod(n\, 120)\, 0\, 7), setpts=N/24/TB" output.mp4
To output everything into PNGs, change the output from output.mp4 to output-%04d.png — you'll get sequentially numbered PNGs.
Select 1 frame out of every 10 frames
You can use the select video filter in ffmpeg to do this:
ffmpeg -i input.mov -vf "select=not(mod(n\,10))" -vsync vfr -q:v 2 img_%03d.jpg
For JPG output you can vary quality with
-q:v. Effective range is 2 (best quality) to 31 (worst quality). You don't need this option if you want to output to PNG instead.This will output
img_001.jpg,img_002.jpg,img_003.jpg, etc.
The most important aspect in your question is the fact that the video uses 29.97 frames per second, not 30. Pesky NTSC.
Anyway, I think it would be easiest to just extract every frame, and then remove the ones you don't need:
ffmpeg -i 1.mov -y -f image2 -c:v mjpeg %03d.jpg
Then, remove the ones you don't need. Since every tenth frame will end with a 1.jpg, we can just take all the others …
find . -maxdepth 1 -not -iname "*1.jpg"
… and once you're sure these are the ones you want to remove:
find . -maxdepth 1 -not -iname "*1.jpg" -exec rm '{}' \;
If you can use mencoder, you could try the framestep option, as explained in the documentation, like framestep=10 in your case. I personally couldn't install/try it though.
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.
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!

