【问题标题】:FFMPEG Generate N Evenly Spaced PNG ScreenshotsFFMPEG 生成 N 个等距的 PNG 截图
【发布时间】:2017-06-19 14:23:49
【问题描述】:

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

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

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

【问题讨论】:

    标签: ffmpeg


    【解决方案1】:

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

    这是一个 Python 中的简单示例,它基本上完成了我所描述的操作。由于某种原因,我的 ffmpeg 版本生成的前两个静止图像都显示第 0 帧,但 Preview-3 到 Preview-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()
    

    【讨论】:

    • 谢谢。我想在 FFMPEG 中完成这一切(我正在使用不允许编写脚本的外部服务),但我很感激这个答案。
    • 在 print 调用后添加括号以使其与 python3 兼容。
    • 很好的答案!
    【解决方案2】:

    或者只用一个shell命令:

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

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

    【讨论】:

    • 太棒了。 bc 使用 ffprobe 计算 fps 秒数。 scale=6 是该号码中使用的位数。 qscale:v是可变比特率,设置为2。我不知道为什么vframes 10在里面。
    • 具有 FPS(1 / 帧间隔)的视频过滤器应该会产生具有完全正确帧数的流,但有时我们会因为四舍五入而偏离一帧。 -vframes 硬限制帧数(即有时丢弃最后一帧)。
    【解决方案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
    

    【讨论】:

      【解决方案4】:

      我无法让 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
      

      【讨论】:

      • 正确,我故意跳过第一帧。以我的经验,这个框架通常不是很有趣,因为它是黑色的,标题屏幕的开始,或者有人设置演示等。在我们的软件中,我们也默认使用第三个缩略图,因为这通常是动作发生的地方。
      猜你喜欢
      • 2010-11-17
      • 2019-04-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-12-20
      • 1970-01-01
      相关资源
      最近更新 更多