How to capture first X frames every X seconds into a PNG with FFmpeg?

1

I am new to using the command line. It is pretty cool and exciting to learn, but I am stuck.

I have a video where, for example, I want to capture the first 8 frames every 5 seconds into an image.

I've written this command:

ffmpeg -i video.mp4 -vf fps=8/20 out%04d.png

I see it captures 8 frames every 20 seconds, and not the first 8 frames. Is there a way I could specify this in the command?

AFG

Posted 2018-12-30T01:06:53.283

Reputation: 11

I was trying to get the direct video link from my Dropbox folder instead of downloading. I was using the wrong link, but I figured it out! – AFG – 2018-12-30T16:52:07.763

Answers

2

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.

Gyan

Posted 2018-12-30T01:06:53.283

Reputation: 21 016

Pretty complex expression. Had to translate that to pseudocode to figure out what was going on. – slhck – 2018-12-30T22:00:55.163

1

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.

slhck

Posted 2018-12-30T01:06:53.283

Reputation: 182 472