feat(main.py): enhance video editor with rendering state checks and logging
This commit is contained in:
@@ -460,6 +460,12 @@ class VideoEditor:
|
|||||||
# Try to load saved state for this media file
|
# Try to load saved state for this media file
|
||||||
if self.load_state():
|
if self.load_state():
|
||||||
print("Loaded saved state for this media file")
|
print("Loaded saved state for this media file")
|
||||||
|
if self.cut_start_frame is not None:
|
||||||
|
print(f" Cut start frame: {self.cut_start_frame}")
|
||||||
|
if self.cut_end_frame is not None:
|
||||||
|
print(f" Cut end frame: {self.cut_end_frame}")
|
||||||
|
else:
|
||||||
|
print("No saved state found for this media file")
|
||||||
|
|
||||||
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"""
|
||||||
@@ -511,6 +517,11 @@ class VideoEditor:
|
|||||||
self, direction: int, shift_pressed: bool, ctrl_pressed: bool
|
self, direction: int, shift_pressed: bool, ctrl_pressed: bool
|
||||||
):
|
):
|
||||||
"""Seek video with different frame counts based on modifiers and seek multiplier"""
|
"""Seek video with different frame counts based on modifiers and seek multiplier"""
|
||||||
|
# Don't allow seeking while rendering to prevent crashes
|
||||||
|
if self.is_rendering():
|
||||||
|
print("Cannot seek while rendering is in progress")
|
||||||
|
return
|
||||||
|
|
||||||
if ctrl_pressed:
|
if ctrl_pressed:
|
||||||
base_frames = 60 # Ctrl: 60 frames
|
base_frames = 60 # Ctrl: 60 frames
|
||||||
elif shift_pressed:
|
elif shift_pressed:
|
||||||
@@ -1500,7 +1511,7 @@ class VideoEditor:
|
|||||||
"""Start video rendering in a separate thread"""
|
"""Start video rendering in a separate thread"""
|
||||||
# Check if already rendering
|
# Check if already rendering
|
||||||
if self.render_thread and self.render_thread.is_alive():
|
if self.render_thread and self.render_thread.is_alive():
|
||||||
print("Render already in progress!")
|
print("Render already in progress! Use 'X' to cancel first.")
|
||||||
return False
|
return False
|
||||||
|
|
||||||
# Reset render state
|
# Reset render state
|
||||||
@@ -1515,10 +1526,12 @@ class VideoEditor:
|
|||||||
self.render_thread.start()
|
self.render_thread.start()
|
||||||
|
|
||||||
print(f"Started rendering to {output_path} in background thread...")
|
print(f"Started rendering to {output_path} in background thread...")
|
||||||
|
print("You can continue editing while rendering. Press 'X' to cancel.")
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def _render_video_worker(self, output_path: str):
|
def _render_video_worker(self, output_path: str):
|
||||||
"""Worker method that runs in the render thread"""
|
"""Worker method that runs in the render thread"""
|
||||||
|
render_cap = None
|
||||||
try:
|
try:
|
||||||
if not output_path.endswith(".mp4"):
|
if not output_path.endswith(".mp4"):
|
||||||
output_path += ".mp4"
|
output_path += ".mp4"
|
||||||
@@ -1528,6 +1541,12 @@ class VideoEditor:
|
|||||||
# Send progress update to main thread
|
# Send progress update to main thread
|
||||||
self.render_progress_queue.put(("init", "Initializing render...", 0.0, 0.0))
|
self.render_progress_queue.put(("init", "Initializing render...", 0.0, 0.0))
|
||||||
|
|
||||||
|
# Create a separate VideoCapture for the render thread to avoid thread safety issues
|
||||||
|
render_cap = cv2.VideoCapture(str(self.video_path))
|
||||||
|
if not render_cap.isOpened():
|
||||||
|
self.render_progress_queue.put(("error", "Could not open video for rendering!", 1.0, 0.0))
|
||||||
|
return False
|
||||||
|
|
||||||
# Determine frame range
|
# Determine frame range
|
||||||
start_frame = self.cut_start_frame if self.cut_start_frame is not None else 0
|
start_frame = self.cut_start_frame if self.cut_start_frame is not None else 0
|
||||||
end_frame = (
|
end_frame = (
|
||||||
@@ -1583,9 +1602,9 @@ class VideoEditor:
|
|||||||
self.render_progress_queue.put(("cancelled", "Render cancelled", 0.0, 0.0))
|
self.render_progress_queue.put(("cancelled", "Render cancelled", 0.0, 0.0))
|
||||||
return False
|
return False
|
||||||
|
|
||||||
# Read frame
|
# Read frame using the separate VideoCapture
|
||||||
self.cap.set(cv2.CAP_PROP_POS_FRAMES, frame_idx)
|
render_cap.set(cv2.CAP_PROP_POS_FRAMES, frame_idx)
|
||||||
ret, frame = self.cap.read()
|
ret, frame = render_cap.read()
|
||||||
|
|
||||||
if not ret:
|
if not ret:
|
||||||
break
|
break
|
||||||
@@ -1634,9 +1653,20 @@ class VideoEditor:
|
|||||||
return True
|
return True
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
self.render_progress_queue.put(("error", f"Render error: {str(e)}", 1.0, 0.0))
|
error_msg = str(e)
|
||||||
print(f"Render error: {e}")
|
# Handle specific FFmpeg threading errors
|
||||||
|
if "async_lock" in error_msg or "pthread_frame" in error_msg:
|
||||||
|
error_msg = "FFmpeg threading error - try restarting the application"
|
||||||
|
elif "Assertion" in error_msg:
|
||||||
|
error_msg = "Video codec error - the video file may be corrupted or incompatible"
|
||||||
|
|
||||||
|
self.render_progress_queue.put(("error", f"Render error: {error_msg}", 1.0, 0.0))
|
||||||
|
print(f"Render error: {error_msg}")
|
||||||
return False
|
return False
|
||||||
|
finally:
|
||||||
|
# Always clean up the render VideoCapture
|
||||||
|
if render_cap:
|
||||||
|
render_cap.release()
|
||||||
|
|
||||||
def update_render_progress(self):
|
def update_render_progress(self):
|
||||||
"""Process progress updates from the render thread"""
|
"""Process progress updates from the render thread"""
|
||||||
|
Reference in New Issue
Block a user