使用ffmpeg提取帧的最快方法?

时间:2012-06-09 00:20:27

标签: video ffmpeg

嗨我需要使用ffmpeg从视频中提取帧。有没有比这更快的方法:

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

8 个答案:

答案 0 :(得分:110)

如果JPEG编码步骤性能过于强烈,您可以始终将未压缩的帧存储为BMP图像:

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

这还具有通过转码为JPEG而不会通过量化而导致更多质量损失的优点。 (PNG也是无损的,但往往需要比JPEG更长的时间进行编码。)

答案 1 :(得分:49)

遇到这个问题,所以这里有一个快速比较。比较这两种不同的方式从38m07s长的视频中每分钟提取一帧:

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

1m36.029s

这需要很长时间,因为ffmpeg会解析整个视频文件以获得所需的帧。

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

这大约快20倍。我们使用快速搜索来转到所需的时间索引并提取一个帧,然后为每个时间索引多次调用ffmpeg。请注意-accurate_seek is the default ,并确保在输入视频-ss选项之前添加-i

请注意,使用-filter:v -fps=fps=...代替-r作为the latter may be inaccurate.更好the ticket is marked as fixed虽然{{3}},但我仍然遇到了一些问题,所以最好安全地使用它

答案 2 :(得分:6)

如果你确切知道要提取哪些帧,例如1,200,400,600,800,1000,请尝试使用:

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

我正在使用这个管道来Imagemagick的蒙太奇来从任何视频中获得10帧预览。显然,您需要使用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

小解释:

  1. 在ffmpeg中,+代表OR,而*代表AND
  2. \,只是转义,字符
  3. 没有-vsync vfr -q:v 2它似乎不起作用,但我不知道为什么 - 任何人?

答案 3 :(得分:3)

到目前为止,这比所有其他命令都简单:

ffmpeg -i input.mp4 '%04.png'

04 更改为保存所有帧所需的位数。

答案 4 :(得分:2)

这对我有用

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

答案 5 :(得分:1)

每分钟输出一张图像,分别为img001.jpg,img002.jpg,img003.jpg等。%03d指示每个输出图像的序号将使用3位数字进行格式化。

ffmpeg -i myvideo.avi -vf fps=1/60 img%03d.jpg

fps=1/60更改为fps=1/30,以每30秒捕获一次图像。同样,如果您想每5秒钟捕获一次图像,则将fps=1/60更改为fps=1/5

来源:https://trac.ffmpeg.org/wiki/Create a thumbnail image every X seconds of the video

答案 6 :(得分:0)

在我的情况下,我至少每秒都需要帧。我使用了上面的“寻求”方法,但想知道我是否可以将任务并行化。我在这里使用了带有FIFO方法的N个进程: 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

基本上我用&amp;分叉了这个过程。但将并发线程数限制为N.

在我的情况下,这改善了“寻求”方法从26秒到16秒。唯一的问题是主线程没有干净地退回到终端,因为stdout被淹没了。

答案 7 :(得分:0)

我尝试过。在32秒内达到3600帧。你的方法真的很慢。您应该尝试一下。

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