f Adding an alternate script that outsources the GIF generation process to gifski; it does better than the original script for colored GIFs, looks less good for B&W stuff. Overall, it's better, and it may become the 'main' version of this script.
This commit is contained in:
parent
f99c31f704
commit
13fc4bb70c
77
video_to_gif2.py
Normal file
77
video_to_gif2.py
Normal file
@ -0,0 +1,77 @@
|
||||
|
||||
import argparse
|
||||
from pathlib import Path
|
||||
import random
|
||||
import string
|
||||
import subprocess
|
||||
from typing import Any, Dict, List, Tuple
|
||||
|
||||
|
||||
def get_args() -> Dict[str, Any]:
|
||||
parser = argparse.ArgumentParser(
|
||||
prog='video_to_gif.py',
|
||||
description='Use ffmpeg and gifski to make GIFs from videos',
|
||||
epilog='— Be gay and do crime')
|
||||
parser.add_argument('input', type=str, metavar='INPUT', nargs='+',
|
||||
help="input file, supports passing a glob like /Users/MyName/Videos/*.mov")
|
||||
parser.add_argument('-w', '--width', type=str, default='960',
|
||||
help='width of the GIF in pixels, respecting aspect ratio (default: 960)')
|
||||
parser.add_argument('-r', '--framerate', type=str,
|
||||
default='12', help='framerate of GIF (default: 12)'),
|
||||
parser.add_argument('-t', '--tag', type=str, default=get_tag(),
|
||||
help='optional tag included in file name')
|
||||
return vars(parser.parse_args())
|
||||
|
||||
|
||||
def get_tag() -> str:
|
||||
return ''.join(random.choices(string.ascii_uppercase + string.digits, k=5))
|
||||
|
||||
|
||||
def call_ffmpeg(command: List[str]) -> bool:
|
||||
print("ffmpeg", ' '.join(command))
|
||||
full_command = ["ffmpeg", '-hide_banner', '-loglevel', 'error'] + command
|
||||
|
||||
# TODO: Find a way to avoid shell=True usage.
|
||||
process = subprocess.run(' '.join(full_command), shell=True)
|
||||
|
||||
return process.returncode == 0
|
||||
|
||||
|
||||
def generate_gif_files(inputs: List[str], args: Dict[str, Any]) -> Dict[str, Tuple[bool, str]]:
|
||||
tag = args['tag']
|
||||
width = args['width']
|
||||
framerate = args['framerate']
|
||||
|
||||
output_map = {}
|
||||
for input in inputs:
|
||||
file_name = f"{Path(input).stem}_{tag}.gif"
|
||||
full_path = f"{Path(input).parent}/{file_name}"
|
||||
command = ['-i', input, '-pix_fmt', 'yuv444p', '-f', 'yuv4mpegpipe', '-', '|', 'gifski', \
|
||||
'--width', f"{width}", '-r', f"{framerate}", '-o', f"{full_path}", '-']
|
||||
success = call_ffmpeg(command)
|
||||
# Tuple of (was it successful?, path of output)
|
||||
output_map[input] = (success, full_path)
|
||||
|
||||
return output_map
|
||||
|
||||
|
||||
def make_gifs(args: Dict[str, Any]) -> None:
|
||||
inputs = args['input']
|
||||
output_map = generate_gif_files(inputs, args)
|
||||
successes = 0
|
||||
for input in output_map:
|
||||
entry = output_map[input]
|
||||
if entry[0]:
|
||||
print(f"Created {entry[1]} from {input}")
|
||||
successes += 1
|
||||
total = len(output_map)
|
||||
print(f"{successes} of {total} commands succeeded.")
|
||||
|
||||
|
||||
def main() -> None:
|
||||
make_gifs(get_args())
|
||||
return
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
Loading…
Reference in New Issue
Block a user