Source code for QVideo.dvr.QOpenCVReader
'''OpenCV video reader and threaded playback source.'''
from qtpy import QtCore
from QVideo.lib import QCamera, QVideoReader, QVideoSource
from pathlib import Path
import cv2
__all__ = ['QOpenCVReader', 'QOpenCVSource']
[docs]
class QOpenCVReader(QVideoReader):
'''Video reader for common video file formats (AVI, MKV, MP4, etc.).
Reads frames from a video file using OpenCV's ``VideoCapture``.
Frames are converted from BGR (OpenCV native) to RGB on read.
Parameters
----------
filename : str
Path to the video file to read.
'''
FRAMENUMBER = cv2.CAP_PROP_POS_FRAMES
WIDTH = cv2.CAP_PROP_FRAME_WIDTH
HEIGHT = cv2.CAP_PROP_FRAME_HEIGHT
LENGTH = cv2.CAP_PROP_FRAME_COUNT
FPS = cv2.CAP_PROP_FPS
_COLOR_BGR2RGB = cv2.COLOR_BGR2RGB
def _initialize(self) -> bool:
self._reader = cv2.VideoCapture(self.filename)
if not self._reader.isOpened():
return False
self._framenumber = 0
return True
def _deinitialize(self) -> None:
if self._reader is not None:
self._reader.release()
self._reader = None
[docs]
def read(self) -> QCamera.CameraData:
'''Read the next frame from the video file.
Frames are converted from BGR (OpenCV native) to RGB on read.
Returns
-------
tuple[bool, ndarray or None]
``(True, frame)`` on success, ``(False, None)`` at end-of-file
or when the reader is not open.
'''
if not self.isOpen():
return False, None
ok, frame = self._reader.read()
if not ok:
return False, None
if frame.ndim == 3:
frame = cv2.cvtColor(frame, self._COLOR_BGR2RGB)
self._framenumber += 1
return True, frame
[docs]
@QtCore.Slot(int)
def seek(self, framenumber: int) -> None:
'''Seek to the specified frame number.'''
self._reader.set(self.FRAMENUMBER, framenumber)
self._framenumber = framenumber
@property
def fps(self) -> float:
'''Frame rate reported by the video file [fps].'''
return self._reader.get(self.FPS)
@property
def length(self) -> int:
'''Total number of frames in the video file.'''
return int(self._reader.get(self.LENGTH))
@property
def framenumber(self) -> int:
'''Index of the next frame to be returned by :meth:`read`.'''
return self._framenumber
@property
def width(self) -> int:
'''Frame width in pixels.'''
return int(self._reader.get(self.WIDTH))
@property
def height(self) -> int:
'''Frame height in pixels.'''
return int(self._reader.get(self.HEIGHT))
[docs]
class QOpenCVSource(QVideoSource):
'''Video source for common video file formats (AVI, MKV, MP4, etc.).
Parameters
----------
reader : str, Path, or QOpenCVReader
Path to the video file to read, or an existing
:class:`QOpenCVReader` instance.
'''
def __init__(self, reader: str | Path | QOpenCVReader) -> None:
if isinstance(reader, (str, Path)):
reader = QOpenCVReader(str(reader))
super().__init__(reader)
if __name__ == '__main__': # pragma: no cover
QOpenCVReader.example()