Fastest way to extract frames using ffmpeg?

前端 未结 7 1437
礼貌的吻别
礼貌的吻别 2020-12-07 07:20

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

ffmpeg -i file.mpg -r 1/1 $filename%03d.jpg
<
相关标签:
7条回答
  • 2020-12-07 07:39

    In my case I need frames at least every second. I used the 'seek to' approach above but wondered if I could parallelize the task. I used the N processes with 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 concurrent threads to N.

    This improved the 'seek to' approach from 26 seconds to 16 seconds in my case. The only problem is the main thread does not exit cleanly back to the terminal since stdout gets flooded.

    0 讨论(0)
  • 2020-12-07 07:41

    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.)

    0 讨论(0)
  • 2020-12-07 07:41

    I tried it. 3600 frame in 32 seconds. your method is really slow. You should try this.

    ffmpeg -i file.mpg -s 240x135 -vf fps=1 %d.jpg
    
    0 讨论(0)
  • 2020-12-07 07:43

    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.

    0 讨论(0)
  • 2020-12-07 07:48

    If you know exactly which frames to extract, eg 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'm using this with a pipe to Imagemagick's montage to get 10 frames preview from any videos. Obviously the frame numbers you'll need to figure out using ffprobe

    ffmpeg -i myVideo.mov -vf \
        select='eq(n\,1)+eq(n\,200)+eq(n\,400)+eq(n\,600)+eq(n\,800)+eq(n\,1000)',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
    

    .

    Little explanation:

    1. In ffmpeg expressions + stands for OR and * for AND
    2. \, is simply escaping the , character
    3. Without -vsync vfr -q:v 2 it doesn't seem to work but I don't know why - anyone?
    0 讨论(0)
  • 2020-12-07 07:50

    This worked for me

    ffmpeg -i file.mp4 -vf fps=1 %d.jpg

    0 讨论(0)
提交回复
热议问题