import threading import time from concurrent.futures import ThreadPoolExecutor from urllib.parse import urlparse from . import config from .detector import MockDetector, ONNXDetector def _detector(): if config.MODEL_MODE == "onnx": return ONNXDetector(config.MODEL_PATH, tuple(config.MODEL_LABELS)) return MockDetector(class_name=config.MOCK_CLASS, confidence=config.MOCK_CONFIDENCE) def is_allowed_stream_ref(stream_ref): url = (stream_ref or {}).get("url", "") parsed = urlparse(url) if parsed.scheme not in ("rtsp", "http", "https"): return False if parsed.username or parsed.password: return False host = (parsed.hostname or "").lower() allowed = {item.strip().lower() for item in config.ALLOWED_STREAM_HOSTS} return host in allowed class StreamTaskWorker: def __init__(self, max_workers=2): self.executor = ThreadPoolExecutor(max_workers=max_workers) self.tasks = {} self.lock = threading.Lock() def submit(self, task_id, stream_ref): with self.lock: self.tasks[task_id] = { "taskId": task_id, "status": "queued", "startedAt": time.time(), "finishedAt": None, "frames": 0, "detections": [], "error": None, } self.executor.submit(self._run, task_id, stream_ref) def get(self, task_id): with self.lock: task = self.tasks.get(task_id) return dict(task) if task else None def _run(self, task_id, stream_ref): try: with self.lock: task = self.tasks.get(task_id) if task: task["status"] = "running" try: import cv2 except ImportError: self._fail(task_id, "OpenCV 未安装,无法拉流") return capture = cv2.VideoCapture(stream_ref.get("url", "")) if not capture.isOpened(): self._fail(task_id, "无法连接视频流") return max_frames = min(int(stream_ref.get("maxFrames", config.STREAM_TASK_MAX_FRAMES)), config.STREAM_TASK_MAX_FRAMES) detector = _detector() frames = 0 detections = [] try: while frames < max_frames: ok, frame = capture.read() if not ok: break ok_encode, buf = cv2.imencode(".jpg", frame) if ok_encode: detections.extend(detector.detect(buf.tobytes())) frames += 1 finally: capture.release() with self.lock: task = self.tasks.get(task_id) if task: task["status"] = "completed" task["frames"] = frames task["detections"] = detections[:10] task["finishedAt"] = time.time() except Exception as exc: self._fail(task_id, str(exc)) def _fail(self, task_id, message): with self.lock: task = self.tasks.get(task_id) if task: task["status"] = "failed" task["error"] = message task["finishedAt"] = time.time()