Initial commit for web interface
Change-Id: I133eaf37221a050eb3c87e245b86ae54c610d446
diff --git a/person_detection/base_camera.py b/person_detection/base_camera.py
new file mode 100644
index 0000000..96c148a
--- /dev/null
+++ b/person_detection/base_camera.py
@@ -0,0 +1,101 @@
+import time
+import threading
+try:
+ from greenlet import getcurrent as get_ident
+except ImportError:
+ try:
+ from thread import get_ident
+ except ImportError:
+ from _thread import get_ident
+
+
+class CameraEvent(object):
+ """An Event-like class that signals all active clients when a new frame is
+ available.
+ """
+ def __init__(self):
+ self.events = {}
+
+ def wait(self):
+ """Invoked from each client's thread to wait for the next frame."""
+ ident = 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] = [threading.Event(), time.time()]
+ return self.events[ident][0].wait()
+
+ def set(self):
+ """Invoked by the camera thread when 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):
+ """Invoked from each client's thread after a frame was processed."""
+ self.events[get_ident()][0].clear()
+
+
+class BaseCamera(object):
+ thread = None # background thread that reads frames from camera
+ frame = None # current frame is stored here by background thread
+ last_access = 0 # time of last client access to the camera
+ event = CameraEvent()
+
+ def __init__(self):
+ """Start the background camera thread if it isn't running yet."""
+ if BaseCamera.thread is None:
+ BaseCamera.last_access = time.time()
+
+ # start background frame thread
+ BaseCamera.thread = threading.Thread(target=self._thread)
+ BaseCamera.thread.start()
+
+ # wait until frames are available
+ while self.get_frame() is None:
+ time.sleep(0)
+
+ def get_frame(self):
+ """Return the current camera frame."""
+ BaseCamera.last_access = time.time()
+
+ # wait for a signal from the camera thread
+ BaseCamera.event.wait()
+ BaseCamera.event.clear()
+
+ return BaseCamera.frame
+
+ def frames():
+ """"Generator that returns frames from the camera."""
+ raise RuntimeError('Must be implemented by subclasses.')
+
+ def _thread(self):
+ """Camera background thread."""
+ frames_iterator = self.frames()
+ for frame in frames_iterator:
+ BaseCamera.frame = frame
+ BaseCamera.event.set() # send signal to clients
+ time.sleep(0)
+
+ # if there hasn't been any clients asking for frames in
+ # the last 10 seconds then stop the thread
+ if time.time() - BaseCamera.last_access > 10:
+ frames_iterator.close()
+ print('Stopping camera thread due to inactivity.')
+ break
+ BaseCamera.thread = None