Greatly improve performance
yippie!
This commit is contained in:
@@ -180,9 +180,32 @@ class VideoEditor:
|
|||||||
self.cap.release()
|
self.cap.release()
|
||||||
|
|
||||||
self.video_path = video_path
|
self.video_path = video_path
|
||||||
self.cap = cv2.VideoCapture(str(self.video_path))
|
|
||||||
|
# Try different backends for better performance
|
||||||
if not self.cap.isOpened():
|
# 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.cap = None
|
||||||
|
for backend in backends_to_try:
|
||||||
|
try:
|
||||||
|
self.cap = cv2.VideoCapture(str(self.video_path), backend)
|
||||||
|
if self.cap.isOpened():
|
||||||
|
# Optimize buffer settings for better performance
|
||||||
|
self.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.cap.set(cv2.CAP_PROP_HW_ACCELERATION, cv2.VIDEO_ACCELERATION_ANY)
|
||||||
|
break
|
||||||
|
self.cap.release()
|
||||||
|
except:
|
||||||
|
continue
|
||||||
|
|
||||||
|
if not self.cap or not self.cap.isOpened():
|
||||||
raise ValueError(f"Could not open video file: {video_path}")
|
raise ValueError(f"Could not open video file: {video_path}")
|
||||||
|
|
||||||
# Video properties
|
# Video properties
|
||||||
@@ -191,6 +214,13 @@ class VideoEditor:
|
|||||||
self.frame_width = int(self.cap.get(cv2.CAP_PROP_FRAME_WIDTH))
|
self.frame_width = int(self.cap.get(cv2.CAP_PROP_FRAME_WIDTH))
|
||||||
self.frame_height = int(self.cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
|
self.frame_height = int(self.cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
|
||||||
|
|
||||||
|
# Get codec information for debugging
|
||||||
|
fourcc = int(self.cap.get(cv2.CAP_PROP_FOURCC))
|
||||||
|
codec = "".join([chr((fourcc >> 8 * i) & 0xFF) for i in range(4)])
|
||||||
|
|
||||||
|
# Get backend information
|
||||||
|
backend = self.cap.getBackendName()
|
||||||
|
|
||||||
# Reset playback state for new video
|
# Reset playback state for new video
|
||||||
self.current_frame = 0
|
self.current_frame = 0
|
||||||
self.is_playing = False
|
self.is_playing = False
|
||||||
@@ -212,6 +242,16 @@ class VideoEditor:
|
|||||||
print(
|
print(
|
||||||
f"Loaded video: {self.video_path.name} ({self.current_video_index + 1}/{len(self.video_files)})"
|
f"Loaded video: {self.video_path.name} ({self.current_video_index + 1}/{len(self.video_files)})"
|
||||||
)
|
)
|
||||||
|
print(f" Codec: {codec} | Backend: {backend} | Resolution: {self.frame_width}x{self.frame_height}")
|
||||||
|
print(f" FPS: {self.fps:.2f} | Frames: {self.total_frames} | Duration: {self.total_frames/self.fps:.1f}s")
|
||||||
|
|
||||||
|
# Performance warning for known problematic cases
|
||||||
|
if codec in ['H264', 'H.264', 'AVC1', 'avc1'] and self.total_frames > 10000:
|
||||||
|
print(f" Warning: Large H.264 video detected - seeking may be slow")
|
||||||
|
if self.frame_width * self.frame_height > 1920 * 1080:
|
||||||
|
print(f" Warning: High resolution video - decoding may be slow")
|
||||||
|
if self.fps > 60:
|
||||||
|
print(f" Warning: High framerate video - may impact playback smoothness")
|
||||||
|
|
||||||
def switch_to_video(self, index: int):
|
def switch_to_video(self, index: int):
|
||||||
"""Switch to a specific video by index"""
|
"""Switch to a specific video by index"""
|
||||||
@@ -271,15 +311,23 @@ class VideoEditor:
|
|||||||
self.load_current_frame()
|
self.load_current_frame()
|
||||||
|
|
||||||
def advance_frame(self) -> bool:
|
def advance_frame(self) -> bool:
|
||||||
"""Advance to next frame"""
|
"""Advance to next frame - optimized to avoid seeking"""
|
||||||
if not self.is_playing:
|
if not self.is_playing:
|
||||||
return True
|
return True
|
||||||
|
|
||||||
self.current_frame += 1
|
self.current_frame += 1
|
||||||
if self.current_frame >= self.total_frames:
|
if self.current_frame >= self.total_frames:
|
||||||
self.current_frame = 0 # Loop
|
self.current_frame = 0 # Loop - this will require a seek
|
||||||
|
return self.load_current_frame()
|
||||||
|
|
||||||
return self.load_current_frame()
|
# For sequential playback, just read the next frame without seeking
|
||||||
|
ret, frame = self.cap.read()
|
||||||
|
if ret:
|
||||||
|
self.current_display_frame = frame
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
# If sequential read failed, fall back to seeking (might be end of file or codec issue)
|
||||||
|
return self.load_current_frame()
|
||||||
|
|
||||||
def apply_crop_zoom_and_rotation(self, frame):
|
def apply_crop_zoom_and_rotation(self, frame):
|
||||||
"""Apply current crop, zoom, rotation, and brightness/contrast settings to frame"""
|
"""Apply current crop, zoom, rotation, and brightness/contrast settings to frame"""
|
||||||
@@ -1245,6 +1293,7 @@ class VideoEditor:
|
|||||||
self.load_current_frame()
|
self.load_current_frame()
|
||||||
|
|
||||||
while True:
|
while True:
|
||||||
|
# Only update display if needed
|
||||||
self.display_current_frame()
|
self.display_current_frame()
|
||||||
|
|
||||||
delay = self.calculate_frame_delay() if self.is_playing else 30
|
delay = self.calculate_frame_delay() if self.is_playing else 30
|
||||||
@@ -1355,7 +1404,6 @@ class VideoEditor:
|
|||||||
print(f"Contracted crop from left by {self.crop_size_step}px")
|
print(f"Contracted crop from left by {self.crop_size_step}px")
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# Auto advance frame when playing
|
# Auto advance frame when playing
|
||||||
if self.is_playing:
|
if self.is_playing:
|
||||||
self.advance_frame()
|
self.advance_frame()
|
||||||
|
Reference in New Issue
Block a user