Class to write a video on disk, image by image.
This class is embedding a VideoWriter() object and define some getters and setters to manage such video easily.
Videos have a default resolution of "SD": (704*528)@25
Class to write a video on disk, image by image.
This class is embedding a VideoWriter() object and define some getters and setters to manage such video easily.
Videos have a default resolution of "SD": (704*528)@25
Create a sppasVideoWriter.
def __init__(self):
"""Create a sppasVideoWriter. """
self.__video = cv2.VideoWriter()
self._fps = 25.0
self._size = (704, 528)
self._aspect = sppasVideoWriter.ASPECT['extend']
self.__lock = False
self.__nframes = 0
Return the list of supported file extensions.
@staticmethod
def get_extensions():
"""Return the list of supported file extensions."""
return tuple(sppasVideoWriter.FOURCC.keys())
Return the FOURCC string corresponding to an extension.
@staticmethod
def get_fourcc(ext):
"""Return the FOURCC string corresponding to an extension.
:param ext: (str) Extension of a filename
:return: (str)
"""
ext = str(ext)
if ext.startswith('.') is False:
ext = '.' + ext.lower()
return sppasVideoWriter.FOURCC.get(ext, '')
Return the extension string corresponding to the fourcc.
@staticmethod
def get_ext(fourcc):
"""Return the extension string corresponding to the fourcc.
:param fourcc: (str) FOURCC name
:return: (str)
"""
if isinstance(fourcc, (list, tuple)):
fourcc = ''.join(fourcc)
else:
fourcc = str(fourcc)
fourcc = fourcc.replace(' ', '')
fourcc = fourcc.lower()
for ext in sppasVideoWriter.FOURCC:
if sppasVideoWriter.FOURCC[ext] == fourcc:
return ext
return ''
Set the video resolution: images size and frame rate.
Some of the possible values for the name of the resolution are:
VideoLockError, sppasKeyError
def set_resolution(self, name='SD'):
"""Set the video resolution: images size and frame rate.
Some of the possible values for the name of the resolution are:
- LD: 640 x 480 / 15 fps
- SD: 704 x 528 / 25 fps
- HD: 1920 x 1080 / 25 fps
- WFHD: 2560 x 1080 / 25 fps
- UHD: 2560 x 1440 / 25 fps
- 4K: 3840 x 2160 / 30 fps
- 8K: 7680 x 4320 / 60 fps
:param name: (str) Name of the resolution
:raise: VideoLockError, sppasKeyError
"""
if self.__lock is True:
logging.error('The video resolution can only be changed if the video stream is not already opened.')
raise VideoLockError
if name.upper() not in sppasVideoWriter.RESOLUTIONS.keys():
raise sppasKeyError(name, 'RESOLUTIONS')
resolution = sppasVideoWriter.RESOLUTIONS[name.upper()]
self._size = (resolution[0], resolution[1])
self._fps = resolution[2]
Return the (width, height) of the video.
def get_size(self):
"""Return the (width, height) of the video."""
return self._size
Fix a personalized size for the video to write.
def set_size(self, width, height):
"""Fix a personalized size for the video to write.
:param width: (int) number of columns in range (20, 12000)
:param height: (int) number of rows in range (20, 5000)
"""
if self.__lock is True:
logging.error('The video size can only be changed if the video stream is not already opened.')
raise VideoLockError
width = int(width)
height = int(height)
if width < 0 or width > 10000:
raise IntervalRangeException(width, 0, 5000)
if height < 0 or height > 5000:
raise IntervalRangeException(height, 0, 5000)
self._size = (width, height)
Return the defined fps value (float) to write video files.
def get_fps(self):
"""Return the defined fps value (float) to write video files."""
return self._fps
Fix the framerate of the output video.
NegativeValueError, IntervalRangeError
def set_fps(self, value):
"""Fix the framerate of the output video.
:param value: (float) frame per seconds
:raise: NegativeValueError, IntervalRangeError
"""
if self.__lock is True:
logging.error('The video fps can only be changed if the video stream is not already opened.')
raise VideoLockError
value = float(value)
if value < 0.0:
raise NegativeValueError(value)
if value > sppasVideoWriter.MAX_FPS:
raise IntervalRangeException(value, 0.0, sppasVideoWriter.MAX_FPS)
self._fps = value
Open a file stream to write images into.
def open(self, video):
"""Open a file stream to write images into.
:param video: (str) Filename
"""
if self.__lock is True:
logging.error("The video can't be opened because another video stream is not already opened.")
raise VideoLockError
fourcc = cv2.VideoWriter_fourcc(*'mp4v')
try:
self.__video.open(video, fourcc, self._fps, self._size)
if self.__video.isOpened() is False:
raise IOError('The video was not opened by OpenCV Library for an unknown reason.')
self.__lock = True
self.__nframes = 0
except Exception as e:
logging.error("Video {} can't be created: {}".format(video, str(e)))
raise VideoWriteError(video)
Return True if a video is already opened and ready to write.
def is_opened(self):
"""Return True if a video is already opened and ready to write."""
return self.__lock
Release the flow taken by the reading of the video.
def close(self):
"""Release the flow taken by the reading of the video."""
self.__video.release()
self.__lock = False
self.__nframes = 0
Return the FPS of the current video (float).
def get_framerate(self):
"""Return the FPS of the current video (float)."""
return self._fps
Return the width of the frames in the video.
def get_width(self):
"""Return the width of the frames in the video."""
return self._size[0]
Return the height of the frames in the video.
def get_height(self):
"""Return the height of the frames in the video."""
return self._size[1]
Return the number of frames written in the video.
def get_nframes(self):
"""Return the number of frames written in the video."""
return self.__nframes
Return the duration of the written video in seconds (float).
def get_duration(self):
"""Return the duration of the written video in seconds (float)."""
if self.__lock is False:
return 0.0
return float(self.get_nframes()) * (1.0 / self.get_framerate())
Return a string defining the aspect strategy to write images.
def get_aspect(self, as_int=True):
"""Return a string defining the aspect strategy to write images."""
if as_int is True:
return self._aspect
return sppasVideoWriter.ASPECT[self._aspect]
Set the aspect strategy to write the image.
def set_aspect(self, aspect):
"""Set the aspect strategy to write the image.
:param aspect: (int or str)
"""
if aspect not in sppasVideoWriter.ASPECT:
raise KeyError('Unknown image aspect {}'.format(self._aspect))
if isinstance(aspect, int):
aspect = sppasVideoWriter.ASPECT[aspect]
self._aspect = sppasVideoWriter.ASPECT[aspect]
Append an image to the video stream.
def write(self, image):
"""Append an image to the video stream.
:param image: (sppasImage or None) If the given image is None, a blank image is written.
"""
if self.__lock is False:
raise Exception("Actually there's no video stream defined.")
if image is not None:
w, h = self._size
if self._aspect in ('center', sppasVideoWriter.ASPECT['center']):
img = image.icenter(w, h)
elif self._aspect in ('stretch', sppasVideoWriter.ASPECT['stretch']):
img = image.iresize(w, h)
elif self._aspect in ('extend', sppasVideoWriter.ASPECT['extend']):
img = image.iextend(w, h)
elif self._aspect in ('zoom', sppasVideoWriter.ASPECT['zoom']):
img = image.izoom(w, h)
else:
raise Exception("Can't write image: unknown image aspect {}".format(self._aspect))
if img.width != w or img.height != h:
img = img.iresize(w, h)
else:
w, h = self._size
img = sppasImage(0).blank_image(w, h)
self.__video.write(img)