From 43c8fea37f531dab10f392a03838a8af1b9dc376 Mon Sep 17 00:00:00 2001 From: Joel Collins Date: Fri, 27 Mar 2020 15:07:11 +0000 Subject: [PATCH] Use LabThings ClientEvent --- openflexure_microscope/camera/base.py | 55 +++------------------------ 1 file changed, 6 insertions(+), 49 deletions(-) diff --git a/openflexure_microscope/camera/base.py b/openflexure_microscope/camera/base.py index e203f44f..2d1e930a 100644 --- a/openflexure_microscope/camera/base.py +++ b/openflexure_microscope/camera/base.py @@ -3,16 +3,18 @@ import time import os import shutil import threading -import gevent.event import datetime import logging +import threading + from abc import ABCMeta, abstractmethod from collections import OrderedDict from .capture import CaptureObject, build_captures_from_exif from openflexure_microscope.utilities import entry_by_uuid from labthings.core.lock import StrictLock +from labthings.core.event import ClientEvent from openflexure_microscope.paths import data_file_path @@ -45,51 +47,6 @@ def generate_numbered_basename(obj_list: list) -> str: return basename -class CameraEvent(object): - """ - A frame-signaller object used by any instances or subclasses of BaseCamera. - - An event-like class that signals all active clients when a new frame is available. - """ - - def __init__(self): - self.events = {} - - def wait(self, timeout: int = 5): - """Wait for the next frame (invoked from each client's thread).""" - ident = threading.get_ident() - if ident not in self.events: - # this is a new client - # add an entry for it in the self.events dict - # each entry has two elements, a threading.Event() and a timestamp - self.events[ident] = [gevent.event.Event(), time.time()] - return self.events[ident][0].wait(timeout) - - def set(self): - """Signal that a new frame is available.""" - now = time.time() - remove = None - for ident, event in self.events.items(): - if not event[0].isSet(): - # if this client's event is not set, then set it - # also update the last set timestamp to now - event[0].set() - event[1] = now - else: - # if the client's event is already set, it means the client - # did not process a previous frame - # if the event stays set for more than 5 seconds, then assume - # the client is gone and remove it - if now - event[1] > 5: - remove = ident - if remove: - del self.events[remove] - - def clear(self): - """Clear frame event, once processed.""" - self.events[threading.get_ident()][0].clear() - - class BaseCamera(metaclass=ABCMeta): """ Base implementation of StreamingCamera. @@ -99,11 +56,11 @@ class BaseCamera(metaclass=ABCMeta): self.thread = None self.camera = None - self.lock = StrictLock(timeout=1) + self.lock = StrictLock(timeout=1, name="Camera") self.frame = None self.last_access = 0 - self.event = CameraEvent() + self.event = ClientEvent() self.stop = False # Used to indicate that the stream loop should break self.stream_timeout = 20 @@ -307,6 +264,7 @@ class BaseCamera(metaclass=ABCMeta): self.stop = False if not self.stream_active: + # Spawn a greenlet to handle stream # start background frame thread self.thread = threading.Thread(target=self._thread) self.thread.daemon = True @@ -368,7 +326,6 @@ class BaseCamera(metaclass=ABCMeta): for frame in self.frames_iterator: self.frame = frame self.event.set() # send signal to clients - time.sleep(0) # Handle timeout if (