Skip to content

Instantly share code, notes, and snippets.

@alexflint
Last active November 10, 2021 16:36
Show Gist options
  • Save alexflint/9609202 to your computer and use it in GitHub Desktop.
Save alexflint/9609202 to your computer and use it in GitHub Desktop.
Create a video from a sequence of images (or PDFs) in python (using ffmpeg internally)
import os
import sys
import tempfile
import argparse
import subprocess
NATURAL_FPS = 30.
# Formats convertible by imagemagick:
CONVERTIBLE_EXTENSIONS = ['png', 'jpeg', 'jpg', 'pdf', 'pgm', 'bmp']
# Formats readable by ffmpeg:
FFMPEG_EXTENSIONS = ['png', 'jpg', 'jpeg']
def extension(path):
return os.path.splitext(path)[1][1:].lower()
def main():
parser = argparse.ArgumentParser(description='Make a video from a sequence of video frames')
parser.add_argument('--limit', type=int, required=False)
parser.add_argument('--fps', type=float, default=NATURAL_FPS)
parser.add_argument('input', nargs='+',
help='Images or PDFs from which to create the video, or a directory '+\
'containing images or pdfs')
parser.add_argument('output', type=str)
args = parser.parse_args()
if os.path.exists(args.output):
ext = extension(args.output)
if ext in CONVERTIBLE_EXTENSIONS:
print 'Error: Cannot overwrite with output: %s' % args.output
return -1
# Process input paths
input_paths = []
for path in args.input:
if os.path.isdir(path):
for entry in sorted(os.listdir(path)):
if extension(entry) in CONVERTIBLE_EXTENSIONS:
input_paths.append(os.path.join(path, entry))
else:
input_paths.append(path)
if args.limit:
input_paths = input_paths[:args.limit]
# Pick an intermediate format to convert the frames to
temp_ext = extension(input_paths[0])
if temp_ext not in FFMPEG_EXTENSIONS:
print '%s files are not readable by ffmpeg: will convert to png.' % temp_ext
temp_ext = 'png'
# Create symlinks
tempdir = tempfile.mkdtemp()
index = 0
for index, input_path in enumerate(input_paths):
ext = extension(input_path)
temp_path = os.path.join(tempdir, '%08d.%s' % (index, temp_ext))
if ext == temp_ext:
os.symlink(input_path, temp_path)
else:
print 'Converting %s to %s' % (input_path, temp_ext)
retval = subprocess.call(['convert', input_path, temp_path])
if retval:
print 'Unable to convert %s to %s' % (input_path, temp_ext)
return -1
# Create video
print '\nRunning ffmpeg:'
ffmpeg_options = {
'-filter:v' : 'setpts=%f*PTS' % (NATURAL_FPS / args.fps),
'-b:v' : '1000k',
'-f': 'image2',
'-i': os.path.join(tempdir, '%%08d.%s' % temp_ext)
}
command = ['ffmpeg']
for key, value in ffmpeg_options.iteritems():
command.extend((key, str(value)))
command.append('-y') # overwrite outputs
command.append(args.output)
print ' '.join(command)
subprocess.call(command)
print '\nWrote output to %s' % args.output
return 0
if __name__ == '__main__':
sys.exit(main())
@seghier
Copy link

seghier commented Sep 13, 2017

i test it and got error : usage: player.py [-h] [--limit LIMIT] [--fps FPS] input [input ...] c:/output
player.py: error: too few arguments

@MikeTheWatchGuy
Copy link

MikeTheWatchGuy commented Jan 12, 2018

Hi!
Do you have a Python 3 port?

I changed all the print statements and am getting this error about Symlinks.
I'm running windows 10

I LOVE how you kept everything using only standard stuff that I already have, but I need it to run of course :-)

I put my PNG images into a folder named inputs... does that work or do I need to name PNG?

I really would like to use this if I can.

Thank you for posting it.

Here is my error:
C:\Python\PycharmProjects\MIDI-Video>python "Make Video.py" inputs output
Traceback (most recent call last):
File "Make Video.py", line 94, in
main()
File "Make Video.py", line 62, in main
os.symlink(input_path, temp_path)
OSError: symbolic link privilege not held

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment