from __future__ import annotations from PySide6.QtCore import QObject, Signal from PySide6.QtMultimedia import ( QCamera, QCameraDevice, QCameraFormat, QMediaCaptureSession, QMediaDevices, QVideoSink, ) from PySide6.QtMultimediaWidgets import QVideoWidget class CameraService(QObject): error_occurred = Signal(str) def __init__(self, parent: QObject | None = None) -> None: super().__init__(parent) self._session = QMediaCaptureSession() self._camera: QCamera | None = None @property def session(self) -> QMediaCaptureSession: return self._session def set_video_widget(self, widget: QVideoWidget) -> None: self._session.setVideoOutput(widget) def set_video_sink(self, sink: QVideoSink) -> None: self._session.setVideoSink(sink) @staticmethod def available_cameras() -> list[QCameraDevice]: return QMediaDevices.videoInputs() def is_active(self) -> bool: return self._camera is not None and self._camera.isActive() def start(self, device: QCameraDevice) -> None: self.stop() self._camera = QCamera(device, self) self._camera.errorOccurred.connect(self._on_error) self._session.setCamera(self._camera) self._camera.start() def stop(self) -> None: if self._camera is not None: self._camera.stop() self._session.setCamera(None) self._camera.deleteLater() self._camera = None def set_camera_format(self, fmt: QCameraFormat) -> None: if self._camera is not None: self._camera.setCameraFormat(fmt) def _on_error(self, error: QCamera.Error, error_string: str) -> None: self.error_occurred.emit(error_string)