|
@@ -0,0 +1,91 @@ |
|
|
|
|
|
#!/bin/python3 |
|
|
|
|
|
""" basicclips.py -- generate video of clips from another video |
|
|
|
|
|
uses ffprobe, ffmpeg and MELT |
|
|
|
|
|
|
|
|
|
|
|
""" |
|
|
|
|
|
|
|
|
|
|
|
DEFAULT_CLIPS = 9 |
|
|
|
|
|
DEFAULT_DURATION = 15 |
|
|
|
|
|
DEFAULT_MIXER_DURATION = 2 |
|
|
|
|
|
FRAMERATE = 60 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def get_video_duration(videofile=None): |
|
|
|
|
|
"""Get video duration in seconds using ffprobe""" |
|
|
|
|
|
import subprocess |
|
|
|
|
|
|
|
|
|
|
|
if videofile is not None: |
|
|
|
|
|
ffprobe_args = ["ffprobe", "-v", "error", "-show_entries", |
|
|
|
|
|
"format=duration", "-of", |
|
|
|
|
|
"default=noprint_wrappers=1:nokey=1", |
|
|
|
|
|
videofile] |
|
|
|
|
|
seconds = subprocess.run(ffprobe_args, capture_output=True) |
|
|
|
|
|
if seconds: |
|
|
|
|
|
try: |
|
|
|
|
|
seconds = int(float(seconds.stdout)) |
|
|
|
|
|
return seconds |
|
|
|
|
|
except ValueError as e: |
|
|
|
|
|
print("Error getting seconds for ", videofile) |
|
|
|
|
|
print(e) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if __name__ == "__main__": |
|
|
|
|
|
import sys |
|
|
|
|
|
import os |
|
|
|
|
|
import tempfile |
|
|
|
|
|
import subprocess |
|
|
|
|
|
|
|
|
|
|
|
# Check/set settings using env vars |
|
|
|
|
|
|
|
|
|
|
|
if os.environ.get("HIGHLIGHT_CLIPS"): |
|
|
|
|
|
clips = os.environ.get("HIGHLIGHT_CLIPS") |
|
|
|
|
|
else: |
|
|
|
|
|
clips = DEFAULT_CLIPS |
|
|
|
|
|
|
|
|
|
|
|
if os.environ.get("HIGHLIGHT_DURATION"): |
|
|
|
|
|
duration = os.environ.get("HIGHLIGHT_DURATION") |
|
|
|
|
|
else: |
|
|
|
|
|
duration = DEFAULT_DURATION |
|
|
|
|
|
|
|
|
|
|
|
# TODO: argv sanity checks |
|
|
|
|
|
|
|
|
|
|
|
videofile = sys.argv[1] |
|
|
|
|
|
outputfile = sys.argv[2] |
|
|
|
|
|
|
|
|
|
|
|
video_duration = get_video_duration(videofile) |
|
|
|
|
|
mixer_duration = FRAMERATE * DEFAULT_MIXER_DURATION |
|
|
|
|
|
|
|
|
|
|
|
ffmpeg_common_args = ["ffmpeg", "-hide_banner", |
|
|
|
|
|
"-loglevel", "quiet"] |
|
|
|
|
|
melt_args = [] |
|
|
|
|
|
|
|
|
|
|
|
with tempfile.TemporaryDirectory() as tmpdir: |
|
|
|
|
|
tempclip_length = duration - 3 |
|
|
|
|
|
|
|
|
|
|
|
for i in range(1, clips+1): |
|
|
|
|
|
print("Processing clip", i) |
|
|
|
|
|
seek = int(float(video_duration * i / float(clips+1))) |
|
|
|
|
|
|
|
|
|
|
|
if i == 1: |
|
|
|
|
|
# no intro mixer on first clip |
|
|
|
|
|
melt_args.extend(["melt", |
|
|
|
|
|
os.path.join(tmpdir, "hi{}.mkv".format(i))]) |
|
|
|
|
|
else: |
|
|
|
|
|
melt_args.extend([os.path.join(tmpdir, "hi{}.mkv".format(i)), |
|
|
|
|
|
"-mix", str(mixer_duration), |
|
|
|
|
|
"-mixer", "luma"]) |
|
|
|
|
|
ffmpeg_args = ffmpeg_common_args + [ |
|
|
|
|
|
"-ss", str(seek), |
|
|
|
|
|
"-i", videofile, "-t", str(tempclip_length), |
|
|
|
|
|
"-c", "copy", os.path.join(tmpdir, "hi{}.mkv".format(i)) |
|
|
|
|
|
] |
|
|
|
|
|
print(ffmpeg_args) |
|
|
|
|
|
subprocess.run(ffmpeg_args) |
|
|
|
|
|
|
|
|
|
|
|
# MELT output format |
|
|
|
|
|
melt_args.extend(["-consumer", "avformat:{}".format(outputfile), |
|
|
|
|
|
"crf=20"]) |
|
|
|
|
|
print(melt_args) |
|
|
|
|
|
subprocess.run(melt_args) |
|
|
|
|
|
|
|
|
|
|
|
print("Done!") |