diff --git a/frigate/review/maintainer.py b/frigate/review/maintainer.py index 77d3d2a6b..5bd2d5247 100644 --- a/frigate/review/maintainer.py +++ b/frigate/review/maintainer.py @@ -68,7 +68,8 @@ class PendingReviewSegment: self.last_update = frame_time # thumbnail - self.frame = np.zeros((THUMB_HEIGHT * 3 // 2, THUMB_WIDTH), np.uint8) + self._frame = np.zeros((THUMB_HEIGHT * 3 // 2, THUMB_WIDTH), np.uint8) + self.has_frame = False self.frame_active_count = 0 self.frame_path = os.path.join( CLIPS_DIR, f"review/thumb-{self.camera}-{self.id}.webp" @@ -101,25 +102,27 @@ class PendingReviewSegment: color_frame = cv2.cvtColor(frame, cv2.COLOR_YUV2BGR_I420) color_frame = color_frame[region[1] : region[3], region[0] : region[2]] width = int(THUMB_HEIGHT * color_frame.shape[1] / color_frame.shape[0]) - self.frame = cv2.resize( + self._frame = cv2.resize( color_frame, dsize=(width, THUMB_HEIGHT), interpolation=cv2.INTER_AREA ) - if self.frame is not None: + if self._frame is not None: + self.has_frame = True cv2.imwrite( - self.frame_path, self.frame, [int(cv2.IMWRITE_WEBP_QUALITY), 60] + 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( + self._frame = cv2.resize( color_frame, dsize=(width, THUMB_HEIGHT), interpolation=cv2.INTER_AREA ) - if self.frame is not None: + if self._frame is not None: + self.has_frame = True cv2.imwrite( - self.frame_path, self.frame, [int(cv2.IMWRITE_WEBP_QUALITY), 60] + self.frame_path, self._frame, [int(cv2.IMWRITE_WEBP_QUALITY), 60] ) def get_data(self, ended: bool) -> dict: @@ -194,7 +197,10 @@ class ReviewSegmentMaintainer(threading.Thread): ) -> None: """Update segment.""" prev_data = segment.get_data(ended=False) - segment.update_frame(camera_config, frame, objects) + + if frame is not None: + segment.update_frame(camera_config, frame, objects) + new_data = segment.get_data(ended=False) self.requestor.send_data(UPSERT_REVIEW_SEGMENT, new_data) self.requestor.send_data( @@ -282,33 +288,23 @@ class ReviewSegmentMaintainer(threading.Thread): except FileNotFoundError: return else: + if not segment.has_frame: + 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) + self.update_segment(segment, camera_config, None, []) + except FileNotFoundError: + return + 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( @@ -472,6 +468,7 @@ class ReviewSegmentMaintainer(threading.Thread): or audio in camera_config.review.detections.labels ): current_segment.audio.add(audio) + elif topic == DetectionTypeEnum.api: if manual_info["state"] == ManualEventState.complete: current_segment.detections[manual_info["event_id"]] = (