Draft of new semantics
This commit is contained in:
parent
b39a0653f2
commit
19af98736d
13 changed files with 252 additions and 187 deletions
|
|
@ -121,7 +121,8 @@ class BaseCamera(metaclass=ABCMeta):
|
|||
self.stream_timeout = 20
|
||||
self.stream_timeout_enabled = False
|
||||
|
||||
self.status = {"board": None}
|
||||
self.stream_active = False
|
||||
self.record_active = False
|
||||
|
||||
self.paths = {"default": BASE_CAPTURE_PATH, "temp": TEMP_CAPTURE_PATH}
|
||||
|
||||
|
|
@ -129,8 +130,24 @@ class BaseCamera(metaclass=ABCMeta):
|
|||
self.images = []
|
||||
self.videos = []
|
||||
|
||||
@property
|
||||
@abstractmethod
|
||||
def apply_settings(self, config: dict):
|
||||
def configuration(self):
|
||||
"""The current camera configuration."""
|
||||
pass
|
||||
|
||||
@property
|
||||
@abstractmethod
|
||||
def state(self):
|
||||
"""The current read-only camera state."""
|
||||
pass
|
||||
|
||||
@property
|
||||
def settings(self):
|
||||
return self.read_settings()
|
||||
|
||||
@abstractmethod
|
||||
def update_settings(self, config: dict):
|
||||
"""Update settings from a config dictionary"""
|
||||
with self.lock:
|
||||
# Apply valid config params to camera object
|
||||
|
|
@ -187,7 +204,7 @@ class BaseCamera(metaclass=ABCMeta):
|
|||
self.last_access = time.time()
|
||||
self.stop = False
|
||||
|
||||
if not self.status["stream_active"]:
|
||||
if not self.stream_active:
|
||||
# start background frame thread
|
||||
self.thread = threading.Thread(target=self._thread)
|
||||
self.thread.daemon = True
|
||||
|
|
@ -207,12 +224,12 @@ class BaseCamera(metaclass=ABCMeta):
|
|||
logging.debug("Stopping worker thread")
|
||||
timeout_time = time.time() + timeout
|
||||
|
||||
if self.status["stream_active"]:
|
||||
if self.stream_active:
|
||||
self.stop = True
|
||||
self.thread.join() # Wait for stream thread to exit
|
||||
logging.debug("Waiting for stream thread to exit.")
|
||||
|
||||
while self.status["stream_active"]:
|
||||
while self.stream_active:
|
||||
if time.time() > timeout_time:
|
||||
logging.debug("Timeout waiting for worker thread close.")
|
||||
raise TimeoutError("Timeout waiting for worker thread close.")
|
||||
|
|
@ -352,7 +369,7 @@ class BaseCamera(metaclass=ABCMeta):
|
|||
self.frames_iterator = self.frames()
|
||||
logging.debug("Entering worker thread.")
|
||||
|
||||
self.status["stream_active"] = True
|
||||
self.stream_active = True
|
||||
|
||||
for frame in self.frames_iterator:
|
||||
self.frame = frame
|
||||
|
|
@ -365,9 +382,7 @@ class BaseCamera(metaclass=ABCMeta):
|
|||
and ( # If using timeout
|
||||
time.time() - self.last_access > self.stream_timeout
|
||||
)
|
||||
and not self.status[ # And timeout time
|
||||
"preview_active"
|
||||
] # And GPU preview is not active
|
||||
and not self.preview_active # And GPU preview is not active
|
||||
):
|
||||
self.frames_iterator.close()
|
||||
break
|
||||
|
|
@ -383,4 +398,4 @@ class BaseCamera(metaclass=ABCMeta):
|
|||
|
||||
logging.debug("BaseCamera worker thread exiting...")
|
||||
# Set stream_activate state
|
||||
self.status["stream_active"] = False
|
||||
self.stream_active = False
|
||||
|
|
|
|||
|
|
@ -26,17 +26,13 @@ We override the logging settings in api.app by setting a level for PIL here.
|
|||
pil_logger = logging.getLogger("PIL")
|
||||
pil_logger.setLevel(logging.INFO)
|
||||
|
||||
|
||||
# MAIN CLASS
|
||||
class MockStreamer(BaseCamera):
|
||||
class MissingCamera(BaseCamera):
|
||||
def __init__(self):
|
||||
# Run BaseCamera init
|
||||
BaseCamera.__init__(self)
|
||||
|
||||
# Store state of PiCameraStreamer
|
||||
self.status.update(
|
||||
{"stream_active": False, "record_active": False, "board": None}
|
||||
)
|
||||
|
||||
# Update config properties
|
||||
self.image_resolution = (1312, 976)
|
||||
self.stream_resolution = (640, 480)
|
||||
|
|
@ -71,6 +67,16 @@ class MockStreamer(BaseCamera):
|
|||
|
||||
image.save(self.stream, format="JPEG")
|
||||
|
||||
@property
|
||||
def configuration(self):
|
||||
"""The current camera configuration."""
|
||||
return {}
|
||||
|
||||
@property
|
||||
def state(self):
|
||||
"""The current read-only camera state."""
|
||||
return {}
|
||||
|
||||
def initialisation(self):
|
||||
"""Run any initialisation code when the frame iterator starts."""
|
||||
pass
|
||||
|
|
@ -101,7 +107,7 @@ class MockStreamer(BaseCamera):
|
|||
|
||||
return conf_dict
|
||||
|
||||
def apply_settings(self, config: dict):
|
||||
def update_settings(self, config: dict):
|
||||
"""
|
||||
Write a config dictionary to the PiCameraStreamer config.
|
||||
|
||||
|
|
@ -117,7 +123,7 @@ class MockStreamer(BaseCamera):
|
|||
with self.lock:
|
||||
|
||||
# Apply valid config params to camera object
|
||||
if not self.status["record_active"]: # If not recording a video
|
||||
if not self.record_active: # If not recording a video
|
||||
|
||||
for key, value in config.items(): # For each provided setting
|
||||
if hasattr(self, key):
|
||||
|
|
|
|||
|
|
@ -47,6 +47,7 @@ from .base import BaseCamera, CaptureObject
|
|||
from .set_picamera_gain import set_analog_gain, set_digital_gain
|
||||
|
||||
from openflexure_microscope.paths import settings_file_path
|
||||
from openflexure_microscope.utilities import serialise_array_b64
|
||||
|
||||
|
||||
# MAIN CLASS
|
||||
|
|
@ -85,14 +86,7 @@ class PiCameraStreamer(BaseCamera):
|
|||
) #: :py:class:`picamera.PiCamera`: Picamera object
|
||||
|
||||
# Store status of PiCameraStreamer
|
||||
self.status.update(
|
||||
{
|
||||
"stream_active": False,
|
||||
"record_active": False,
|
||||
"preview_active": False,
|
||||
"board": f"picamera_{self.camera.revision}",
|
||||
}
|
||||
)
|
||||
self.preview_active = False
|
||||
|
||||
# Reset variable states
|
||||
self.set_zoom(1.0)
|
||||
|
|
@ -116,15 +110,37 @@ class PiCameraStreamer(BaseCamera):
|
|||
"picamera_lst.npy"
|
||||
) #: str: Path of .npy lens shading table file
|
||||
|
||||
# Update board identifier
|
||||
self.status.update({})
|
||||
|
||||
# Create an empty stream
|
||||
self.stream = io.BytesIO()
|
||||
|
||||
# Start streaming
|
||||
self.start_worker()
|
||||
|
||||
@property
|
||||
def configuration(self):
|
||||
"""The current camera configuration."""
|
||||
config = {
|
||||
"board": self.camera.revision,
|
||||
}
|
||||
|
||||
if self.read_lens_shading_table():
|
||||
b64_string, dtype, shape = serialise_array_b64(self.read_lens_shading_table())
|
||||
|
||||
config.update({
|
||||
"lens_shading_table": {
|
||||
"b64_string": b64_string,
|
||||
"dtype": dtype,
|
||||
"shape": shape,
|
||||
}
|
||||
})
|
||||
|
||||
return config
|
||||
|
||||
@property
|
||||
def state(self):
|
||||
"""The current read-only camera state."""
|
||||
return {}
|
||||
|
||||
def initialisation(self):
|
||||
"""Run any initialisation code when the frame iterator starts."""
|
||||
pass
|
||||
|
|
@ -176,7 +192,7 @@ class PiCameraStreamer(BaseCamera):
|
|||
logging.info("Saving picamera_lst to {}".format(self.picamera_lst_path))
|
||||
self.save_lens_shading_table()
|
||||
|
||||
def apply_settings(self, config: dict):
|
||||
def update_settings(self, config: dict):
|
||||
"""
|
||||
Write a config dictionary to the PiCameraStreamer config.
|
||||
|
||||
|
|
@ -194,10 +210,10 @@ class PiCameraStreamer(BaseCamera):
|
|||
with self.lock:
|
||||
|
||||
# Apply valid config params to Picamera object
|
||||
if not self.status["record_active"]: # If not recording a video
|
||||
if not self.record_active: # If not recording a video
|
||||
|
||||
# Pause stream while changing settings
|
||||
if self.status["stream_active"]: # If stream is active
|
||||
if self.stream_active: # If stream is active
|
||||
logging.info("Pausing stream to update config.")
|
||||
self.stop_stream_recording() # Pause stream
|
||||
paused_stream = True # Remember to unpause stream when done
|
||||
|
|
@ -365,7 +381,7 @@ class PiCameraStreamer(BaseCamera):
|
|||
self.camera.preview.window = window
|
||||
if fullscreen:
|
||||
self.camera.preview.fullscreen = fullscreen
|
||||
self.status["preview_active"] = True
|
||||
self.preview_active = True
|
||||
except picamera.exc.PiCameraMMALError as e:
|
||||
logging.error(
|
||||
"Suppressed a MMALError in start_preview. Exception: {}".format(e)
|
||||
|
|
@ -380,7 +396,7 @@ class PiCameraStreamer(BaseCamera):
|
|||
def stop_preview(self):
|
||||
"""Stop the on board GPU camera preview."""
|
||||
self.camera.stop_preview()
|
||||
self.status["preview_active"] = False
|
||||
self.preview_active = False
|
||||
|
||||
def start_recording(self, output, fmt: str = "h264", quality: int = 15):
|
||||
"""Start recording.
|
||||
|
|
@ -398,7 +414,7 @@ class PiCameraStreamer(BaseCamera):
|
|||
"""
|
||||
with self.lock:
|
||||
# Start recording method only if a current recording is not running
|
||||
if not self.status["record_active"]:
|
||||
if not self.record_active:
|
||||
|
||||
# Start the camera video recording on port 2
|
||||
logging.info("Recording to {}".format(output))
|
||||
|
|
@ -412,7 +428,7 @@ class PiCameraStreamer(BaseCamera):
|
|||
)
|
||||
|
||||
# Update status dictionary
|
||||
self.status["record_active"] = True
|
||||
self.record_active = True
|
||||
|
||||
return output
|
||||
|
||||
|
|
@ -432,7 +448,7 @@ class PiCameraStreamer(BaseCamera):
|
|||
logging.info("Recording stopped")
|
||||
|
||||
# Update status dictionary
|
||||
self.status["record_active"] = False
|
||||
self.record_active = False
|
||||
|
||||
def stop_stream_recording(
|
||||
self, splitter_port: int = 1, resolution: Tuple[int, int] = None
|
||||
|
|
@ -500,7 +516,7 @@ class PiCameraStreamer(BaseCamera):
|
|||
self.camera.resolution = resolution
|
||||
|
||||
# If the stream should be active
|
||||
if self.status["stream_active"]:
|
||||
if self.stream_active:
|
||||
try:
|
||||
# Start recording on stream port
|
||||
self.camera.start_recording(
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue