嗨,我需要使用ffmpeg从视频中提取帧。有没有比这更快的方法:
ffmpeg -i file.mpg -r 1/1 $filename%03d.jpg
?
parallel -i {} -r 1/1 {.}-%03d.bmp ::: *mpg
嗨,我需要使用ffmpeg从视频中提取帧。有没有比这更快的方法:
ffmpeg -i file.mpg -r 1/1 $filename%03d.jpg
?
parallel -i {} -r 1/1 {.}-%03d.bmp ::: *mpg
Answers:
如果JPEG编码步骤过于注重性能,则始终可以将未压缩的帧存储为BMP图像:
ffmpeg -i file.mpg -r 1/1 $filename%03d.bmp
这也具有不通过转码为JPEG量化而导致更多质量损失的优点。(PNG也是无损的,但是编码所需的时间往往比JPEG长得多。)
ffmpeg -r 1 file.mp4 -r 1 "$filename%03d.png"
ffmpeg -r 1 -i file.mp4 -r 1 "$filename%03d.png
吧?(您错过了-i
)
遇到了这个问题,因此这里有一个快速比较。比较这两种不同的方法,从38m07s长的视频中每分钟提取一帧:
time ffmpeg -i input.mp4 -filter:v fps=fps=1/60 ffmpeg_%0d.bmp
1分36.029秒
这需要很长时间,因为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
0分4.89秒
这快了大约20倍。我们使用快速查找转到所需的时间索引并提取帧,然后为每个时间索引多次调用ffmpeg。请注意,这-accurate_seek
是默认设置
,并确保您-ss
在输入视频-i
选项之前添加。
请注意,最好使用-filter:v -fps=fps=...
而不是,-r
因为后者可能不准确。尽管票被标记为固定票,但我仍然遇到了一些问题,因此最好放心使用。
bc
是不是原生Ubuntu的软件包,而不是一个可以使用bash: let "i = $i * 60"
。顺便说一句-好主意
-ss
之前添加-i
。否则,整个视频将被解码,不需要的帧将被丢弃
ffmpeg
在主机的每个内核上运行一个内核-对于bmp(对于bmp),其速度几乎呈线性提高(直到遇到其他瓶颈,例如磁盘)。
如果您确切知道要提取的帧,例如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
。
小解释:
+
代表OR和*
AND\,
只是逃避,
角色-vsync vfr -q:v 2
它似乎不起作用,但我不知道为什么-任何人?我尝试过这个。在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链接的地方。
ffmpeg -i file.mpg -vf fps=1 %d.jpg
就我而言,我至少每秒需要一帧。我使用了上面的“寻求”方法,但想知道是否可以并行执行任务。我在这里使用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秒。唯一的问题是,由于stdout被淹没,主线程不能干净地退出到终端。