From 2a5f570e5e3379fe6d90c78f95cb0b191a972233 Mon Sep 17 00:00:00 2001 From: bartool Date: Sun, 12 Oct 2025 13:08:40 +0200 Subject: [PATCH] feat: implement CameraDetectionWorker for asynchronous camera detection --- core/camera/camera_manager.py | 92 +++++++++++++++++++++++------------ 1 file changed, 62 insertions(+), 30 deletions(-) diff --git a/core/camera/camera_manager.py b/core/camera/camera_manager.py index e3b7e2c..ab5fb0c 100644 --- a/core/camera/camera_manager.py +++ b/core/camera/camera_manager.py @@ -1,4 +1,4 @@ -from PySide6.QtCore import QObject, Signal +from PySide6.QtCore import QObject, Signal, QRunnable, QThreadPool from PySide6.QtGui import QPixmap from .camera_controller import CameraController @@ -6,6 +6,50 @@ from .gphoto_camera import GPhotoCamera from .opencv_camera import OpenCvCamera from .base_camera import BaseCamera + +class CameraDetectionWorker(QRunnable): + """ + Worker thread for detecting cameras to avoid blocking the GUI. + """ + class WorkerSignals(QObject): + finished = Signal(list) + error = Signal(str) + + def __init__(self): + super().__init__() + self.signals = self.WorkerSignals() + + def run(self) -> None: + """The main work of the worker.""" + detected_cameras = [] + + try: + gphoto_cameras = GPhotoCamera.detect() + for index, info in gphoto_cameras.items(): + detected_cameras.append({ + "id": f"gphoto_{index}", + "name": f"{info['name']} ({info['port']})", + "type": "gphoto", + "index": index + }) + except Exception as e: + self.signals.error.emit(f"Błąd podczas wykrywania kamer GPhoto: {e}") + + try: + opencv_cameras = OpenCvCamera.detect() + for index, info in opencv_cameras.items(): + detected_cameras.append({ + "id": f"opencv_{index}", + "name": f"OpenCV: {info['name']}", + "type": "opencv", + "index": index + }) + except Exception as e: + self.signals.error.emit(f"Błąd podczas wykrywania kamer OpenCV: {e}") + + self.signals.finished.emit(detected_cameras) + + class CameraManager(QObject): """ Zarządza wszystkimi operacjami związanymi z kamerami, @@ -13,7 +57,10 @@ class CameraManager(QObject): """ frame_ready = Signal(QPixmap) error_occurred = Signal(str) + + detection_started = Signal() cameras_detected = Signal(list) + camera_started = Signal() camera_stopped = Signal() @@ -23,41 +70,26 @@ class CameraManager(QObject): self._detected_cameras: list[dict] = [] self._active_camera: BaseCamera | None = None self._active_camera_info: dict | None = None + self.thread_pool = QThreadPool.globalInstance() - # Przekazywanie sygnałów z kontrolera kamery na zewnątrz self._camera_controller.frame_ready.connect(self.frame_ready) self._camera_controller.error_occurred.connect(self.error_occurred) def detect_cameras(self) -> None: - """Wykrywa wszystkie dostępne kamery (GPhoto i OpenCV).""" - self._detected_cameras.clear() - - # Wykryj kamery GPhoto - try: - gphoto_cameras = GPhotoCamera.detect() - for index, info in gphoto_cameras.items(): - self._detected_cameras.append({ - "id": f"gphoto_{index}", - "name": f"{info['name']} ({info['port']})", - "type": "gphoto", - "index": index - }) - except Exception as e: - self.error_occurred.emit(f"Błąd podczas wykrywania kamer GPhoto: {e}") - - # Wykryj kamery OpenCV - try: - opencv_cameras = OpenCvCamera.detect() - for index, info in opencv_cameras.items(): - self._detected_cameras.append({ - "id": f"opencv_{index}", - "name": f"OpenCV: {info['name']}", - "type": "opencv", - "index": index - }) - except Exception as e: - self.error_occurred.emit(f"Błąd podczas wykrywania kamer OpenCV: {e}") + """ + Rozpoczyna asynchroniczne wykrywanie kamer w osobnym wątku. + """ + self.detection_started.emit() + worker = CameraDetectionWorker() + worker.signals.finished.connect(self._on_detection_finished) + worker.signals.error.connect(self.error_occurred) + self.thread_pool.start(worker) + def _on_detection_finished(self, detected_cameras: list): + """ + Slot wywoływany po zakończeniu pracy workera wykrywającego kamery. + """ + self._detected_cameras = detected_cameras self.cameras_detected.emit(self._detected_cameras) def get_detected_cameras(self) -> list[dict]: