import logging import threading import time import cv2 from flask import Flask, Response, render_template_string app = Flask(__name__) logging.basicConfig( level=logging.INFO, format="%(asctime)s - %(levelname)s - %(message)s" ) class UsbCamera: def __init__(self, device_index=0, resolution=(640, 480), framerate=30): self.device_index = device_index self.resolution = resolution self.framerate = framerate self.cap = None self.frame = None self.lock = threading.Lock() self.running = False self.thread = None def start(self): self.cap = cv2.VideoCapture(self.device_index) if not self.cap.isOpened(): raise RuntimeError(f"Cannot open camera device {self.device_index}") self.cap.set(cv2.CAP_PROP_FRAME_WIDTH, self.resolution[0]) self.cap.set(cv2.CAP_PROP_FRAME_HEIGHT, self.resolution[1]) self.cap.set(cv2.CAP_PROP_FPS, self.framerate) # Give the driver a moment to apply settings time.sleep(0.5) self.running = True self.thread = threading.Thread(target=self._capture, daemon=True) self.thread.start() logging.info("USB camera started.") def _capture(self): while self.running: ret, img = self.cap.read() if not ret: logging.warning("Failed to read frame from camera.") time.sleep(0.05) continue ret2, buf = cv2.imencode(".jpg", img) if ret2: with self.lock: self.frame = buf.tobytes() # Throttle slightly to avoid maxing CPU time.sleep(1.0 / max(self.framerate, 1)) def get_frame(self): with self.lock: return self.frame def stop(self): self.running = False if self.thread: self.thread.join(timeout=2.0) if self.cap: self.cap.release() logging.info("USB camera stopped.") camera = None HTML_PAGE = """
{{ resolution }} @ {{ framerate }} fps