From 539b5d6d103c5d4846dfb4d220b70c40377e85a4 Mon Sep 17 00:00:00 2001 From: Pozitronik Date: Thu, 22 Feb 2024 11:21:20 +0400 Subject: [PATCH 1/8] fixed: issues with the source/the target change --- sinner/gui/GUIModel.py | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/sinner/gui/GUIModel.py b/sinner/gui/GUIModel.py index 6526ed75..71a87d59 100644 --- a/sinner/gui/GUIModel.py +++ b/sinner/gui/GUIModel.py @@ -165,10 +165,8 @@ def source_path(self) -> str | None: def source_path(self, value: str | None) -> None: self.parameters.source = value self.reload_parameters() - - if self.player_is_started: - self.TimeLine = FrameTimeLine(source_name=self._source_path, target_name=self._target_path, temp_dir=self.temp_dir, frame_time=self.frame_handler.frame_time, start_frame=self.TimeLine.last_requested_index, end_frame=self.frame_handler.fc) - else: + self.TimeLine = FrameTimeLine(source_name=self._source_path, target_name=self._target_path, temp_dir=self.temp_dir, frame_time=self.frame_handler.frame_time, start_frame=self.TimeLine.last_requested_index, end_frame=self.frame_handler.fc) + if not self.player_is_started: self.update_preview() @property @@ -180,9 +178,9 @@ def target_path(self, value: str | None) -> None: self.parameters.target = value self.reload_parameters() self.Player.clear() + self.TimeLine = FrameTimeLine(source_name=self._source_path, target_name=self._target_path, temp_dir=self.temp_dir, frame_time=self.frame_handler.frame_time, start_frame=1, end_frame=self.frame_handler.fc) if self.player_is_started: self.player_stop(reload_frames=True) - self.TimeLine = FrameTimeLine(source_name=self._source_path, target_name=self._target_path, temp_dir=self.temp_dir, frame_time=self.frame_handler.frame_time, start_frame=self.TimeLine.last_requested_index, end_frame=self.frame_handler.fc) self.position.set(1) self.player_start(start_frame=1) else: From 7c3bcea626df3383898c12fae57f23098b622bcc Mon Sep 17 00:00:00 2001 From: Pozitronik Date: Thu, 22 Feb 2024 11:22:18 +0400 Subject: [PATCH 2/8] remove unused attribute --- sinner/gui/GUIModel.py | 7 ------- 1 file changed, 7 deletions(-) diff --git a/sinner/gui/GUIModel.py b/sinner/gui/GUIModel.py index 71a87d59..fa8e5236 100644 --- a/sinner/gui/GUIModel.py +++ b/sinner/gui/GUIModel.py @@ -41,7 +41,6 @@ class GUIModel(Status): execution_threads: int bootstrap_processors: bool # bootstrap_processors processors on startup _prepare_frames: bool # True: always extract and use, False: newer extract nor use, Null: newer extract, use if exists. Note: attribute can't be typed as bool | None due to AttributeLoader limitations - _initial_frame_buffer_length: int # frames needs to be rendered before player start. Also used to determine initial frame drop _scale_quality: float # the processed frame size scale from 0 to 1 parameters: Namespace @@ -117,12 +116,6 @@ def rules(self) -> Rules: 'default': True, 'help': 'Bootstrap frame processors on startup' }, - { - 'parameter': 'initial_frame_buffer_length', - 'attribute': '_initial_frame_buffer_length', - 'default': lambda: int(self.frame_handler.fps * 2), # two seconds - 'help': 'The count of preprocessed frames' - }, { 'parameter': 'temp-dir', 'default': lambda: suggest_temp_dir(self.temp_dir), From 80c5dd8458021a10613f9744a05a5a1d69d8acdc Mon Sep 17 00:00:00 2001 From: Pozitronik Date: Thu, 22 Feb 2024 11:40:00 +0400 Subject: [PATCH 3/8] use FrameExtractor module to extract frames within GUIModel --- sinner/gui/GUIModel.py | 22 +++------------------- 1 file changed, 3 insertions(+), 19 deletions(-) diff --git a/sinner/gui/GUIModel.py b/sinner/gui/GUIModel.py index fa8e5236..d62c86d3 100644 --- a/sinner/gui/GUIModel.py +++ b/sinner/gui/GUIModel.py @@ -6,8 +6,6 @@ from tkinter import IntVar from typing import List, Callable, Any -from tqdm import tqdm - from sinner.BatchProcessingCore import BatchProcessingCore from sinner.Status import Status, Mood from sinner.gui.controls.FramePlayer.BaseFramePlayer import BaseFramePlayer @@ -107,7 +105,7 @@ def rules(self) -> Rules: { 'parameter': {'prepare-frames'}, 'attribute': '_prepare_frames', - 'default': None, + 'default': True, 'help': 'Extract target frames to files to make realtime player run smoother' }, { @@ -457,22 +455,8 @@ def extract_frames(self) -> bool: elif self._prepare_frames is True: if state.is_started: self.update_status(f'Temp resources for this target already exists with {state.processed_frames_count} frames extracted, continue with {state.processor_name}') - with tqdm( - total=state.frames_count, - desc=state.processor_name, unit='frame', - dynamic_ncols=True, - bar_format='{l_bar}{bar}| {n_fmt}/{total_fmt} [{elapsed}<{remaining}, {rate_fmt}{postfix}]', - initial=state.processed_frames_count, - ) as progress: - self.frame_handler.current_frame_index = state.processed_frames_count - for frame_num in self.frame_handler: - n_frame = self.frame_handler.extract_frame(frame_num) - state.save_temp_frame(n_frame) - progress.update() - self.ProgressBarsManager.update(name=EXTRACTING_PROGRESS_NAME, value=state.processed_frames_count, max_value=state.frames_count) - self.ProgressBarsManager.done(EXTRACTING_PROGRESS_NAME) - - frame_extractor.release_resources() + frame_extractor.process(self.frame_handler, state) + frame_extractor.release_resources() if state_is_finished: self._target_handler = DirectoryHandler(state.path, self.parameters, self.frame_handler.fps, self.frame_handler.fc, self.frame_handler.resolution) self._is_target_frames_extracted = state_is_finished From 14c682bf3f62760fb11c45428fdece3694f7ef8c Mon Sep 17 00:00:00 2001 From: Pozitronik Date: Thu, 22 Feb 2024 11:43:23 +0400 Subject: [PATCH 4/8] article --- sinner/processors/frame/FrameExtractor.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sinner/processors/frame/FrameExtractor.py b/sinner/processors/frame/FrameExtractor.py index 9d5b8afb..36924a12 100644 --- a/sinner/processors/frame/FrameExtractor.py +++ b/sinner/processors/frame/FrameExtractor.py @@ -18,7 +18,7 @@ class FrameExtractor(BaseFrameProcessor): def rules(self) -> Rules: return [ { - 'module_help': 'This module extracts frames from video file as set of png images' + 'module_help': 'This module extracts frames from video file as a set of png images' } ] From 1dd85edf6b75be1c27f47ff4c6af364cd6ad4b31 Mon Sep 17 00:00:00 2001 From: Pozitronik Date: Thu, 22 Feb 2024 11:45:50 +0400 Subject: [PATCH 5/8] revert default value to none --- sinner/gui/GUIModel.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sinner/gui/GUIModel.py b/sinner/gui/GUIModel.py index d62c86d3..d7e9521d 100644 --- a/sinner/gui/GUIModel.py +++ b/sinner/gui/GUIModel.py @@ -105,7 +105,7 @@ def rules(self) -> Rules: { 'parameter': {'prepare-frames'}, 'attribute': '_prepare_frames', - 'default': True, + 'default': None, 'help': 'Extract target frames to files to make realtime player run smoother' }, { From e58f128aaba6e86b216d5cfdf41c84cd6d0d6df3 Mon Sep 17 00:00:00 2001 From: Pozitronik Date: Thu, 22 Feb 2024 11:57:48 +0400 Subject: [PATCH 6/8] todo added --- sinner/gui/GUIModel.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sinner/gui/GUIModel.py b/sinner/gui/GUIModel.py index d7e9521d..a905f0b4 100644 --- a/sinner/gui/GUIModel.py +++ b/sinner/gui/GUIModel.py @@ -455,7 +455,7 @@ def extract_frames(self) -> bool: elif self._prepare_frames is True: if state.is_started: self.update_status(f'Temp resources for this target already exists with {state.processed_frames_count} frames extracted, continue with {state.processor_name}') - frame_extractor.process(self.frame_handler, state) + frame_extractor.process(self.frame_handler, state) # todo: return the GUI progressbar frame_extractor.release_resources() if state_is_finished: self._target_handler = DirectoryHandler(state.path, self.parameters, self.frame_handler.fps, self.frame_handler.fc, self.frame_handler.resolution) From 2411fa26096d207ef36b01f682983bfc54dc32d5 Mon Sep 17 00:00:00 2001 From: Pozitronik Date: Thu, 22 Feb 2024 12:11:06 +0400 Subject: [PATCH 7/8] fixed: wrong processing FPS calculation (frames time were used instead) --- sinner/gui/GUIModel.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sinner/gui/GUIModel.py b/sinner/gui/GUIModel.py index a905f0b4..47a84ddd 100644 --- a/sinner/gui/GUIModel.py +++ b/sinner/gui/GUIModel.py @@ -366,8 +366,8 @@ def process_done(future_: Future[float | None]) -> None: if len(results) >= 30: # limit mean time base to last 30 executions results.pop(0) results.append(process_time) - self._process_fps = sum(results) / len(results) * self.execution_threads - self._status("Processing FPS/Frame skip", f"{round(self._process_fps, 4)}FPS/{frame_skip - 1}") + self._process_fps = self._process_fps = self.execution_threads / (sum(results) / len(results)) + self._status("Mean FPS/Last frame/Frame skip", f"{round(self._process_fps, 4)}/{round(1/process_time, 4)}/{frame_skip - 1}") futures.remove(future_) futures: list[Future[float | None]] = [] From 26b6668586232a390e5e9fa0983c69abb8683c3f Mon Sep 17 00:00:00 2001 From: Pozitronik Date: Thu, 22 Feb 2024 12:50:12 +0400 Subject: [PATCH 8/8] properly handle existed but not-readable frames --- sinner/models/FrameDirectoryBuffer.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/sinner/models/FrameDirectoryBuffer.py b/sinner/models/FrameDirectoryBuffer.py index 8d863dd4..cddbd0a8 100644 --- a/sinner/models/FrameDirectoryBuffer.py +++ b/sinner/models/FrameDirectoryBuffer.py @@ -74,14 +74,20 @@ def get_frame(self, index: int, return_previous: bool = True) -> NumberedFrame | filename = str(index).zfill(self.zfill_length) + '.png' filepath = str(os.path.join(self.path, filename)) if path_exists(filepath): - return NumberedFrame(index, read_from_image(filepath)) + try: + return NumberedFrame(index, read_from_image(filepath)) + except Exception: + pass elif return_previous: for previous_number in range(index - 1, 0, -1): if self.has_frame(previous_number): previous_filename = str(previous_number).zfill(self.zfill_length) + '.png' previous_file_path = os.path.join(self.path, previous_filename) if path_exists(previous_file_path): - return NumberedFrame(index, read_from_image(previous_file_path)) + try: + return NumberedFrame(index, read_from_image(previous_file_path)) + except Exception: # the file may exist but can be locked in another thread. + pass return None def has_frame(self, index: int) -> bool: