Compare commits
2 Commits
a6886a8ab8
...
01ea25168a
Author | SHA1 | Date | |
---|---|---|---|
01ea25168a | |||
fc0aa1317b |
55
main.py
55
main.py
@@ -7,6 +7,8 @@ import argparse
|
|||||||
import shutil
|
import shutil
|
||||||
import time
|
import time
|
||||||
import threading
|
import threading
|
||||||
|
import subprocess
|
||||||
|
import json
|
||||||
from concurrent.futures import ThreadPoolExecutor
|
from concurrent.futures import ThreadPoolExecutor
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import List
|
from typing import List
|
||||||
@@ -58,6 +60,7 @@ class MediaGrader:
|
|||||||
self.segment_caps = []
|
self.segment_caps = []
|
||||||
self.segment_frames = []
|
self.segment_frames = []
|
||||||
self.segment_positions = []
|
self.segment_positions = []
|
||||||
|
self.segment_end_positions = [] # Track where each segment should loop back to
|
||||||
|
|
||||||
self.timeline_visible = True
|
self.timeline_visible = True
|
||||||
|
|
||||||
@@ -486,34 +489,27 @@ class MediaGrader:
|
|||||||
if not self.is_video(self.media_files[self.current_index]):
|
if not self.is_video(self.media_files[self.current_index]):
|
||||||
return
|
return
|
||||||
|
|
||||||
# Safety check for huge videos
|
|
||||||
safe_frame_count = max(1, int(self.total_frames * 0.6))
|
|
||||||
|
|
||||||
# Calculate actual memory usage based on frame dimensions
|
# Calculate actual memory usage based on frame dimensions
|
||||||
frame_width = int(self.current_cap.get(cv2.CAP_PROP_FRAME_WIDTH))
|
frame_width = int(self.current_cap.get(cv2.CAP_PROP_FRAME_WIDTH))
|
||||||
frame_height = int(self.current_cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
|
frame_height = int(self.current_cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
|
||||||
bytes_per_frame = frame_width * frame_height * 3 # RGB (3 bytes per pixel)
|
total_mb = frame_width * frame_height * 3 / (1024 * 1024)
|
||||||
total_bytes = safe_frame_count * bytes_per_frame
|
|
||||||
total_mb = total_bytes / (1024 * 1024)
|
|
||||||
total_gb = total_mb / 1024
|
|
||||||
|
|
||||||
# Memory-based limits (not frame count)
|
# Memory-based limits (not frame count)
|
||||||
if total_gb > 8: # 8GB limit
|
if total_mb > 8000: # 8GB limit
|
||||||
print(f"Video too large for preloading!")
|
print(f"Video too large for preloading!")
|
||||||
print(f" Resolution: {frame_width}x{frame_height}")
|
print(f" Resolution: {frame_width}x{frame_height}")
|
||||||
print(f" Frames: {safe_frame_count} frames would use {total_gb:.1f}GB RAM")
|
print(f" Frames: {self.total_frames} frames would use {total_mb:.1f}GB RAM")
|
||||||
print(f"Multi-segment mode not available for videos requiring >8GB RAM")
|
print(f"Multi-segment mode not available for videos requiring >8GB RAM")
|
||||||
return
|
return
|
||||||
elif total_mb > 500: # 500MB warning
|
elif total_mb > 500: # 500MB warning
|
||||||
print(f"Large video detected:")
|
print(f"Large video detected:")
|
||||||
print(f" Resolution: {frame_width}x{frame_height}")
|
print(f" Resolution: {frame_width}x{frame_height}")
|
||||||
print(f" Memory: {safe_frame_count} frames will use {total_mb:.0f}MB RAM")
|
print(f" Memory: {self.total_frames} frames will use {total_mb:.0f}GB RAM")
|
||||||
print("Press any key to continue or 'q' to cancel...")
|
print("Press any key to continue or 'q' to cancel...")
|
||||||
# Note: In a real implementation, you'd want proper input handling here
|
# Note: In a real implementation, you'd want proper input handling here
|
||||||
|
|
||||||
start_time = time.time()
|
start_time = time.time()
|
||||||
print(f"Setting up {self.segment_count} segments with video preloading...")
|
print(f"Setting up {self.segment_count} segments with video preloading...")
|
||||||
print(f"Will preload {safe_frame_count} frames ({frame_width}x{frame_height}) = {total_mb:.0f}MB RAM")
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
print("Cleaning up existing captures...")
|
print("Cleaning up existing captures...")
|
||||||
@@ -527,6 +523,7 @@ class MediaGrader:
|
|||||||
self.segment_caps = [None] * self.segment_count # Keep for compatibility
|
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_end_positions = []
|
||||||
self.segment_current_frames = [0] * self.segment_count # Track current frame for each segment
|
self.segment_current_frames = [0] * self.segment_count # Track current frame for each segment
|
||||||
|
|
||||||
# Calculate target positions
|
# Calculate target positions
|
||||||
@@ -538,13 +535,23 @@ class MediaGrader:
|
|||||||
for i in range(self.segment_count):
|
for i in range(self.segment_count):
|
||||||
if self.segment_count <= 1:
|
if self.segment_count <= 1:
|
||||||
position_ratio = 0
|
position_ratio = 0
|
||||||
|
end_ratio = 1.0
|
||||||
else:
|
else:
|
||||||
position_ratio = i / (self.segment_count - 1)
|
position_ratio = i / (self.segment_count - 1)
|
||||||
start_frame = int(position_ratio * (safe_frame_count - 1))
|
end_ratio = (i + 1) / (self.segment_count - 1) if i < self.segment_count - 1 else 1.0
|
||||||
start_frame = max(0, min(start_frame, safe_frame_count - 1))
|
|
||||||
|
start_frame = int(position_ratio * (self.total_frames - 1))
|
||||||
|
end_frame = int(end_ratio * (self.total_frames - 1))
|
||||||
|
|
||||||
|
start_frame = max(0, min(start_frame, self.total_frames - 1))
|
||||||
|
end_frame = max(start_frame + 1, min(end_frame, self.total_frames - 1)) # Ensure at least 1 frame per segment
|
||||||
|
|
||||||
self.segment_positions.append(start_frame)
|
self.segment_positions.append(start_frame)
|
||||||
|
self.segment_end_positions.append(end_frame)
|
||||||
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}")
|
||||||
|
print(f"Segment end positions: {self.segment_end_positions}")
|
||||||
|
|
||||||
# Preload the entire video into memory - simple and fast
|
# Preload the entire video into memory - simple and fast
|
||||||
print("Preloading entire video into memory...")
|
print("Preloading entire video into memory...")
|
||||||
@@ -557,7 +564,7 @@ class MediaGrader:
|
|||||||
frames = []
|
frames = []
|
||||||
frame_count = 0
|
frame_count = 0
|
||||||
|
|
||||||
while frame_count < safe_frame_count:
|
while frame_count < self.total_frames:
|
||||||
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:
|
||||||
frames.append(frame)
|
frames.append(frame)
|
||||||
@@ -600,25 +607,35 @@ class MediaGrader:
|
|||||||
self.segment_caps = []
|
self.segment_caps = []
|
||||||
self.segment_frames = []
|
self.segment_frames = []
|
||||||
self.segment_positions = []
|
self.segment_positions = []
|
||||||
|
self.segment_end_positions = []
|
||||||
if hasattr(self, 'video_frame_cache'):
|
if hasattr(self, 'video_frame_cache'):
|
||||||
self.video_frame_cache = []
|
self.video_frame_cache = []
|
||||||
if hasattr(self, 'segment_current_frames'):
|
if hasattr(self, 'segment_current_frames'):
|
||||||
self.segment_current_frames = []
|
self.segment_current_frames = []
|
||||||
|
|
||||||
def update_segment_frames(self):
|
def update_segment_frames(self):
|
||||||
"""Update frames for segments using the preloaded video array - smooth playback!"""
|
"""Update frames for segments - each segment loops within its own range"""
|
||||||
if not self.multi_segment_mode or not self.segment_frames or not hasattr(self, 'video_frame_cache'):
|
if not self.multi_segment_mode or not self.segment_frames or not hasattr(self, 'video_frame_cache'):
|
||||||
return
|
return
|
||||||
|
|
||||||
for i in range(len(self.segment_frames)):
|
for i in range(len(self.segment_frames)):
|
||||||
if self.segment_frames[i] is not None and self.video_frame_cache:
|
if self.segment_frames[i] is not None and self.video_frame_cache:
|
||||||
|
# Advance to next frame in this segment
|
||||||
self.segment_current_frames[i] += 1
|
self.segment_current_frames[i] += 1
|
||||||
|
|
||||||
if self.segment_current_frames[i] >= len(self.video_frame_cache):
|
# Get the segment boundaries
|
||||||
self.segment_current_frames[i] = 0
|
start_frame = self.segment_positions[i]
|
||||||
|
end_frame = self.segment_end_positions[i]
|
||||||
|
|
||||||
# Direct reference - no copy needed for display
|
# Loop within the segment bounds
|
||||||
self.segment_frames[i] = self.video_frame_cache[self.segment_current_frames[i]]
|
if self.segment_current_frames[i] > end_frame:
|
||||||
|
# Loop back to start of segment
|
||||||
|
self.segment_current_frames[i] = start_frame
|
||||||
|
|
||||||
|
# Ensure we don't go beyond the video cache
|
||||||
|
if self.segment_current_frames[i] < len(self.video_frame_cache):
|
||||||
|
# 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"""
|
||||||
|
Reference in New Issue
Block a user