Source code for QVideo.lib.QVideoWriter
'''Abstract base class for video file writers.'''
from abc import (ABCMeta, abstractmethod)
from qtpy import QtCore
from QVideo.lib.videotypes import Image
import numpy as np
import logging
logger = logging.getLogger(__name__)
__all__ = ['QVideoWriter']
class QVideoWriterMeta(type(QtCore.QObject), ABCMeta):
pass
[docs]
class QVideoWriter(QtCore.QObject, metaclass=QVideoWriterMeta):
'''Abstract base class for saving videos to files
Parameters
----------
filename : str
The output video filename.
fps : int
The frame rate of the output video [frames per second].
nframes : int
The maximum number of frames to write.
nskip : int
The number of frames to skip between writes.
kwargs : dict
Additional keyword arguments to pass to the QObject constructor.
Returns
-------
QVideoWriter : QObject
The video writer object.
Signals
-------
frameNumber(int)
Emitted when a new frame is written, providing the
current frame number.
finished()
Emitted when the video writing is finished.
Slots
-----
write(frame: Image) -> None
Write a video frame to the file.
close() -> None
Close the video file.
Properties
----------
filename : str
The output video filename.
fps : int
The frame rate of the output video [frames per second].
nskip : int
The number of frames to skip between writes.
nframes : int
The maximum number of frames to write.
Abstract Methods
----------------
open(frame: Image) -> bool
Open the video file for writing.
isOpen() -> bool
Check if the video file is open.
_write(frame: Image) -> None
Write a video frame to the file.
close() -> None
Close the video file.
'''
#: Emitted when a new frame is written, with the current frame number.
frameNumber = QtCore.Signal(int)
#: Emitted when video writing is complete.
finished = QtCore.Signal()
def __init__(self,
filename: str,
fps: int = 24,
nframes: int = 10_000,
nskip: int = 1,
**kwargs) -> None:
super().__init__(**kwargs)
self.filename = filename
self.fps = fps
self.framenumber = 0
self.nskip = nskip
self.target = nframes
self.blank = False
[docs]
@abstractmethod
def open(self, frame: Image) -> bool:
'''Open the output file using frame dimensions from the first frame.
Called automatically by :meth:`write` on the first frame.
Parameters
----------
frame : Image
The first video frame; dimensions and color mode are read
from this array.
Returns
-------
bool
``True`` if the file was opened successfully.
'''
[docs]
@abstractmethod
def isOpen(self) -> bool:
'''Return ``True`` if the output file is currently open.'''
[docs]
@QtCore.Slot(np.ndarray)
def write(self, frame: Image) -> None:
'''Write a video frame.
Opens the file on the first call, skips frames according to
:attr:`nskip`, and emits :attr:`finished` when :attr:`nframes`
have been written or when the file cannot be opened.
Parameters
----------
frame : Image
Video frame to write.
'''
if not self.isOpen():
if not self.open(frame):
logger.warning(f'Could not write to {self.filename}')
self.finished.emit()
return
if (self.framenumber >= self.target):
self.finished.emit()
return
if self.framenumber % self.nskip == 0:
self._write(np.zeros_like(frame) if self.blank else frame)
self.framenumber += 1
self.frameNumber.emit(self.framenumber)
@abstractmethod
def _write(self, frame: Image) -> None:
pass
[docs]
@QtCore.Slot()
@abstractmethod
def close(self) -> None:
pass