Skip to content

Commit a5fe6e2

Browse files
add event signals for video frames
1 parent 4be700c commit a5fe6e2

File tree

1 file changed

+56
-0
lines changed

1 file changed

+56
-0
lines changed

base_camera.py

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,61 @@
11
import time
22
import threading
3+
try:
4+
from greenlet import getcurrent as get_ident
5+
except ImportError:
6+
try:
7+
from thread import get_ident
8+
except ImportError:
9+
from _thread import get_ident
10+
11+
12+
class CameraEvent(object):
13+
"""An Event-like class that signals all active clients when a new frame is
14+
available.
15+
"""
16+
def __init__(self):
17+
self.events = {}
18+
19+
def wait(self):
20+
"""Invoked from each client's thread to wait for the next frame."""
21+
ident = get_ident()
22+
if ident not in self.events:
23+
# this is a new client
24+
# add an entry for it in the self.events dict
25+
# each entry has two elements, a threading.Event() and a timestamp
26+
self.events[ident] = [threading.Event(), time.time()]
27+
return self.events[ident][0].wait()
28+
29+
def set(self):
30+
"""Invoked by the camera thread when a new frame is available."""
31+
now = time.time()
32+
remove = None
33+
for ident, event in self.events.items():
34+
if not event[0].isSet():
35+
# if this client's event is not set, then set it
36+
# also update the last set timestamp to now
37+
event[0].set()
38+
event[1] = now
39+
else:
40+
# if the client's event is already set, it means the client
41+
# did not process a previous frame
42+
# if the event stays set for more than 5 seconds, then assume
43+
# the client is gone and remove it
44+
if now - event[1] > 5:
45+
remove = ident
46+
if remove:
47+
del self.events[remove]
48+
49+
def clear(self):
50+
"""Invoked from each client's thread after a frame was processed."""
51+
self.events[get_ident()][0].clear()
352

453

554
class BaseCamera(object):
655
thread = None # background thread that reads frames from camera
756
frame = None # current frame is stored here by background thread
857
last_access = 0 # time of last client access to the camera
58+
event = CameraEvent()
959

1060
def __init__(self):
1161
"""Start the background camera thread if it isn't running yet."""
@@ -21,6 +71,11 @@ def __init__(self):
2171
def get_frame(self):
2272
"""Return the current camera frame."""
2373
BaseCamera.last_access = time.time()
74+
75+
# wait for a signal from the camera thread
76+
BaseCamera.event.wait()
77+
BaseCamera.event.clear()
78+
2479
return BaseCamera.frame
2580

2681
@staticmethod
@@ -35,6 +90,7 @@ def _thread(cls):
3590
frames_iterator = cls.frames()
3691
for frame in frames_iterator:
3792
BaseCamera.frame = frame
93+
BaseCamera.event.set() # send signal to clients
3894

3995
# if there hasn't been any clients asking for frames in
4096
# the last 10 seconds then stop the thread

0 commit comments

Comments
 (0)