diff --git a/src/video2x.py b/src/video2x.py index 087af74..a800909 100755 --- a/src/video2x.py +++ b/src/video2x.py @@ -13,7 +13,7 @@ __ __ _ _ ___ __ __ Name: Video2X Controller Creator: K4YT3X Date Created: Feb 24, 2018 -Last Modified: January 4, 2020 +Last Modified: February 26, 2020 Editor: BrianPetkovsek Editor: SAT3LL @@ -34,7 +34,7 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License -along with this program. If not, see . +along with this program. If not, see . Description: Video2X is an automation software based on waifu2x image enlarging engine. It extracts frames from a video, enlarge it by a @@ -53,6 +53,7 @@ import contextlib import pathlib import re import shutil +import subprocess import sys import tempfile import time @@ -65,7 +66,7 @@ import GPUtil import psutil -VERSION = '3.0.0' +VERSION = '3.1.0' LEGAL_INFO = f'''Video2X Version: {VERSION} Author: K4YT3X @@ -82,10 +83,10 @@ LOGO = r''' \/ |_| \__,_| \___| \___/ |____| /_/ \_\ ''' -# each thread might take up to 2.5 GB during initialization. +# each process might take up to 2.5 GB during initialization. # (system memory, not to be confused with GPU memory) -SYS_MEM_PER_THREAD = 2.5 -GPU_MEM_PER_THREAD = 3.5 +SYS_MEM_PER_PROCESS = 2.5 +GPU_MEM_PER_PROCESS = 3.5 def parse_arguments(): @@ -107,7 +108,7 @@ def parse_arguments(): upscaler_options.add_argument('-m', '--method', help='upscaling method', action='store', default='gpu', choices=['cpu', 'gpu', 'cudnn']) upscaler_options.add_argument('-d', '--driver', help='upscaling driver', action='store', default='waifu2x_caffe', choices=AVAILABLE_DRIVERS) upscaler_options.add_argument('-y', '--model_dir', type=pathlib.Path, help='directory containing model JSON files', action='store') - upscaler_options.add_argument('-t', '--threads', help='number of threads to use for upscaling', action='store', type=int, default=1) + upscaler_options.add_argument('-p', '--processes', help='number of processes to use for upscaling', action='store', type=int, default=1) upscaler_options.add_argument('-c', '--config', type=pathlib.Path, help='video2x config file location', action='store', default=pathlib.Path(sys.argv[0]).parent.absolute() / 'video2x.yaml') upscaler_options.add_argument('-b', '--batch', help='enable batch mode (select all default values to questions)', action='store_true') @@ -135,7 +136,7 @@ def print_logo(): def check_memory(): """ Check usable system memory Warn the user if insufficient memory is available for - the number of threads that the user have chosen. + the number of processes that the user have chosen. """ memory_status = [] @@ -150,7 +151,7 @@ def check_memory(): pathlib.Path(r'C:\Program Files\NVIDIA Corporation\NVSMI\nvidia-smi.exe').is_file()): # Nvidia System Management Interface not available Avalon.warning('Nvidia-smi not available, skipping available memory check') - Avalon.warning('If you experience error \"cudaSuccess out of memory\", try reducing number of threads you\'re using') + Avalon.warning('If you experience error \"cudaSuccess out of memory\", try reducing number of processes you\'re using') else: with contextlib.suppress(ValueError): # "0" is GPU ID. Both waifu2x drivers use the first GPU available, therefore only 0 makes sense @@ -161,28 +162,28 @@ def check_memory(): for memory_type, memory_available in memory_status: if memory_type == 'system': - mem_per_thread = SYS_MEM_PER_THREAD + mem_per_process = SYS_MEM_PER_PROCESS else: - mem_per_thread = GPU_MEM_PER_THREAD + mem_per_process = GPU_MEM_PER_PROCESS - # if user doesn't even have enough memory to run even one thread - if memory_available < mem_per_thread: + # if user doesn't even have enough memory to run even one process + if memory_available < mem_per_process: Avalon.warning(f'You might have insufficient amount of {memory_type} memory available to run this program ({memory_available} GB)') Avalon.warning('Proceed with caution') - if args.threads > 1: - if Avalon.ask('Reduce number of threads to avoid crashing?', default=True, batch=args.batch): - args.threads = 1 + if args.processes > 1: + if Avalon.ask('Reduce number of processes to avoid crashing?', default=True, batch=args.batch): + args.processes = 1 # if memory available is less than needed, warn the user - elif memory_available < (mem_per_thread * args.threads): - Avalon.warning(f'Each waifu2x-caffe thread will require up to {SYS_MEM_PER_THREAD} GB of system memory') - Avalon.warning(f'You demanded {args.threads} threads to be created, but you only have {round(memory_available, 4)} GB {memory_type} memory available') - Avalon.warning(f'{mem_per_thread * args.threads} GB of {memory_type} memory is recommended for {args.threads} threads') - Avalon.warning(f'With your current amount of {memory_type} memory available, {int(memory_available // mem_per_thread)} threads is recommended') + elif memory_available < (mem_per_process * args.processes): + Avalon.warning(f'Each waifu2x-caffe process will require up to {SYS_MEM_PER_PROCESS} GB of system memory') + Avalon.warning(f'You demanded {args.processes} processes to be created, but you only have {round(memory_available, 4)} GB {memory_type} memory available') + Avalon.warning(f'{mem_per_process * args.processes} GB of {memory_type} memory is recommended for {args.processes} processes') + Avalon.warning(f'With your current amount of {memory_type} memory available, {int(memory_available // mem_per_process)} processes is recommended') # ask the user if he / she wants to change to the recommended - # number of threads + # number of processes if Avalon.ask('Change to the recommended value?', default=True, batch=args.batch): - args.threads = int(memory_available // mem_per_thread) + args.processes = int(memory_available // mem_per_process) else: Avalon.warning('Proceed with caution') @@ -285,20 +286,20 @@ if (args.width and not args.height) or (not args.width and args.height): if args.driver in ['waifu2x_caffe', 'waifu2x_converter', 'waifu2x_ncnn_vulkan']: check_memory() -# anime4k runs significantly faster with more threads -if args.driver == 'anime4k' and args.threads <= 1: - Avalon.warning('Anime4K runs significantly faster with more threads') - if Avalon.ask('Use more threads of Anime4K?', default=True, batch=args.batch): +# anime4k runs significantly faster with more processes +if args.driver == 'anime4k' and args.processes <= 1: + Avalon.warning('Anime4K runs significantly faster with more processes') + if Avalon.ask('Use more processes of Anime4K?', default=True, batch=args.batch): while True: try: - threads = Avalon.gets('Amount of threads to use [5]: ', default=5, batch=args.batch) - args.threads = int(threads) + processes = Avalon.gets('Amount of processes to use [5]: ', default=5, batch=args.batch) + args.processes = int(processes) break except ValueError: - if threads == '': - args.threads = 5 + if processes == '': + args.processes = 5 break - Avalon.error(f'{threads} is not a valid integer') + Avalon.error(f'{processes} is not a valid integer') # read configurations from configuration file config = read_config(args.config) @@ -309,17 +310,39 @@ config = read_config(args.config) driver_settings = config[args.driver] # check if driver path exists -if not pathlib.Path(driver_settings['path']).is_file(): - if not pathlib.Path(f'{driver_settings["path"]}.exe').is_file(): +if not pathlib.Path(driver_settings['path']).exists(): + if not pathlib.Path(f'{driver_settings["path"]}.exe').exists(): Avalon.error('Specified driver executable directory doesn\'t exist') Avalon.error('Please check the configuration file settings') raise FileNotFoundError(driver_settings['path']) # if the driver is Anime4K, check if JDK 12 is installed +jdk_available = True if args.driver == 'anime4k': - if not pathlib.Path('C:/Program Files/Java/jdk-12.0.2/bin/java.exe').is_file(): - Avalon.warning('Cannot find JDK 12 at its default installation location') - Avalon.warning('Please ensure you have JDK 12 installed and configured') + + # if specified JDK path doesn't exist + if not pathlib.Path(driver_settings['java_path']).is_file(): + + # try to find JDK on system + if shutil.which('java') is not None: + + # check if JDK has master version 12 + java_version_output = subprocess.run(['java', '-version'], capture_output=True).stderr + if re.search(r'java version "12\.\d\.\d"', java_version_output.decode().split('\n')[0]) is not None: + driver_settings['java_path'] = shutil.which('java') + else: + jdk_available = False + + # if java is not found in PATH + else: + jdk_available = False + +# if JDK 12 is not found +# warn the user and exit +if jdk_available is False: + Avalon.error('Cannot find JDK 12 on this system') + Avalon.error('Please ensure you have JDK 12 installed and configured') + sys.exit(1) # read FFmpeg configuration ffmpeg_settings = config['ffmpeg'] @@ -388,7 +411,7 @@ try: upscaler.scale_height = args.height upscaler.scale_ratio = args.ratio upscaler.model_dir = args.model_dir - upscaler.threads = args.threads + upscaler.processes = args.processes upscaler.video2x_cache_directory = video2x_cache_directory upscaler.image_format = image_format upscaler.preserve_frames = preserve_frames @@ -416,7 +439,7 @@ try: upscaler.scale_height = args.height upscaler.scale_ratio = args.ratio upscaler.model_dir = args.model_dir - upscaler.threads = args.threads + upscaler.processes = args.processes upscaler.video2x_cache_directory = video2x_cache_directory upscaler.image_format = image_format upscaler.preserve_frames = preserve_frames