Last active
October 1, 2017 01:40
-
-
Save tusing/c48035ec0bdeb67109a7b980c8fd1ee6 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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