| import threading |
| from queue import Queue |
| import queue |
| import cv2 |
|
|
| from CPR_Module.Common.logging_config import cpr_logger |
|
|
| class ThreadedCamera: |
| def __init__(self, source, requested_fps = 30): |
|
|
| |
| self.cap = cv2.VideoCapture(source) |
| if not self.cap.isOpened(): |
| raise ValueError(f"[VIDEO CAPTURE] Unable to open camera source: {source}") |
| cpr_logger.info(f"[VIDEO CAPTURE] Camera source opened: {source}") |
|
|
| |
| |
| |
| set_success = self.cap.set(cv2.CAP_PROP_FPS, requested_fps) |
|
|
| |
| |
| actual_fps = self.cap.get(cv2.CAP_PROP_FPS) |
| self.fps = actual_fps |
|
|
| cpr_logger.info(f"[VIDEO CAPTURE] Requested FPS: {requested_fps}, Set Success: {set_success}, Actual FPS: {actual_fps}") |
|
|
| |
| number_of_seconds_to_buffer = 5 |
| queue_size = int(actual_fps * number_of_seconds_to_buffer) |
| self.q = Queue(maxsize=queue_size) |
| cpr_logger.info(f"[VIDEO CAPTURE] Queue size: {queue_size}") |
|
|
| |
| self.running = threading.Event() |
| self.running.set() |
| cpr_logger.info(f"[VIDEO CAPTURE] Camera running: {self.running.is_set()}") |
|
|
| self.number_of_total_frames = 0 |
| self.number_of_dropped_frames = 0 |
|
|
| self.thread = None |
|
|
| def start_capture(self): |
| |
| while not self.q.empty(): |
| self.q.get() |
|
|
| |
| |
| self.thread = threading.Thread(target=self._reader) |
| cpr_logger.info(f"[VIDEO CAPTURE] Thread initialized: {self.thread}") |
| |
| |
| |
| |
| self.thread.daemon = True |
| cpr_logger.info(f"[VIDEO CAPTURE] Thread daemon: {self.thread.daemon}") |
|
|
| |
| |
| self.thread.start() |
|
|
| def _reader(self): |
| while self.running.is_set(): |
| ret, frame = self.cap.read() |
| if not ret: |
| cpr_logger.info("Camera disconnected") |
| self.q.put(None) |
| break |
| |
| try: |
| self.number_of_total_frames += 1 |
| self.q.put(frame, timeout=0.1) |
| except queue.Full: |
| cpr_logger.info("Frame dropped") |
| self.number_of_dropped_frames += 1 |
|
|
| def read(self): |
| return self.q.get() |
|
|
| def release(self): |
| |
| cpr_logger.error(f"[VIDEO CAPTURE] Total frames: {self.number_of_total_frames}, Dropped frames: {self.number_of_dropped_frames}") |
| |
| self.running.clear() |
| |
| |
| self.cap.release() |
| |
| |
| self.thread.join(timeout=1.0) |
| |
| if self.thread.is_alive(): |
| cpr_logger.info("Warning: Thread didn't terminate cleanly") |
| |
|
|
| def isOpened(self): |
| return self.running.is_set() and self.cap.isOpened() |
|
|
| def __del__(self): |
| if self.running.is_set(): |
| self.release() |