From 4216d080998ce20b6fa299df3fbd3649a102a31d Mon Sep 17 00:00:00 2001 From: Nicolas Mowen Date: Thu, 9 May 2024 07:20:33 -0600 Subject: [PATCH] Backend and webui fixes (#11309) * Ensure that items without end times are set to not have a snapshot * Save full frame if no frame is currently saved * Webui fixes * Cleanup --- frigate/app.py | 6 ++-- frigate/review/maintainer.py | 34 +++++++++++++++++++ .../player/dynamic/DynamicVideoPlayer.tsx | 2 +- web/src/hooks/use-camera-previews.ts | 2 +- 4 files changed, 39 insertions(+), 5 deletions(-) diff --git a/frigate/app.py b/frigate/app.py index c2a489b75..1fce7c1ac 100644 --- a/frigate/app.py +++ b/frigate/app.py @@ -683,9 +683,9 @@ class FrigateApp: self.stop_event.set() # set an end_time on entries without an end_time before exiting - Event.update(end_time=datetime.datetime.now().timestamp()).where( - Event.end_time == None - ).execute() + Event.update( + end_time=datetime.datetime.now().timestamp(), has_snapshot=False + ).where(Event.end_time == None).execute() ReviewSegment.update(end_time=datetime.datetime.now().timestamp()).where( ReviewSegment.end_time == None ).execute() diff --git a/frigate/review/maintainer.py b/frigate/review/maintainer.py index 8963c555c..77d3d2a6b 100644 --- a/frigate/review/maintainer.py +++ b/frigate/review/maintainer.py @@ -110,6 +110,18 @@ class PendingReviewSegment: self.frame_path, self.frame, [int(cv2.IMWRITE_WEBP_QUALITY), 60] ) + def save_full_frame(self, camera_config: CameraConfig, frame): + color_frame = cv2.cvtColor(frame, cv2.COLOR_YUV2BGR_I420) + width = int(THUMB_HEIGHT * color_frame.shape[1] / color_frame.shape[0]) + self.frame = cv2.resize( + color_frame, dsize=(width, THUMB_HEIGHT), interpolation=cv2.INTER_AREA + ) + + if self.frame is not None: + cv2.imwrite( + self.frame_path, self.frame, [int(cv2.IMWRITE_WEBP_QUALITY), 60] + ) + def get_data(self, ended: bool) -> dict: return { ReviewSegment.id: self.id, @@ -273,8 +285,30 @@ class ReviewSegmentMaintainer(threading.Thread): if segment.severity == SeverityEnum.alert and frame_time > ( segment.last_update + THRESHOLD_ALERT_ACTIVITY ): + if segment.frame is None: + try: + frame_id = f"{camera_config.name}{frame_time}" + yuv_frame = self.frame_manager.get( + frame_id, camera_config.frame_shape_yuv + ) + segment.save_full_frame(camera_config, yuv_frame) + self.frame_manager.close(frame_id) + except FileNotFoundError: + return + self.end_segment(segment) elif frame_time > (segment.last_update + THRESHOLD_DETECTION_ACTIVITY): + if segment.frame is None: + try: + frame_id = f"{camera_config.name}{frame_time}" + yuv_frame = self.frame_manager.get( + frame_id, camera_config.frame_shape_yuv + ) + segment.save_full_frame(camera_config, yuv_frame) + self.frame_manager.close(frame_id) + except FileNotFoundError: + return + self.end_segment(segment) def check_if_new_segment( diff --git a/web/src/components/player/dynamic/DynamicVideoPlayer.tsx b/web/src/components/player/dynamic/DynamicVideoPlayer.tsx index 7d1c7e4d9..e3e677530 100644 --- a/web/src/components/player/dynamic/DynamicVideoPlayer.tsx +++ b/web/src/components/player/dynamic/DynamicVideoPlayer.tsx @@ -204,8 +204,8 @@ export default function DynamicVideoPlayer({ /> ( fetchPreviews - ? `preview/${camera}/start/${timeRange.after}/end/${timeRange.before}` + ? `preview/${camera}/start/${Math.round(timeRange.after)}/end/${Math.round(timeRange.before)}` : null, { revalidateOnFocus: false, revalidateOnReconnect: false }, );