refactor(main.py): update segment setup and preloading to improve video handling and performance
This commit is contained in:
73
main.py
73
main.py
@@ -518,7 +518,7 @@ class MediaGrader:
|
|||||||
return
|
return
|
||||||
|
|
||||||
start_time = time.time()
|
start_time = time.time()
|
||||||
print(f"Setting up {self.segment_count} segments with frame caching...")
|
print(f"Setting up {self.segment_count} segments with video preloading...")
|
||||||
|
|
||||||
try:
|
try:
|
||||||
# Clean up existing segment captures
|
# Clean up existing segment captures
|
||||||
@@ -528,11 +528,12 @@ class MediaGrader:
|
|||||||
current_file = self.media_files[self.current_index]
|
current_file = self.media_files[self.current_index]
|
||||||
print(f"Working with file: {current_file}")
|
print(f"Working with file: {current_file}")
|
||||||
|
|
||||||
# Initialize arrays - no individual captures, just cached frames
|
# Initialize arrays
|
||||||
print("Initializing arrays...")
|
print("Initializing arrays...")
|
||||||
self.segment_caps = [None] * self.segment_count # Keep for compatibility, but won't use
|
self.segment_caps = [None] * self.segment_count # Keep for compatibility
|
||||||
self.segment_frames = [None] * self.segment_count
|
self.segment_frames = [None] * self.segment_count
|
||||||
self.segment_positions = []
|
self.segment_positions = []
|
||||||
|
self.segment_current_frames = [0] * self.segment_count # Track current frame for each segment
|
||||||
|
|
||||||
# Calculate target positions
|
# Calculate target positions
|
||||||
print("Calculating segment positions...")
|
print("Calculating segment positions...")
|
||||||
@@ -552,27 +553,44 @@ class MediaGrader:
|
|||||||
start_frame = int(position_ratio * (safe_frame_count - 1))
|
start_frame = int(position_ratio * (safe_frame_count - 1))
|
||||||
start_frame = max(0, min(start_frame, safe_frame_count - 1))
|
start_frame = max(0, min(start_frame, safe_frame_count - 1))
|
||||||
self.segment_positions.append(start_frame)
|
self.segment_positions.append(start_frame)
|
||||||
|
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}")
|
||||||
|
|
||||||
# Use the existing main capture to quickly read all segment frames
|
# Preload the entire video into memory
|
||||||
print("Pre-loading segment frames...")
|
print("Preloading entire video into memory...")
|
||||||
cache_start = time.time()
|
preload_start = time.time()
|
||||||
|
|
||||||
|
self.video_frame_cache = [] # Array to hold all frames
|
||||||
|
|
||||||
if self.current_cap and self.current_cap.isOpened():
|
if self.current_cap and self.current_cap.isOpened():
|
||||||
for i, frame_pos in enumerate(self.segment_positions):
|
# Reset to beginning
|
||||||
self.current_cap.set(cv2.CAP_PROP_POS_FRAMES, frame_pos)
|
self.current_cap.set(cv2.CAP_PROP_POS_FRAMES, 0)
|
||||||
|
|
||||||
|
frame_count = 0
|
||||||
|
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:
|
||||||
self.segment_frames[i] = frame.copy()
|
self.video_frame_cache.append(frame.copy())
|
||||||
print(f"Cached segment {i} at frame {frame_pos}")
|
frame_count += 1
|
||||||
|
|
||||||
|
# Show progress for large videos
|
||||||
|
if frame_count % 50 == 0:
|
||||||
|
print(f"Preloaded {frame_count}/{safe_frame_count} frames...")
|
||||||
else:
|
else:
|
||||||
print(f"Failed to cache segment {i} at frame {frame_pos}")
|
print(f"Reached end of video at frame {frame_count}")
|
||||||
|
break
|
||||||
|
|
||||||
# Reset main capture to original position
|
# Reset main capture to original position
|
||||||
self.current_cap.set(cv2.CAP_PROP_POS_FRAMES, self.current_frame)
|
self.current_cap.set(cv2.CAP_PROP_POS_FRAMES, self.current_frame)
|
||||||
|
|
||||||
cache_time = (time.time() - cache_start) * 1000
|
preload_time = (time.time() - preload_start) * 1000
|
||||||
print(f"Frame caching: {cache_time:.1f}ms")
|
print(f"Video preloading: {preload_time:.1f}ms ({len(self.video_frame_cache)} frames)")
|
||||||
|
|
||||||
|
# Initialize segment frames from the preloaded cache
|
||||||
|
print("Initializing segment frames...")
|
||||||
|
for i in range(self.segment_count):
|
||||||
|
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()
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"Error in setup: {e}")
|
print(f"Error in setup: {e}")
|
||||||
@@ -585,7 +603,7 @@ class MediaGrader:
|
|||||||
|
|
||||||
# Report success
|
# Report success
|
||||||
successful_segments = sum(1 for frame in self.segment_frames if frame is not None)
|
successful_segments = sum(1 for frame in self.segment_frames if frame is not None)
|
||||||
print(f"Successfully cached {successful_segments}/{self.segment_count} segments")
|
print(f"Successfully preloaded video with {successful_segments}/{self.segment_count} active segments")
|
||||||
|
|
||||||
def _create_segment_parallel(self, segment_index: int, file_path: str, start_frame: int):
|
def _create_segment_parallel(self, segment_index: int, file_path: str, start_frame: int):
|
||||||
"""Create a single segment capture and load its initial frame (runs in thread)"""
|
"""Create a single segment capture and load its initial frame (runs in thread)"""
|
||||||
@@ -645,13 +663,17 @@ class MediaGrader:
|
|||||||
return None, None
|
return None, None
|
||||||
|
|
||||||
def cleanup_segment_captures(self):
|
def cleanup_segment_captures(self):
|
||||||
"""Clean up all segment video captures"""
|
"""Clean up all segment video captures and preloaded cache"""
|
||||||
for cap in self.segment_caps:
|
for cap in self.segment_caps:
|
||||||
if cap:
|
if cap:
|
||||||
cap.release()
|
cap.release()
|
||||||
self.segment_caps = []
|
self.segment_caps = []
|
||||||
self.segment_frames = []
|
self.segment_frames = []
|
||||||
self.segment_positions = []
|
self.segment_positions = []
|
||||||
|
if hasattr(self, 'video_frame_cache'):
|
||||||
|
self.video_frame_cache = [] # Clear preloaded video cache
|
||||||
|
if hasattr(self, 'segment_current_frames'):
|
||||||
|
self.segment_current_frames = [] # Clear frame tracking
|
||||||
# Clear frame cache
|
# Clear frame cache
|
||||||
self.frame_cache.clear()
|
self.frame_cache.clear()
|
||||||
|
|
||||||
@@ -769,15 +791,22 @@ class MediaGrader:
|
|||||||
return segment_index, None
|
return segment_index, None
|
||||||
|
|
||||||
def update_segment_frames(self):
|
def update_segment_frames(self):
|
||||||
"""Update frames for segments - now using static cached frames for simplicity"""
|
"""Update frames for segments using the preloaded video array - smooth playback!"""
|
||||||
if not self.multi_segment_mode or not self.segment_frames:
|
if not self.multi_segment_mode or not self.segment_frames or not hasattr(self, 'video_frame_cache'):
|
||||||
return
|
return
|
||||||
|
|
||||||
# Since we're using cached static frames, no updates needed during playback
|
# Each segment advances through the video at its own pace
|
||||||
# This dramatically improves performance by eliminating I/O during playback
|
for i in range(len(self.segment_frames)):
|
||||||
# The segments show different parts of the video but don't animate
|
if self.segment_frames[i] is not None and self.video_frame_cache:
|
||||||
# For animation, we'd need to implement frame interpolation or periodic cache updates
|
# Advance this segment's current frame
|
||||||
pass
|
self.segment_current_frames[i] += 1
|
||||||
|
|
||||||
|
# Loop back to start if we reach the end
|
||||||
|
if self.segment_current_frames[i] >= len(self.video_frame_cache):
|
||||||
|
self.segment_current_frames[i] = 0
|
||||||
|
|
||||||
|
# Update the segment frame from the cache
|
||||||
|
self.segment_frames[i] = self.video_frame_cache[self.segment_current_frames[i]].copy()
|
||||||
|
|
||||||
def reposition_segments_around_frame(self, center_frame: int):
|
def reposition_segments_around_frame(self, center_frame: int):
|
||||||
"""Reposition all segments around a center frame while maintaining spacing"""
|
"""Reposition all segments around a center frame while maintaining spacing"""
|
||||||
|
Reference in New Issue
Block a user