Source code for civiq6.capture

"""
Capturing the frames
====================

:mod:`civiq6.capture` provides interface to acquire the frames from
:class:`VimbaCamera` and to save them.

.. autoclass:: VimbaCaptureSession
   :members:

"""

import vimba  # type: ignore[import]
from .qt_compat import QtCore, QtMultimedia, get_frame_data
from .camera import VimbaCamera
from typing import Optional, Protocol


__all__ = [
    "VimbaCaptureSession",
]


COMPATIBLE_FORMATS = {
    vimba.PixelFormat.Mono8: QtMultimedia.QVideoFrameFormat.PixelFormat.Format_Y8,
    vimba.PixelFormat.Mono16: QtMultimedia.QVideoFrameFormat.PixelFormat.Format_Y16,
}


[docs] class VimbaCaptureSession(QtCore.QObject): cameraChanged = QtCore.Signal() imageCaptureChanged = QtCore.Signal() recorderChanged = QtCore.Signal() videoOutputChanged = QtCore.Signal() def __init__(self, parent=None): super().__init__(parent) self._camera = None self._imageCapture = None self._recorder = None self._videoSink = None self._videoOutput = None def camera(self) -> Optional[VimbaCamera]: return self._camera def setCamera(self, camera: Optional[VimbaCamera]): old_camera = self.camera() if old_camera is not None: old_camera._setCaptureSession(None) self._camera = camera if camera is not None: camera._setCaptureSession(self) self.cameraChanged.emit() def imageCapture(self) -> Optional["ImageCaptureProtocol"]: return self._imageCapture def setImageCapture(self, imageCapture: Optional["ImageCaptureProtocol"]): old_capture = self._imageCapture if old_capture is not None: old_capture._setCaptureSession(None) self._imageCapture = imageCapture if imageCapture is not None: imageCapture._setCaptureSession(self) self.imageCaptureChanged.emit() def recorder(self) -> Optional["RecorderProtocol"]: return self._recorder def setRecorder(self, recorder: Optional["RecorderProtocol"]): old_recorder = self._recorder if old_recorder is not None: old_recorder._setCaptureSession(None) self._recorder = recorder if recorder is not None: recorder._setCaptureSession(self) self.recorderChanged.emit() def videoSink(self) -> Optional[QtMultimedia.QVideoSink]: return self._videoSink def videoOutput(self) -> Optional[QtCore.QObject]: return self._videoOutput def setVideoSink(self, videoSink: Optional[QtMultimedia.QVideoSink]): self._videoSink = videoSink def setVideoOutput(self, videoOutput: Optional[QtCore.QObject]): self._videoOutput = videoOutput if videoOutput is None: self._videoSink = None elif hasattr(videoOutput, "videoSink"): self._videoSink = videoOutput.videoSink() else: self._videoSink = None self.videoOutputChanged.emit() def _setFrame(self, frame: vimba.Frame): imageCapture = self._imageCapture if imageCapture is not None: imageCapture._setFrame(frame) recorder = self._recorder if recorder is not None: recorder._setFrame(frame) videoSink = self._videoSink if videoSink is not None: # convert vimba frame to QVideoFrame pixelFormat = COMPATIBLE_FORMATS.get( frame.get_pixel_format(), QtMultimedia.QVideoFrameFormat.PixelFormat.Format_Invalid, ) w, h = frame.get_width(), frame.get_height() frameFormat = QtMultimedia.QVideoFrameFormat( QtCore.QSize(w, h), pixelFormat, ) videoFrame = QtMultimedia.QVideoFrame(frameFormat) if pixelFormat != QtMultimedia.QVideoFrameFormat.PixelFormat.Format_Invalid: videoFrame.map(QtMultimedia.QVideoFrame.MapMode.WriteOnly) get_frame_data(videoFrame)[:] = bytes(frame.get_buffer()) videoFrame.unmap() # save the modified memory # set constructed QVideoFrame to video sink videoSink.setVideoFrame(videoFrame)
class ImageCaptureProtocol(Protocol): def _setCaptureSession(self, captureSession: VimbaCaptureSession): ... def _setFrame(self, frame: vimba.Frame): ... class RecorderProtocol(Protocol): def _setCaptureSession(self, captureSession: VimbaCaptureSession): ... def _setFrame(self, frame: vimba.Frame): ...