Remove separate camera stream thread

This commit is contained in:
Joel Collins 2020-11-17 16:19:55 +00:00
parent 94bc49cd5c
commit 021745da26
5 changed files with 137 additions and 232 deletions

View file

@ -3,6 +3,7 @@
from __future__ import division
import logging
import threading
import time
from datetime import datetime
@ -35,7 +36,11 @@ class MissingCamera(BaseCamera):
self.generate_new_dummy_image()
# Start streaming
self.stop = False # Used to indicate that the stream loop should break
self.start_worker()
# Wait until frames are available
logging.info("Waiting for frames")
self.stream.new_frame.wait()
def generate_new_dummy_image(self):
# Create a dummy image to serve in the stream
@ -55,6 +60,60 @@ class MissingCamera(BaseCamera):
image.save(self.stream, format="JPEG")
def start_worker(self, **_) -> bool:
"""Start the background camera thread if it isn't running yet."""
self.stop = False
if not self.stream_active:
# Start background frame thread
self.thread = threading.Thread(target=self._thread)
self.thread.daemon = True
self.thread.start()
return True
def stop_worker(self, timeout: int = 5) -> bool:
"""Flag worker thread for stop. Waits for thread close or timeout."""
logging.debug("Stopping worker thread")
timeout_time = time.time() + timeout
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.stream_active:
if time.time() > timeout_time:
logging.debug("Timeout waiting for worker thread close.")
raise TimeoutError("Timeout waiting for worker thread close.")
else:
time.sleep(0.1)
return True
def _thread(self):
"""Camera background thread."""
# Set the camera object's frame iterator
logging.debug("Entering worker thread.")
self.stream_active = True
while True:
# Only serve frames at 1fps
time.sleep(1)
# Generate new dummy image
self.generate_new_dummy_image()
try:
if self.stop is True:
logging.debug("Worker thread flagged for stop.")
break
except AttributeError:
pass
logging.debug("BaseCamera worker thread exiting...")
# Set stream_activate state
self.stream_active = False
@property
def configuration(self):
"""The current camera configuration."""
@ -65,9 +124,6 @@ class MissingCamera(BaseCamera):
"""The current read-only camera state."""
return {}
def initialisation(self):
"""Run any initialisation code when the frame iterator starts."""
def close(self):
"""Close the Raspberry Pi PiCameraStreamer."""
# Run BaseCamera close method
@ -181,28 +237,3 @@ class MissingCamera(BaseCamera):
output.close()
else:
output.flush()
# HANDLE STREAM FRAMES
def frames(self):
"""
Create generator that returns frames from the camera.
"""
# Run this initialisation method
self.initialisation()
# Update state
logging.debug("STREAM ACTIVE")
# While the iterator is not closed
try:
while True:
time.sleep(1) # Only serve frames at 1fps
# Generate new dummy image
self.generate_new_dummy_image()
# Wait for the next frame and then yield it
yield self.stream.getframe()
# When GeneratorExit or StopIteration raised, run cleanup code
finally:
logging.debug("FRAME ITERATOR END")