def run(self): """ Main controller for Video2X This function controls the flow of video conversion and handles all necessary functions. """ # parse arguments for waifu2x # check argument sanity self._check_arguments() # convert paths to absolute paths self.input_video = self.input_video.absolute() self.output_video = self.output_video.absolute() # drivers that have native support for video processing if self.driver == 'anime4kcpp': # append FFmpeg path to the end of PATH # Anime4KCPP will then use FFmpeg to migrate audio tracks os.environ['PATH'] += f';{self.ffmpeg_settings["ffmpeg_path"]}' Avalon.info(_('Starting to upscale extracted images')) # import and initialize Anime4KCPP wrapper DriverWrapperMain = getattr( importlib.import_module('wrappers.anime4kcpp'), 'WrapperMain') driver = DriverWrapperMain(copy.deepcopy(self.driver_settings)) # run Anime4KCPP driver.upscale(self.input_video, self.output_video, self.scale_ratio, self.processes).wait() Avalon.info(_('Upscaling completed')) else: self.create_temp_directories() # initialize objects for ffmpeg and waifu2x-caffe fm = Ffmpeg(self.ffmpeg_settings, self.image_format) Avalon.info(_('Reading video information')) video_info = fm.get_video_info(self.input_video) # analyze original video with ffprobe and retrieve framerate # width, height = info['streams'][0]['width'], info['streams'][0]['height'] # find index of video stream video_stream_index = None for stream in video_info['streams']: if stream['codec_type'] == 'video': video_stream_index = stream['index'] break # exit if no video stream found if video_stream_index is None: Avalon.error(_('Aborting: No video stream found')) raise StreamNotFoundError('no video stream found') # extract frames from video fm.extract_frames(self.input_video, self.extracted_frames) # get average frame rate of video stream framerate = float( Fraction(video_info['streams'][video_stream_index] ['avg_frame_rate'])) fm.pixel_format = video_info['streams'][video_stream_index][ 'pix_fmt'] # get a dict of all pixel formats and corresponding bit depth pixel_formats = fm.get_pixel_formats() # try getting pixel format's corresponding bti depth try: self.bit_depth = pixel_formats[fm.pixel_format] except KeyError: Avalon.error( _('Unsupported pixel format: {}').format(fm.pixel_format)) raise UnsupportedPixelError( f'unsupported pixel format {fm.pixel_format}') Avalon.info(_('Framerate: {}').format(framerate)) # width/height will be coded width/height x upscale factor if self.scale_ratio: original_width = video_info['streams'][video_stream_index][ 'width'] original_height = video_info['streams'][video_stream_index][ 'height'] self.scale_width = int(self.scale_ratio * original_width) self.scale_height = int(self.scale_ratio * original_height) # upscale images one by one using waifu2x Avalon.info(_('Starting to upscale extracted images')) self._upscale_frames() Avalon.info(_('Upscaling completed')) # frames to Video Avalon.info(_('Converting extracted frames into video')) # use user defined output size fm.convert_video(framerate, f'{self.scale_width}x{self.scale_height}', self.upscaled_frames) Avalon.info(_('Conversion completed')) # migrate audio tracks and subtitles Avalon.info( _('Migrating audio tracks and subtitles to upscaled video')) fm.migrate_audio_tracks_subtitles(self.input_video, self.output_video, self.upscaled_frames) # destroy temp directories self.cleanup_temp_directories()
def run(self): """ Main controller for Video2X This function controls the flow of video conversion and handles all necessary functions. """ # external stop signal when called in a thread self.stop_signal = False # define process pool to contain processes self.process_pool = [] # parse arguments for waifu2x # check argument sanity self._check_arguments() # define processing queue processing_queue = queue.Queue() # if input specified is single file if self.input_path.is_file(): Avalon.info(_('Upscaling single video file: {}').format(self.input_path)) processing_queue.put((self.input_path.absolute(), self.output_path.absolute())) # if input specified is a directory elif self.input_path.is_dir(): # make output directory if it doesn't exist self.output_path.mkdir(parents=True, exist_ok=True) for input_video in [f for f in self.input_path.iterdir() if f.is_file()]: output_video = self.output_path / input_video.name processing_queue.put((input_video.absolute(), output_video.absolute())) while not processing_queue.empty(): input_video, output_video = processing_queue.get() # drivers that have native support for video processing if self.driver == 'anime4kcpp': # append FFmpeg path to the end of PATH # Anime4KCPP will then use FFmpeg to migrate audio tracks os.environ['PATH'] += f';{self.ffmpeg_settings["ffmpeg_path"]}' Avalon.info(_('Starting to upscale extracted images')) # import and initialize Anime4KCPP wrapper DriverWrapperMain = getattr(importlib.import_module('wrappers.anime4kcpp'), 'WrapperMain') driver = DriverWrapperMain(copy.deepcopy(self.driver_settings)) # run Anime4KCPP self.process_pool.append(driver.upscale(input_video, output_video, self.scale_ratio, self.processes)) self._wait() Avalon.info(_('Upscaling completed')) else: try: self.create_temp_directories() # initialize objects for ffmpeg and waifu2x-caffe fm = Ffmpeg(self.ffmpeg_settings, self.image_format) Avalon.info(_('Reading video information')) video_info = fm.get_video_info(input_video) # analyze original video with ffprobe and retrieve framerate # width, height = info['streams'][0]['width'], info['streams'][0]['height'] # find index of video stream video_stream_index = None for stream in video_info['streams']: if stream['codec_type'] == 'video': video_stream_index = stream['index'] break # exit if no video stream found if video_stream_index is None: Avalon.error(_('Aborting: No video stream found')) raise StreamNotFoundError('no video stream found') # extract frames from video self.process_pool.append((fm.extract_frames(input_video, self.extracted_frames))) self._wait() # get average frame rate of video stream framerate = float(Fraction(video_info['streams'][video_stream_index]['avg_frame_rate'])) fm.pixel_format = video_info['streams'][video_stream_index]['pix_fmt'] # get a dict of all pixel formats and corresponding bit depth pixel_formats = fm.get_pixel_formats() # try getting pixel format's corresponding bti depth try: self.bit_depth = pixel_formats[fm.pixel_format] except KeyError: Avalon.error(_('Unsupported pixel format: {}').format(fm.pixel_format)) raise UnsupportedPixelError(f'unsupported pixel format {fm.pixel_format}') Avalon.info(_('Framerate: {}').format(framerate)) # width/height will be coded width/height x upscale factor if self.scale_ratio: original_width = video_info['streams'][video_stream_index]['width'] original_height = video_info['streams'][video_stream_index]['height'] self.scale_width = int(self.scale_ratio * original_width) self.scale_height = int(self.scale_ratio * original_height) # upscale images one by one using waifu2x Avalon.info(_('Starting to upscale extracted images')) self._upscale_frames() Avalon.info(_('Upscaling completed')) # frames to Video Avalon.info(_('Converting extracted frames into video')) # use user defined output size self.process_pool.append(fm.convert_video(framerate, f'{self.scale_width}x{self.scale_height}', self.upscaled_frames)) self._wait() Avalon.info(_('Conversion completed')) # migrate audio tracks and subtitles Avalon.info(_('Migrating audio tracks and subtitles to upscaled video')) self.process_pool.append(fm.migrate_audio_tracks_subtitles(input_video, output_video, self.upscaled_frames)) self._wait() # destroy temp directories self.cleanup_temp_directories() except (Exception, KeyboardInterrupt, SystemExit) as e: with contextlib.suppress(ValueError): self.cleanup_temp_directories() raise e