Maybe faster.......

This commit is contained in:
2025-09-04 15:00:51 +02:00
parent cf09fd172e
commit 692c413f13

View File

@@ -6,9 +6,6 @@ import numpy as np
from pathlib import Path from pathlib import Path
from typing import Optional, Tuple, List from typing import Optional, Tuple, List
import time import time
import threading
from concurrent.futures import ThreadPoolExecutor
from queue import Queue
class VideoEditor: class VideoEditor:
@@ -547,96 +544,45 @@ class VideoEditor:
print("Error: Could not open video writer!") print("Error: Could not open video writer!")
return False return False
# Simple sequential processing - the I/O is the bottleneck anyway
total_output_frames = end_frame - start_frame + 1 total_output_frames = end_frame - start_frame + 1
frames_written = 0
last_progress_update = 0 last_progress_update = 0
# Batch processing configuration
batch_size = min(50, max(10, total_output_frames // 20)) # Adaptive batch size
frame_queue = Queue(maxsize=batch_size * 2)
processed_queue = Queue(maxsize=batch_size * 2)
def frame_reader():
"""Background thread for reading frames"""
try:
for frame_idx in range(start_frame, end_frame + 1): for frame_idx in range(start_frame, end_frame + 1):
# Read frame
self.cap.set(cv2.CAP_PROP_POS_FRAMES, frame_idx) self.cap.set(cv2.CAP_PROP_POS_FRAMES, frame_idx)
ret, frame = self.cap.read() ret, frame = self.cap.read()
if ret:
frame_queue.put((frame_idx, frame))
else:
break
finally:
frame_queue.put(None) # Signal end of frames
def frame_processor(): if not ret:
"""Background thread for processing frames"""
try:
while True:
item = frame_queue.get()
if item is None: # End signal
break break
frame_idx, frame = item # Process and write frame directly (minimize memory copies)
processed_frame = self._process_frame_for_render(frame, output_width, output_height) processed_frame = self._process_frame_for_render(frame, output_width, output_height)
if processed_frame is not None: if processed_frame is not None:
processed_queue.put((frame_idx, processed_frame)) out.write(processed_frame)
frame_queue.task_done() frames_written = frame_idx - start_frame + 1
finally:
processed_queue.put(None) # Signal end of processing
# Start background threads # Throttled progress update
reader_thread = threading.Thread(target=frame_reader, daemon=True)
processor_thread = threading.Thread(target=frame_processor, daemon=True)
reader_thread.start()
processor_thread.start()
# Main thread writes frames in order
expected_frame = start_frame
frame_buffer = {} # Buffer for out-of-order frames
while frames_written < total_output_frames:
item = processed_queue.get()
if item is None: # End signal
break
frame_idx, processed_frame = item
frame_buffer[frame_idx] = processed_frame
# Write frames in order
while expected_frame in frame_buffer:
out.write(frame_buffer.pop(expected_frame))
frames_written += 1
expected_frame += 1
# Progress update (throttled to avoid too frequent updates)
current_time = time.time() current_time = time.time()
if current_time - last_progress_update > 0.5: # Update every 0.5 seconds if current_time - last_progress_update > 0.5:
progress = frames_written / total_output_frames * 100 progress = frames_written / total_output_frames * 100
elapsed = current_time - start_time elapsed = current_time - start_time
if frames_written > 0:
eta = (elapsed / frames_written) * (total_output_frames - frames_written)
fps_rate = frames_written / elapsed fps_rate = frames_written / elapsed
eta = (elapsed / frames_written) * (total_output_frames - frames_written)
print(f"Progress: {progress:.1f}% | {frames_written}/{total_output_frames} | " print(f"Progress: {progress:.1f}% | {frames_written}/{total_output_frames} | "
f"FPS: {fps_rate:.1f} | ETA: {eta:.1f}s\r", end="") f"FPS: {fps_rate:.1f} | ETA: {eta:.1f}s\r", end="")
last_progress_update = current_time last_progress_update = current_time
processed_queue.task_done()
# Wait for threads to complete
reader_thread.join()
processor_thread.join()
out.release() out.release()
total_time = time.time() - start_time total_time = time.time() - start_time
avg_fps = frames_written / total_time if total_time > 0 else 0 total_frames_written = end_frame - start_frame + 1
avg_fps = total_frames_written / total_time if total_time > 0 else 0
print(f"\nVideo rendered successfully to {output_path}") print(f"\nVideo rendered successfully to {output_path}")
print(f"Rendered {frames_written} frames in {total_time:.2f}s (avg {avg_fps:.1f} FPS)") print(f"Rendered {total_frames_written} frames in {total_time:.2f}s (avg {avg_fps:.1f} FPS)")
return True return True
def _process_frame_for_render(self, frame, output_width: int, output_height: int): def _process_frame_for_render(self, frame, output_width: int, output_height: int):