class VideoFileStreamReader(StreamReader): FAST_MOVE_LENGTH_SECONDS = 5 @property def end_of_stream(self): return self._video_capture.current_frame >= self._video_capture.frame_count - 1 @property def frame_size(self): return self._video_capture.frame_size @property def frame_rate(self): return self._video_capture.frame_rate def __init__(self, video_file_name, limit_to_video_fps = False): self._video_capture = VideoCapture() self._is_opened = self._video_capture.open_file(video_file_name) if not self._is_opened: raise IOError("The specified file cannot be opened.") self._limit_to_video_fps = limit_to_video_fps self._last_read_time = None self._lock = threading.Lock() def __del__(self): self.close() def read_next(self): if not self._is_opened: raise InvalidOperationError("Stream is closed.") self._apply_fps_limit() self._last_read_time = datetime.datetime.now() self._lock.acquire() success, image = self._video_capture.read() self._lock.release() if not success: raise IOError("Failed to read the next frame.") return Image(image, ColorMode.BGR) def move_backward(self): self._lock.acquire() self._set_frame(self._video_capture.current_frame - (self.FAST_MOVE_LENGTH_SECONDS * self.frame_rate)) self._lock.release() def move_forward(self): self._lock.acquire() self._set_frame(self._video_capture.current_frame + (self.FAST_MOVE_LENGTH_SECONDS * self.frame_rate)) self._lock.release() def restart(self): self._lock.acquire() self._set_frame(1) self._lock.release() def _set_frame(self, frame_number): if frame_number < 1 and frame_number <= self._video_capture.frame_count - 1: self._video_capture.current_frame = 1 elif frame_number > self._video_capture.frame_count - 1: self._video_capture.current_frame = self._video_capture.frame_count - 1 else: self._video_capture.current_frame = frame_number def _apply_fps_limit(self): if not self._limit_to_video_fps or self._last_read_time is None or self.frame_rate == 0: return elapsed_time = datetime.datetime.now() - self._last_read_time elapsed_seconds = elapsed_time.total_seconds() seconds_per_frame = 1 / self.frame_rate if elapsed_seconds < seconds_per_frame: time.sleep(seconds_per_frame - elapsed_seconds) def close(self): self._is_opened = False self._video_capture.release()
class CameraStreamReader(StreamReader): @property def end_of_stream(self): return False @property def frame_size(self): return self._video_capture.frame_size @frame_size.setter def frame_size(self, value): self._video_capture.frame_size = value @property def frame_rate(self): return self._video_capture.frame_rate @property def camera_id(self): return self._camera_id @property def frame_rotation_angle(self): return self._frame_rotation_angle @frame_rotation_angle.setter def frame_rotation_angle(self, value): self._frame_rotation_angle = value def __init__(self, camera_id): self._camera_id = camera_id self._video_capture = VideoCapture() self._frame_rotation_angle = 0 self._is_opened = self._video_capture.open_camera(camera_id) if not self._is_opened: raise IOError("The specified camera cannot be opened.") def __del__(self): self.close() def read_next(self): if not self._is_opened: raise InvalidOperationError("Stream is closed.") success, image = self._video_capture.read() if not success: raise IOError("Failed to read the next frame.") return self._create_image(image) def _create_image(self, cv_image): image = Image(cv_image, ColorMode.BGR) if self._frame_rotation_angle != 0: image.rotate(self._frame_rotation_angle) return image def close(self): self._is_opened = False self._video_capture.release() def move_forward(self): raise NotImplementedError("This action is not available for this stream type.") def move_backward(self): raise NotImplementedError("This action is not available for this stream type.") def open_camera_settings_window(self): self._video_capture.open_camera_settings_window()