FFMPEG generates N evenly spaced PNG screenshots

I am trying to create 8 screenshots for a downloaded video using FFMPEG. I currently have:

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

Creates a screenshot every 5 seconds. How to add the ability to create a screenshot for frames distributed as a percentage of the total time. Thank you In addition, is it possible to create a screenshot with 50%, for example? Thank.

+3
source share
4 answers

If you run ffmpeg with only the -i option, it will give you the length of the video on stderr (among many other things). You can write something around this by converting the duration and estimated number of frames to the correct -r option.

python, , . - , ffmpeg, 0, Preview-3 to 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()
+9

:

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 , .

+5

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 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

I could not get the brilliant oneliner Manfred Stienstra to create frames in the exact right place. If I asked to create 8 images from a movie with a frequency of 240 seconds, the first will be 15, the second - 45, etc. I wanted the first to be 0, the second to 30, etc.

So, I took it oneliner and created it

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
+1
source

Source: https://habr.com/ru/post/1755929/


All Articles