From de61f81a836b4a382552dd562cd97084f4aee955 Mon Sep 17 00:00:00 2001 From: Couleur <82747632+couleurm@users.noreply.github.com> Date: Fri, 4 Feb 2022 20:11:14 +0100 Subject: [PATCH] yaml to ini, random fruits as output filename suffix, and many fixes configs will now be ini instead of yaml renaming resampling to frame blending additional bool aliases random fruits as output (opt out) custom output folder verbose switch --- blender.vpy | 61 +++++++++++++++++++++--------------------- settings/recipe.ini | 35 ++++++++++++++++++++++++ settings/recipe.yaml | 27 ------------------- smoothie.py | 63 ++++++++++++++++++++------------------------ 4 files changed, 94 insertions(+), 92 deletions(-) create mode 100644 settings/recipe.ini delete mode 100644 settings/recipe.yaml diff --git a/blender.vpy b/blender.vpy index 3e86493..02e8c01 100644 --- a/blender.vpy +++ b/blender.vpy @@ -1,17 +1,15 @@ from vapoursynth import core import vapoursynth as vs from os import path # To split file extension -from yaml import load, FullLoader +from configparser import ConfigParser import havsfunc # aka Interframe2 -input_video="D:\\Video Vault\\R 01-30 15-30.mkv" -config_filepath="D:\\GitHub\\Smoothie\\settings\\recipe.yaml" - -conf = load(open(f"{config_filepath}"), Loader=FullLoader) +conf = ConfigParser() +conf.read(config_filepath) # Bool aliases yes = ['True','true','yes','y','1'] -no = ['False','false','no','n','0'] +no = ['False','false','no','n','0','null','',None] if path.splitext(input_video)[1] == '.avi': video = core.avisource.AVISource(f"{input_video}") @@ -19,50 +17,51 @@ if path.splitext(input_video)[1] == '.avi': video = core.fmtc.resampling(clip=video, css="420") video = core.fmtc.bitdepth(clip=video, bits=8) else: - video = core.ffms2.Source(source=f"{input_video}", cache=False) - -if float(conf['misc']['timescale']['in']) != 1: # Input timescale, done before interpolation - video = core.std.AssumeFPS(video, fpsnum=(video.fps * (1 / conf['misc']['timescale']['in']))) + video = core.ffms2.Source(source=input_video, cache=False) -if str(conf['interpolation']['pre interpolation']['enabled']).lower() in yes: # Pre-interpolating with RIFE +if float(conf['timescale']['in']) != 1: # Input timescale, done before interpolation + video = core.std.AssumeFPS(video, fpsnum=(video.fps * (1 / float(conf['timescale']['in'])))) - video = core.resize.Bicubic(video, format=vs.RGBS) - if str(conf['interpolation']['pre interpolation']['rife type']).lower() == 'cuda': - from vsrife import RIFE - while video.fps > conf['interpolation']['pre interpolation']['minimum fps']: - video = RIFE(video) - elif str(conf['interpolation']['pre interpolation']['rife type']).lower() == 'ncnn': - video = core.resize.Bicubic(video, format=vs.RGBS) - while video.fps < conf['interpolation']['pre interpolation']['minimum fps']: - video = core.rife.RIFE(video) - video = core.resize.Bicubic(video, format=vs.YUV420P8, matrix_s="709") +# if str(conf['interpolation']['pre interpolation']['enabled']).lower() in yes: # Pre-interpolating with RIFE +# +# video = core.resize.Bicubic(video, format=vs.RGBS) +# if str(conf['interpolation']['pre interpolation']['rife type']).lower() == 'cuda': +# from vsrife import RIFE +# while video.fps > conf['interpolation']['pre interpolation']['minimum fps']: +# video = RIFE(video) +# elif str(conf['interpolation']['pre interpolation']['rife type']).lower() == 'ncnn': +# video = core.resize.Bicubic(video, format=vs.RGBS) +# while video.fps < conf['interpolation']['pre interpolation']['minimum fps']: +# video = core.rife.RIFE(video) +# video = core.resize.Bicubic(video, format=vs.YUV420P8, matrix_s="709") if str(conf['interpolation']['enabled']).lower() in yes: # Interpolation using Interframe2 (uses SVP-Flow, which is what blur uses) video = havsfunc.InterFrame( video, GPU=True, - NewNum=conf['interpolation']['fps'], - Preset=conf['interpolation']['speed'], - Tuning=conf['interpolation']['tuning'], - OverrideAlgo=conf['interpolation']['algorithm'] + NewNum=int(conf['interpolation']['fps']), + Preset=str(conf['interpolation']['speed']), + Tuning=str(conf['interpolation']['tuning']), + OverrideAlgo=int(conf['interpolation']['algorithm']) ) -if float(conf['misc']['timescale']['out']) != 1: # Output timescale, done after interpolation - video = core.std.AssumeFPS(video, fpsnum=(video.fps * conf['misc']['timescale']['out'])) +if float(conf['timescale']['out']) != 1: # Output timescale, done after interpolation + video = core.std.AssumeFPS(video, fpsnum=(video.fps * float(conf['timescale']['out']))) if str(conf['misc']['deduplication']).lower() in yes: import filldrops video = filldrops.FillDrops(video, thresh=0.001) -if str(conf['resampling']['enabled']).lower() in yes: +if str(conf['frame blending']['enabled']).lower() in yes: import weighting - frame_gap = int(video.fps / conf['resampling']['fps']) - blended_frames = int(frame_gap * conf['resampling']['intensity']) + frame_gap = int(video.fps / int(conf['frame blending']['fps'])) + blended_frames = int(frame_gap * float(conf['frame blending']['intensity'])) if blended_frames > 0: if blended_frames % 2 == 0: blended_frames += 1 weights = weighting.equal(blended_frames) video = core.frameblender.FrameBlend(video, weights, True) - video = havsfunc.ChangeFPS(video, conf['resampling']['fps']) + video = havsfunc.ChangeFPS(video, int(conf['frame blending']['fps'])) + video.set_output() diff --git a/settings/recipe.ini b/settings/recipe.ini new file mode 100644 index 0000000..abd3064 --- /dev/null +++ b/settings/recipe.ini @@ -0,0 +1,35 @@ +# Will uses SVP-Flow to "guess" frames for a smoother resampling, slowers the higher you go +[interpolation] +enabled=y + # This completly disables interpolation, same thing goes for resampling +fps=960 +speed=medium +tuning=weak +algorithm=23 + +# Blends the frames to make a smoother video with a lower FPS (e.g 60FPS) +[frame blending] +enabled=y +fps=60 +intensity=1.27 + # The higher the frameblending's fps, the higher you can set this to + +[encoding] # How your video will be encoded +process=ffmpeg +args=-c:v hevc_nvenc -preset p7 -rc constqp -qp 18 + +[misc] +folder= + # Set a folder here if you wish to redirect all outputted videos to a specific folder, else leave it empty +deduplication=y + # Finds duplicate frames (e.g if you had encoding lag) and tries patching them with interpolation +container=mp4 + # If you prefer mkv, or would like to use uncompressed avi +verbose=false +flavors=fruits + # If you wish to disable random fruits being added to your video's prefixes, make this empty + +[timescale] +in=1 +out=1 + # If your clips are slowed down / you wish to accelerate your clips before resampling \ No newline at end of file diff --git a/settings/recipe.yaml b/settings/recipe.yaml deleted file mode 100644 index 3ef5317..0000000 --- a/settings/recipe.yaml +++ /dev/null @@ -1,27 +0,0 @@ -interpolation: # Will uses SVP-Flow to "guess" frames for a smoother resampling, slowers the higher you go - enabled: false # None of the settings will be affected if you disable this, same thing goes for resampling - fps: 960 - speed: medium - tuning: weak - algorithm: 23 - pre interpolation: # WIP - enabled: false - rife type: cuda - factor: 4 - -resampling: # Blends the frames to make a smoother video with a lower FPS (e.g 60FPS) - enabled: true - fps: 60 - intensity: 1.27 # The higher the resampling (final output) fps, the higher you can set this to - -encoding: # How your video will be encoded - process: ffmpeg - args: -c:v hevc_nvenc -preset p7 -rc vbr -qp 18 - -misc: - deduplication: y # Finds duplicate frames (e.g if you had encoding lag) and tries patching them with interpolation - custom output folder: null # Set a folder here if you wish to redirect all outputted videos, else leave it set to "null" - - timescale: # If your clips are slowed down / you wish to accelerate your clips before resampling - in: 1 - out: 1 \ No newline at end of file diff --git a/smoothie.py b/smoothie.py index 2868065..132762d 100644 --- a/smoothie.py +++ b/smoothie.py @@ -1,9 +1,13 @@ from sys import argv # parse args -from os import _exit, path # split file extension -from yaml import load,FullLoader # parse the config +from os import path # split file extension +from configparser import ConfigParser from subprocess import run # Run vs from random import choice # Randomize the smoothie's flavor)) +# Bool aliases +yes = ['True','true','yes','y','1'] +no = ['False','false','no','n','0','null','',None] + if len(argv) == 1: print(''' using Smoothie from the command line: @@ -21,68 +25,59 @@ def ensure(file, desc): print(f"{desc} file not found: {file}") exit(1) -if path.splitext(argv[1])[1] in ['.conf','.cfg','.txt','.json','.yml','yaml']: +if path.splitext(argv[1])[1] in ['.ini','.txt']: if path.dirname(argv[1]) == '': # If no directory, look for it in the settings folder recipe = path.join(path.dirname(argv[0]), f"settings\\{argv[1]}") config_filepath = recipe - conf = load(open(recipe), Loader=FullLoader) + conf = ConfigParser() + conf.read(recipe) else: # If there is a directory, it's a full path so just load it in - conf = load(open(argv[1]), Loader=FullLoader) + conf = ConfigParser() + conf.read(argv[1]) config_filepath = argv[1] queue = argv[2:] else: - recipe = path.join(path.dirname(argv[0]), "settings\\recipe.yaml") + recipe = path.join(path.dirname(argv[0]), "settings\\recipe.ini") config_filepath = recipe - conf = load(open(recipe), Loader=FullLoader) + conf = ConfigParser() + conf.read(recipe) queue = argv[1:] for video in queue: - if ['conf']['misc']['random flavors'] == True: + if str(conf['misc']['flavors']) in [yes,'fruits']: flavors = [ - 'Strawberry' - 'Blueberry' - 'Raspberry' - 'Blackberry' - 'Cherry' - 'Cranberry' - 'Coconut' - 'Peach' - 'Apricot' - 'Dragonftui' - 'Grapefruit' - 'Melon' - 'Papaya' - 'Watermelon' - 'Banana' - 'Pineapple' - 'Apple' - 'Kiwi' + 'Strawberry','Blueberry','Raspberry','Blackberry','Cherry','Cranberry','Coconut','Pineapple','Kiwi' + 'Peach','Apricot','Dragonfuit','Grapefruit','Melon','Papaya','Watermelon','Banana','Apple','Pear','Orange' ] else: flavors = ['Smoothie'] filename, ext = path.splitext(video) - if conf['misc']['custom output folder'] in [None,'null','','none','no','n']: + if conf['misc']['folder'] in no: outdir = path.dirname(video) else: - outdir = conf['misc']['custom output folder'] + outdir = conf['misc']['folder'] - out = path.join(outdir, filename + f'- {choice(flavors)}' + ext) + out = path.join(outdir, filename + f' - {choice(flavors)}' + ext) count=2 while path.exists(out): - out = path.join(outdir, filename + f'- {choice(flavors)}' + f' ({count})' + ext) + out = path.join(outdir, filename + f' - {choice(flavors)}' + f' ({count})' + ext) count+=1 command = [ # Split in two for readability - f"vspipe -i \"{path.join(path.dirname(argv[0]), 'blender.vpy')}\" --arg input_video=\"{video}\" --arg config_filepath=\"{config_filepath}\" --container y4m", - f"-| {conf['encoding']['process']} -hide_banner -loglevel warning -stats -i - {conf['encoding']['args']} \"{out}\"" + + f"cmd /c vspipe -y \"{path.join(path.dirname(argv[0]), 'blender.vpy')}\" --arg input_video=\"{video}\" --arg config_filepath=\"{config_filepath}\"", + f"- | {conf['encoding']['process']} -hide_banner -loglevel warning -stats -i - {conf['encoding']['args']} \"{out}\"" + # -i \"{video}\" -map 0:v -map 1:a? ] - print(command) + if (conf['misc']['verbose']) in yes: + print(command) + print(f"VIDEO: {video}") - run(' '.join(command),shell=True) + run(' '.join(command),shell=True) \ No newline at end of file