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