From 646dc24a9126a4bd77d4440df84659e93711f56b Mon Sep 17 00:00:00 2001 From: Joel Collins Date: Thu, 17 Jan 2019 12:23:54 +0000 Subject: [PATCH] Fixed captures trying to restart recording for a stopped stream --- openflexure_microscope/camera/base.py | 4 + openflexure_microscope/camera/pi.py | 106 ++++++++++++-------------- 2 files changed, 51 insertions(+), 59 deletions(-) diff --git a/openflexure_microscope/camera/base.py b/openflexure_microscope/camera/base.py index 944482e6..0a5b31b9 100644 --- a/openflexure_microscope/camera/base.py +++ b/openflexure_microscope/camera/base.py @@ -313,6 +313,8 @@ class BaseCamera(object): self.frames_iterator = self.frames() logging.debug("Entering worker thread.") + self.state['stream_active'] = True + for frame in self.frames_iterator: self.frame = frame self.event.set() # send signal to clients @@ -337,5 +339,7 @@ class BaseCamera(object): pass logging.debug("BaseCamera worker thread exiting...") + # Set stream_activate state + self.state['stream_active'] = False # Reset thread self.thread = None diff --git a/openflexure_microscope/camera/pi.py b/openflexure_microscope/camera/pi.py index 23551989..7b4a52ee 100644 --- a/openflexure_microscope/camera/pi.py +++ b/openflexure_microscope/camera/pi.py @@ -210,7 +210,7 @@ class StreamingCamera(BaseCamera): # Pause stream while changing settings if self.state['stream_active']: # If stream is active logging.info("Pausing stream to update config.") - self.pause_stream() # Pause stream + self.stop_stream_recording() # Pause stream paused_stream = True # Remember to unpause stream when done # PiCamera parameters (applied directly to PiCamera object) @@ -239,7 +239,7 @@ class StreamingCamera(BaseCamera): # If stream was paused to update config, unpause if paused_stream: logging.info("Resuming stream.") - self.resume_stream() + self.start_stream_recording() else: raise Exception( @@ -342,18 +342,17 @@ class StreamingCamera(BaseCamera): # Update state dictionary self.state['record_active'] = False - def pause_stream( + def stop_stream_recording( self, splitter_port: int=1, resolution: Tuple[int, int]=None) -> None: """ - Pause capture on a splitter port. + Sets the camera resolution to the still-image resolution, and stops recording if the stream is active. Args: splitter_port (int): Splitter port to stop recording on resolution ((int, int)): Resolution to set the camera to, after stopping recording. """ - logging.debug("Pausing stream") # If no resolution is specified, default to image_resolution if not resolution: resolution = self.config['image_resolution'] @@ -361,36 +360,46 @@ class StreamingCamera(BaseCamera): # Stop the camera video recording on port 1 try: self.camera.stop_recording(splitter_port=splitter_port) + logging.info("Stopped MJPEG stream on port {1}. Switching to {0}.".format(resolution, splitter_port)) except picamera.exc.PiCameraNotRecording: logging.info("Not recording on splitter_port {}".format(splitter_port)) # Increase the resolution for taking an image self.camera.resolution = resolution - def resume_stream( + def start_stream_recording( self, splitter_port: int=1, resolution: Tuple[int, int]=None) -> None: """ - Resume capture on a splitter port. + Sets the camera resolution to the video/stream resolution, and starts recording if the stream should be active. Args: splitter_port (int): Splitter port to start recording on - resolution ((int, int)): Resolution to set the camera to, before starting recording. + resolution ((int, int)): Resolution to set the camera to, before starting recording. Defaults to `self.config['video_resolution']`. """ - logging.debug("Resuming stream") + + # If no stream object exists + if not hasattr(self, 'stream'): + self.stream = io.BytesIO() # Create a stream object + + # If no explicit resolution is passed if not resolution: - resolution = self.config['video_resolution'] + resolution = self.config['video_resolution'] # Default to video recording resolution # Reduce the resolution for video streaming self.camera.resolution = resolution - # Resume the video channel - self.camera.start_recording( - self.stream, - format='mjpeg', - quality=self.config['jpeg_quality'], - splitter_port=splitter_port) + # If the stream should be active + if self.state['stream_active']: + # Start recording on stream port + self.camera.start_recording( + self.stream, + format='mjpeg', + quality=self.config['jpeg_quality'], + splitter_port=splitter_port) + + logging.debug("Started MJPEG stream at {} on port {}".format(resolution, splitter_port)) def capture( self, @@ -421,31 +430,21 @@ class StreamingCamera(BaseCamera): logging.info("Capturing to {}".format(output)) - - # TODO: Do we really always want bayer data for full captures? + # Set resolution and stop stream recording if necesarry if not use_video_port: + self.stop_stream_recording() - # Pause video splitter port 1 - self.pause_stream() + self.camera.capture( + output_stream, + format=fmt, + quality=100, + resize=resize, + bayer=(not use_video_port) and bayer, + use_video_port=use_video_port) - self.camera.capture( - output_stream, - format=fmt, - quality=100, - resize=resize, - bayer=bayer) - - # Resume video splitter port 1 - self.resume_stream() - - else: - self.camera.capture( - output_stream, - format=fmt, - quality=100, - resize=resize, - bayer=False, - use_video_port=bayer) + # Set resolution and start stream recording if necesarry + if not use_video_port: + self.start_stream_recording() return output @@ -471,7 +470,7 @@ class StreamingCamera(BaseCamera): size = resolution if not use_video_port: - self.pause_stream(resolution=resolution) + self.stop_stream_recording(resolution=resolution) logging.debug("Creating PiYUVArray") with picamera.array.PiYUVArray(self.camera, size=size) as output: @@ -485,7 +484,7 @@ class StreamingCamera(BaseCamera): use_video_port=use_video_port) if not use_video_port: - self.resume_stream() + self.start_stream_recording() if rgb: logging.debug("Converting to RGB") @@ -515,7 +514,7 @@ class StreamingCamera(BaseCamera): size = resolution # Always pause stream, to prevent resizer memory issues - self.pause_stream(resolution=resolution) + self.stop_stream_recording(resolution=resolution) logging.debug("Creating PiRGBArray") with picamera.array.PiRGBArray(self.camera, size=size) as output: @@ -529,7 +528,7 @@ class StreamingCamera(BaseCamera): use_video_port=use_video_port) # Resume stream - self.resume_stream() + self.start_stream_recording() return output.array @@ -544,25 +543,14 @@ class StreamingCamera(BaseCamera): """ # Run this initialisation method self.initialisation() - self.wait_for_camera() - # Set stream resolution - self.camera.resolution = self.config['video_resolution'] - - # Create stream - self.stream = io.BytesIO() - - # Start recording on video splitter port 1 - self.camera.start_recording( - self.stream, - format='mjpeg', - quality=self.config['jpeg_quality'], - splitter_port=1) + # Start stream recording (and set resolution) + self.start_stream_recording() # Update state logging.debug("STREAM ACTIVE") - self.state['stream_active'] = True + #self.state['stream_active'] = True # While the iterator is not closed try: @@ -582,7 +570,7 @@ class StreamingCamera(BaseCamera): yield frame # When GeneratorExit or StopIteration raised, run cleanup code finally: - logging.debug("Stopping stream recording on port 1") - self.camera.stop_recording(splitter_port=1) - self.state['stream_active'] = False + # Stop stream recording (and set resolution) + self.stop_stream_recording() + logging.debug("FRAME ITERATOR END")