forked from platypush/platypush
Added stream_on_start
argument to camera
plugins.
It replaces the functionalities of the deprecated `camera` backends.
This commit is contained in:
parent
9cf95125a6
commit
9ad9bd20e4
1 changed files with 84 additions and 30 deletions
|
@ -86,6 +86,7 @@ class CameraPlugin(RunnablePlugin, ABC):
|
||||||
stream_format: str = 'mjpeg',
|
stream_format: str = 'mjpeg',
|
||||||
listen_port: Optional[int] = 5000,
|
listen_port: Optional[int] = 5000,
|
||||||
bind_address: str = '0.0.0.0',
|
bind_address: str = '0.0.0.0',
|
||||||
|
stream_on_start: bool = False,
|
||||||
ffmpeg_bin: str = 'ffmpeg',
|
ffmpeg_bin: str = 'ffmpeg',
|
||||||
input_codec: Optional[str] = None,
|
input_codec: Optional[str] = None,
|
||||||
output_codec: Optional[str] = None,
|
output_codec: Optional[str] = None,
|
||||||
|
@ -94,41 +95,57 @@ class CameraPlugin(RunnablePlugin, ABC):
|
||||||
"""
|
"""
|
||||||
:param device: Identifier of the default capturing device.
|
:param device: Identifier of the default capturing device.
|
||||||
:param resolution: Default resolution, as a tuple of two integers.
|
:param resolution: Default resolution, as a tuple of two integers.
|
||||||
:param frames_dir: Directory where the camera frames will be stored (default:
|
:param frames_dir: Directory where the camera frames will be stored
|
||||||
``~/.local/share/platypush/<plugin.name>/frames``)
|
(default: ``~/.local/share/platypush/<plugin.name>/frames``)
|
||||||
:param warmup_frames: Cameras usually take a while to adapt their
|
:param warmup_frames: Cameras usually take a while to adapt their
|
||||||
luminosity and focus to the environment when taking a picture.
|
luminosity and focus to the environment when taking a picture.
|
||||||
This parameter allows you to specify the number of "warmup" frames
|
This parameter allows you to specify the number of "warmup" frames
|
||||||
to capture upon picture command before actually capturing a frame
|
to capture upon picture command before actually capturing a frame
|
||||||
(default: 5 but you may want to calibrate this parameter for your
|
(default: 5 but you may want to calibrate this parameter for your
|
||||||
camera)
|
camera)
|
||||||
:param warmup_seconds: Number of seconds to wait before a picture is taken or the first frame of a
|
:param warmup_seconds: Number of seconds to wait before a picture is
|
||||||
video/sequence is captured (default: 0).
|
taken or the first frame of a video/sequence is captured (default:
|
||||||
:param capture_timeout: Maximum number of seconds to wait between the programmed termination of a capture
|
0).
|
||||||
session and the moment the device is released.
|
:param capture_timeout: Maximum number of seconds to wait between the
|
||||||
:param scale_x: If set, the images will be scaled along the x-axis by the specified factor
|
programmed termination of a capture session and the moment the
|
||||||
:param scale_y: If set, the images will be scaled along the y-axis by the specified factor
|
device is released.
|
||||||
|
:param scale_x: If set, the images will be scaled along the x-axis by
|
||||||
|
the specified factor
|
||||||
|
:param scale_y: If set, the images will be scaled along the y-axis by
|
||||||
|
the specified factor
|
||||||
:param color_transform: Color transformation to apply to the images.
|
:param color_transform: Color transformation to apply to the images.
|
||||||
:param grayscale: Whether the output should be converted to grayscale.
|
:param grayscale: Whether the output should be converted to grayscale.
|
||||||
:param rotate: If set, the images will be rotated by the specified number of degrees
|
:param rotate: If set, the images will be rotated by the specified
|
||||||
|
number of degrees
|
||||||
:param fps: Frames per second (default: 25).
|
:param fps: Frames per second (default: 25).
|
||||||
:param horizontal_flip: If set, the images will be flipped on the horizontal axis.
|
:param horizontal_flip: If set, the images will be flipped on the
|
||||||
:param vertical_flip: If set, the images will be flipped on the vertical axis.
|
horizontal axis.
|
||||||
:param listen_port: Default port to be used for streaming over TCP (default: 5000).
|
:param vertical_flip: If set, the images will be flipped on the vertical
|
||||||
:param bind_address: Default bind address for TCP streaming (default: 0.0.0.0, accept any connections).
|
axis.
|
||||||
:param input_codec: Specify the ffmpeg video codec (``-vcodec``) used for the input.
|
:param listen_port: Default port to be used for streaming over TCP
|
||||||
:param output_codec: Specify the ffmpeg video codec (``-vcodec``) to be used for encoding the output. For some
|
(default: 5000).
|
||||||
ffmpeg output formats (e.g. ``h264`` and ``rtp``) this may default to ``libxvid``.
|
:param bind_address: Default bind address for TCP streaming (default:
|
||||||
|
0.0.0.0, accept connections on any network interface).
|
||||||
|
:param stream_on_start: If set, the camera will start streaming on the
|
||||||
|
specified ``bind_address`` and ``listen_port`` as soon as the plugin
|
||||||
|
is started. Otherwise, the stream will be started only when the
|
||||||
|
:meth:`.start_streaming` method is called. Default: False.
|
||||||
|
:param input_codec: Specify the ffmpeg video codec (``-vcodec``) used
|
||||||
|
for the input.
|
||||||
|
:param output_codec: Specify the ffmpeg video codec (``-vcodec``) to be
|
||||||
|
used for encoding the output. For some ffmpeg output formats (e.g.
|
||||||
|
``h264`` and ``rtp``) this may default to ``libxvid``.
|
||||||
:param input_format: Plugin-specific format/type for the input stream.
|
:param input_format: Plugin-specific format/type for the input stream.
|
||||||
:param output_format: Plugin-specific format/type for the output videos.
|
:param output_format: Plugin-specific format/type for the output videos.
|
||||||
:param ffmpeg_bin: Path to the ffmpeg binary (default: ``ffmpeg``).
|
:param ffmpeg_bin: Path to the ffmpeg binary (default: ``ffmpeg``).
|
||||||
:param stream_format: Default format for the output when streamed to a network device. Available:
|
:param stream_format: Default format for the output when streamed to a
|
||||||
|
network device. Available:
|
||||||
|
|
||||||
- ``MJPEG`` (default)
|
- ``MJPEG`` (default)
|
||||||
- ``H264`` (over ``ffmpeg``)
|
- ``H264`` (over ``ffmpeg``)
|
||||||
- ``H265`` (over ``ffmpeg``)
|
- ``H265`` (over ``ffmpeg``)
|
||||||
- ``MKV`` (over ``ffmpeg``)
|
- ``MKV`` (over ``ffmpeg``)
|
||||||
- ``MP4`` (over ``ffmpeg``)
|
- ``MP4`` (over ``ffmpeg``)
|
||||||
|
|
||||||
"""
|
"""
|
||||||
super().__init__(**kwargs)
|
super().__init__(**kwargs)
|
||||||
|
@ -137,6 +154,7 @@ class CameraPlugin(RunnablePlugin, ABC):
|
||||||
plugin_name = get_plugin_name_by_class(self)
|
plugin_name = get_plugin_name_by_class(self)
|
||||||
assert isinstance(workdir, str) and plugin_name
|
assert isinstance(workdir, str) and plugin_name
|
||||||
self.workdir = os.path.join(workdir, plugin_name)
|
self.workdir = os.path.join(workdir, plugin_name)
|
||||||
|
self._stream_on_start = stream_on_start
|
||||||
pathlib.Path(self.workdir).mkdir(mode=0o755, exist_ok=True, parents=True)
|
pathlib.Path(self.workdir).mkdir(mode=0o755, exist_ok=True, parents=True)
|
||||||
|
|
||||||
self.camera_info = self._camera_info_class(
|
self.camera_info = self._camera_info_class(
|
||||||
|
@ -322,7 +340,9 @@ class CameraPlugin(RunnablePlugin, ABC):
|
||||||
raise NotImplementedError()
|
raise NotImplementedError()
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def store_frame(frame, filepath: str, format: Optional[str] = None):
|
def store_frame( # pylint: disable=redefined-builtin
|
||||||
|
frame, filepath: str, format: Optional[str] = None
|
||||||
|
):
|
||||||
"""
|
"""
|
||||||
Capture a frame to the filesystem using the ``PIL`` library - it can be overridden by derived classes.
|
Capture a frame to the filesystem using the ``PIL`` library - it can be overridden by derived classes.
|
||||||
|
|
||||||
|
@ -346,9 +366,9 @@ class CameraPlugin(RunnablePlugin, ABC):
|
||||||
def _store_frame(
|
def _store_frame(
|
||||||
self,
|
self,
|
||||||
frame,
|
frame,
|
||||||
|
*args,
|
||||||
frames_dir: Optional[str] = None,
|
frames_dir: Optional[str] = None,
|
||||||
image_file: Optional[str] = None,
|
image_file: Optional[str] = None,
|
||||||
*args,
|
|
||||||
**kwargs,
|
**kwargs,
|
||||||
) -> str:
|
) -> str:
|
||||||
"""
|
"""
|
||||||
|
@ -792,21 +812,39 @@ class CameraPlugin(RunnablePlugin, ABC):
|
||||||
self,
|
self,
|
||||||
device: Optional[Union[int, str]] = None,
|
device: Optional[Union[int, str]] = None,
|
||||||
duration: Optional[float] = None,
|
duration: Optional[float] = None,
|
||||||
stream_format: str = 'mkv',
|
stream_format: Optional[str] = None,
|
||||||
**camera,
|
**camera,
|
||||||
) -> dict:
|
) -> dict:
|
||||||
"""
|
"""
|
||||||
Expose the video stream of a camera over a TCP connection.
|
Expose the video stream of a camera over a TCP connection.
|
||||||
|
|
||||||
:param device: Name/path/ID of the device to capture from (default: None, use the default device).
|
When the streaming is started, the plugin will listen on the specified
|
||||||
:param duration: Streaming thread duration (default: until :meth:`.stop_streaming` is called).
|
``bind_address`` and ``listen_port`` and stream camera frames to
|
||||||
:param stream_format: Format of the output stream - e.g. ``h264``, ``mjpeg``, ``mkv`` etc. (default: ``mkv``).
|
connected clients. If ``stream_format`` is a video format (H264, H265,
|
||||||
|
MKV, MP4 etc.) then the camera stream can be viewed using a video
|
||||||
|
player - for example, using ``vlc``:
|
||||||
|
|
||||||
|
.. code-block:: bash
|
||||||
|
|
||||||
|
vlc tcp://<host>:<port>
|
||||||
|
|
||||||
|
:param device: Name/path/ID of the device to capture from (default:
|
||||||
|
None, use the default device).
|
||||||
|
:param duration: Streaming thread duration (default: until
|
||||||
|
:meth:`.stop_streaming` is called).
|
||||||
|
:param stream_format: Format of the output stream - e.g. ``h264``,
|
||||||
|
``mjpeg``, ``mkv`` etc. If not specified, the ``stream_format``
|
||||||
|
configured on the plugin will be used.
|
||||||
:param camera: Camera object properties - see constructor parameters.
|
:param camera: Camera object properties - see constructor parameters.
|
||||||
:return: The status of the device.
|
:return: The status of the device.
|
||||||
"""
|
"""
|
||||||
camera = self.open_device(
|
camera = self.open_device(
|
||||||
device=device, stream=True, stream_format=stream_format, **camera
|
device=device,
|
||||||
|
stream=True,
|
||||||
|
stream_format=stream_format or self.camera_info.stream_format,
|
||||||
|
**camera,
|
||||||
)
|
)
|
||||||
|
|
||||||
return self._start_streaming(camera, duration, stream_format) # type: ignore
|
return self._start_streaming(camera, duration, stream_format) # type: ignore
|
||||||
|
|
||||||
def _start_streaming(
|
def _start_streaming(
|
||||||
|
@ -981,7 +1019,23 @@ class CameraPlugin(RunnablePlugin, ABC):
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
def main(self):
|
def main(self):
|
||||||
self.wait_stop()
|
if not self._stream_on_start:
|
||||||
|
self.wait_stop()
|
||||||
|
return
|
||||||
|
|
||||||
|
while not self.should_stop():
|
||||||
|
if self._stream_on_start:
|
||||||
|
self.start_streaming()
|
||||||
|
|
||||||
|
cameras = list(self._streams.values())
|
||||||
|
if not cameras:
|
||||||
|
self.logger.warning('No camera devices could be streamed')
|
||||||
|
self.wait_stop()
|
||||||
|
break
|
||||||
|
|
||||||
|
camera = cameras[0]
|
||||||
|
wait_for_either(self._should_stop, camera.stop_stream_event)
|
||||||
|
self.stop_streaming()
|
||||||
|
|
||||||
|
|
||||||
# vim:sw=4:ts=4:et:
|
# vim:sw=4:ts=4:et:
|
||||||
|
|
Loading…
Reference in a new issue