diff --git a/src/upscaler.py b/src/upscaler.py index 5e33b78..780dbf2 100755 --- a/src/upscaler.py +++ b/src/upscaler.py @@ -85,9 +85,12 @@ class Upscaler: self.preserve_frames = False # other internal members and signals - self.stop_signal = False + self.running = False self.total_frames_upscaled = 0 self.total_frames = 0 + self.total_videos = 0 + self.total_processed = 0 + self.current_input_video = pathlib.Path() def create_temp_directories(self): """create temporary directories @@ -347,7 +350,7 @@ class Upscaler: while self.process_pool: # if stop signal received, terminate all processes - if self.stop_signal is True: + if self.running is False: raise SystemExit for process in self.process_pool: @@ -386,7 +389,7 @@ class Upscaler: """ # external stop signal when called in a thread - self.stop_signal = False + self.running = True # define process pool to contain processes self.process_pool = [] @@ -396,7 +399,7 @@ class Upscaler: self._check_arguments() # define processing queue - processing_queue = queue.Queue() + self.processing_queue = queue.Queue() # if input is a list of files if isinstance(self.input, list): @@ -407,17 +410,17 @@ class Upscaler: if input_path.is_file(): output_video = self.output / input_path.name - processing_queue.put((input_path.absolute(), output_video.absolute())) + self.processing_queue.put((input_path.absolute(), output_video.absolute())) elif input_path.is_dir(): for input_video in [f for f in input_path.iterdir() if f.is_file()]: output_video = self.output / input_video.name - processing_queue.put((input_video.absolute(), output_video.absolute())) + self.processing_queue.put((input_video.absolute(), output_video.absolute())) # if input specified is single file elif self.input.is_file(): Avalon.info(_('Upscaling single video file: {}').format(self.input)) - processing_queue.put((self.input.absolute(), self.output.absolute())) + self.processing_queue.put((self.input.absolute(), self.output.absolute())) # if input specified is a directory elif self.input.is_dir(): @@ -426,10 +429,13 @@ class Upscaler: self.output.mkdir(parents=True, exist_ok=True) for input_video in [f for f in self.input.iterdir() if f.is_file()]: output_video = self.output / input_video.name - processing_queue.put((input_video.absolute(), output_video.absolute())) + self.processing_queue.put((input_video.absolute(), output_video.absolute())) - while not processing_queue.empty(): - input_video, output_video = processing_queue.get() + # record video count for external calls + self.total_videos = self.processing_queue.qsize() + + while not self.processing_queue.empty(): + self.current_input_video, output_video = self.processing_queue.get() # drivers that have native support for video processing if self.driver == 'anime4kcpp': # append FFmpeg path to the end of PATH @@ -442,7 +448,7 @@ class Upscaler: 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.process_pool.append(driver.upscale(self.current_input_video, output_video, self.scale_ratio, self.processes)) self._wait() Avalon.info(_('Upscaling completed')) @@ -454,7 +460,7 @@ class Upscaler: fm = Ffmpeg(self.ffmpeg_settings, self.image_format) Avalon.info(_('Reading video information')) - video_info = fm.get_video_info(input_video) + video_info = fm.get_video_info(self.current_input_video) # analyze original video with ffprobe and retrieve framerate # width, height = info['streams'][0]['width'], info['streams'][0]['height'] @@ -471,7 +477,7 @@ class Upscaler: raise StreamNotFoundError('no video stream found') # extract frames from video - self.process_pool.append((fm.extract_frames(input_video, self.extracted_frames))) + self.process_pool.append((fm.extract_frames(self.current_input_video, self.extracted_frames))) self._wait() # get average frame rate of video stream @@ -512,7 +518,7 @@ class Upscaler: # 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.process_pool.append(fm.migrate_audio_tracks_subtitles(self.current_input_video, output_video, self.upscaled_frames)) self._wait() # destroy temp directories @@ -522,3 +528,9 @@ class Upscaler: with contextlib.suppress(ValueError): self.cleanup_temp_directories() raise e + + # increment total number of videos processed + self.total_processed += 1 + + # signal upscaling completion + self.running = False diff --git a/src/video2x_gui.py b/src/video2x_gui.py index 7592a53..d57cc78 100755 --- a/src/video2x_gui.py +++ b/src/video2x_gui.py @@ -219,11 +219,17 @@ class Video2XMainWindow(QMainWindow): self.scale_ratio_double_spin_box = self.findChild(QDoubleSpinBox, 'scaleRatioDoubleSpinBox') self.preserve_frames_check_box = self.findChild(QCheckBox, 'preserveFramesCheckBox') - # progress bar and start/stop controls - self.progress_bar = self.findChild(QProgressBar, 'progressBar') + # currently processing + self.currently_processing_label = self.findChild(QLabel, 'currentlyProcessingLabel') + self.current_progress_bar = self.findChild(QProgressBar, 'currentProgressBar') self.time_elapsed_label = self.findChild(QLabel, 'timeElapsedLabel') self.time_remaining_label = self.findChild(QLabel, 'timeRemainingLabel') self.rate_label = self.findChild(QLabel, 'rateLabel') + self.frames_label = self.findChild(QLabel, 'framesLabel') + + # overall progress + self.overall_progress_bar = self.findChild(QProgressBar, 'overallProgressBar') + self.overall_progress_label = self.findChild(QLabel, 'overallProgressLabel') self.start_button = self.findChild(QPushButton, 'startButton') self.start_button.clicked.connect(self.start) self.stop_button = self.findChild(QPushButton, 'stopButton') @@ -625,38 +631,33 @@ class Video2XMainWindow(QMainWindow): message_box.exec_() def start_progress_bar(self, progress_callback): - # wait for progress monitor to come online - while 'progress_monitor' not in self.upscaler.__dict__: - if self.upscaler.stop_signal: - return - time.sleep(0.1) # initialize progress bar values upscale_begin_time = time.time() - progress_callback.emit((0, 0, 0, upscale_begin_time)) + progress_callback.emit((upscale_begin_time, 0, 0, 0, 0, pathlib.Path())) # keep querying upscaling process and feed information to callback signal - while self.upscaler.progress_monitor.running: - try: - progress_percentage = int(100 * self.upscaler.total_frames_upscaled / self.upscaler.total_frames) - except ZeroDivisionError: - progress_percentage = 0 + while self.upscaler.running: - progress_callback.emit((progress_percentage, + progress_callback.emit((upscale_begin_time, self.upscaler.total_frames_upscaled, self.upscaler.total_frames, - upscale_begin_time)) + self.upscaler.total_processed, + self.upscaler.total_videos, + self.upscaler.current_input_video)) time.sleep(1) # upscale process will stop at 99% # so it's set to 100 manually when all is done - progress_callback.emit((100, 0, 0, upscale_begin_time)) + progress_callback.emit((upscale_begin_time, 0, 0, 0, 0, pathlib.Path())) def set_progress(self, progress_information: tuple): - progress_percentage = progress_information[0] + upscale_begin_time = progress_information[0] total_frames_upscaled = progress_information[1] total_frames = progress_information[2] - upscale_begin_time = progress_information[3] + total_processed = progress_information[3] + total_videos = progress_information[4] + current_input_video = progress_information[5] # calculate fields based on frames and time elapsed time_elapsed = time.time() - upscale_begin_time @@ -668,10 +669,29 @@ class Video2XMainWindow(QMainWindow): time_remaining = 0.0 # set calculated values in GUI - self.progress_bar.setValue(progress_percentage) + self.current_progress_bar.setMaximum(total_frames) + self.current_progress_bar.setValue(total_frames_upscaled) + self.frames_label.setText('Frames: {}/{}'.format(total_frames_upscaled, total_frames)) self.time_elapsed_label.setText('Time Elapsed: {}'.format(time.strftime("%H:%M:%S", time.gmtime(time_elapsed)))) self.time_remaining_label.setText('Time Remaining: {}'.format(time.strftime("%H:%M:%S", time.gmtime(time_remaining)))) self.rate_label.setText('Rate (FPS): {}'.format(round(rate, 2))) + self.overall_progress_label.setText('Overall Progress: {}/{}'.format(total_processed, total_videos)) + self.overall_progress_bar.setMaximum(total_videos) + self.overall_progress_bar.setValue(total_processed) + self.currently_processing_label.setText('Currently Processing: {}'.format(str(current_input_video.name))) + + def reset_progress_display(self): + # reset progress display UI elements + self.current_progress_bar.setMaximum(100) + self.current_progress_bar.setValue(0) + self.frames_label.setText('Frames: {}/{}'.format(0, 0)) + self.time_elapsed_label.setText('Time Elapsed: {}'.format(time.strftime("%H:%M:%S", time.gmtime(0)))) + self.time_remaining_label.setText('Time Remaining: {}'.format(time.strftime("%H:%M:%S", time.gmtime(0)))) + self.rate_label.setText('Rate (FPS): {}'.format(0.0)) + self.overall_progress_label.setText('Overall Progress: {}/{}'.format(0, 0)) + self.overall_progress_bar.setMaximum(100) + self.overall_progress_bar.setValue(0) + self.currently_processing_label.setText('Currently Processing:') def start(self): @@ -736,12 +756,14 @@ class Video2XMainWindow(QMainWindow): self.threadpool.waitForDone(5) self.start_button.setEnabled(True) self.stop_button.setEnabled(False) + self.reset_progress_display() def upscale_interrupted(self): self.show_message('Upscale has been interrupted') self.threadpool.waitForDone(5) self.start_button.setEnabled(True) self.stop_button.setEnabled(False) + self.reset_progress_display() def upscale_successful(self): # if all threads have finished @@ -749,10 +771,11 @@ class Video2XMainWindow(QMainWindow): self.show_message('Upscale finished successfully, taking {} seconds'.format(round((time.time() - self.begin_time), 5))) self.start_button.setEnabled(True) self.stop_button.setEnabled(False) + self.reset_progress_display() def stop(self): with contextlib.suppress(AttributeError): - self.upscaler.stop_signal = True + self.upscaler.running = False def closeEvent(self, event): # try cleaning up temp directories diff --git a/src/video2x_gui.pyproject.user b/src/video2x_gui.pyproject.user index fcf05fd..3d612f6 100644 --- a/src/video2x_gui.pyproject.user +++ b/src/video2x_gui.pyproject.user @@ -1,6 +1,6 @@ - + EnvironmentId diff --git a/src/video2x_gui.ui b/src/video2x_gui.ui index b99a934..c330060 100644 --- a/src/video2x_gui.ui +++ b/src/video2x_gui.ui @@ -7,7 +7,7 @@ 0 0 718 - 668 + 740 @@ -1276,72 +1276,184 @@ - - - - - 0 - - - - - - - - - false - - - QFrame::StyledPanel - - - Time Elapsed: 00:00:00 - - - - - - - QFrame::StyledPanel - - - Time Remaining: 00:00:00 - - - - - - - QFrame::StyledPanel - - - Rate (FPS): 0.0 - - - - - - - false - - - Start - - - - - - - false - - - Stop - - - - - - + + + Current Video Processing Progress + + + + + + + 0 + 20 + + + + Currently Processing: + + + + + + + 0 + + + + + + + + + + 0 + 20 + + + + false + + + QFrame::StyledPanel + + + Time Elapsed: 00:00:00 + + + + + + + + 0 + 20 + + + + QFrame::StyledPanel + + + Time Remaining: 00:00:00 + + + + + + + + 0 + 20 + + + + QFrame::StyledPanel + + + Rate (FPS): 0.0 + + + + + + + QFrame::StyledPanel + + + Frames: 0/0 + + + + + + + + + + + + Overall Video Processing Progress + + + + + + 0 + + + + + + + + + + 0 + 20 + + + + + 16777215 + 16777215 + + + + QFrame::StyledPanel + + + Overall Progress: 0/0 + + + + + + + false + + + + 130 + 0 + + + + + 16777215 + 16777215 + + + + Start + + + + + + + false + + + + 130 + 0 + + + + + 16777215 + 16777215 + + + + Stop + + + + + + +