[FFmpeg-user] Grab stills on scene change math question

Moritz Barsnick barsnick at gmx.net
Tue Aug 25 15:18:20 CEST 2015

On Tue, Aug 25, 2015 at 14:22:31 +0200, Bouke (VideoToolShed) wrote:
> > calculate the images you want, and present them to the select filter in
> > the second run.
> But, I'm clueless on how to do that?.
> (Except restarting FFmpeg for each frame with a -ss)
> Btw, is there a -ss  option that i can input frames instead of time?

Assuming you can get the scene detection filter to print you the frame
numbers, and they turn out to be (e.g.) 0 22 134 157 222 331 413, you
can do this shell magic (line broken with '\' for readability):

for f in 0 22 134 157 222 331 413; do \
  if [ "$FRAMESPEC" = "" ]; then FRAMESPEC="eq(n\,${f})"; else FRAMESPEC="${FRAMESPEC}+eq(n\,${f})"; fi; \
done; \
ffmpeg -i video.mkv -vf "select=$FRAMESPEC" -vsync 0 video.%04d.jpg

(The "if" term is a bit crude and can be improved by some ${?bla}
construct. I didn't bother.)

In other words: Give the select filter an expression which evaluates to
!= 0 on the correct frames (frame number 'n'). That's a logical "OR"
expression, achieved in ffmpeg by adding the "eq()" expression terms.

The "-vsync" was added so that the image2 muxer doesn't blow the
resulting stream back up to 25 fps, but only passes through the frames
from the filter one by one.

(The %04d does _not_ represent 'n', as the muxer has no knowledge of
that - it just counts upward. You shouldn't mind.)

I verified this with a video where each frame was overlayed with its
number (drawtext filter with "text=%{n}"), and by selecting those
frames with my script and checking whether the correct ones were

Try that,

P.S.: The whole thing will break once the Unix command line or the
amount of command line bytes to be evaluated by ffmpeg get too long.

More information about the ffmpeg-user mailing list