178

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

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

?

4

8 回答 8

210

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

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

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

于 2012-06-09T15:53:46.240 回答
92

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

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 是默认设置 ,并确保-ss在输入视频-i选项之前添加。

请注意,最好使用-filter:v -fps=fps=...而不是后者,-r因为后者可能不准确。虽然票被标记为 fixed,但我还是遇到了一些问题,所以最好谨慎行事。

于 2015-02-04T12:56:41.013 回答
15

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

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

更改04为保存所有帧所需的位数。确保0在数字之前始终有一个,因此输出帧名称是零填充的。

于 2021-03-08T03:54:44.663 回答
14

如果您确切知道要提取哪些帧,例如 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\,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

.

小解释:

  1. 在 ffmpeg 中,表达式+代表 OR 和*AND
  2. \,只是逃避,角色
  3. 没有-vsync vfr -q:v 2它似乎不起作用,但我不知道为什么 - 任何人?
于 2016-03-23T22:25:25.977 回答
11

每分钟输出一张图片,命名为 img001.jpg、img002.jpg、img003.jpg 等。%03d 表示每张输出图片的序号将使用 3 位进行格式化。

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

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

来源:https://trac.ffmpeg.org/wiki/每 X 秒的视频创建一个缩略图

于 2020-10-08T10:27:52.753 回答
4

我尝试过这个。32 秒内 3600 帧。你的方法真的很慢。你应该试试这个。

ffmpeg -i file.mpg -s 240x135 -vf fps=1 %d.jpg
于 2019-01-30T14:28:50.497 回答
3

这对我有用

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

于 2020-07-13T10:32:13.253 回答
1

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

本质上,我用 & 分叉了进程,但将并发线程的数量限制为 N。

就我而言,这将“寻找”方法从 26 秒提高到了 16 秒。唯一的问题是主线程没有干净地退出到终端,因为标准输出被淹没了。

于 2018-02-15T15:10:38.020 回答