diff --git a/src/video2x_gui.py b/src/video2x_gui.py index 522495a..b064106 100755 --- a/src/video2x_gui.py +++ b/src/video2x_gui.py @@ -10,16 +10,13 @@ Last Modified: May 6, 2020 # local imports from upscaler import Upscaler -# built-in imports -import pathlib -import sys - # built-in imports import contextlib +import pathlib import re import shutil +import sys import tempfile -import threading import time import traceback import yaml @@ -45,21 +42,45 @@ AVAILABLE_DRIVERS = { 'Anime4KCPP': 'anime4kcpp' } +def resource_path(relative_path: str) -> pathlib.Path: + try: + base_path = pathlib.Path(sys._MEIPASS) + except Exception: + base_path = pathlib.Path(__file__).parent + return base_path / relative_path -class UpscalerSignals(QObject): - finished = pyqtSignal() + +class WorkerSignals(QObject): + progress = pyqtSignal(tuple) error = pyqtSignal(str) + finished = pyqtSignal() -class Worker(QRunnable): +class ProgressBarWorker(QRunnable): + def __init__(self, fn, *args, **kwargs): + super(ProgressBarWorker, self).__init__() + self.fn = fn + self.args = args + self.kwargs = kwargs + self.signals = WorkerSignals() + self.kwargs['progress_callback'] = self.signals.progress + + @pyqtSlot() + def run(self): + try: + self.fn(*self.args, **self.kwargs) + except Exception: + pass + +class UpscalerWorker(QRunnable): def __init__(self, fn, *args, **kwargs): - super(Worker, self).__init__() + super(UpscalerWorker, self).__init__() # Store constructor arguments (re-used for processing) self.fn = fn self.args = args self.kwargs = kwargs - self.signals = UpscalerSignals() + self.signals = WorkerSignals() @pyqtSlot() def run(self): @@ -78,9 +99,9 @@ class Video2XMainWindow(QtWidgets.QMainWindow): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) - uic.loadUi('video2x_gui.ui', self) + uic.loadUi(str(resource_path('video2x_gui.ui')), self) - self.video2x_icon_path = str((pathlib.Path(__file__).parent / 'images' / 'video2x.png').absolute()) + self.video2x_icon_path = str(resource_path('images/video2x.png')) self.setWindowTitle(f'Video2X GUI {VERSION}') self.setWindowIcon(QtGui.QIcon(self.video2x_icon_path)) @@ -126,8 +147,11 @@ class Video2XMainWindow(QtWidgets.QMainWindow): # progress bar and start/stop controls self.progress_bar = self.findChild(QtWidgets.QProgressBar, 'progressBar') + self.time_elapsed_label = self.findChild(QtWidgets.QLabel, 'timeElapsedLabel') + self.time_remaining_label = self.findChild(QtWidgets.QLabel, 'timeRemainingLabel') + self.rate_label = self.findChild(QtWidgets.QLabel, 'rateLabel') self.start_button = self.findChild(QtWidgets.QPushButton, 'startButton') - self.start_button.clicked.connect(self.upscale) + self.start_button.clicked.connect(self.start) self.stop_button = self.findChild(QtWidgets.QPushButton, 'stopButton') self.stop_button.clicked.connect(self.stop) @@ -482,7 +506,7 @@ class Video2XMainWindow(QtWidgets.QMainWindow): message_box.setText(message) message_box.exec_() - def start_progress_bar(self): + def start_progress_bar(self, progress_callback): # initialize variables early self.upscaler.progress_bar_exit_signal = False @@ -490,14 +514,43 @@ class Video2XMainWindow(QtWidgets.QMainWindow): self.upscaler.total_frames = 1 # initialize progress bar values - self.progress_bar.setValue(0) + upscale_begin_time = time.time() + progress_callback.emit((0, 0, 0, upscale_begin_time)) + # keep querying upscaling process and feed information to callback signal while not self.upscaler.progress_bar_exit_signal: - self.progress_bar.setValue(int(100 * self.upscaler.total_frames_upscaled / self.upscaler.total_frames)) + progress_callback.emit((int(100 * self.upscaler.total_frames_upscaled / self.upscaler.total_frames), + self.upscaler.total_frames_upscaled, + self.upscaler.total_frames, + upscale_begin_time)) time.sleep(1) - self.progress_bar.setValue(100) - def upscale(self): + # 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)) + + def set_progress(self, progress_information: tuple): + progress_percentage = progress_information[0] + total_frames_upscaled = progress_information[1] + total_frames = progress_information[2] + upscale_begin_time = progress_information[3] + + # calculate fields based on frames and time elapsed + time_elapsed = time.time() - upscale_begin_time + try: + rate = total_frames_upscaled / (time.time() - upscale_begin_time) + time_remaining = (total_frames - total_frames_upscaled) / rate + except Exception: + rate = 0.0 + time_remaining = 0.0 + + # set calculated values in GUI + self.progress_bar.setValue(progress_percentage) + 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))) + + def start(self): # start execution try: @@ -505,6 +558,13 @@ class Video2XMainWindow(QtWidgets.QMainWindow): self.begin_time = time.time() # resolve input and output directories from GUI + if self.input_line_edit.text().strip() == '': + self.show_error('Input path not specified') + return + if self.output_line_edit.text().strip() == '': + self.show_error('Output path not specified') + return + input_directory = pathlib.Path(self.input_line_edit.text()) output_directory = pathlib.Path(self.output_line_edit.text()) @@ -520,8 +580,6 @@ class Video2XMainWindow(QtWidgets.QMainWindow): # if input specified is a single file if input_directory.is_file(): - # upscale single video file - # check for input output format mismatch if output_directory.is_dir(): self.show_error('Input and output path type mismatch\n\ @@ -547,11 +605,12 @@ class Video2XMainWindow(QtWidgets.QMainWindow): # start progress bar if AVAILABLE_DRIVERS[self.driver_combo_box.currentText()] != 'anime4kcpp': - progress_bar_worker = Worker(self.start_progress_bar) + progress_bar_worker = ProgressBarWorker(self.start_progress_bar) + progress_bar_worker.signals.progress.connect(self.set_progress) self.threadpool.start(progress_bar_worker) # run upscaler - worker = Worker(self.upscaler.run) + worker = UpscalerWorker(self.upscaler.run) worker.signals.error.connect(self.upscale_errored) worker.signals.finished.connect(self.upscale_completed) self.threadpool.start(worker) @@ -582,11 +641,11 @@ class Video2XMainWindow(QtWidgets.QMainWindow): # start progress bar if AVAILABLE_DRIVERS[self.driver_combo_box.currentText()] != 'anime4kcpp': - progress_bar_worker = Worker(self.start_progress_bar) + progress_bar_worker = ProgressBarWorker(self.start_progress_bar) self.threadpool.start(progress_bar_worker) # run upscaler - worker = Worker(self.upscaler.run) + worker = UpscalerWorker(self.upscaler.run) worker.signals.error.connect(self.upscale_errored) worker.signals.finished.connect(self.upscale_completed) self.threadpool.start(worker) @@ -598,8 +657,6 @@ class Video2XMainWindow(QtWidgets.QMainWindow): except Exception: self.upscale_errored(traceback.format_exc()) - - finally: self.upscale_completed() def upscale_errored(self, error_message): @@ -624,7 +681,6 @@ class Video2XMainWindow(QtWidgets.QMainWindow): # TODO unimplemented yet pass - app = QtWidgets.QApplication(sys.argv) window = Video2XMainWindow() window.show() diff --git a/src/video2x_gui.ui b/src/video2x_gui.ui index 17c6dc0..61ae2bb 100644 --- a/src/video2x_gui.ui +++ b/src/video2x_gui.ui @@ -6,8 +6,8 @@ 0 0 - 617 - 474 + 691 + 503 @@ -194,82 +194,78 @@ - + - - - - - Driver - - - - - - - - Waifu2X Caffe - - - - - Waifu2X Converter CPP - - - - - Waifu2X NCNN Vulkan - - - - - SRMD NCNN Vulkan - - - - - Anime4KCPP - - - - - + + + Driver + + - + - - - Processes - - + + Waifu2X Caffe + - - - 1 - - + + Waifu2X Converter CPP + - + + + Waifu2X NCNN Vulkan + + + + + SRMD NCNN Vulkan + + + + + Anime4KCPP + + + + + + + + + + + + Processes + + - - - - - Scale Ratio - - - - - - - 2.000000000000000 - - - - + + + 1 + + + + + + + + + + + Scale Ratio + + + + + + + 2.000000000000000 + + @@ -1188,7 +1184,7 @@ - + @@ -1197,24 +1193,61 @@ - - - false - - - Start - - - - - - - false - - - Stop - - + + + + + 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 + + + + @@ -1225,7 +1258,7 @@ 0 0 - 617 + 691 21