feat(main.py): implement smart video seeking with keyframe optimization

This commit is contained in:
2025-09-07 23:04:44 +02:00
parent b85e757871
commit 366de8e796

View File

@@ -13,8 +13,6 @@ import json
class VideoEditor:
# Configuration constants
BASE_FRAME_DELAY_MS = 16 # ~60 FPS
KEY_REPEAT_RATE_SEC = 0.3
FAST_SEEK_ACTIVATION_TIME = 1.5
SPEED_INCREMENT = 0.2
MIN_PLAYBACK_SPEED = 0.1
MAX_PLAYBACK_SPEED = 10.0
@@ -502,17 +500,68 @@ class VideoEditor:
self.current_frame = target_frame
self.load_current_frame()
def seek_video_smart(self, frames_delta: int):
"""Seek using keyframe jumping for large jumps"""
target_frame = max(
0, min(self.current_frame + frames_delta, self.total_frames - 1)
)
# For small jumps, use regular seeking
if abs(frames_delta) <= 10:
self.current_frame = target_frame
self.load_current_frame()
return
# For larger jumps, use keyframe seeking
# Jump to nearest keyframe first, then seek forward
keyframe_interval = self._detect_keyframe_interval()
nearest_keyframe = (target_frame // keyframe_interval) * keyframe_interval
# Seek to keyframe first
self.cap.set(cv2.CAP_PROP_POS_FRAMES, nearest_keyframe)
self.current_frame = nearest_keyframe
# Then seek forward to target frame
frames_to_seek = target_frame - nearest_keyframe
for _ in range(frames_to_seek):
ret, frame = self.cap.read()
if not ret:
break
self.current_frame += 1
self.current_display_frame = frame if 'frame' in locals() else None
def _detect_keyframe_interval(self):
"""Detect the keyframe interval for the current video"""
# Try to get keyframe interval from video properties
try:
# Some backends support keyframe interval detection
keyframe_interval = self.cap.get(cv2.CAP_PROP_FRAME_COUNT) / self.cap.get(cv2.CAP_PROP_FPS)
if keyframe_interval > 0:
return int(keyframe_interval)
except:
pass
# Fallback: estimate based on video characteristics
if self.fps >= 60:
return 60 # High FPS videos often have keyframes every 60 frames
elif self.fps >= 30:
return 30 # Standard videos have keyframes every 30 frames
else:
return 15 # Lower FPS videos have keyframes every 15 frames
def seek_video_with_modifier(
self, direction: int, shift_pressed: bool, ctrl_pressed: bool
):
"""Seek video with different frame counts based on modifiers"""
if ctrl_pressed:
frames = direction * 60 # Ctrl: 60 frames
self.seek_video_smart(frames)
elif shift_pressed:
frames = direction * 10 # Shift: 10 frames
self.seek_video_smart(frames)
else:
frames = direction * 1 # Default: 1 frame
self.seek_video(frames)
def start_auto_repeat_seek(self, key: int, direction: int, shift_pressed: bool, ctrl_pressed: bool):
@@ -544,12 +593,9 @@ class VideoEditor:
# Do initial seek immediately
self.seek_video_with_modifier(direction, shift_pressed, ctrl_pressed)
print(f"DEBUG: Started auto-repeat for key {key}")
def stop_auto_repeat_seek(self):
"""Stop auto-repeat seeking"""
if self.auto_repeat_active:
print(f"DEBUG: Stopped auto-repeat")
self.auto_repeat_active = False
self.auto_repeat_key = None
self.auto_repeat_direction = 0
@@ -1826,26 +1872,19 @@ class VideoEditor:
delay = self.calculate_frame_delay() if self.is_playing else 1 # Very short delay for responsive key detection
key = cv2.waitKey(delay) & 0xFF
# Debug key detection
if key != 255:
print(f"DEBUG: Key detected: {key} (auto_repeat_active: {self.auto_repeat_active}, auto_repeat_key: {self.auto_repeat_key})")
# Handle auto-repeat - stop if a different key is pressed or no key for too long
if key == 255 and self.auto_repeat_active: # 255 means no key pressed
# Check if enough time has passed since last key activity (key was released)
if time.time() - self.last_key_activity > 0.1: # 100ms timeout
print(f"DEBUG: Key released - stopping auto-repeat")
self.stop_auto_repeat_seek()
elif key != 255 and self.auto_repeat_active:
# A key is pressed, update the last key activity time
self.last_key_activity = time.time()
# If it's a different key, stop auto-repeat
if key != self.auto_repeat_key:
print(f"DEBUG: Different key pressed ({key} vs {self.auto_repeat_key}) - stopping auto-repeat")
self.stop_auto_repeat_seek()
# If it's the same key, just update the last activity time (don't restart auto-repeat)
else:
print(f"DEBUG: Same key pressed ({key}) - updating last activity time")
# Get modifier key states
window_title = "Image Editor" if self.is_image_mode else "Video Editor"