From 975c88dee6dad8459c12e0693f84e07a314811fb Mon Sep 17 00:00:00 2001 From: marko Date: Sat, 19 Feb 2022 10:33:14 +0100 Subject: [PATCH] Added thumbnails for 8.Kyu --- DieJudoGürtelprüfung/Kyu8.json | 60 +++++++++++++++++++----- DieJudoGürtelprüfung/clipper | 86 ++++++++++++++++++++-------------- 2 files changed, 100 insertions(+), 46 deletions(-) diff --git a/DieJudoGürtelprüfung/Kyu8.json b/DieJudoGürtelprüfung/Kyu8.json index f39afe6..490bd03 100644 --- a/DieJudoGürtelprüfung/Kyu8.json +++ b/DieJudoGürtelprüfung/Kyu8.json @@ -1,50 +1,86 @@ [ { "source": "http://download.m-m-sports.com/extras/judo_guertelpruefung/1_8%20fallrw.mp4", - "target": "videos/8terKyu/Ukemi/Ushiro.webm" + "target": "videos/8terKyu/Ukemi/Ushiro.webm", + "poster":{ + "timeIndex": "34.760" + } }, { "source": "http://mmurl.de/judo02", - "target": "videos/8terKyu/Ukemi/Yoko.webm" + "target": "videos/8terKyu/Ukemi/Yoko.webm", + "poster":{ + "timeIndex": "23.320" + } }, { "source": "http://mmurl.de/judo03", - "target": "videos/8terKyu/NageWaza/OGoshiUkiGoshi.webm" + "target": "videos/8terKyu/NageWaza/OGoshiUkiGoshi.webm", + "poster":{ + "timeIndex": "42.000" + } }, { "source": "http://mmurl.de/judo04", - "target": "videos/8terKyu/NageWaza/BeidbeinigeEindrehtechnik.webm" + "target": "videos/8terKyu/NageWaza/BeidbeinigeEindrehtechnik.webm", + "poster":{ + "timeIndex": "27.760" + } }, { "source": "http://mmurl.de/judo05", - "target": "videos/8terKyu/NageWaza/OSotoOtoshi.webm" + "target": "videos/8terKyu/NageWaza/OSotoOtoshi.webm", + "poster":{ + "timeIndex": "12.920" + } }, { "source": "http://mmurl.de/judo06", - "target": "videos/8terKyu/OsaeKomiWaza/KesaGatame.webm" + "target": "videos/8terKyu/OsaeKomiWaza/KesaGatame.webm", + "poster":{ + "timeIndex": "11.800" + } }, { "source": "http://mmurl.de/judo07", - "target": "videos/8terKyu/OsaeKomiWaza/MuneGatame.webm" + "target": "videos/8terKyu/OsaeKomiWaza/MuneGatame.webm", + "poster":{ + "timeIndex": "14.240" + } }, { "source": "http://mmurl.de/judo08", - "target": "videos/8terKyu/TachiWaza/EindrehtechnikUkeSchiebt.webm" + "target": "videos/8terKyu/TachiWaza/EindrehtechnikUkeSchiebt.webm", + "poster":{ + "timeIndex": "28.920" + } }, { "source": "http://mmurl.de/judo09", - "target": "videos/8terKyu/TachiWaza/OSotoOtoshiUkeZieht.webm" + "target": "videos/8terKyu/TachiWaza/OSotoOtoshiUkeZieht.webm", + "poster":{ + "timeIndex": "14.440" + } }, { "source": "http://mmurl.de/judo10", - "target": "videos/8terKyu/TachiWaza/UebergangStandBoden.webm" + "target": "videos/8terKyu/TachiWaza/UebergangStandBoden.webm", + "poster":{ + "timeIndex": "1:08.560" + } }, { "source": "http://mmurl.de/judo11", - "target": "videos/8terKyu/NeWaza/BefreiungOsaeKomi.webm" + "target": "videos/8terKyu/NeWaza/BefreiungOsaeKomi.webm", + "poster":{ + "timeIndex": "1:02.680" + } }, { "source": "http://mmurl.de/judo12", - "target": "videos/8terKyu/Randori/Randori.webm" + "target": "videos/8terKyu/Randori/Randori.webm", + "poster":{ + "timeIndex": "35.400" + } } ] \ No newline at end of file diff --git a/DieJudoGürtelprüfung/clipper b/DieJudoGürtelprüfung/clipper index e9da10e..03c3e8a 100755 --- a/DieJudoGürtelprüfung/clipper +++ b/DieJudoGürtelprüfung/clipper @@ -9,16 +9,41 @@ import sys import argparse import os +def generate_thumbnail(in_filename, out_filename, time, height): + try: + ( + ffmpeg + .input(in_filename, ss=time) + .filter('scale', -2, height) + .output(out_filename, vframes=1) + .overwrite_output() + .run(capture_stdout=True, capture_stderr=True) + ) + except ffmpeg.Error as e: + print(e.stderr.decode(), file=sys.stderr) + sys.exit(1) + +# setting width and height from hardcoded defaults -> configured defaults -> clip +def getDimensions(config, clip): + h = config['height'] if 'height' in config else 480 + w = config['width'] if 'width' in config else -2 + if 'scale' in clip: + h = clip['scale']['h'] if 'h' in clip['scale'] else h + w = clip['scale']['w'] if 'w' in clip['scale'] else w + + return h, w + config = { 'vcodec': "vp9", - 'acodec': "libopus" + 'acodec': "libopus", + 'height': 480, + 'quality': "best", } argParser = argparse.ArgumentParser() - jsonFileName = sys.argv[1] clipDict = {} @@ -28,7 +53,7 @@ with open(jsonFileName) as jf: ydl_opts = {"outtmpl": "%(id)s"} for clip in clipDict: - # create the directories so ffmped doesn't complain + # create the directories so ffmpeg doesn't complain try: outputDir = os.path.dirname(clip['target']) os.makedirs(outputDir) @@ -41,20 +66,22 @@ for clip in clipDict: ydl.download([clip['source']]) if infoDict is not None: - if 'from' in clip and 'to' in clip: - stream = ffmpeg.input( - # @todo This is a very bad hack because the outtmpl options doesn't seem to be working if the file gets reencoded - glob.glob(infoDict['id']+"*")[0], - ss=clip['from'], - to=clip['to'], - ) - else: - stream = ffmpeg.input( - glob.glob(infoDict['id']+"*")[0], - ) + # @todo This is a very bad hack because the outtmpl options doesn't seem to be working if the file gets reencoded + inputFilename = glob.glob(infoDict['id']+"*")[0] - video = stream.video - audio = stream.audio + # generate preview image for the video + if 'poster' in clip: + generate_thumbnail(inputFilename, os.path.splitext(clip['target'])[0]+".jpg", clip['poster']['timeIndex'], h ) + + kwArgs = {} + if 'from' in clip: + kwArgs['ss'] = clip['from'] + if 'to' in clip: + kwArgs['to'] = clip['to'] + + stream = ffmpeg.input( inputFilename, **kwArgs) + + video, audio = stream.video, stream.audio if 'crop' in clip: stream = ffmpeg.filter(stream, @@ -65,12 +92,7 @@ for clip in clipDict: h=clip['crop']['h'] ) - h = 480 - w = -2 - if 'scale' in clip: - h = clip['scale']['h'] if 'h' in clip['scale'] else 480 - w = clip['scale']['w'] if 'w' in clip['scale'] else -2 - stream = ffmpeg.filter(stream, "scale", height=h, width=w ) + h, w = getDimensions(config, clip) stream = ffmpeg.output(stream, clip['target'], @@ -82,7 +104,7 @@ for clip in clipDict: # "b:v":"276k", "minrate":"138k", "maxrate":"400k", # x360 "b:v":"512k", "minrate":"256k", "maxrate":"742k", # x480 LQ # "b:v":"750k", "minrate":"375k", "maxrate":"1088k", # x480 MQ - "quality":"good", + "quality": config['quality'] if 'quality' in config else "best", } ) try: @@ -110,12 +132,7 @@ for clip in clipDict: h=clip['crop']['h'] ) - h = 480 - w = -2 - if 'scale' in clip: - h = clip['scale']['h'] if 'h' in clip['scale'] else 480 - w = clip['scale']['w'] if 'w' in clip['scale'] else -2 - stream = ffmpeg.filter(stream, "scale", height=h, width=w ) + h, w = getDimensions(config, clip) stream = ffmpeg.output(stream, audio, clip['target'], @@ -124,8 +141,10 @@ for clip in clipDict: # "an":None, "y":None, "pass":"2", - "b:v":"512k", "minrate":"375k", "maxrate":"1088k", - "quality":"good", + # "b:v":"276k", "minrate":"138k", "maxrate":"400k", # x360 + "b:v":"512k", "minrate":"256k", "maxrate":"742k", # x480 LQ + # "b:v":"750k", "minrate":"375k", "maxrate":"1088k", # x480 MQ + "quality": config['quality'] if 'quality' in config else "best", "acodec": config['acodec'], } ) @@ -133,6 +152,5 @@ for clip in clipDict: ffmpeg.run(stream) except: print(infoDict) - - -#640x480p @ 24,25,30 512 (LQ), 750 (MQ) 256 (LQ) 375 (MQ) 742 (LQ) 1088 (MQ) + + exit(-1)