From b64b0ac48701329c7be97fb4d7c30c9ad47674c5 Mon Sep 17 00:00:00 2001 From: Nick Mowen Date: Mon, 1 May 2023 12:26:59 -0600 Subject: [PATCH] Fix snapshot saving --- frigate/events/external.py | 37 +++++++++++++++++++++++++++++++++---- frigate/http.py | 7 ++++++- 2 files changed, 39 insertions(+), 5 deletions(-) diff --git a/frigate/events/external.py b/frigate/events/external.py index 38f78778e..b414c9371 100644 --- a/frigate/events/external.py +++ b/frigate/events/external.py @@ -1,7 +1,9 @@ """Handle external events created by the user.""" +import cv2 import datetime import logging +import os import random import string @@ -9,9 +11,9 @@ from typing import Optional from multiprocessing.queues import Queue -from frigate.config import FrigateConfig +from frigate.config import CameraConfig, FrigateConfig +from frigate.const import CLIPS_DIR from frigate.events.maintainer import EventTypeEnum -from frigate.models import Event logger = logging.getLogger(__name__) @@ -28,6 +30,7 @@ class ExternalEventProcessor: sub_label: Optional[str], duration: Optional[int], include_recording: bool, + snapshot_frame: any, ) -> str: now = datetime.datetime.now().timestamp() camera_config = self.config.cameras.get(camera) @@ -36,6 +39,7 @@ class ExternalEventProcessor: rand_id = "".join(random.choices(string.ascii_lowercase + string.digits, k=6)) event_id = f"{now}-{rand_id}" + self._write_snapshots(camera_config, event_id, snapshot_frame) self.queue.put( ( EventTypeEnum.api, @@ -50,16 +54,41 @@ class ExternalEventProcessor: "end_time": now + duration if duration is not None else None, "thumbnail": "", # TODO create thumbnail icon "has_clip": camera_config.record.enabled and include_recording, - "has_snapshot": False, # TODO get snapshot frame passed in + "has_snapshot": True, }, ) ) return event_id - def finish_manual_event(self, event_id: str): + def finish_manual_event(self, event_id: str) -> None: """Finish external event with indeterminate duration.""" now = datetime.datetime.now().timestamp() self.queue.put( (EventTypeEnum.api, "end", None, {"id": event_id, "end_time": now}) ) + + def _write_snapshots( + self, camera_config: CameraConfig, event_id: str, img_bytes: any + ) -> None: + # write jpg snapshot + ret, jpg = cv2.imencode(".jpg", img_bytes) + with open( + os.path.join(CLIPS_DIR, f"{camera_config.name}-{event_id}.jpg"), + "wb", + ) as j: + j.write(jpg.tobytes()) + + # write clean snapshot if enabled + if camera_config.snapshots.clean_copy: + ret, png = cv2.imencode(".png", img_bytes) + + if ret: + with open( + os.path.join( + CLIPS_DIR, + f"{camera_config.name}-{event_id}-clean.png", + ), + "wb", + ) as p: + p.write(png.tobytes()) diff --git a/frigate/http.py b/frigate/http.py index e99d361e6..9de68f398 100644 --- a/frigate/http.py +++ b/frigate/http.py @@ -859,16 +859,21 @@ def create_event(camera_name, label): json: dict[str, any] = request.get_json(silent=True) or {} try: + frame = current_app.detected_frames_processor.get_current_frame(camera_name) + event_id = current_app.external_processor.create_manual_event( camera_name, label, json.get("sub_label", None), json.get("duration", 30), json.get("include_recording", True), + frame, ) except Exception as e: logger.error(f"The error is {e}") - return jsonify({"success": False, "message": f"An unknown error occurred: {e}"}, 404) + return jsonify( + {"success": False, "message": f"An unknown error occurred: {e}"}, 404 + ) return jsonify( {