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

Posted

技术标签:

【中文标题】使用ffmpeg提取帧的最快方法?【英文标题】:Fastest way to extract frames using ffmpeg? 【发布时间】:2012-06-13 00:26:49 【问题描述】:

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

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

?

【问题讨论】:

^ 更新网址:trac.ffmpeg.org/wiki/Seeking 如果您有空闲的 CPU 周期,您可以并行从多个视频中提取:parallel -i -r 1/1 .-%03d.bmp ::: *mpg 【参考方案1】:

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

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

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

【讨论】:

这会导致我的机器上大量丢帧。我可以告诉 ffmpeg 渲染所有内容吗? @Evi1M4chine 只需删除 -r 参数,这将提取所有帧 我想补充一点,虽然 JPEG 在 CPU 上并不是很困难,但未压缩的位图在存储上真的很困难,所以我怀疑与 JPEG 相比,使用 BMP 会获得更高的吞吐量. 提取所有帧:ffmpeg -r 1 file.mp4 -r 1 "$filename%03d.png" 你的意思是ffmpeg -r 1 -i file.mp4 -r 1 "$filename%03d.png,对吧? (你错过了-i【参考方案2】:

遇到了这个问题,所以这里有一个快速比较。比较这两种从 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_seekis the default ,并确保在输入视频-i 选项之前添加-ss

请注意,最好使用-filter:v -fps=fps=... 而不是-r 作为the latter may be inaccurate. 尽管the ticket is marked as fixed,我还是遇到了一些问题,所以最好谨慎行事。

【讨论】:

2016 年 2 月:从 ffmpeg 2.1 开始,精确搜索选项现在是默认选项 - trac.ffmpeg.org/wiki/Seeking bc 不是原生 Ubuntu 软件包,可以使用 bash:let "i = $i * 60"。顺便说一句 - 好主意 -i 之前添加-ss 的好提示。否则,整个视频将被解码,不需要的帧将被丢弃 由于这是谷歌的***,我想指出,在 2018 年,这仍然是一种产生红利的方法。最好的结果似乎是在主机的每个内核上运行一个 ffmpeg - 这(对于 bmp)会产生近乎线性的速度提升(直到遇到其他瓶颈,例如磁盘)。 @Franva 应该是这样的(未测试):-ss `let "j = $i * 60" && echo $j`【参考方案3】:

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

.

小解释:

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

【讨论】:

eq(n\,1) 将提取第二帧(顺序从 0 开始) -q:v-qscale:v (trac.ffmpeg.org/wiki/Encode/MPEG-4) 的别名,用于控制图像质量。 -vsync vfr是视频同步方式(你首先要了解-vf是一个filtergraph)。根据文档vfr 表示Frames are passed through with their timestamp or dropped so as to prevent 2 frames from having the same timestamp. 我认为 这是为了避免默认选项cfr 如此处所述ffmpeg.org/ffmpeg.html【参考方案4】:

就我而言,我至少每秒都需要帧。我使用了上面的“寻求”方法,但想知道我是否可以并行化任务。我在这里使用了 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 秒。唯一的问题是主线程没有干净地退出到终端,因为标准输出被淹没了。

【讨论】:

【参考方案5】:

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

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

【讨论】:

我正在尝试ffmpeg -i "input URL" -vf fps=1/5 out%d.png,其中输入 URL 必须是 https 链接。 当然,将它们缩小到很小的尺寸会更快,但这不是他想要的。【参考方案6】:

这对我有用

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

【讨论】:

【参考方案7】:

每分钟输出一张图片,命名为 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

【讨论】:

【参考方案8】:

这比目前所有其他命令都简单:

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

04 更改为您需要保存所有帧的位数。确保在数字前始终有一个0,以便输出帧名称用零填充。

【讨论】:

不需要-pix_fmt rgba。 PNG 编码器会自动选择合适的像素格式。 @llogan 谢谢,通过编辑将其删除。不过有来源吗? 您可以使用 ffmpeg -h encoder=png 查看 PNG 编码器支持的像素格式列表。见avcodec_find_best_pix_fmt_of_list documentation。 需要添加一个额外的dffmpeg -i input.mp4 '%04d.png'

以上是关于使用ffmpeg提取帧的最快方法?的主要内容,如果未能解决你的问题,请参考以下文章

使用 Python 从 Oracle 读取大量数据作为数据帧的最快方法

使用 pandas 合并和附加多个 CSV/数据帧的最快方法

使用 FFMPEG 将 -movflags +faststart 添加到 MP4 的最快方法,其他所有内容保持原样

使用 ffmpeg 进行最快解码的编码

如何设置ffmpeg使得转码最快

在 F# 中比较两个字节数组的最快方法