FFMPEG生成N个均匀间隔的PNG屏幕截图

时间:2010-07-22 08:08:39

标签: ffmpeg

我正在尝试使用FFMPEG为上传的视频生成8个屏幕截图。我目前有:

  

ffmpeg -i Trailer-720p.mov -r .2   -vcodec png Preview-%d.png

每5秒生成一次屏幕截图。如何添加为分配超过总时间百分比的帧生成屏幕截图的功能。谢谢。此外,是否可以生成50%的屏幕截图?感谢。

4 个答案:

答案 0 :(得分:9)

如果仅使用-i参数运行ffmpeg,它将为您提供stderr上的视频长度(以及许多其他内容)。你可以写一些东西,将持续时间和预期的帧数转换成正确的-r参数。

这是python中的一个快速示例,它基本上完成了我所描述的内容。出于某种原因,我的ffmpeg版本生成的前两个静止图像都显示帧0,但预览-3到预览n的帧间隔正确。运行它,将第二个参数设置为'1',它将生成中间帧为Preview-3.png。

#!/usr/bin/env python

import sys,os,re
from subprocess import *

if len(sys.argv)<=1:
  print("usage: python oneinn.py filename frames")
  sys.exit(0)

try:
  fvideo = sys.argv[1]
  frames = float(sys.argv[2])
except:
  sys.stderr.write("Failed to parse parameters.\n")
  sys.exit(1)

output = Popen(["ffmpeg", "-i", fvideo], stderr=PIPE).communicate()

# searching and parsing "Duration: 00:05:24.13," from ffmpeg stderr, ignoring the centiseconds
re_duration = re.compile("Duration: (.*?)\.")
duration = re_duration.search(output[1]).groups()[0]

seconds = reduce(lambda x,y:x*60+y,map(int,duration.split(":")))
rate = frames/seconds

print("Duration = %s (%i seconds)" % (duration, seconds))
print("Capturing one frame every %.1f seconds" % (1/rate))

output = Popen(["ffmpeg", "-i", fvideo, "-r", str(rate), "-vcodec", "png", 'Preview-%d.png']).communicate()

答案 1 :(得分:7)

或者只是使用shell命令:

  

ffmpeg -i input.m4v -vf fps = 1 / $(echo'scale = 6;'$(ffprobe -loglevel   quiet -of'compact = nokey = 1:print_section = 0'-show_format_entry   持续时间输入.m4v)'/ 10'| bc)-vframes 10 -qscale:v 2   thumbnail-%d.png

这会创建10个缩略图,其尺寸与源视频相同。

答案 2 :(得分:3)

这是Ruby中的一个:

#!/usr/bin/env ruby
# pass the video source file(s) into the command line args
# resulting images are jpg, just change the appropriate ffmpeg option for png.
# the last line uses ImageMagick to stitch the images together into a strip.    
# the first image is thrown away, since it's a duplicate of the second image.

ARGV.each do|a|
  total_shots = 4
  size = '200x200'
  meta = %x(ffmpeg -i #{a} 2>&1 | grep 'Duration' | cut -d ' ' -f 4 | sed s/,//)
  time_parts = meta.match /(\d\d):(\d\d):(\d\d)\.(\d\d)/
  duration_seconds = time_parts[1].to_i*60*60+time_parts[2].to_i*60+time_parts[3].to_i+time_parts[4].to_f/100
  puts "*** Duration seconds: " +  duration_seconds.to_s
  %x(ffmpeg -i #{a} -r #{total_shots/duration_seconds} -s #{size} -f image2 -vframes #{total_shots+1} foo-%03d.jpg )
  files = (1..total_shots+1).map{|i| 'foo-' + ("%03d" % i) + '.jpg'}
  files.delete_at 0
  %x(convert -append #{files.join ' '} shot-strip.jpg)
end

答案 3 :(得分:1)

我无法让曼弗雷德·斯蒂恩斯特拉(Manfred Stienstra)精彩的oneliner在正确的位置生成帧。如果我指定从240秒的电影中生成8个图像,则第一个将是15,第二个是45,等等。我希望第一个是0,第二个是30,等等。

所以我把他的oneliner分开并创建了这个

ffmpeg=../bin/ffmpeg
ffprobe=../bin/ffprobe
outdir=../test
infile=../testmovie.mp4
outbase=testmovie

steps=8

len=`$ffprobe -loglevel quiet -of 'compact=nokey=1:print_section=0' -show_format_entry duration $infile`
echo length $len

secs=`echo 'scale=6;' $len ' /  ' $steps | bc`
echo secs $secs

for ((i=0; i <= $steps ; i++)); do
    echo =========================
    echo $ffmpeg -nostats -loglevel 0 \
            -i $infile -f image2 -ss `echo $secs \* $i | bc` \
             -vframes 1 "$outdir/$outbase"-$i.jpg
    $ffmpeg -nostats -loglevel 0 \
            -i $infile -f image2 -ss `echo $secs \* $i | bc`  \
             -vframes 1 "$outdir/$outbase"-$i.jpg
done