diff --git a/bin/__pycache__/handler.cpython-310.pyc b/bin/__pycache__/handler.cpython-310.pyc index f429df0..d3492d8 100644 Binary files a/bin/__pycache__/handler.cpython-310.pyc and b/bin/__pycache__/handler.cpython-310.pyc differ diff --git a/bin/__pycache__/probe.cpython-310.pyc b/bin/__pycache__/probe.cpython-310.pyc index 8e413cb..e3146e1 100644 Binary files a/bin/__pycache__/probe.cpython-310.pyc and b/bin/__pycache__/probe.cpython-310.pyc differ diff --git a/bin/handler.py b/bin/handler.py index 01058c1..314f529 100644 --- a/bin/handler.py +++ b/bin/handler.py @@ -32,7 +32,7 @@ class Handler: self.tmppath = "" self.videometa = {} - def handler(self, fsrpath, filepath, quality_mode, quality_setting, output_path, sharpening, scaling, threads=4 ): + def handler(self, fsrpath, filepath, quality_mode, quality_setting, output_path, sharpening, scaling, filetype, threads=4 ): # Function to be called when using this class as this function automatically determines if file is video or image print( '\n\nFSRImageVideoUpscalerFrontend - V1.1.0\n\nCopyright 2023 FSRImageVideoUpscalerFrontend contributors\n\n\n\n' ); @@ -61,7 +61,7 @@ class Handler: # Determining filetype if str(filepath)[len(filepath) - 4:] == ".mp4" or str(filepath)[len(filepath) - 4:] == ".mkv" or str(filepath)[len(filepath) - 4:] == ".MP4": print( '\n\n==> Upscaling video' ) - self.video_scaling(fsrpath, filepath, quality_mode, quality_setting, output_path, threads, sharpening, scaling) + self.video_scaling( fsrpath, filepath, quality_mode, quality_setting, output_path, threads, sharpening, scaling, filetype ) elif str(filepath)[len(filepath) - 4:] == ".JPG" or str(filepath)[len(filepath) - 4:] == ".png" or str(filepath)[len(filepath) - 4:] == ".jpg" or str(filepath)[len(filepath) - 5:] == ".jpeg": print( '\n==>upscaling image' ) self.photo_scaling(fsrpath, filepath, quality_mode, quality_setting, output_path) @@ -91,7 +91,7 @@ class Handler: os.system(self.command) print( '\n\n==>Photo upscaled' ); - def video_scaling( self, fsrpath, filepath, quality_mode, quality_setting, output_path, threads, sharpening, scaling ): + def video_scaling( self, fsrpath, filepath, quality_mode, quality_setting, output_path, threads, sharpening, scaling, filetype ): # DO NOT CALL THIS! Use Handler().handler() instead! # Splitting video into frames @@ -107,9 +107,9 @@ class Handler: print( '\n==> Created directory' ) if self.os_type == "linux": - self.command = f"ffmpeg -i {str(self.filepath)} {self.tmppath}ex%08d.bmp" + self.command = f"ffmpeg -i {str(self.filepath)} {self.tmppath}ex%08d.{ filetype }" elif self.os_type == "win32": - self.command = f"ffmpeg -i {str(self.filepath)} \"{self.tmppath}ex%08d.bmp\"" + self.command = f"ffmpeg -i {str(self.filepath)} \"{self.tmppath}ex%08d.{ filetype }\"" else: print("OS CURRENTLY UNSUPPORTED!") return False @@ -126,9 +126,9 @@ class Handler: for self.file in self.filelist: self.number += 1 if ( self.os_type == 'win32' ): - self.file_list.append( f"{self.tmppath}{self.file} {self.tmppath}sc\\ig{str(self.number).zfill(8)}.bmp " ); + self.file_list.append( f"{self.tmppath}{self.file} {self.tmppath}us\\ig{str(self.number).zfill(8)}.{ filetype } " ); else: - self.file_list.append( f"{self.tmppath}{self.file} {self.tmppath}sc/ig{str(self.number).zfill(8)}.bmp " ); + self.file_list.append( f"{self.tmppath}{self.file} {self.tmppath}us/ig{str(self.number).zfill(8)}.{ filetype } " ); if ( self.os_type == 'win32' ): self.maxlength = 8000 @@ -157,7 +157,7 @@ class Handler: time.sleep( 2 ); try: - os.mkdir(f"{self.tmppath}sc") + os.mkdir( f'{self.tmppath}us' ) except FileExistsError: pass @@ -166,31 +166,82 @@ class Handler: # Thread optimisation: Divide workload up into different threads & upscale using helper function # ############################################ - self.threads = threads if ( threads > multiprocessing.cpu_count() ): self.threads = multiprocessing.cpu_count(); - print( f'\n\n==>Using { self.threads } threads <==\n\n' ); + if ( not scaling ): + print( f'\n\n==> Upscaling using { self.threads } threads <==\n\n' ); - time.sleep( 2 ); + time.sleep( 2 ); - self.command_list = []; - self.file_list_length = len( self.file_list ); - for i in range( self.threads ): - self.files = ''; - for _ in range( int( self.file_list_length // self.threads ) ): - self.files += self.file_list.pop( 0 ); + self.command_list = []; + self.file_list_length = len( self.file_list ); + for i in range( self.threads ): + self.files = ''; + for _ in range( int( self.file_list_length // self.threads ) ): + self.files += self.file_list.pop( 0 ); + + if ( i == self.threads - 1 ): + for element in self.file_list: + self.files += element; + self.command_list.append( ( quality_mode, self.files, fsrpath, quality_setting, i, self.maxlength, self.os_type ) ) + + self.pool = multiprocessing.Pool( self.threads ) + self.pool.starmap( upscalerEngine, self.command_list ); + self.pool.close(); + self.pool.join(); + + if sharpening != '': + print( f'\n\n\n==> Sharpening using { self.threads } threads <==\n\n' ); + time.sleep( 2 ); + + self.pathSharpening = self.tmppath + + if ( not scaling ): + self.pathSharpening += 'us' + + time.sleep( 2 ); + try: + os.mkdir( f'{self.tmppath}sh' ) + except FileExistsError: + pass + # Locate Images and assemble FSR-Command + self.file_list = [] + self.filelist = os.listdir( self.pathSharpening ) + self.filelist.pop(0) + self.filelist.sort() + self.number = 0 + for self.file in self.filelist: + self.number += 1 + if ( self.os_type == 'win32' ): + self.file_list.append( f"{self.pathSharpening}\\{self.file} {self.tmppath}sh\\ig{str(self.number).zfill(8)}.{ filetype } " ); + else: + self.file_list.append( f"{self.pathSharpening}/{self.file} {self.tmppath}sh/ig{str(self.number).zfill(8)}.{ filetype } " ); - if ( i == self.threads - 1 ): - for element in self.file_list: - self.files += element; - self.command_list.append( ( quality_mode, self.files, fsrpath, quality_setting, i, self.maxlength, self.os_type, sharpening, scaling ) ) + if ( self.os_type == 'win32' ): + self.maxlength = 8000 + else: + self.maxlength = 31900 + self.pos = 1 - self.pool = multiprocessing.Pool( self.threads ) - self.pool.starmap( upscalerEngine, self.command_list ); - self.pool.close(); - self.pool.join(); + # assemble command list + self.command_list = []; + self.file_list_length = len( self.file_list ); + for i in range( self.threads ): + self.files = ''; + for _ in range( int( self.file_list_length // self.threads ) ): + self.files += self.file_list.pop( 0 ); + + if ( i == self.threads - 1 ): + for element in self.file_list: + self.files += element; + self.command_list.append( ( self.files, fsrpath, i, self.maxlength, self.os_type, sharpening ) ) + + self.pool = multiprocessing.Pool( self.threads ) + self.pool.starmap( sharpeningEngine, self.command_list ); + self.pool.close(); + self.pool.join(); # get Video's audio @@ -211,11 +262,19 @@ class Handler: os.system( self.command ) # reassemble Video - print( '\n\n==>Reassembling Video... with framerate @', self.framerate, '\n\n' ) + + self.outputPath = self.tmppath + if ( sharpening != '' ): + self.outputPath += 'sh' + else: + self.outputPath += 'us' + + + print( '\n\n==> Reassembling Video... with framerate @', self.framerate, ' <==\n\n' ) if self.os_type == 'linux': - self.command = f'ffmpeg -framerate {self.framerate} -i {self.tmppath}sc/ig%08d.bmp {output_path} -i {self.tmppath}audio.aac' + self.command = f'ffmpeg -framerate {self.framerate} -i {self.outputPath}/ig%08d.{ filetype } { output_path } -i {self.tmppath}audio.aac' elif self.os_type == 'win32': - self.command = f'ffmpeg -framerate {self.framerate} -i \"{self.tmppath}sc\\ig%08d.bmp\" {output_path} -i {self.tmppath}audio.aac' + self.command = f'ffmpeg -framerate {self.framerate} -i \"{self.outputPath}\\ig%08d.{ filetype }\" { output_path } -i {self.tmppath}audio.aac' else: print( 'OS CURRENTLY UNSUPPORTED!' ); return False @@ -223,7 +282,7 @@ class Handler: -def upscalerEngine ( quality_mode, files, fsrpath, quality_setting, number, maxlength, os_type, sharpening, scaling ): +def upscalerEngine ( quality_mode, files, fsrpath, quality_setting, number, maxlength, os_type ): files = files; # Refactoring of commands that are longer than 32K characters fileout = []; @@ -273,36 +332,94 @@ def upscalerEngine ( quality_mode, files, fsrpath, quality_setting, number, max while len( fileout ) > 0: files_handle = fileout.pop(0) - if ( not scaling ): - if quality_mode == 'default': - if os_type == 'linux': - command_us = f'wine {fsrpath} -QualityMode {quality_setting} {files_handle}' - elif os_type == 'win32': - command_us = f'FidelityFX_CLI -QualityMode {quality_setting} {files_handle}' - else: - print( 'OS CURRENTLY UNSUPPORTED!' ) - return False - else: - if os_type == 'linux': - command_us = f'wine {fsrpath} -Scale {quality_setting} {quality_setting} {files_handle}' - elif os_type == 'win32': - command_us = f'FidelityFX_CLI -Scale {quality_setting} {quality_setting} {files_handle}' - else: - print( 'OS CURRENTLY UNSUPPORTED!' ) - return False - sub = subprocess.Popen( command_us, shell=True ); - sub.wait(); - if sharpening != '': - print( '\n\n\n PROCESS: ', number, '\nRunning sharpening filter\n\n\n' ); + if quality_mode == 'default': if os_type == 'linux': - command_sharpening = f'wine {fsrpath} -Mode CAS -Sharpness {sharpening} {files_handle}' + command_us = f'wine {fsrpath} -QualityMode {quality_setting} {files_handle}' elif os_type == 'win32': - command_sharpening = f'FidelityFX_CLI -Mode CAS -Sharpness {sharpening} {files_handle}' + command_us = f'FidelityFX_CLI -QualityMode {quality_setting} {files_handle}' else: print( 'OS CURRENTLY UNSUPPORTED!' ) return False - sub2 = subprocess.Popen( command_sharpening, shell=True ); - sub2.wait() - + else: + if os_type == 'linux': + command_us = f'wine {fsrpath} -Scale {quality_setting} {quality_setting} {files_handle}' + elif os_type == 'win32': + command_us = f'FidelityFX_CLI -Scale {quality_setting} {quality_setting} {files_handle}' + else: + print( 'OS CURRENTLY UNSUPPORTED!' ) + return False + sub = subprocess.Popen( command_us, shell=True ); + sub.wait(); time.sleep(3) print( '\n\nCompleted executing Job\n\n\n PROCESS: ', number, '\n\n\n' ); + + +######################## +# +# Sharpening +# +####################### + +def sharpeningEngine ( files, fsrpath, number, maxlength, os_type, sharpening ): + files = files; + # Refactoring of commands that are longer than 32K characters + fileout = []; + pos = 0; + if len( files ) > maxlength: + while files[maxlength - pos:maxlength - pos + 1] != ' ': + pos += 1 + file_processing = files[:maxlength - pos] + if file_processing[len(file_processing) - 14:len(file_processing) - 12] == 'ex': + pos += 5 + else: + pass + while files[maxlength - pos:maxlength - pos + 1] != ' ': + pos += 1 + fileout.append(files[:maxlength - pos]) + filesopt = files[maxlength - pos:] + posx = 0 + posy = maxlength + + # Command refactoring for commands that are longer than 64K characters + if len(filesopt) > maxlength: + while len(filesopt) > maxlength: + posx += maxlength - pos + posy += maxlength - pos + pos = 1 + while files[posy - pos:posy - pos + 1] != ' ': + pos += 1 + file_processing = files[posx:posy - pos] + if file_processing[len(file_processing) - 14:len(file_processing) - 12] == 'ex': + pos += 5 + else: + pass + while files[posy - pos:posy - pos + 1] != ' ': + pos += 1 + + file_processing = files[posx:posy - pos] + fileout.append(file_processing) + filesopt = files[posy - pos:] + fileout.append(filesopt) + else: + fileout.append(files[maxlength - pos:]) + else: + fileout.append(files) + + # Upscaling images + print( '\n\n\nSharpening images... \n\n\n\n\n\n PROCESS: ', number, '\n\n\n' ) + + while len( fileout ) > 0: + files_handle = fileout.pop(0) + print( '\n\n\n PROCESS: ', number, '\nRunning sharpening filter\n\n\n' ); + if os_type == 'linux': + command_sharpening = f'wine {fsrpath} -Mode CAS -Sharpness {sharpening} {files_handle}' + elif os_type == 'win32': + command_sharpening = f'FidelityFX_CLI -Mode CAS -Sharpness {sharpening} {files_handle}' + else: + print( 'OS CURRENTLY UNSUPPORTED!' ) + return False + sub2 = subprocess.Popen( command_sharpening, shell=True ); + sub2.wait() + time.sleep(3) + print( '\n\nCompleted executing Job\n\n\n PROCESS: ', number, '\n\n\n' ); + diff --git a/config/settings.ini b/config/settings.ini index 352a9e9..de5ea23 100644 --- a/config/settings.ini +++ b/config/settings.ini @@ -1,6 +1,6 @@ [PathSettings] defaultOutputPath = $HOME/FSRImageVideoUpscaler/ -tmpPathLinux = /tmp/ +tmpPathLinux = /home/janis/ tmpPathWindows = C:\temp [DevSettings] diff --git a/fsrimagevideoupscaler-cli.py b/fsrimagevideoupscaler-cli.py index 73d60fa..de3f66a 100644 --- a/fsrimagevideoupscaler-cli.py +++ b/fsrimagevideoupscaler-cli.py @@ -12,11 +12,14 @@ import bin.handler import os import multiprocessing +allowedFiletypes = [ 'bmp', 'png', 'jpg' ]; + if __name__ == '__main__': - ap = argparse.ArgumentParser( description='FSRImageVideoUpscaler - CLI, a CLI application to upscale videos and images using FSR. ' ) + ap = argparse.ArgumentParser( description='FSRImageVideoUpscaler - CLI, a CLI application to upscale videos and images using FSR.' ) ap.add_argument( 'inputfile', help='File path for the video / image to be upscaled' ) ap.add_argument( 'outputfile', help='File path for the video / image that was upscaled' ) ap.add_argument( '-s', '--scalefactor', help='Scale factor for the video / image' ) + ap.add_argument( '-F', '--filetype', help='Change the file type of the temporary image files. Supports bmp, png, jpg. Video quality: bmp > png > jpg. Only use bmp for short videos only, or on high end, high-capacity SSDs, as it uses lots of storage space! png is default, if not specified.' ) ap.add_argument( '-S', '--sharpening', help='Sharpening factor (between 0 and 1 wheras 0 means no sharpening, 1 the most sharpening. Recommendation: Do not exceed 0.25, as it often looks bad)' ) ap.add_argument( '-N', '--noscaling', help='Do not upscale video, instead only sharpen. Sharpening argument required!', action='store_true' ) ap.add_argument( '-T', '--threads', help='Thread count to use. Cannot exceed CPU thread count. Scaling non-linear (using 2 threads is not exactly 2x the speed of 1 thread)' ) @@ -25,6 +28,8 @@ if __name__ == '__main__': handler = bin.handler.Handler() go = True; + go2 = True; + go3 = True; multiprocessing.freeze_support(); if ( os.path.exists( args.outputfile ) ): @@ -38,32 +43,41 @@ if __name__ == '__main__': if ( args.noscaling ): if ( args.sharpening != None ): if ( float( args.sharpening ) > 0 ): - go = True; + go2 = True; else: - go = False; + go2 = False; else: print( 'Missing argument for Sharpening. Please specify that argument and try again!' ) - go = False; + go2 = False; if ( args.sharpening != None ): if ( float( args.sharpening ) > 1 ): print( 'Invalid argument for Sharpening, please specify value between 0 and 1!' ) - go = False; + go3 = False; + + if ( args.filetype != None ): + if ( args.filetype in allowedFiletypes ): + filetype = args.filetype + else: + g3o = False + print( 'Invalid filetype for temp images specified. Please ensure to only use png, bmp or jpg!' ); + else: + filetype = 'png' - if ( go ): + if ( go and go2 and go3 ): if ( args.scalefactor ): if ( args.scalefactor[ len(args.scalefactor) -1: ] == 'x' ): if ( args.threads != None ): - handler.handler( 'bin/lib/FidelityFX_CLI.exe', args.inputfile, 'custom', args.scalefactor, args.outputfile, args.sharpening, args.noscaling, threads=int( args.threads ) ); + handler.handler( 'bin/lib/FidelityFX_CLI.exe', args.inputfile, 'custom', args.scalefactor, args.outputfile, args.sharpening, args.noscaling, filetype, threads=int( args.threads ) ); else: - handler.handler( 'bin/lib/FidelityFX_CLI.exe', args.inputfile, 'custom', args.scalefactor, args.outputfile, args.sharpening, args.noscaling ); + handler.handler( 'bin/lib/FidelityFX_CLI.exe', args.inputfile, 'custom', args.scalefactor, args.outputfile, args.sharpening, args.noscaling, filetype ); else: raise NameError( 'Argument Scale does require to be of form 2x! (it has to end in x)' ) else: if ( args.threads != None ): - handler.handler( 'bin/lib/FidelityFX_CLI.exe', args.inputfile, 'custom', '2x', args.outputfile, args.sharpening, args.noscaling, threads=int( args.threads ) ); + handler.handler( 'bin/lib/FidelityFX_CLI.exe', args.inputfile, 'custom', '2x', args.outputfile, args.sharpening, args.noscaling, filetype, threads=int( args.threads ) ); else: - handler.handler( 'bin/lib/FidelityFX_CLI.exe', args.inputfile, 'custom', '2x', args.outputfile, args.sharpening, args.noscaling ) + handler.handler( 'bin/lib/FidelityFX_CLI.exe', args.inputfile, 'custom', '2x', args.outputfile, args.sharpening, args.noscaling, filetype ) print( '\n\n---------------------------------------------------------------------------------\n\nDONE \n\nFSRImageVideoUpscalerFrontend V1.1.0\n\nCopyright 2023 FSRImageVideoUpscalerFrontend contributors\nThis application comes with absolutely no warranty to the extent permitted by applicable law\n\n' )