feat(main.py): optimize video capture initialization and add backend fallback for improved performance and reliability
This commit is contained in:
116
main.py
116
main.py
@@ -202,13 +202,44 @@ class MediaGrader:
|
||||
self.current_cap.release()
|
||||
|
||||
if self.is_video(file_path):
|
||||
# Suppress OpenCV error messages for unsupported codecs
|
||||
self.current_cap = cv2.VideoCapture(str(file_path))
|
||||
if not self.current_cap.isOpened():
|
||||
# Try different backends for better performance
|
||||
# Order of preference: DirectShow (Windows), FFmpeg, any available
|
||||
backends_to_try = []
|
||||
if hasattr(cv2, 'CAP_DSHOW'): # Windows DirectShow
|
||||
backends_to_try.append(cv2.CAP_DSHOW)
|
||||
if hasattr(cv2, 'CAP_FFMPEG'): # FFmpeg
|
||||
backends_to_try.append(cv2.CAP_FFMPEG)
|
||||
backends_to_try.append(cv2.CAP_ANY) # Fallback
|
||||
|
||||
self.current_cap = None
|
||||
for backend in backends_to_try:
|
||||
try:
|
||||
self.current_cap = cv2.VideoCapture(str(file_path), backend)
|
||||
if self.current_cap.isOpened():
|
||||
# Optimize buffer settings for better performance
|
||||
self.current_cap.set(cv2.CAP_PROP_BUFFERSIZE, 1) # Minimize buffer to reduce latency
|
||||
# Try to set hardware acceleration if available
|
||||
if hasattr(cv2, 'CAP_PROP_HW_ACCELERATION'):
|
||||
self.current_cap.set(cv2.CAP_PROP_HW_ACCELERATION, cv2.VIDEO_ACCELERATION_ANY)
|
||||
break
|
||||
self.current_cap.release()
|
||||
except:
|
||||
continue
|
||||
|
||||
if not self.current_cap or not self.current_cap.isOpened():
|
||||
print(f"Warning: Could not open video file {file_path.name} (unsupported codec)")
|
||||
return False
|
||||
|
||||
self.total_frames = int(self.current_cap.get(cv2.CAP_PROP_FRAME_COUNT))
|
||||
self.current_frame = 0
|
||||
|
||||
# Get codec information for debugging
|
||||
fourcc = int(self.current_cap.get(cv2.CAP_PROP_FOURCC))
|
||||
codec = "".join([chr((fourcc >> 8 * i) & 0xFF) for i in range(4)])
|
||||
backend = self.current_cap.getBackendName()
|
||||
|
||||
print(f"Loaded: {file_path.name} | Codec: {codec} | Backend: {backend} | Frames: {self.total_frames}")
|
||||
|
||||
else:
|
||||
self.current_cap = None
|
||||
self.total_frames = 1
|
||||
@@ -499,7 +530,29 @@ class MediaGrader:
|
||||
load_start = time.time()
|
||||
|
||||
shared_cap_start = time.time()
|
||||
shared_cap = cv2.VideoCapture(str(current_file))
|
||||
|
||||
# Use same backend optimization as main capture
|
||||
backends_to_try = []
|
||||
if hasattr(cv2, 'CAP_DSHOW'): # Windows DirectShow
|
||||
backends_to_try.append(cv2.CAP_DSHOW)
|
||||
if hasattr(cv2, 'CAP_FFMPEG'): # FFmpeg
|
||||
backends_to_try.append(cv2.CAP_FFMPEG)
|
||||
backends_to_try.append(cv2.CAP_ANY) # Fallback
|
||||
|
||||
shared_cap = None
|
||||
for backend in backends_to_try:
|
||||
try:
|
||||
shared_cap = cv2.VideoCapture(str(current_file), backend)
|
||||
if shared_cap.isOpened():
|
||||
shared_cap.set(cv2.CAP_PROP_BUFFERSIZE, 1)
|
||||
break
|
||||
shared_cap.release()
|
||||
except:
|
||||
continue
|
||||
|
||||
if not shared_cap:
|
||||
shared_cap = cv2.VideoCapture(str(current_file)) # Fallback
|
||||
|
||||
shared_cap_create_time = (time.time() - shared_cap_start) * 1000
|
||||
print(f"Capture creation: {shared_cap_create_time:.1f}ms")
|
||||
|
||||
@@ -585,7 +638,29 @@ class MediaGrader:
|
||||
if self.current_cap:
|
||||
# Create a temporary capture to avoid interfering with main playback
|
||||
current_file = self.media_files[self.current_index]
|
||||
temp_cap = cv2.VideoCapture(str(current_file))
|
||||
|
||||
# Use optimized backend for temporary capture too
|
||||
temp_cap = None
|
||||
backends_to_try = []
|
||||
if hasattr(cv2, 'CAP_DSHOW'):
|
||||
backends_to_try.append(cv2.CAP_DSHOW)
|
||||
if hasattr(cv2, 'CAP_FFMPEG'):
|
||||
backends_to_try.append(cv2.CAP_FFMPEG)
|
||||
backends_to_try.append(cv2.CAP_ANY)
|
||||
|
||||
for backend in backends_to_try:
|
||||
try:
|
||||
temp_cap = cv2.VideoCapture(str(current_file), backend)
|
||||
if temp_cap.isOpened():
|
||||
temp_cap.set(cv2.CAP_PROP_BUFFERSIZE, 1)
|
||||
break
|
||||
temp_cap.release()
|
||||
except:
|
||||
continue
|
||||
|
||||
if not temp_cap:
|
||||
temp_cap = cv2.VideoCapture(str(current_file)) # Fallback
|
||||
|
||||
if temp_cap.isOpened():
|
||||
temp_cap.set(cv2.CAP_PROP_POS_FRAMES, frame_number)
|
||||
ret, frame = temp_cap.read()
|
||||
@@ -609,9 +684,31 @@ class MediaGrader:
|
||||
"""Get or create a capture for a specific segment (lazy loading)"""
|
||||
if segment_index >= len(self.segment_caps) or self.segment_caps[segment_index] is None:
|
||||
if segment_index < len(self.segment_caps):
|
||||
# Create capture on demand
|
||||
# Create capture on demand with optimized backend
|
||||
current_file = self.media_files[self.current_index]
|
||||
cap = cv2.VideoCapture(str(current_file))
|
||||
|
||||
# Use optimized backend for segment capture
|
||||
cap = None
|
||||
backends_to_try = []
|
||||
if hasattr(cv2, 'CAP_DSHOW'):
|
||||
backends_to_try.append(cv2.CAP_DSHOW)
|
||||
if hasattr(cv2, 'CAP_FFMPEG'):
|
||||
backends_to_try.append(cv2.CAP_FFMPEG)
|
||||
backends_to_try.append(cv2.CAP_ANY)
|
||||
|
||||
for backend in backends_to_try:
|
||||
try:
|
||||
cap = cv2.VideoCapture(str(current_file), backend)
|
||||
if cap.isOpened():
|
||||
cap.set(cv2.CAP_PROP_BUFFERSIZE, 1)
|
||||
break
|
||||
cap.release()
|
||||
except:
|
||||
continue
|
||||
|
||||
if not cap:
|
||||
cap = cv2.VideoCapture(str(current_file)) # Fallback
|
||||
|
||||
if cap.isOpened():
|
||||
cap.set(cv2.CAP_PROP_POS_FRAMES, self.segment_positions[segment_index])
|
||||
self.segment_caps[segment_index] = cap
|
||||
@@ -1060,6 +1157,11 @@ class MediaGrader:
|
||||
for _ in range(frames_to_skip + 1):
|
||||
ret, frame = self.current_cap.read()
|
||||
if not ret:
|
||||
# Hit actual end of video - check if frame count was wrong
|
||||
actual_frame = int(self.current_cap.get(cv2.CAP_PROP_POS_FRAMES))
|
||||
if actual_frame < self.total_frames - 5: # Allow some tolerance
|
||||
print(f"Frame count mismatch! Reported: {self.total_frames}, Actual: {actual_frame}")
|
||||
self.total_frames = actual_frame
|
||||
return False
|
||||
|
||||
self.current_display_frame = frame
|
||||
|
Reference in New Issue
Block a user