I'm looking a way to extract every second (2nd) I-Frame using ffmpeg and save them as a new timelapse video.
So far I managed to save all I-frames by the following command:
ffmpeg -i $FILE -vf "select='eq(pict_type,I)',setpts=N/FRAME_RATE/TB" -r 29.97 -vcodec libx264 -b:v 62M -an ./enc/${FILE}_cnv.mp4
but I need twice less I-frames in the resulting video. For example, if the I-frames in the original video are 1-8-16-24-32-40..., I need only 1-16-32-48... Is there a way to extract them without making a temporary video with all keyframes?
Update: since no universal solution was found, I decided to cheat with: -vf "select='eq(pict_type,I)*not(mod(n,16))',setpts=N/FRAME_RATE/TB"
At first glance it seems like you should be able to use a second step in your filter to select only even or odd numbered I frames, but after testing it doesn't seem like this is actually possible.
When looking at frame numbers we have two choices:
n, which seems to be the absolute frame number, andselected_n, which seems to be the filtered frame number. The ffmpeg filter docs are not very clear on how these values are defined.In my tests, it looks like if you use a filter like this:
You will get the same number of frames as you would if you omitted the
*not(mod(n,2)), which I assume is because I frames will always fall on odd-numberedndue to how the encoding works.If we try using
selected_ninstead, though, I find that only a single frame is ever selected. This makes sense because the filter can't ever match an even-number of selected frames, so it will only ever match the first one.Given this, I think your only choice here is to use a 2-stage approach, where you use one run of ffmpeg to get your iframes, then a second run of ffmpeg to drop every other frame. Something like: