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)
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)
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()
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")