forked from platypush/platypush
pylint fixes for the camera plugin.
This commit is contained in:
parent
9aa8e4538a
commit
2f4229d7b1
2 changed files with 37 additions and 61 deletions
|
@ -7,6 +7,7 @@ import time
|
||||||
|
|
||||||
from abc import ABC, abstractmethod
|
from abc import ABC, abstractmethod
|
||||||
from contextlib import contextmanager
|
from contextlib import contextmanager
|
||||||
|
from dataclasses import asdict
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from multiprocessing import Process
|
from multiprocessing import Process
|
||||||
from queue import Queue
|
from queue import Queue
|
||||||
|
@ -152,21 +153,21 @@ class CameraPlugin(Plugin, ABC):
|
||||||
"""
|
"""
|
||||||
super().__init__(**kwargs)
|
super().__init__(**kwargs)
|
||||||
|
|
||||||
self.workdir = os.path.join(
|
workdir = Config.get('workdir')
|
||||||
Config.get('workdir'), get_plugin_name_by_class(self)
|
plugin_name = get_plugin_name_by_class(self)
|
||||||
)
|
assert isinstance(workdir, str) and plugin_name
|
||||||
|
self.workdir = os.path.join(workdir, plugin_name)
|
||||||
pathlib.Path(self.workdir).mkdir(mode=0o755, exist_ok=True, parents=True)
|
pathlib.Path(self.workdir).mkdir(mode=0o755, exist_ok=True, parents=True)
|
||||||
|
|
||||||
# noinspection PyArgumentList
|
|
||||||
self.camera_info = self._camera_info_class(
|
self.camera_info = self._camera_info_class(
|
||||||
device,
|
device,
|
||||||
color_transform=color_transform,
|
color_transform=color_transform,
|
||||||
warmup_frames=warmup_frames,
|
warmup_frames=warmup_frames,
|
||||||
warmup_seconds=warmup_seconds,
|
warmup_seconds=warmup_seconds or 0,
|
||||||
rotate=rotate,
|
rotate=rotate,
|
||||||
scale_x=scale_x,
|
scale_x=scale_x,
|
||||||
scale_y=scale_y,
|
scale_y=scale_y,
|
||||||
capture_timeout=capture_timeout,
|
capture_timeout=capture_timeout or 20,
|
||||||
fps=fps,
|
fps=fps,
|
||||||
input_format=input_format,
|
input_format=input_format,
|
||||||
output_format=output_format,
|
output_format=output_format,
|
||||||
|
@ -227,13 +228,12 @@ class CameraPlugin(Plugin, ABC):
|
||||||
camera.start_event.clear()
|
camera.start_event.clear()
|
||||||
camera.capture_thread = None
|
camera.capture_thread = None
|
||||||
else:
|
else:
|
||||||
# noinspection PyArgumentList
|
|
||||||
camera = self._camera_class(info=info)
|
camera = self._camera_class(info=info)
|
||||||
|
|
||||||
camera.info.set(**params)
|
camera.info.set(**params)
|
||||||
camera.object = self.prepare_device(camera)
|
camera.object = self.prepare_device(camera)
|
||||||
|
|
||||||
if stream:
|
if stream and camera.info.stream_format:
|
||||||
writer_class = StreamWriter.get_class_by_name(camera.info.stream_format)
|
writer_class = StreamWriter.get_class_by_name(camera.info.stream_format)
|
||||||
camera.stream = writer_class(
|
camera.stream = writer_class(
|
||||||
camera=camera, plugin=self, redis_queue=redis_queue
|
camera=camera, plugin=self, redis_queue=redis_queue
|
||||||
|
@ -283,7 +283,7 @@ class CameraPlugin(Plugin, ABC):
|
||||||
def open(
|
def open(
|
||||||
self,
|
self,
|
||||||
device: Optional[Union[int, str]] = None,
|
device: Optional[Union[int, str]] = None,
|
||||||
stream: bool = None,
|
stream: bool = False,
|
||||||
redis_queue: Optional[str] = None,
|
redis_queue: Optional[str] = None,
|
||||||
**info,
|
**info,
|
||||||
) -> Generator[Camera, None, None]:
|
) -> Generator[Camera, None, None]:
|
||||||
|
@ -304,7 +304,8 @@ class CameraPlugin(Plugin, ABC):
|
||||||
)
|
)
|
||||||
yield camera
|
yield camera
|
||||||
finally:
|
finally:
|
||||||
self.close_device(camera)
|
if camera:
|
||||||
|
self.close_device(camera)
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
def prepare_device(self, device: Camera):
|
def prepare_device(self, device: Camera):
|
||||||
|
@ -333,7 +334,6 @@ class CameraPlugin(Plugin, ABC):
|
||||||
"""
|
"""
|
||||||
raise NotImplementedError()
|
raise NotImplementedError()
|
||||||
|
|
||||||
# noinspection PyShadowingBuiltins
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def store_frame(frame, filepath: str, format: Optional[str] = None):
|
def store_frame(frame, filepath: str, format: Optional[str] = None):
|
||||||
"""
|
"""
|
||||||
|
@ -347,7 +347,7 @@ class CameraPlugin(Plugin, ABC):
|
||||||
|
|
||||||
if isinstance(frame, bytes):
|
if isinstance(frame, bytes):
|
||||||
frame = list(frame)
|
frame = list(frame)
|
||||||
elif not isinstance(frame, Image.Image):
|
if not isinstance(frame, Image.Image):
|
||||||
frame = Image.fromarray(frame)
|
frame = Image.fromarray(frame)
|
||||||
|
|
||||||
save_args = {}
|
save_args = {}
|
||||||
|
@ -571,7 +571,7 @@ class CameraPlugin(Plugin, ABC):
|
||||||
video_file: Optional[str] = None,
|
video_file: Optional[str] = None,
|
||||||
preview: bool = False,
|
preview: bool = False,
|
||||||
**camera,
|
**camera,
|
||||||
) -> Union[str, dict]:
|
) -> Optional[Union[str, dict]]:
|
||||||
"""
|
"""
|
||||||
Capture a video.
|
Capture a video.
|
||||||
|
|
||||||
|
@ -596,7 +596,7 @@ class CameraPlugin(Plugin, ABC):
|
||||||
self.wait_capture(camera)
|
self.wait_capture(camera)
|
||||||
return video_file
|
return video_file
|
||||||
|
|
||||||
return self.status(camera.info.device)
|
return self.status(camera.info.device).output
|
||||||
|
|
||||||
@action
|
@action
|
||||||
def stop_capture(self, device: Optional[Union[int, str]] = None):
|
def stop_capture(self, device: Optional[Union[int, str]] = None):
|
||||||
|
@ -606,12 +606,12 @@ class CameraPlugin(Plugin, ABC):
|
||||||
:param device: Name/path/ID of the device to stop (default: all the active devices).
|
:param device: Name/path/ID of the device to stop (default: all the active devices).
|
||||||
"""
|
"""
|
||||||
devices = self._devices.copy()
|
devices = self._devices.copy()
|
||||||
stop_devices = list(devices.values())[:]
|
stop_devices = list(devices.values())
|
||||||
if device:
|
if device:
|
||||||
stop_devices = [self._devices[device]] if device in self._devices else []
|
stop_devices = [self._devices[device]] if device in self._devices else []
|
||||||
|
|
||||||
for device in stop_devices:
|
for dev in stop_devices:
|
||||||
self.close_device(device)
|
self.close_device(dev)
|
||||||
|
|
||||||
@action
|
@action
|
||||||
def capture_image(self, image_file: str, preview: bool = False, **camera) -> str:
|
def capture_image(self, image_file: str, preview: bool = False, **camera) -> str:
|
||||||
|
@ -635,9 +635,8 @@ class CameraPlugin(Plugin, ABC):
|
||||||
|
|
||||||
return image_file
|
return image_file
|
||||||
|
|
||||||
# noinspection PyUnusedLocal
|
|
||||||
@action
|
@action
|
||||||
def take_picture(self, image_file: str, preview: bool = False, **camera) -> str:
|
def take_picture(self, image_file: str, **camera) -> str:
|
||||||
"""
|
"""
|
||||||
Alias for :meth:`.capture_image`.
|
Alias for :meth:`.capture_image`.
|
||||||
|
|
||||||
|
@ -646,7 +645,7 @@ class CameraPlugin(Plugin, ABC):
|
||||||
:param preview: Show a preview of the camera frames.
|
:param preview: Show a preview of the camera frames.
|
||||||
:return: The local path to the saved image.
|
:return: The local path to the saved image.
|
||||||
"""
|
"""
|
||||||
return self.capture_image(image_file, **camera)
|
return str(self.capture_image(image_file, **camera).output)
|
||||||
|
|
||||||
@action
|
@action
|
||||||
def capture_sequence(
|
def capture_sequence(
|
||||||
|
@ -655,7 +654,7 @@ class CameraPlugin(Plugin, ABC):
|
||||||
n_frames: Optional[int] = None,
|
n_frames: Optional[int] = None,
|
||||||
preview: bool = False,
|
preview: bool = False,
|
||||||
**camera,
|
**camera,
|
||||||
) -> str:
|
) -> Optional[str]:
|
||||||
"""
|
"""
|
||||||
Capture a sequence of frames from a camera and store them to a directory.
|
Capture a sequence of frames from a camera and store them to a directory.
|
||||||
|
|
||||||
|
@ -687,7 +686,7 @@ class CameraPlugin(Plugin, ABC):
|
||||||
"""
|
"""
|
||||||
camera = self.open_device(frames_dir=None, **camera)
|
camera = self.open_device(frames_dir=None, **camera)
|
||||||
self.start_camera(camera, duration=duration, n_frames=n_frames, preview=True)
|
self.start_camera(camera, duration=duration, n_frames=n_frames, preview=True)
|
||||||
return self.status(camera.info.device)
|
return self.status(camera.info.device) # type: ignore
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _prepare_server_socket(camera: Camera) -> socket.socket:
|
def _prepare_server_socket(camera: Camera) -> socket.socket:
|
||||||
|
@ -729,10 +728,11 @@ class CameraPlugin(Plugin, ABC):
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if camera.info.device not in self._devices:
|
if camera.info.device not in self._devices:
|
||||||
info = camera.info.to_dict()
|
info = asdict(camera.info)
|
||||||
info['stream_format'] = stream_format
|
info['stream_format'] = stream_format
|
||||||
camera = self.open_device(stream=True, **info)
|
camera = self.open_device(stream=True, **info)
|
||||||
|
|
||||||
|
assert camera.stream, 'No camera stream available'
|
||||||
camera.stream.sock = sock
|
camera.stream.sock = sock
|
||||||
self.start_camera(
|
self.start_camera(
|
||||||
camera, duration=duration, frames_dir=None, image_file=None
|
camera, duration=duration, frames_dir=None, image_file=None
|
||||||
|
@ -741,7 +741,9 @@ class CameraPlugin(Plugin, ABC):
|
||||||
self._cleanup_stream(camera, server_socket, sock)
|
self._cleanup_stream(camera, server_socket, sock)
|
||||||
self.logger.info('Stopped camera stream')
|
self.logger.info('Stopped camera stream')
|
||||||
|
|
||||||
def _cleanup_stream(self, camera: Camera, server_socket: socket.socket, client: IO):
|
def _cleanup_stream(
|
||||||
|
self, camera: Camera, server_socket: socket.socket, client: Optional[IO]
|
||||||
|
):
|
||||||
if client:
|
if client:
|
||||||
try:
|
try:
|
||||||
client.close()
|
client.close()
|
||||||
|
@ -772,7 +774,7 @@ class CameraPlugin(Plugin, ABC):
|
||||||
:return: The status of the device.
|
:return: The status of the device.
|
||||||
"""
|
"""
|
||||||
camera = self.open_device(stream=True, stream_format=stream_format, **camera)
|
camera = self.open_device(stream=True, stream_format=stream_format, **camera)
|
||||||
return self._start_streaming(camera, duration, stream_format)
|
return self._start_streaming(camera, duration, stream_format) # type: ignore
|
||||||
|
|
||||||
def _start_streaming(
|
def _start_streaming(
|
||||||
self, camera: Camera, duration: Optional[float], stream_format: str
|
self, camera: Camera, duration: Optional[float], stream_format: str
|
||||||
|
@ -781,6 +783,7 @@ class CameraPlugin(Plugin, ABC):
|
||||||
assert (
|
assert (
|
||||||
not camera.stream_event.is_set() and camera.info.device not in self._streams
|
not camera.stream_event.is_set() and camera.info.device not in self._streams
|
||||||
), f'A streaming session is already running for device {camera.info.device}'
|
), f'A streaming session is already running for device {camera.info.device}'
|
||||||
|
assert camera.info.device, 'No device name available'
|
||||||
|
|
||||||
self._streams[camera.info.device] = camera
|
self._streams[camera.info.device] = camera
|
||||||
camera.stream_event.set()
|
camera.stream_event.set()
|
||||||
|
@ -804,12 +807,12 @@ class CameraPlugin(Plugin, ABC):
|
||||||
:param device: Name/path/ID of the device to stop (default: all the active devices).
|
:param device: Name/path/ID of the device to stop (default: all the active devices).
|
||||||
"""
|
"""
|
||||||
streams = self._streams.copy()
|
streams = self._streams.copy()
|
||||||
stop_devices = list(streams.values())[:]
|
stop_devices = list(streams.values())
|
||||||
if device:
|
if device:
|
||||||
stop_devices = [self._streams[device]] if device in self._streams else []
|
stop_devices = [self._streams[device]] if device in self._streams else []
|
||||||
|
|
||||||
for device in stop_devices:
|
for dev in stop_devices:
|
||||||
self._stop_streaming(device)
|
self._stop_streaming(dev)
|
||||||
|
|
||||||
def _stop_streaming(self, camera: Camera):
|
def _stop_streaming(self, camera: Camera):
|
||||||
camera.stream_event.clear()
|
camera.stream_event.clear()
|
||||||
|
@ -825,7 +828,7 @@ class CameraPlugin(Plugin, ABC):
|
||||||
return {}
|
return {}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
**camera.info.to_dict(),
|
**asdict(camera.info),
|
||||||
'active': bool(camera.capture_thread and camera.capture_thread.is_alive()),
|
'active': bool(camera.capture_thread and camera.capture_thread.is_alive()),
|
||||||
'capturing': bool(
|
'capturing': bool(
|
||||||
camera.capture_thread
|
camera.capture_thread
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import math
|
import math
|
||||||
import threading
|
import threading
|
||||||
from dataclasses import dataclass
|
from dataclasses import asdict, dataclass
|
||||||
from typing import Optional, Union, Tuple, Set
|
from typing import Optional, Union, Tuple, Set
|
||||||
|
|
||||||
import numpy as np
|
import numpy as np
|
||||||
|
@ -17,8 +17,8 @@ from platypush.plugins.camera.model.writer.preview import PreviewWriter
|
||||||
class CameraInfo:
|
class CameraInfo:
|
||||||
device: Optional[Union[int, str]]
|
device: Optional[Union[int, str]]
|
||||||
bind_address: Optional[str] = None
|
bind_address: Optional[str] = None
|
||||||
capture_timeout: float = 20.0
|
capture_timeout: float = 0
|
||||||
color_transform: Optional[str] = None
|
color_transform: Optional[Union[int, str]] = None
|
||||||
ffmpeg_bin: Optional[str] = None
|
ffmpeg_bin: Optional[str] = None
|
||||||
fps: Optional[float] = None
|
fps: Optional[float] = None
|
||||||
frames_dir: Optional[str] = None
|
frames_dir: Optional[str] = None
|
||||||
|
@ -36,42 +36,15 @@ class CameraInfo:
|
||||||
stream_format: Optional[str] = None
|
stream_format: Optional[str] = None
|
||||||
vertical_flip: bool = False
|
vertical_flip: bool = False
|
||||||
warmup_frames: int = 0
|
warmup_frames: int = 0
|
||||||
warmup_seconds: float = 0.0
|
warmup_seconds: float = 0
|
||||||
|
|
||||||
def set(self, **kwargs):
|
def set(self, **kwargs):
|
||||||
for k, v in kwargs.items():
|
for k, v in kwargs.items():
|
||||||
if hasattr(self, k):
|
if hasattr(self, k):
|
||||||
setattr(self, k, v)
|
setattr(self, k, v)
|
||||||
|
|
||||||
def to_dict(self) -> dict:
|
|
||||||
return {
|
|
||||||
'bind_address': self.bind_address,
|
|
||||||
'capture_timeout': self.capture_timeout,
|
|
||||||
'color_transform': self.color_transform,
|
|
||||||
'device': self.device,
|
|
||||||
'ffmpeg_bin': self.ffmpeg_bin,
|
|
||||||
'fps': self.fps,
|
|
||||||
'frames_dir': self.frames_dir,
|
|
||||||
'grayscale': self.grayscale,
|
|
||||||
'horizontal_flip': self.horizontal_flip,
|
|
||||||
'input_codec': self.input_codec,
|
|
||||||
'input_format': self.input_format,
|
|
||||||
'listen_port': self.listen_port,
|
|
||||||
'output_codec': self.output_codec,
|
|
||||||
'output_format': self.output_format,
|
|
||||||
'resolution': list(self.resolution or ()),
|
|
||||||
'rotate': self.rotate,
|
|
||||||
'scale_x': self.scale_x,
|
|
||||||
'scale_y': self.scale_y,
|
|
||||||
'stream_format': self.stream_format,
|
|
||||||
'vertical_flip': self.vertical_flip,
|
|
||||||
'warmup_frames': self.warmup_frames,
|
|
||||||
'warmup_seconds': self.warmup_seconds,
|
|
||||||
}
|
|
||||||
|
|
||||||
def clone(self):
|
def clone(self):
|
||||||
# noinspection PyArgumentList
|
return self.__class__(**asdict(self))
|
||||||
return self.__class__(**self.to_dict())
|
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
|
|
Loading…
Reference in a new issue