Fastest way to extract frames with ffmpeg?

Hi, I need to extract frames from a video using ffmpeg .. Is there a faster way to do this than this:

ffmpeg -i file.mpg -r 1/1 $filename%03d.jpg 

?

+74
ffmpeg video
Jun 09 2018-12-12T00:
source share
5 answers

If the JPEG encoding step is too intense, it can always save uncompressed frames as BMP images:

 ffmpeg -i file.mpg -r 1/1 $filename%03d.bmp 

This also has the advantage that when quantized by transcoding to JPEG, there is no loss of quality. (PNG is also lossless, but tends to take much longer than JPEG for encoding.)

+95
Jun 09 '12 at 15:53
source share

Passed through this question, so here is a quick comparison. Compare these two different ways to extract one frame per minute from 38 m07 video:

 time ffmpeg -i input.mp4 -filter:v fps=fps=1/60 ffmpeg_%0d.bmp 

1m36.029s

This takes a lot of time because ffmpeg parses the entire video file to get the right 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 quickly use a quick time index search and retrieve a frame, then call ffmpeg several times for each time index. Note that -accurate_seek is the default , and make sure you add -ss before the original video -i .

Note that it is better to use -filter:v -fps=fps=... instead of -r the latter may be inaccurate. Although the ticket is marked as fixed , I still experienced some problems, so it’s better to play safely.

+47
Feb 04 '15 at 12:56
source share

If you know exactly what frames to extract, for example, 1, 200, 400, 600, 800, 1000, try using:

 select='eq(n\,1)+eq(n\,200)+eq(n\,400)+eq(n\,600)+eq(n\,800)+eq(n\,1000)' \ -vsync vfr -q:v 2 

I use this with the Imagemagick editing pipeline to get 10 preview frames from any video. Obviously the frame numbers you need to find out with ffprobe

 ffmpeg -i myVideo.mov -vf \ select='eq(n\,1)+eq(n\,200)+eq(n\,400)+eq(n\,600)+eq(n\,800)+eq(n\,100)',scale=320:-1 \ -vsync vfr -q:v 2 -f image2pipe -vcodec ppm - \ | montage -tile x1 -geometry "1x1+0+0<" -quality 100 -frame 1 - output.png 

,

A little explanation:

  1. In expressions, ffmpeg + stands for OR and * stands for AND
  2. \, Just an escape , character
  3. Without -vsync vfr -q:v 2 doesn't seem to work, but I don’t know why - anyone?
+6
Mar 23 '16 at 10:25
source share

In my case, I need frames at least every second. I used the β€œsearch” approach above, but wondered if I could parallelize the task. I used N processes with the FIFO approach here: https://unix.stackexchange.com/questions/103920/parallelize-a-bash-for-loop/216475#216475

 open_sem(){ mkfifo /tmp/pipe-$$ exec 3<>/tmp/pipe-$$ rm /tmp/pipe-$$ local i=$1 for((;i>0;i--)); do printf %s 000 >&3 done } run_with_lock(){ local x read -u 3 -n 3 x && ((0==x)) || exit $x ( "$@" printf '%.3d' $? >&3 )& } N=16 open_sem $N time for i in {0..39} ; do run_with_lock ffmpeg -ss 'echo $i' -i /tmp/input/GOPR1456.MP4 -frames:v 1 /tmp/output/period_down_$i.jpg & done 

Essentially, I forked the process with &, but limited the number of simultaneous threads to N.

This improved the search approach in my case from 26 to 16 seconds. The only problem is that the main thread does not exit cleanly back to the terminal, since stdout is loading.

0
Feb 15 '18 at 15:10
source share

I have tried this. 3600 frames in 32 seconds. Your method is really slow. You must try this.

ffmpeg -i file.mpg -s 240x135 -vf fps = 1% d.jpg

0
Jan 30 '19 at 14:28
source share



All Articles