From 6b551ca0736a14af8da3fe0996f1da618293ceb2 Mon Sep 17 00:00:00 2001 From: Nicolas Mowen Date: Sat, 17 Feb 2024 06:24:49 -0700 Subject: [PATCH] Create main manager for review segments --- frigate/app.py | 25 ++++++++++++++++++++++++- frigate/review/__init__.py | 0 frigate/review/maintainer.py | 28 ++++++++++++++++++++++++++++ frigate/review/review.py | 36 ++++++++++++++++++++++++++++++++++++ 4 files changed, 88 insertions(+), 1 deletion(-) create mode 100644 frigate/review/__init__.py create mode 100644 frigate/review/maintainer.py create mode 100644 frigate/review/review.py diff --git a/frigate/app.py b/frigate/app.py index 81050e30b..95a742515 100644 --- a/frigate/app.py +++ b/frigate/app.py @@ -45,6 +45,7 @@ from frigate.models import ( Recordings, RecordingsToDelete, Regions, + ReviewSegment, Timeline, ) from frigate.object_detection import ObjectDetectProcess @@ -55,6 +56,7 @@ from frigate.ptz.autotrack import PtzAutoTrackerThread from frigate.ptz.onvif import OnvifController from frigate.record.cleanup import RecordingCleanup from frigate.record.record import manage_recordings +from frigate.review.review import manage_review_segments from frigate.stats import StatsEmitter, stats_init from frigate.storage import StorageMaintainer from frigate.timeline import TimelineProcessor @@ -283,6 +285,18 @@ class FrigateApp: self.processes["recording"] = recording_process.pid or 0 logger.info(f"Recording process started: {recording_process.pid}") + def init_review_segment_manager(self) -> None: + review_segment_process = mp.Process( + target=manage_review_segments, + name="review_segment_manager", + args=(self.config,), + ) + review_segment_process.daemon = True + self.review_segment_process = review_segment_process + review_segment_process.start() + self.processes["review_segment"] = review_segment_process.pid or 0 + logger.info(f"Recording process started: {review_segment_process.pid}") + def bind_database(self) -> None: """Bind db to the main process.""" # NOTE: all db accessing processes need to be created before the db can be bound to the main process @@ -297,7 +311,15 @@ class FrigateApp: 60, 10 * len([c for c in self.config.cameras.values() if c.enabled]) ), ) - models = [Event, Recordings, RecordingsToDelete, Previews, Regions, Timeline] + models = [ + Event, + Previews, + Recordings, + RecordingsToDelete, + Regions, + ReviewSegment, + Timeline, + ] self.db.bind(models) def init_stats(self) -> None: @@ -608,6 +630,7 @@ class FrigateApp: self.init_database() self.init_onvif() self.init_recording_manager() + self.init_review_segment_manager() self.init_go2rtc() self.bind_database() self.init_inter_process_communicator() diff --git a/frigate/review/__init__.py b/frigate/review/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/frigate/review/maintainer.py b/frigate/review/maintainer.py new file mode 100644 index 000000000..67c7fabf3 --- /dev/null +++ b/frigate/review/maintainer.py @@ -0,0 +1,28 @@ +"""Maintain review segments in db.""" + +import logging +import threading +from multiprocessing.synchronize import Event as MpEvent + +from frigate.comms.config_updater import ConfigSubscriber +from frigate.comms.detections_updater import DetectionSubscriber, DetectionTypeEnum +from frigate.comms.inter_process import InterProcessRequestor +from frigate.config import FrigateConfig + +logger = logging.getLogger(__name__) + + +class ReviewSegmentMaintainer(threading.Thread): + """Maintain review segments.""" + + def __init__(self, config: FrigateConfig, stop_event: MpEvent): + threading.Thread.__init__(self) + self.name = "review_segment_maintainer" + self.config = config + + # create communication for review segments + self.requestor = InterProcessRequestor() + self.config_subscriber = ConfigSubscriber("config/record/") + self.detection_subscriber = DetectionSubscriber(DetectionTypeEnum.all) + + self.stop_event = stop_event diff --git a/frigate/review/review.py b/frigate/review/review.py new file mode 100644 index 000000000..dafa6c802 --- /dev/null +++ b/frigate/review/review.py @@ -0,0 +1,36 @@ +"""Run recording maintainer and cleanup.""" + +import logging +import multiprocessing as mp +import signal +import threading +from types import FrameType +from typing import Optional + +from setproctitle import setproctitle + +from frigate.config import FrigateConfig +from frigate.review.maintainer import ReviewSegmentMaintainer +from frigate.util.services import listen + +logger = logging.getLogger(__name__) + + +def manage_review_segments(config: FrigateConfig) -> None: + stop_event = mp.Event() + + def receiveSignal(signalNumber: int, frame: Optional[FrameType]) -> None: + stop_event.set() + + signal.signal(signal.SIGTERM, receiveSignal) + signal.signal(signal.SIGINT, receiveSignal) + + threading.current_thread().name = "process:review_segment_manager" + setproctitle("frigate.review_segment_manager") + listen() + + maintainer = ReviewSegmentMaintainer( + config, + stop_event, + ) + maintainer.start()