11import time
22import 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
554class 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