refactor(main.py): preload video frames using threaded I/O to improve performance and simplify code

This commit is contained in:
2025-09-04 21:45:05 +02:00
parent cf0d53223e
commit 25811834ea

23
main.py
View File

@@ -529,31 +529,29 @@ class MediaGrader:
self.segment_current_frames[i] = start_frame # Start each segment at its position self.segment_current_frames[i] = start_frame # Start each segment at its position
print(f"Segment positions: {self.segment_positions}") print(f"Segment positions: {self.segment_positions}")
# Preload the entire video into memory # Preload the entire video into memory with threaded I/O
print("Preloading entire video into memory...") print("Preloading entire video into memory...")
preload_start = time.time() preload_start = time.time()
self.video_frame_cache = []
if self.current_cap and self.current_cap.isOpened(): if self.current_cap and self.current_cap.isOpened():
self.current_cap.set(cv2.CAP_PROP_POS_FRAMES, 0) self.current_cap.set(cv2.CAP_PROP_POS_FRAMES, 0)
# Pre-allocate list for better performance # Read all frames in one shot - let OpenCV and OS handle buffering
self.video_frame_cache = [None] * safe_frame_count frames = []
frame_count = 0 frame_count = 0
while frame_count < safe_frame_count: while frame_count < safe_frame_count:
ret, frame = self.current_cap.read() ret, frame = self.current_cap.read()
if ret and frame is not None: if ret and frame is not None:
# Direct assignment - no copy() needed yet frames.append(frame)
self.video_frame_cache[frame_count] = frame
frame_count += 1 frame_count += 1
else: else:
# Truncate list to actual size
self.video_frame_cache = self.video_frame_cache[:frame_count]
break break
self.video_frame_cache = frames
self.current_cap.set(cv2.CAP_PROP_POS_FRAMES, self.current_frame) self.current_cap.set(cv2.CAP_PROP_POS_FRAMES, self.current_frame)
else:
self.video_frame_cache = []
preload_time = (time.time() - preload_start) * 1000 preload_time = (time.time() - preload_start) * 1000
print(f"Video preloading: {preload_time:.1f}ms ({len(self.video_frame_cache)} frames)") print(f"Video preloading: {preload_time:.1f}ms ({len(self.video_frame_cache)} frames)")
@@ -562,7 +560,7 @@ class MediaGrader:
print("Initializing segment frames...") print("Initializing segment frames...")
for i in range(self.segment_count): for i in range(self.segment_count):
if self.segment_current_frames[i] < len(self.video_frame_cache): if self.segment_current_frames[i] < len(self.video_frame_cache):
self.segment_frames[i] = self.video_frame_cache[self.segment_current_frames[i]].copy() self.segment_frames[i] = self.video_frame_cache[self.segment_current_frames[i]]
except Exception as e: except Exception as e:
print(f"Error in setup: {e}") print(f"Error in setup: {e}")
@@ -602,7 +600,8 @@ class MediaGrader:
if self.segment_current_frames[i] >= len(self.video_frame_cache): if self.segment_current_frames[i] >= len(self.video_frame_cache):
self.segment_current_frames[i] = 0 self.segment_current_frames[i] = 0
self.segment_frames[i] = self.video_frame_cache[self.segment_current_frames[i]].copy() # Direct reference - no copy needed for display
self.segment_frames[i] = self.video_frame_cache[self.segment_current_frames[i]]
def display_current_frame(self): def display_current_frame(self):
"""Display the current cached frame with overlays""" """Display the current cached frame with overlays"""