Example #1
0
# overwrite driver_settings with driver_args
if driver_args is not None:
    driver_args_dict = vars(driver_args)
    for key in driver_args_dict:
        if driver_args_dict[key] is not None:
            driver_settings[key] = driver_args_dict[key]

# start execution
try:
    # start timer
    begin_time = time.time()

    # initialize upscaler object
    upscaler = Upscaler(input_path=video2x_args.input,
                        output_path=video2x_args.output,
                        driver_settings=driver_settings,
                        ffmpeg_settings=ffmpeg_settings,
                        gifski_settings=gifski_settings)

    # set upscaler optional options
    upscaler.driver = video2x_args.driver
    upscaler.scale_ratio = video2x_args.ratio
    upscaler.processes = video2x_args.processes
    upscaler.video2x_cache_directory = video2x_cache_directory
    upscaler.image_format = image_format
    upscaler.preserve_frames = preserve_frames

    # run upscaler
    upscaler.run()

    Avalon.info(
Example #2
0
    def load(self):

        debug_prefix = "[Dandere2x.load]"
    
        # Create Utils
        self.utils = Utils()

        # Set the log file, here's why loglevel 0 isn't literally 0
        self.utils.clean_set_log()

        self.utils.log(colors["phases"], 3, debug_prefix, "# # [Load phase] # #")
        self.utils.log(color, 3, debug_prefix, "Created Utils()")

        # Check a few things and make sure the settings are compatible
        self.utils.log(color, 3, debug_prefix, "Creating FailSafe()")
        self.failsafe = FailSafe(self.utils)

        # Communication between files, static
        self.utils.log(color, 3, debug_prefix, "Creating Context()")
        self.context = Context(self.utils, self.config, self.failsafe)

        # Communication between files, depends on runtime
        self.utils.log(color, 3, debug_prefix, "Creating Controller()")
        self.controller = Controller(self.utils, self.context)

        # Let Utils access Controller
        self.utils.log(color, 3, debug_prefix, "Giving Utils, Controller")
        self.utils.set_controller(self.controller)

        # Let Utils access Context
        self.utils.log(color, 3, debug_prefix, "Giving Utils, Context")
        self.utils.set_context(self.context)

        # Stats
        self.utils.log(color, 3, debug_prefix, "Creating Dandere2xStats()")
        self.stats = Dandere2xStats(self.context, self.utils, self.controller)

        # Deals with Video related stuff
        self.utils.log(color, 3, debug_prefix, "Creating Video()")
        self.video = Video(self.context, self.utils, self.controller)

        # Deals with images, mostly numpy wrapper and special functions like block substitution
        self.utils.log(color, 3, debug_prefix, "Creating Frame()")
        self.frame = Frame

        # Our upscale wrapper, on which the default is upscaler
        self.utils.log(color, 3, debug_prefix, "Creating Upscaler()")
        self.upscaler = Upscaler(self.context, self.utils, self.controller, self.frame)

        # Math utils, specific cases for Dandere2x
        self.utils.log(color, 3, debug_prefix, "Creating Dandere2xMath()")
        self.d2xmath = Dandere2xMath(self.context, self.utils)

        # Dandere2x C++ wrapper
        self.utils.log(color, 3, debug_prefix, "Creating Dandere2xCPPWraper()")
        self.d2xcpp = Dandere2xCPPWraper(self.context, self.utils, self.controller, self.video, self.stats)

        # "Layers" of processing before the actual upscale from upscaler
        self.utils.log(color, 3, debug_prefix, "Creating Processing()")
        self.processing = Processing(self.context, self.utils, self.controller, self.frame, self.video, self.upscaler)

        # On where everything is controlled and starts
        self.utils.log(color, 3, debug_prefix, "Creating Core()")
        self.core = Core(self.context, self.utils, self.controller, self.upscaler, self.d2xcpp, self.processing, self.stats, self.video)

        # Vapoursynth wrapper
        self.utils.log(color, 3, debug_prefix, "Creating VapourSynthWrapper()")
        self.vapoursynth_wrapper = VapourSynthWrapper(self.context, self.utils, self.controller)
Example #3
0
# start execution
try:
    # start timer
    begin_time = time.time()

    # initialize upscaler object
    upscaler = Upscaler(
        # required parameters
        input_path=video2x_args.input,
        output_path=video2x_args.output,
        driver_settings=driver_settings,
        ffmpeg_settings=ffmpeg_settings,
        gifski_settings=gifski_settings,
        # optional parameters
        driver=video2x_args.driver,
        scale_ratio=video2x_args.ratio,
        scale_width=video2x_args.width,
        scale_height=video2x_args.height,
        processes=video2x_args.processes,
        video2x_cache_directory=video2x_cache_directory,
        extracted_frame_format=extracted_frame_format,
        output_file_name_format_string=output_file_name_format_string,
        image_output_extension=image_output_extension,
        video_output_extension=video_output_extension,
        preserve_frames=preserve_frames,
    )

    # run upscaler
    upscaler.run()

    Avalon.info(
        _("Program completed, taking {} seconds").format(
Example #4
0
    if args.input.is_file():

        # upscale single video file
        Avalon.info(f'Upscaling single video file: {args.input}')

        # check for input output format mismatch
        if args.output.is_dir():
            Avalon.error('Input and output path type mismatch')
            Avalon.error('Input is single file but output is directory')
            raise Exception('input output path type mismatch')
        if not re.search(r'.*\..*$', str(args.output)):
            Avalon.error('No suffix found in output file path')
            Avalon.error('Suffix must be specified for FFmpeg')
            raise Exception('No suffix specified')

        upscaler = Upscaler(input_video=args.input, output_video=args.output, method=args.method, waifu2x_settings=waifu2x_settings, ffmpeg_settings=ffmpeg_settings)

        # set optional options
        upscaler.waifu2x_driver = args.driver
        upscaler.scale_width = args.width
        upscaler.scale_height = args.height
        upscaler.scale_ratio = args.ratio
        upscaler.model_dir = args.model_dir
        upscaler.threads = args.threads
        upscaler.video2x_cache_directory = video2x_cache_directory
        upscaler.image_format = image_format
        upscaler.preserve_frames = preserve_frames

        # run upscaler
        upscaler.create_temp_directories()
        upscaler.run()
Example #5
0
class Dandere2x():
    def __init__(self, config):
        self.config = config

        #os.system("sh release/compile_d2xcpp_linux.sh")
        #os.system("sh dandere2x_cpp_tremx/linux_cross_compile_windows.sh")
        #exit()

    # This function loads up the "core" variables and objects
    def load(self):

        debug_prefix = "[Dandere2x.load]"
    
        # Create Utils
        self.utils = Utils()

        # Set the log file, here's why loglevel 0 isn't literally 0
        self.utils.clean_set_log()

        self.utils.log(colors["phases"], 3, debug_prefix, "# # [Load phase] # #")
        self.utils.log(color, 3, debug_prefix, "Created Utils()")

        # Check a few things and make sure the settings are compatible
        self.utils.log(color, 3, debug_prefix, "Creating FailSafe()")
        self.failsafe = FailSafe(self.utils)

        # Communication between files, static
        self.utils.log(color, 3, debug_prefix, "Creating Context()")
        self.context = Context(self.utils, self.config, self.failsafe)

        # Communication between files, depends on runtime
        self.utils.log(color, 3, debug_prefix, "Creating Controller()")
        self.controller = Controller(self.utils, self.context)

        # Let Utils access Controller
        self.utils.log(color, 3, debug_prefix, "Giving Utils, Controller")
        self.utils.set_controller(self.controller)

        # Let Utils access Context
        self.utils.log(color, 3, debug_prefix, "Giving Utils, Context")
        self.utils.set_context(self.context)

        # Stats
        self.utils.log(color, 3, debug_prefix, "Creating Dandere2xStats()")
        self.stats = Dandere2xStats(self.context, self.utils, self.controller)

        # Deals with Video related stuff
        self.utils.log(color, 3, debug_prefix, "Creating Video()")
        self.video = Video(self.context, self.utils, self.controller)

        # Deals with images, mostly numpy wrapper and special functions like block substitution
        self.utils.log(color, 3, debug_prefix, "Creating Frame()")
        self.frame = Frame

        # Our upscale wrapper, on which the default is upscaler
        self.utils.log(color, 3, debug_prefix, "Creating Upscaler()")
        self.upscaler = Upscaler(self.context, self.utils, self.controller, self.frame)

        # Math utils, specific cases for Dandere2x
        self.utils.log(color, 3, debug_prefix, "Creating Dandere2xMath()")
        self.d2xmath = Dandere2xMath(self.context, self.utils)

        # Dandere2x C++ wrapper
        self.utils.log(color, 3, debug_prefix, "Creating Dandere2xCPPWraper()")
        self.d2xcpp = Dandere2xCPPWraper(self.context, self.utils, self.controller, self.video, self.stats)

        # "Layers" of processing before the actual upscale from upscaler
        self.utils.log(color, 3, debug_prefix, "Creating Processing()")
        self.processing = Processing(self.context, self.utils, self.controller, self.frame, self.video, self.upscaler)

        # On where everything is controlled and starts
        self.utils.log(color, 3, debug_prefix, "Creating Core()")
        self.core = Core(self.context, self.utils, self.controller, self.upscaler, self.d2xcpp, self.processing, self.stats, self.video)

        # Vapoursynth wrapper
        self.utils.log(color, 3, debug_prefix, "Creating VapourSynthWrapper()")
        self.vapoursynth_wrapper = VapourSynthWrapper(self.context, self.utils, self.controller)

    # This function mainly configures things before upscaling and verifies stuff,
    # sees if it's a resume session, etc
    def setup(self):
        
        debug_prefix = "[Dandere2x.setup]"

        self.utils.log(colors["phases"], 3, debug_prefix, "# # [Setup phase] # #")

        # Make session folder
        self.utils.log(color, 3, debug_prefix, "Creating sessions directory if it doesn't exist [%s]" % self.context.sessions_folder)
        self.utils.mkdir_dne(self.context.sessions_folder)

        # Verify upscaler, get the binary
        self.utils.log(color, 3, debug_prefix, "Verifying upscaler")
        self.upscaler.verify()

        self.utils.log(color, 3, debug_prefix, "Generating run command from upscaler")
        self.upscaler.generate_run_command()

        # Warn the user and log mindisk mode
        if self.context.mindisk:
            self.utils.log(color, 2, debug_prefix, "[MINDISK] [WARNING] MINDISK MODE [ON]")
        else:
            self.utils.log(color, 2, debug_prefix, "[MINDISK] [WARNING] MINDISK MODE [OFF]")

        # Check if context_vars file exist and is set to be resume
        # If force argument is set, force not resume session
        if self.context.force:
            self.utils.log(colors["hard_warning"], 0, debug_prefix, "FORCE MODE ENABLED, FORCING RESUME=FALSE")
            # Set resume and force to false as both aren't true anymore
            self.context.resume = False
            self.context.force = False
        else:
            self.utils.log(color, 1, debug_prefix, "Checking if is Resume session")
            self.context.resume = self.utils.check_resume()

        # NOT RESUME SESSION, delete previous session, load up and check directories
        if not self.context.resume:

            # Log and reset session directory
            self.utils.log(colors["li_red"], 0, debug_prefix, "NOT RESUME SESSION, deleting session [%s]" % self.context.session_name)
            self.utils.rmdir(self.context.session)

            # Check dirs
            self.utils.log(color, 3, debug_prefix, "Checking directories")
            self.utils.check_dirs()

            # Reset files
            self.utils.log(color, 3, debug_prefix, "Reseting files")
            self.utils.reset_files()

            # Debugging, show static files
            self.utils.log(color, 3, debug_prefix, "Showing static files")
            self.utils.show_static_files()

            # Get video info
            self.utils.log(color, 3, debug_prefix, "Getting video info")
            self.video.get_video_info()
            self.utils.log(color, 3, debug_prefix, "Showing video info")
            self.video.show_info()

            # Values that should be setted up automatically
            self.d2xmath.set_block_size()

            # Save vars of context so we can resume it later
            self.utils.log(color, 3, debug_prefix, "Saving Context vars to file")
            self.context.save_vars()

            # Apply pre vapoursynth filter
            if self.context.use_vapoursynth:

                # Apply pre filter
                self.vapoursynth_wrapper.apply_filter(
                    self.context.vapoursynth_pre,
                    self.context.input_file,
                    self.context.vapoursynth_processing
                )

                # As we applied pre filter, our input video is now the processed one by vapoursynth
                self.context.input_file = self.context.vapoursynth_processing

                # # As something like a transpose can modify the video resolution we get the new info

                # Get video info
                self.utils.log(color, 3, debug_prefix, "Getting new video info [Vapoursynth can modify resolution]")
                self.video.get_video_info()

                self.utils.log(color, 3, debug_prefix, "Showing new video info")
                self.video.show_info()

        # IS RESUME SESSION, basically load instructions from the context saved vars
        else:
            self.utils.log(colors["li_red"], debug_prefix, 0, "IS RESUME SESSION")

            # Delete previous residuals / upscaled as they can cause some trouble
            self.utils.log(color, 1, debug_prefix, "[FAILSAFE] DELETING RESIDUAL, UPSCALE DIR AND PLUGINS INPUT FILE")
            self.utils.rmdir(self.context.residual)
            self.utils.rmdir(self.context.upscaled)

            # We just deleted two dirs, so gotta make sure they exist
            self.utils.log(color, 1, debug_prefix, "[FAILSAFE] REGENERATING DIRS")
            self.utils.check_dirs()

            # Load previous stopped session from the context
            self.utils.log(color, 1, debug_prefix, "Loading Context vars from context_vars file")
            self.context.load_vars_from_file(self.context.context_vars)

            # Get the last frame we piped to the last partial video as the starting frame of the next partial
            self.video.save_last_frame_of_video_ffmpeg(self.utils.get_last_partial_video_path(), self.context.resume_video_frame)
        
        # Create the encoding FFmpeg pipe
        self.video.ffmpeg.pipe_one_time(self.utils.get_partial_video_path())

    # Here's the core logic for Dandere2x
    def run(self):

        debug_prefix = "[Dandere2x.run]"

        # Generate the command to run Dandere2x C++
        self.d2xcpp.generate_run_command()

        # Only run Dandere2x C++
        if self.context.only_run_dandere2x_cpp:
            self.context.mindisk = False
            self.d2xcpp.generate_run_command()
            self.utils.log(color, 0, debug_prefix, "WRITE ONLY DEBUG VIDEO SET TO TRUE, CALLING CPP AND QUITTING")
            self.context.last_processing_frame = 0
            self.d2xcpp.run()
            self.controller.exit()
            return 0

        # As now we get into the run part of Dandere2x, we don't really want to log
        # within the "global" log on the root folder so we move the logfile to session/log.log
        self.utils.move_log_file(self.context.logfile)

        self.utils.log(colors["phases"], 3, debug_prefix, "# # [Run phase] # #")

        # Start core Dandere2x, ie, start the threads
        self.core.start()

        # Set resume to True as we just started Dandere2x
        # It's not a good idea to stop an session early on, can yield blank videos and will not be merged properly at the end
        self.context.resume = True

        # Show the user we're still alive
        while True:

            # If controller stops or upscale is finished, break
            if self.controller.stop:
                break
            if self.controller.upscale_finished:
                break
            if not self.context.show_stats:
                self.utils.log(color, 1, debug_prefix, "Total upscale time: %s" % self.context.total_upscale_time)

            self.context.total_upscale_time += 1
            time.sleep(1)

        # # When we exit the while loop before either we finished or we stopped

        # If we finished
        if self.controller.upscale_finished:

            # How many partials videos there is on the session partial directory?
            partials = len(os.listdir(self.context.partial))

            # 1? Just copy it to the upscaled video
            if partials == 1:
                self.utils.rename(self.context.partial + "0.mkv", self.context.upscaled_video)

            # More than 1? Concatenate all of them
            elif partials > 1:
                # If we have two or more partials video
                self.video.ffmpeg.concat_video_folder_reencode(self.context.partial, self.context.upscaled_video)

                # Delete the partial dir
                self.utils.rmdir(self.context.partial)

            # None? oops, error
            else:
                self.utils.log(color, 0, debug_prefix, "[ERROR] No partials were found in [%s]" % self.context.partial)
                sys.exit(-1)

            # We still gotta add the audio to the upscaled file or / and post filters we might be interested into

            # Apply post vapoursynth filter as the upscale finished
            if self.context.use_vapoursynth:

                self.utils.log(color, 1, debug_prefix, "APPLYING POST VAPOURSYNTH FILTER")

                if self.context.use_vapoursynth:
                    self.vapoursynth_wrapper.apply_filter(
                        self.context.vapoursynth_pos,
                        self.context.upscaled_video,
                        self.context.vapoursynth_processing
                    )

                    # Make the processed one the new upscaled
                    self.utils.delete_file(self.context.upscaled_video)
                    self.utils.rename(self.context.vapoursynth_processing, self.context.upscaled_video)

            # Migrate audio tracks from the original video to the new one
            self.video.ffmpeg.copy_videoA_audioB_to_other_videoC(
                self.context.upscaled_video,
                self.context.input_file,
                self.context.joined_audio
            )

            # Delete old only upscaled video as migrated tracks
            self.utils.delete_file(self.context.upscaled_video)
            self.utils.rename(self.context.joined_audio, self.context.output_file)

            self.utils.log(color, 1, debug_prefix, "Total upscale time: %s" % self.context.total_upscale_time)
            
            # Move the logfile to the root folder as we're gonna delete the session folder
            self.utils.log(color, 1, debug_prefix, "Moving session log to root Dandere2x folder and Removing session folder [%s]" % self.context.session)
            self.utils.rename(self.context.logfile, self.context.logfile_last_session)

            # For removing the dir we gotta have a writable log file
            self.utils.logfile = self.context.logfile_last_session

            # Remove session folder as we finished everything
            self.utils.rmdir(self.context.session)
            
            # Happy upscaled video :)

        else:
            # Save progress for later resuming
            self.context.save_vars()

            self.utils.log(color, 0, debug_prefix, "Exiting Dandere2x.run")
Example #6
0
    # if input specified is a single file
    if os.path.isfile(args.input):
        """ Upscale single video file """
        Avalon.info('Upscaling single video file: {}'.format(args.input))

        # check for input output format mismatch
        if os.path.isdir(args.output):
            Avalon.error('Input and output path type mismatch')
            Avalon.error('Input is single file but output is folder')
            raise Exception('input output path type mismatch')
        if not re.search('.*\..*$', args.output):
            Avalon.error('No suffix found in output file path')
            Avalon.error('Suffix must be specified for FFmpeg')
            raise Exception('No suffix specified')

        upscaler = Upscaler(input_video=args.input, output_video=args.output, method=args.method, waifu2x_settings=waifu2x_settings, ffmpeg_settings=ffmpeg_settings)

        # set optional options
        upscaler.waifu2x_driver = args.driver
        upscaler.scale_width = args.width
        upscaler.scale_height = args.height
        upscaler.scale_ratio = args.ratio
        upscaler.model_dir = args.model_dir
        upscaler.threads = args.threads
        upscaler.video2x_cache_folder = video2x_cache_folder
        upscaler.image_format = image_format
        upscaler.preserve_frames = preserve_frames

        # run upscaler-
        upscaler.run()
        upscaler.cleanup()
Example #7
0
        exit(1)

# start execution
try:
    # start timer
    begin_time = time.time()

    if os.path.isfile(args.input):
        """ Upscale single video file """
        Avalon.info('Upscaling single video file: {}'.format(args.input))
        upscaler = Upscaler(input_video=args.input,
                            output_video=args.output,
                            method=args.method,
                            waifu2x_settings=waifu2x_settings,
                            ffmpeg_settings=ffmpeg_settings,
                            waifu2x_driver=args.driver,
                            scale_width=args.width,
                            scale_height=args.height,
                            scale_ratio=args.ratio,
                            model_dir=args.model_dir,
                            threads=args.threads,
                            video2x_cache_folder=video2x_cache_folder)
        upscaler.run()
        upscaler.cleanup()
    elif os.path.isdir(args.input):
        """ Upscale videos in a folder/directory """
        Avalon.info('Upscaling videos in folder/directory: {}'.format(
            args.input))
        for input_video in [
                f for f in os.listdir(args.input)
                if os.path.isfile(os.path.join(args.input, f))
        ]:
Example #8
0
class Video2xGui():
    def __init__(self):

        self.running = False

        # create main window
        self.main_window = Tk()
        self.main_window.title(f'Video2X GUI {VERSION}')
        self.main_frame = Frame()
        self.main_frame.pack(fill=BOTH, expand=True)

        # add menu bar
        self.menu_bar = Menu(self.main_frame)

        # file menu
        self.file_menu = Menu(self.menu_bar, tearoff=0)
        self.file_menu.add_command(label='Exit', command=self.main_frame.quit)
        self.menu_bar.add_cascade(label='File', menu=self.file_menu)

        # help menu
        self.help_menu = Menu(self.menu_bar, tearoff=0)
        self.help_menu.add_command(label='About', command=self._display_help)
        self.menu_bar.add_cascade(label='Help', menu=self.help_menu)

        self.main_window.config(menu=self.menu_bar)

        # file frame
        self.file_frame = Frame(self.main_frame)
        self.file_frame.pack(fill=X, padx=5, pady=5, expand=True)

        # input file
        self.input_file = StringVar()
        label_text = StringVar()
        label_text.set('Input File')
        Label(self.file_frame, textvariable=label_text, relief=RIDGE,
              width=10).grid(row=0, column=0, padx=5, pady=5, sticky=W)
        Entry(self.file_frame, textvariable=self.input_file,
              width=60).grid(row=0, column=1, padx=5, pady=5, sticky=W)
        Button(self.file_frame, text='Select',
               command=self._select_input).grid(row=0,
                                                column=2,
                                                padx=5,
                                                pady=5,
                                                sticky=W)

        # output file
        self.output_file = StringVar()
        label_text = StringVar()
        label_text.set('Output File')
        Label(self.file_frame, textvariable=label_text, relief=RIDGE,
              width=10).grid(row=1, column=0, padx=5, pady=5, sticky=W)
        Entry(self.file_frame, textvariable=self.output_file,
              width=60).grid(row=1, column=1, padx=5, pady=5, sticky=W)
        Button(self.file_frame, text='Select',
               command=self._select_output).grid(row=1,
                                                 column=2,
                                                 padx=5,
                                                 pady=5,
                                                 sticky=W)

        # options
        self.options_frame = Frame()
        # self.options_left.pack(fill=X, padx=5, pady=5, expand=True)
        self.options_frame.pack(fill=X, padx=5, pady=5, expand=True)

        self.options_left = Frame(self.options_frame)
        # self.options_left.pack(fill=X, padx=5, pady=5, expand=True)
        self.options_left.grid(row=0, column=0, padx=5, pady=5, sticky=N)

        # width
        self.width = IntVar()
        # self.width.set(1920)
        Label(self.options_left, text='Width', relief=RIDGE,
              width=15).grid(row=0, column=0, padx=2, pady=3)
        width_field = Entry(self.options_left, textvariable=self.width)
        width_field.grid(row=0, column=1, padx=2, pady=3, sticky=W)

        # height
        self.height = IntVar()
        # self.height.set(1080)
        Label(self.options_left, text='Height', relief=RIDGE,
              width=15).grid(row=1, column=0, padx=2, pady=3)
        height_field = Entry(self.options_left, textvariable=self.height)
        height_field.grid(row=1, column=1, padx=2, pady=3, sticky=W)

        # scale ratio
        self.scale_ratio = DoubleVar()
        # self.scale_ratio.set(2.0)
        Label(self.options_left, text='Scale Ratio', relief=RIDGE,
              width=15).grid(row=2, column=0, padx=2, pady=3)
        scale_ratio_field = Entry(self.options_left,
                                  textvariable=self.scale_ratio)
        scale_ratio_field.grid(row=2, column=1, padx=2, pady=3, sticky=W)

        # image format
        self.image_format = StringVar(self.options_left)
        self.image_format.set('PNG')
        Label(self.options_left, text='Image Format', relief=RIDGE,
              width=15).grid(row=3, column=0, padx=2, pady=3)
        image_format_menu = OptionMenu(self.options_left, self.image_format,
                                       *IMAGE_FORMATS)
        image_format_menu.grid(row=3, column=1, padx=2, pady=3, sticky=W)

        # options
        self.options_right = Frame(self.options_frame)
        # self.options_left.pack(fill=X, padx=5, pady=5, expand=True)
        self.options_right.grid(row=0, column=1, padx=5, pady=5, sticky=N)

        # threads
        self.threads = IntVar()
        self.threads.set(1)
        Label(self.options_right, text='Threads', relief=RIDGE,
              width=15).grid(row=0, column=0, padx=2, pady=3)
        threads_field = Entry(self.options_right, textvariable=self.threads)
        threads_field.grid(row=0, column=1, padx=2, pady=3, sticky=W)

        # method
        self.method = StringVar(self.options_left)
        self.method.set('GPU')
        Label(self.options_right, text='Method', relief=RIDGE,
              width=15).grid(row=1, column=0, padx=2, pady=3)
        method_menu = OptionMenu(self.options_right, self.method,
                                 *AVAILABLE_METHODS)
        method_menu.grid(row=1, column=1, padx=2, pady=3, sticky=W)

        # driver
        self.driver = StringVar(self.options_left)
        self.driver.set('Waifu2X Caffe')
        Label(self.options_right, text='Driver', relief=RIDGE,
              width=15).grid(row=2, column=0, padx=2, pady=3)
        driver_menu = OptionMenu(self.options_right, self.driver,
                                 *AVAILABLE_DRIVERS)
        driver_menu.grid(row=2, column=1, padx=2, pady=3, sticky=W)

        # preserve frames
        self.preserve_frames = BooleanVar(self.options_left)
        self.preserve_frames.set(True)
        Label(self.options_right,
              text='Preserve Frames',
              relief=RIDGE,
              width=15).grid(row=3, column=0, padx=2, pady=3)
        preserve_frames_menu = OptionMenu(self.options_right,
                                          self.preserve_frames, *{True, False})
        preserve_frames_menu.grid(row=3, column=1, padx=2, pady=3, sticky=W)

        # progress bar
        self.progress_bar_frame = Frame()
        self.progress_bar_frame.pack(fill=X, padx=5, pady=5, expand=True)

        self.progress_bar = ttk.Progressbar(self.progress_bar_frame,
                                            orient='horizontal',
                                            length=100,
                                            mode='determinate')
        self.progress_bar.pack(fill=X)

        # start button frame
        self.start_frame = Frame()
        self.start_frame.pack(fill=X, padx=5, pady=5, expand=True)

        # start button
        self.start_button_text = StringVar()
        self.start_button_text.set('Start')
        Button(self.start_frame,
               textvariable=self.start_button_text,
               command=self._launch_upscaling,
               width=20).pack(side=RIGHT)

        self.main_frame.mainloop()

    def _display_help(self):
        messagebox.showinfo('About', LEGAL_INFO)

    def _launch_upscaling(self):

        # prevent launching multiple instances
        if self.running:
            messagebox.showerror('Error', 'Video2X is already running')
            return

        # arguments sanity check
        if self.input_file.get() == '':
            messagebox.showerror(
                'Error', 'You must specify input video file/directory path')
            return
        if self.output_file.get() == '':
            messagebox.showerror(
                'Error', 'You must specify output video file/directory path')
            return
        if (self.driver.get() in [
                'Waifu2X Converter CPP', 'Waifu2x NCNN Vulkan', 'Anime4K'
        ]) and self.width.get() and self.height.get():
            messagebox.showerror(
                'Error',
                f'Selected driver \"{self.driver.get()}\" accepts only scaling ratio'
            )
            return
        if self.driver.get() == 'waifu2x_ncnn_vulkan' and (
                self.scale_ratio.get() > 2
                or not self.scale_ratio.get().is_integer()):
            messagebox.showerror(
                'Error',
                'Scaling ratio must be 1 or 2 for waifu2x_ncnn_vulkan')
            return
        if (self.width.get() or self.height.get()) and self.scale_ratio.get():
            messagebox.showerror(
                'Error',
                'You can only specify either scaling ratio or output width and height'
            )
            return
        if (self.width.get()
                and not self.height.get()) or (not self.width.get()
                                               and self.height.get()):
            messagebox.showerror('Error',
                                 'You must specify both width and height')
            return
        if (not self.width.get()
                or not self.height.get()) and not self.scale_ratio.get():
            messagebox.showerror(
                'Error',
                'You must specify either output dimensions or scaling ratio')
            return

        upscale = threading.Thread(target=self._upscale)
        upscale.start()
        self.running = True
        self.start_button_text.set('Running')

    def _upscale(self):

        # start timer
        begin_time = time.time()

        # read configuration file
        config = read_config('video2x.json')
        config = absolutify_paths(config)

        input_file = pathlib.Path(self.input_file.get())
        output_file = pathlib.Path(self.output_file.get())
        driver = AVAILABLE_DRIVERS[self.driver.get()]

        if driver == 'waifu2x_caffe':
            waifu2x_settings = config['waifu2x_caffe']
            if not pathlib.Path(
                    waifu2x_settings['waifu2x_caffe_path']).is_file():
                messagebox.showerror(
                    'Error',
                    'Specified waifu2x-caffe directory doesn\'t exist\nPlease check the configuration file settings'
                )
                raise FileNotFoundError(waifu2x_settings['waifu2x_caffe_path'])
        elif driver == 'waifu2x_converter':
            waifu2x_settings = config['waifu2x_converter']
            if not pathlib.Path(
                    waifu2x_settings['waifu2x_converter_path']).is_dir():
                messagebox.showerror(
                    'Error',
                    'Specified waifu2x-converter-cpp directory doesn\'t exist\nPlease check the configuration file settings'
                )
                raise FileNotFoundError(
                    waifu2x_settings['waifu2x_converter_path'])
        elif driver == 'waifu2x_ncnn_vulkan':
            waifu2x_settings = config['waifu2x_ncnn_vulkan']
            if not pathlib.Path(
                    waifu2x_settings['waifu2x_ncnn_vulkan_path']).is_file():
                messagebox.showerror(
                    'Error',
                    'Specified waifu2x_ncnn_vulkan directory doesn\'t exist\nPlease check the configuration file settings'
                )
                raise FileNotFoundError(
                    waifu2x_settings['waifu2x_ncnn_vulkan_path'])
        elif driver == 'anime4k':
            waifu2x_settings = config['anime4k']
            if not pathlib.Path(waifu2x_settings['anime4k_path']).is_file():
                messagebox.showerror(
                    'Error',
                    'Specified Anime4K directory doesn\'t exist\nPlease check the configuration file settings'
                )
                raise FileNotFoundError(waifu2x_settings['anime4k_path'])

        # read FFmpeg configuration
        ffmpeg_settings = config['ffmpeg']

        # load video2x settings
        image_format = config['video2x']['image_format'].lower()
        preserve_frames = config['video2x']['preserve_frames']

        # load cache directory
        if isinstance(config['video2x']['video2x_cache_directory'], str):
            video2x_cache_directory = pathlib.Path(
                config['video2x']['video2x_cache_directory'])
        else:
            video2x_cache_directory = pathlib.Path(
                tempfile.gettempdir()) / 'video2x'

        if video2x_cache_directory.exists(
        ) and not video2x_cache_directory.is_dir():
            messagebox.showerror('Error',
                                 'Specified cache directory is a file/link')
            raise FileExistsError('Specified cache directory is a file/link')

        elif not video2x_cache_directory.exists():
            # try creating the cache directory
            if messagebox.askyesno(
                    'Question',
                    f'Specified cache directory {video2x_cache_directory} does not exist\nCreate directory?'
            ):
                try:
                    video2x_cache_directory.mkdir(parents=True, exist_ok=True)

                # there can be a number of exceptions here
                # PermissionError, FileExistsError, etc.
                # therefore, we put a catch-them-all here
                except Exception as e:
                    messagebox.showerror(
                        'Error',
                        f'Unable to create {video2x_cache_directory}\nAborting...'
                    )
                    raise e
            else:
                raise FileNotFoundError('Could not create cache directory')

        # load more settings from gui
        width = self.width.get()
        height = self.height.get()
        scale_ratio = self.scale_ratio.get()
        image_format = self.image_format.get()
        threads = self.threads.get()
        method = AVAILABLE_METHODS[self.method.get()]
        preserve_frames = self.preserve_frames.get()

        self.upscaler = Upscaler(input_video=input_file,
                                 output_video=output_file,
                                 method=method,
                                 waifu2x_settings=waifu2x_settings,
                                 ffmpeg_settings=ffmpeg_settings)

        # set optional options
        self.upscaler.waifu2x_driver = driver
        self.upscaler.scale_width = width
        self.upscaler.scale_height = height
        self.upscaler.scale_ratio = scale_ratio
        self.upscaler.model_dir = None
        self.upscaler.threads = threads
        self.upscaler.video2x_cache_directory = video2x_cache_directory
        self.upscaler.image_format = image_format
        self.upscaler.preserve_frames = preserve_frames

        # run upscaler
        self.upscaler.create_temp_directories()

        # start progress bar
        progress_bar = threading.Thread(target=self._progress_bar)
        progress_bar.start()

        # start upscaling
        self.upscaler.run()
        self.upscaler.cleanup_temp_directories()

        # show message when upscaling completes
        messagebox.showinfo(
            'Info',
            f'Upscaling Completed\nTime Taken: {round((time.time() - begin_time), 5)} seconds'
        )
        self.progress_bar['value'] = 100
        self.running = False
        self.start_button_text.set('Start')

    def _progress_bar(self):
        """ This method prints a progress bar

        This method prints a progress bar by keeping track
        of the amount of frames in the input directory
        and the output directory. This is originally
        suggested by @ArmandBernard.
        """
        # initialize variables early
        self.upscaler.progress_bar_exit_signal = False
        self.upscaler.total_frames_upscaled = 0
        self.upscaler.total_frames = 1

        # initialize progress bar values
        self.progress_bar['value'] = 0

        while not self.upscaler.progress_bar_exit_signal:
            self.progress_bar['value'] = int(
                100 * self.upscaler.total_frames_upscaled /
                self.upscaler.total_frames)
            time.sleep(1)

    def _select_input(self):
        self.input_file.set(askopenfilename(title='Select Input File'))

        # try to set an output file name automatically
        output_file = pathlib.Path(f'{self.input_file.get()}_output.mp4')

        output_file_id = 0
        while output_file.is_file() and output_file_id <= 10:
            output_file = pathlib.Path(
                f'{self.input_file.get()}_output_{output_file_id}.mp4')
            output_file_id += 1

        if not output_file.exists():
            self.output_file.set(str(output_file))

    def _select_output(self):
        self.output_file.set(asksaveasfilename(title='Select Output File'))
Example #9
0
    def _upscale(self):

        # start timer
        begin_time = time.time()

        # read configuration file
        config = read_config('video2x.json')
        config = absolutify_paths(config)

        input_file = pathlib.Path(self.input_file.get())
        output_file = pathlib.Path(self.output_file.get())
        driver = AVAILABLE_DRIVERS[self.driver.get()]

        if driver == 'waifu2x_caffe':
            waifu2x_settings = config['waifu2x_caffe']
            if not pathlib.Path(
                    waifu2x_settings['waifu2x_caffe_path']).is_file():
                messagebox.showerror(
                    'Error',
                    'Specified waifu2x-caffe directory doesn\'t exist\nPlease check the configuration file settings'
                )
                raise FileNotFoundError(waifu2x_settings['waifu2x_caffe_path'])
        elif driver == 'waifu2x_converter':
            waifu2x_settings = config['waifu2x_converter']
            if not pathlib.Path(
                    waifu2x_settings['waifu2x_converter_path']).is_dir():
                messagebox.showerror(
                    'Error',
                    'Specified waifu2x-converter-cpp directory doesn\'t exist\nPlease check the configuration file settings'
                )
                raise FileNotFoundError(
                    waifu2x_settings['waifu2x_converter_path'])
        elif driver == 'waifu2x_ncnn_vulkan':
            waifu2x_settings = config['waifu2x_ncnn_vulkan']
            if not pathlib.Path(
                    waifu2x_settings['waifu2x_ncnn_vulkan_path']).is_file():
                messagebox.showerror(
                    'Error',
                    'Specified waifu2x_ncnn_vulkan directory doesn\'t exist\nPlease check the configuration file settings'
                )
                raise FileNotFoundError(
                    waifu2x_settings['waifu2x_ncnn_vulkan_path'])
        elif driver == 'anime4k':
            waifu2x_settings = config['anime4k']
            if not pathlib.Path(waifu2x_settings['anime4k_path']).is_file():
                messagebox.showerror(
                    'Error',
                    'Specified Anime4K directory doesn\'t exist\nPlease check the configuration file settings'
                )
                raise FileNotFoundError(waifu2x_settings['anime4k_path'])

        # read FFmpeg configuration
        ffmpeg_settings = config['ffmpeg']

        # load video2x settings
        image_format = config['video2x']['image_format'].lower()
        preserve_frames = config['video2x']['preserve_frames']

        # load cache directory
        if isinstance(config['video2x']['video2x_cache_directory'], str):
            video2x_cache_directory = pathlib.Path(
                config['video2x']['video2x_cache_directory'])
        else:
            video2x_cache_directory = pathlib.Path(
                tempfile.gettempdir()) / 'video2x'

        if video2x_cache_directory.exists(
        ) and not video2x_cache_directory.is_dir():
            messagebox.showerror('Error',
                                 'Specified cache directory is a file/link')
            raise FileExistsError('Specified cache directory is a file/link')

        elif not video2x_cache_directory.exists():
            # try creating the cache directory
            if messagebox.askyesno(
                    'Question',
                    f'Specified cache directory {video2x_cache_directory} does not exist\nCreate directory?'
            ):
                try:
                    video2x_cache_directory.mkdir(parents=True, exist_ok=True)

                # there can be a number of exceptions here
                # PermissionError, FileExistsError, etc.
                # therefore, we put a catch-them-all here
                except Exception as e:
                    messagebox.showerror(
                        'Error',
                        f'Unable to create {video2x_cache_directory}\nAborting...'
                    )
                    raise e
            else:
                raise FileNotFoundError('Could not create cache directory')

        # load more settings from gui
        width = self.width.get()
        height = self.height.get()
        scale_ratio = self.scale_ratio.get()
        image_format = self.image_format.get()
        threads = self.threads.get()
        method = AVAILABLE_METHODS[self.method.get()]
        preserve_frames = self.preserve_frames.get()

        self.upscaler = Upscaler(input_video=input_file,
                                 output_video=output_file,
                                 method=method,
                                 waifu2x_settings=waifu2x_settings,
                                 ffmpeg_settings=ffmpeg_settings)

        # set optional options
        self.upscaler.waifu2x_driver = driver
        self.upscaler.scale_width = width
        self.upscaler.scale_height = height
        self.upscaler.scale_ratio = scale_ratio
        self.upscaler.model_dir = None
        self.upscaler.threads = threads
        self.upscaler.video2x_cache_directory = video2x_cache_directory
        self.upscaler.image_format = image_format
        self.upscaler.preserve_frames = preserve_frames

        # run upscaler
        self.upscaler.create_temp_directories()

        # start progress bar
        progress_bar = threading.Thread(target=self._progress_bar)
        progress_bar.start()

        # start upscaling
        self.upscaler.run()
        self.upscaler.cleanup_temp_directories()

        # show message when upscaling completes
        messagebox.showinfo(
            'Info',
            f'Upscaling Completed\nTime Taken: {round((time.time() - begin_time), 5)} seconds'
        )
        self.progress_bar['value'] = 100
        self.running = False
        self.start_button_text.set('Start')
Example #10
0
# Start execution
try:
    # Start timer
    begin_time = time.time()

    if os.path.isfile(args.input):
        """ Upscale single video file """
        Avalon.info('Upscaling single video file: {}'.format(args.input))
        upscaler = Upscaler(input_video=args.input,
                            output_video=args.output,
                            method=args.method,
                            waifu2x_path=waifu2x_path,
                            ffmpeg_path=ffmpeg_path,
                            waifu2x_driver=args.driver,
                            ffmpeg_arguments=ffmpeg_arguments,
                            ffmpeg_hwaccel=ffmpeg_hwaccel,
                            output_width=args.width,
                            output_height=args.height,
                            ratio=args.ratio,
                            model_type=args.model_type,
                            threads=args.threads,
                            extracted_frames=extracted_frames,
                            upscaled_frames=upscaled_frames)
        upscaler.run()
    elif os.path.isdir(args.input):
        """ Upscale videos in a folder/directory """
        Avalon.info('Upscaling videos in folder: {}'.format(args.input))
        for input_video in [
                f for f in os.listdir(args.input)
                if os.path.isfile(os.path.join(args.input, f))
        ]:
Example #11
0
# Start execution
try:
    # Start timer
    begin_time = time.time()

    if os.path.isfile(args.input):
        """ Upscale single video file """
        Avalon.info('Upscaling single video file: {}'.format(args.input))
        upscaler = Upscaler(input_video=args.input,
                            output_video=args.output,
                            method=args.method,
                            waifu2x_path=waifu2x_path,
                            ffmpeg_path=ffmpeg_path,
                            waifu2x_driver=args.driver,
                            ffmpeg_arguments=ffmpeg_arguments,
                            ffmpeg_hwaccel=ffmpeg_hwaccel,
                            output_width=args.width,
                            output_height=args.height,
                            ratio=args.ratio,
                            model_type=args.model_type,
                            threads=args.threads,
                            video2x_cache_folder=video2x_cache_folder)
        upscaler.run()
        upscaler.cleanup()
    elif os.path.isdir(args.input):
        """ Upscale videos in a folder/directory """
        Avalon.info('Upscaling videos in folder/directory: {}'.format(
            args.input))
        for input_video in [
                f for f in os.listdir(args.input)
                if os.path.isfile(os.path.join(args.input, f))
Example #12
0
        # upscale single video file
        Avalon.info(
            _('Upscaling single video file: {}').format(video2x_args.input))

        # check for input output format mismatch
        if video2x_args.output.is_dir():
            Avalon.error(_('Input and output path type mismatch'))
            Avalon.error(_('Input is single file but output is directory'))
            raise Exception('input output path type mismatch')
        if not re.search(r'.*\..*$', str(video2x_args.output)):
            Avalon.error(_('No suffix found in output file path'))
            Avalon.error(_('Suffix must be specified for FFmpeg'))
            raise Exception('No suffix specified')

        upscaler = Upscaler(input_video=video2x_args.input,
                            output_video=video2x_args.output,
                            driver_settings=driver_settings,
                            ffmpeg_settings=ffmpeg_settings)

        # set optional options
        upscaler.driver = video2x_args.driver
        upscaler.scale_width = video2x_args.width
        upscaler.scale_height = video2x_args.height
        upscaler.scale_ratio = video2x_args.ratio
        upscaler.processes = video2x_args.processes
        upscaler.video2x_cache_directory = video2x_cache_directory
        upscaler.image_format = image_format
        upscaler.preserve_frames = preserve_frames

        # run upscaler
        upscaler.run()