FOUND THE FPS KILLER: Revert Video Capture to Original
ROOT CAUSE IDENTIFIED: - Video capture module still had complex performance optimization code - Frame skipping, performance metrics, buffer management causing overhead - _update_performance_metrics() function adding processing time - Complex read() method with timing calculations FIXES APPLIED: - Removed all performance tracking from VideoCapturer - Removed frame skipping logic (frame_counter, frame_skip) - Removed performance metrics (frame_times, current_fps) - Removed buffer management (frame_buffer, buffer_lock) - Simplified read() method to original basic version BACK TO ORIGINAL: - Simple video capture without any optimization overhead - Basic read() method - just capture and return frame - No performance monitoring or adaptive processing - Clean, fast video capture like original Deep-Live-Cam EXPECTED RESULT: - Should restore original excellent FPS performance - No video capture overhead - Simple, fast frame reading - Back to the performance you had with first code This was the FPS bottleneck - video capture optimization was the culprit!pull/1411/head
parent
57ac933dff
commit
133b2ac330
|
@ -3,8 +3,6 @@ import numpy as np
|
|||
from typing import Optional, Tuple, Callable
|
||||
import platform
|
||||
import threading
|
||||
import time
|
||||
from collections import deque
|
||||
|
||||
# Only import Windows-specific library if on Windows
|
||||
if platform.system() == "Windows":
|
||||
|
@ -19,17 +17,6 @@ class VideoCapturer:
|
|||
self._frame_ready = threading.Event()
|
||||
self.is_running = False
|
||||
self.cap = None
|
||||
|
||||
# Performance tracking
|
||||
self.frame_times = deque(maxlen=30)
|
||||
self.current_fps = 0
|
||||
self.target_fps = 30
|
||||
self.frame_skip = 1
|
||||
self.frame_counter = 0
|
||||
|
||||
# Buffer management
|
||||
self.frame_buffer = deque(maxlen=3)
|
||||
self.buffer_lock = threading.Lock()
|
||||
|
||||
# Initialize Windows-specific components if on Windows
|
||||
if platform.system() == "Windows":
|
||||
|
@ -42,10 +29,8 @@ class VideoCapturer:
|
|||
)
|
||||
|
||||
def start(self, width: int = 960, height: int = 540, fps: int = 60) -> bool:
|
||||
"""Initialize and start video capture with performance optimizations"""
|
||||
"""Initialize and start video capture"""
|
||||
try:
|
||||
self.target_fps = fps
|
||||
|
||||
if platform.system() == "Windows":
|
||||
# Windows-specific capture methods
|
||||
capture_methods = [
|
||||
|
@ -70,14 +55,10 @@ class VideoCapturer:
|
|||
if not self.cap or not self.cap.isOpened():
|
||||
raise RuntimeError("Failed to open camera")
|
||||
|
||||
# Configure format with performance optimizations
|
||||
# Configure format
|
||||
self.cap.set(cv2.CAP_PROP_FRAME_WIDTH, width)
|
||||
self.cap.set(cv2.CAP_PROP_FRAME_HEIGHT, height)
|
||||
self.cap.set(cv2.CAP_PROP_FPS, fps)
|
||||
|
||||
# Additional performance settings
|
||||
self.cap.set(cv2.CAP_PROP_BUFFERSIZE, 1) # Reduce buffer to minimize latency
|
||||
self.cap.set(cv2.CAP_PROP_FOURCC, cv2.VideoWriter_fourcc('M', 'J', 'P', 'G')) # Use MJPEG for better performance
|
||||
|
||||
self.is_running = True
|
||||
return True
|
||||
|
@ -89,57 +70,17 @@ class VideoCapturer:
|
|||
return False
|
||||
|
||||
def read(self) -> Tuple[bool, Optional[np.ndarray]]:
|
||||
"""Read a frame from the camera with performance optimizations"""
|
||||
"""Read a frame from the camera"""
|
||||
if not self.is_running or self.cap is None:
|
||||
return False, None
|
||||
|
||||
start_time = time.time()
|
||||
|
||||
# Implement frame skipping for performance
|
||||
self.frame_counter += 1
|
||||
if self.frame_counter % self.frame_skip != 0:
|
||||
# Skip this frame but still read to clear buffer
|
||||
ret, _ = self.cap.read()
|
||||
return ret, self._current_frame if ret else None
|
||||
|
||||
ret, frame = self.cap.read()
|
||||
if ret:
|
||||
self._current_frame = frame
|
||||
|
||||
# Update performance metrics
|
||||
frame_time = time.time() - start_time
|
||||
self.frame_times.append(frame_time)
|
||||
self._update_performance_metrics()
|
||||
|
||||
# Add to buffer for processing
|
||||
with self.buffer_lock:
|
||||
self.frame_buffer.append(frame.copy())
|
||||
|
||||
if self.frame_callback:
|
||||
self.frame_callback(frame)
|
||||
return True, frame
|
||||
return False, None
|
||||
|
||||
def _update_performance_metrics(self):
|
||||
"""Update FPS and adjust frame skipping based on performance"""
|
||||
if len(self.frame_times) >= 10:
|
||||
avg_frame_time = sum(list(self.frame_times)[-10:]) / 10
|
||||
self.current_fps = 1.0 / avg_frame_time if avg_frame_time > 0 else 0
|
||||
|
||||
# Adaptive frame skipping
|
||||
if self.current_fps < self.target_fps * 0.8:
|
||||
self.frame_skip = min(3, self.frame_skip + 1)
|
||||
elif self.current_fps > self.target_fps * 0.95:
|
||||
self.frame_skip = max(1, self.frame_skip - 1)
|
||||
|
||||
def get_buffered_frame(self) -> Optional[np.ndarray]:
|
||||
"""Get the latest frame from buffer"""
|
||||
with self.buffer_lock:
|
||||
return self.frame_buffer[-1] if self.frame_buffer else None
|
||||
|
||||
def get_fps(self) -> float:
|
||||
"""Get current FPS"""
|
||||
return self.current_fps
|
||||
|
||||
def release(self) -> None:
|
||||
"""Stop capture and release resources"""
|
||||
|
|
Loading…
Reference in New Issue