Skip to content

Instantly share code, notes, and snippets.

@tusing
Last active October 1, 2017 01:40
Show Gist options
  • Save tusing/c48035ec0bdeb67109a7b980c8fd1ee6 to your computer and use it in GitHub Desktop.
Save tusing/c48035ec0bdeb67109a7b980c8fd1ee6 to your computer and use it in GitHub Desktop.
import moviepy.editor as mpy
from moviepy.video.tools.cuts import FramesMatches
import argparse
import dill
import glob
from multiprocessing import Process
def main():
parser = argparse.ArgumentParser(description='Find GIF loops in a video')
parser.add_argument('--name', type=str, help='Input file name')
parser.add_argument('--resize', type=int, default=None,
help='Resize GIF to this width (suggested: 200)')
parser.add_argument('--interactive', help='Interactive GIF construction',
action='store_true', default=False)
parser.add_argument('--dill', help='Use existing dill file for this clip',
action='store_true', default=False)
parser.add_argument('--dillEverything', help='Dill all files in this directory',
action='store_true', default=False)
parser.add_argument('--gifEverything', help='Gif all dilled files in this directory',
action='store_true', default=False)
args = parser.parse_args()
if args.name:
filename = args.name
if not args.dill:
clip, matches = dillClip(filename, args.resize)
else:
with open(filename + '.dill', 'rb') as dillFile:
clip, matches = dill.load(dillFile)
dillFile.close()
if args.interactive:
interactiveGiffer(filename, clip, matches)
if args.dillEverything:
fileList = glob.glob('./*.mp4')
for fileName in fileList:
Process(target=dillClip, args=(fileName, None)).start()
if args.gifEverything:
fileList = glob.glob('./*.dill')
for fileName in fileList:
with open(fileName, 'rb') as dillFile:
clip, matches = dill.load(dillFile)
dillFile.close()
Process(target=makeGif, args=(
fileName.replace(".dill", ""), clip, matches, 1.5, clip.fps * 2, 0.33, 10)).start()
def saveDill(dillName, clip, matches):
with open(dillName, 'wb+') as dillFile:
dill.dump([clip, matches], dillFile)
dillFile.close()
def dillClip(name, resize):
dillName = name + '.dill'
if resize:
if resize > 200:
print("Warning: resize arg > 200 - conversion might be slow.")
clip = mpy.VideoFileClip(name).resize(width=resize)
else:
print("Warning: no resize option passed. Conversion might be slow.")
clip = mpy.VideoFileClip(name)
matches = FramesMatches.from_clip(clip, clip.fps * 2, 5)
clip.reader.close()
clip.audio.reader.close_proc()
saveDill(dillName, clip, matches)
return clip, matches
def getBestMatches(clip, matches, dist, search):
try:
best = matches.filter(
lambda x: x.time_span > float(dist)).best()
except IndexError:
print("Recalculating matches...")
matches = FramesMatches.from_clip(clip, int(search), dist)
best = matches.filter(
lambda x: x.time_span > float(dist)).best()
return best
def makeGif(name, clip, matches, dist, search, speed, fps):
best = getBestMatches(clip, matches, dist, search)
final = clip.subclip(best.t1, best.t2).speedx(float(speed))
meta = '_d' + str(dist) + '_s' + str(speed) + '_f' + str(fps)
name = name.replace(".mp4", meta + '.gif')
final.write_gif(name, fps=int(fps))
def interactiveGiffer(name, clip, matches):
while True:
# try:
dist = float(
input("Please enter your desired maximum match distance (default: 1.5): ") or "1.5")
search = int(
input("Please enter your desired search range (default: fps*2): ") or str(int(clip.fps * 2)))
speed = float(
input("Please enter your desired speed (default: 0.33): ") or "0.33")
fps = int(
input("Please enter your desired fps (default: 10): ") or "10")
makeGif(name, clip, matches, dist, search, speed, fps)
# except Exception as e:
# print(e)
# pass
if __name__ == "__main__":
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment