예제 #1
0
    def _pre_processing(self):
        """
        This MUST be the first thing `run` calls, or else dandere2x.py will not work!

        Description: This function is a series of instructions dandere2x MUST perform before the main threads
                     are able to be called, and serves as a preliminary "health checker" for dandere2x to diagnose
                     bugs before the main threads are called.
        """

        self.log.info("Beginning pre-processing stage.")
        self.log.info("Dandere2x will process your video in a way that attempts to remove ambiguities caused by"
                      " container formats.")

        force_delete_directory(self.context.workspace)

        try:
            self.context.load_video_settings_ffprobe(file=self.context.input_file)
        except FileNotFoundError as e:
            from sys import exit
            self.log.error("Caught FileNotFoundError. This is likeley caused by 'externals' missing a neccecary file.")
            self.log.error("Are you sure you hit the 'download externals' button?")
            exit(1)

        if not valid_input_resolution(self.context.width, self.context.height, self.context.block_size):
            """ 
            Dandere2x needs the width and height to be a share a common factor with the block size so append a video
            filter if needed to make the size conform. For example, 1921x1081 is not evenly divisalbe by 30, so we'd 
            need to resize the video in that scenario.
            """

            self.log.warning(
                "Input video needs to be resized to be compatible with block-size - this is expected behaviour.")
            append_video_resize_filter(self.context)

        create_directories(self.context.workspace, self.context.directories)
        self.set_file_logger(self.context.workspace + "log.txt")  # write to a log file in the workspace

        self.waifu2x.verify_upscaling_works()

        """ 
        Re-encode the user input video. We do this because file container formats can be difficult to work with
        and can cause Dandere2x to not function properly (some videos resolutions are different, variable frame rate
        will cause video to have black spots, etc. 
        """
        workspace = self.context.workspace
        input_file = self.context.input_file
        unmigrated = workspace + "d2x_input_video_nonmigrated.mkv"
        pre_processed_video = self.context.pre_processed_video

        # have dandere2x load up the pre-processed video and re-assign video settings to use that instead
        re_encode_video(self.context, input_file, unmigrated, throw_exception=True)
        migrate_tracks(self.context, unmigrated, input_file, pre_processed_video, copy_if_failed=True)
        os.remove(unmigrated)
        wait_on_file(pre_processed_video, controller=self.context.controller)
        self.context.load_pre_processed_video(file=pre_processed_video)
예제 #2
0
    def _pre_processing(self):
        """ This MUST be the first thing `run` calls, or else dandere2x.py will not work! """

        force_delete_directory(self.context.workspace)
        self.context.load_video_settings(file=self.context.input_file)
        """ 
        Dandere2x needs the width and height to be a share a common factor with the block size so append a video
        filter if needed to make the size conform. 
        """
        if not valid_input_resolution(self.context.width, self.context.height,
                                      self.context.block_size):
            append_video_resize_filter(self.context)

        create_directories(self.context.workspace, self.context.directories)

        self.waifu2x.verify_upscaling_works()
        """ 
        Re-encode the user input video. We do this because file container formats can be difficult to work with
        and can cause Dandere2x to not function properly (some videos resolutions are different, variable frame rate
        will cause video to have black spots, etc. 
        """
        workspace = self.context.workspace
        input_file = self.context.input_file
        unmigrated = workspace + "d2x_input_video_nonmigrated.mkv"
        pre_processed_video = self.context.pre_processed_video

        re_encode_video(self.context,
                        input_file,
                        unmigrated,
                        throw_exception=True)
        migrate_tracks(self.context,
                       unmigrated,
                       input_file,
                       pre_processed_video,
                       copy_if_failed=True)
        os.remove(unmigrated)
        wait_on_file_controller(pre_processed_video,
                                controller=self.context.controller)
        self.context.load_video_settings(file=pre_processed_video)
예제 #3
0
    def run(self):
        """
        Starts the dandere2x_python process at large.
        """

        print("threading at start of runtime")
        print(threading.enumerate())

        # directories need to be created before we do anything
        create_directories(self.context.workspace, self.context.directories)

        # dandere2x needs the width and height to be a share a common factor with the block size,
        # so append a video filter if needed to make the size conform
        if not valid_input_resolution(self.context.width, self.context.height,
                                      self.context.block_size):
            append_video_resize_filter(self.context)

        # create the list of threads to use for dandere2x
        self.__setup_jobs()

        if self.resume_session:
            self.__set_first_frame()

        # extract the initial frames needed for execution depending on type (min_disk_usage / non min_disk_usage )
        self.__extract_frames()

        # first frame needs to be upscaled manually before dandere2x process starts.
        self.__upscale_first_frame()

        self.compress_frames_thread.start()
        self.dandere2x_cpp_thread.start()
        self.merge_thread.start()
        self.residual_thread.start()
        self.waifu2x.start()
        self.status_thread.start()

        if self.context.use_min_disk:
            self.min_disk_demon.start()
예제 #4
0
    def run_concurrent(self):
        """
        Starts the dandere2x_python process at large.

        Inputs:
        - context

        Pre-Reqs:
        'This is all the stuff that needs to be done before dandere2x can officially start'

        - creates workspaces needed for dandere2x to work
        - edits the video if it's needed to be trimmed or needs resolution needs to be resized.
        - extracts all the frames in the video into it's own folder.
        - upscales the first frame using waifu2x and ensuring the genesis image upscaled correctly.

        Threading Area:

        - calls a series of threads for dandere2x_python to work
          (residuals, merging, waifu2x, dandere2xcpp, realtime-encoding)
        """

        # load context
        output_file = self.context.output_file

        ############
        # PRE REQS #
        ############

        # The first thing to do is create the dirs we will need during runtime
        create_directories(self.context.directories)
        self.context.set_logger()

        # If the user wishes to trim the video, trim the video, then rename the file_dir to point to the trimmed video
        if self.context.user_trim_video:
            trimed_video = os.path.join(self.context.workspace, "trimmed.mkv")
            trim_video(self.context, trimed_video)
            self.context.input_file = trimed_video

        # Before we extract all the frames, we need to ensure the settings are valid. If not, resize the video
        # To make the settings valid somehow.
        if not valid_input_resolution(self.context.width, self.context.height, self.context.block_size):
            self.append_video_resize_filter()

        # Extract all the frames
        print("extracting frames from video... this might take a while..")
        extract_frames(self.context, self.context.input_file)
        self.context.update_frame_count()

        # Assign the waifu2x object to whatever waifu2x we're using
        waifu2x = self.get_waifu2x_class(self.context.waifu2x_type)

        # Upscale the first file (the genesis file is treated different in Dandere2x)
        one_frame_time = time.time()  # This timer prints out how long it takes to upscale one frame
        waifu2x.upscale_file(input_file=self.context.input_frames_dir + "frame1" + self.context.extension_type,
                             output_file=self.context.merged_dir + "merged_1" + self.context.extension_type)

        # Ensure the first file was able to get upscaled. We literally cannot continue if it doesn't.
        if not file_exists(self.context.merged_dir + "merged_1" + self.context.extension_type):
            print("Could not upscale first file.. check logs file to see what's wrong")
            logging.info("Could not upscale first file.. check logs file to see what's wrong")
            logging.info("Exiting Dandere2x...")
            sys.exit(1)

        print("\n Time to upscale an uncompressed frame: " + str(round(time.time() - one_frame_time, 2)))

        ####################
        #  THREADING AREA  #
        ####################

        # This is where Dandere2x's core functions start. Each core function is divided into a series of threads,
        # All with their own segregated tasks and goals. Dandere2x starts all the threads, and lets it go from there.
        compress_frames_thread = threading.Thread(target=compress_frames, args=(self.context,))
        dandere2xcpp_thread = Dandere2xCppWrapper(self.context)
        merge_thread = threading.Thread(target=merge_loop, args=(self.context,))
        residual_thread = threading.Thread(target=residual_loop, args=(self.context,))
        status_thread = threading.Thread(target=print_status, args=(self.context,))
        realtime_encode_thread = threading.Thread(target=run_realtime_encoding, args=(self.context, output_file))

        logging.info("starting new d2x process")
        waifu2x.start()

        merge_thread.start()
        residual_thread.start()
        dandere2xcpp_thread.start()
        status_thread.start()
        compress_frames_thread.start()

        if self.context.realtime_encoding_enabled:
            realtime_encode_thread.start()

        compress_frames_thread.join()
        merge_thread.join()
        dandere2xcpp_thread.join()
        residual_thread.join()
        waifu2x.join()
        status_thread.join()

        if self.context.realtime_encoding_enabled:
            realtime_encode_thread.join()

        self.context.logger.info("Threaded Processes Finished succcesfully")