mirror of
https://github.com/blakeblackshear/frigate.git
synced 2026-05-02 11:37:41 +03:00
Finalize process
This commit is contained in:
parent
e8dd382280
commit
5ef4f2d440
@ -14,7 +14,6 @@ import uvicorn
|
|||||||
from peewee_migrate import Router
|
from peewee_migrate import Router
|
||||||
from playhouse.sqlite_ext import SqliteExtDatabase
|
from playhouse.sqlite_ext import SqliteExtDatabase
|
||||||
|
|
||||||
import frigate.util as util
|
|
||||||
from frigate.api.auth import hash_password
|
from frigate.api.auth import hash_password
|
||||||
from frigate.api.fastapi_app import create_fastapi_app
|
from frigate.api.fastapi_app import create_fastapi_app
|
||||||
from frigate.camera import CameraMetrics, PTZMetrics
|
from frigate.camera import CameraMetrics, PTZMetrics
|
||||||
@ -42,7 +41,7 @@ from frigate.const import (
|
|||||||
)
|
)
|
||||||
from frigate.data_processing.types import DataProcessorMetrics
|
from frigate.data_processing.types import DataProcessorMetrics
|
||||||
from frigate.db.sqlitevecq import SqliteVecQueueDatabase
|
from frigate.db.sqlitevecq import SqliteVecQueueDatabase
|
||||||
from frigate.embeddings import EmbeddingsContext, manage_embeddings
|
from frigate.embeddings import EmbeddingProcess, EmbeddingsContext
|
||||||
from frigate.events.audio import AudioProcessor
|
from frigate.events.audio import AudioProcessor
|
||||||
from frigate.events.cleanup import EventCleanup
|
from frigate.events.cleanup import EventCleanup
|
||||||
from frigate.events.maintainer import EventProcessor
|
from frigate.events.maintainer import EventProcessor
|
||||||
@ -59,12 +58,12 @@ from frigate.models import (
|
|||||||
User,
|
User,
|
||||||
)
|
)
|
||||||
from frigate.object_detection.base import ObjectDetectProcess
|
from frigate.object_detection.base import ObjectDetectProcess
|
||||||
from frigate.output.output import output_frames
|
from frigate.output.output import OutputProcess
|
||||||
from frigate.ptz.autotrack import PtzAutoTrackerThread
|
from frigate.ptz.autotrack import PtzAutoTrackerThread
|
||||||
from frigate.ptz.onvif import OnvifController
|
from frigate.ptz.onvif import OnvifController
|
||||||
from frigate.record.cleanup import RecordingCleanup
|
from frigate.record.cleanup import RecordingCleanup
|
||||||
from frigate.record.export import migrate_exports
|
from frigate.record.export import migrate_exports
|
||||||
from frigate.record.record import manage_recordings
|
from frigate.record.record import RecordProcess
|
||||||
from frigate.review.review import ReviewProcess
|
from frigate.review.review import ReviewProcess
|
||||||
from frigate.stats.emitter import StatsEmitter
|
from frigate.stats.emitter import StatsEmitter
|
||||||
from frigate.stats.util import stats_init
|
from frigate.stats.util import stats_init
|
||||||
@ -224,11 +223,7 @@ class FrigateApp:
|
|||||||
self.processes["go2rtc"] = proc.info["pid"]
|
self.processes["go2rtc"] = proc.info["pid"]
|
||||||
|
|
||||||
def init_recording_manager(self) -> None:
|
def init_recording_manager(self) -> None:
|
||||||
recording_process = util.Process(
|
recording_process = RecordProcess(self.config)
|
||||||
target=manage_recordings,
|
|
||||||
name="recording_manager",
|
|
||||||
args=(self.config,),
|
|
||||||
)
|
|
||||||
recording_process.daemon = True
|
recording_process.daemon = True
|
||||||
self.recording_process = recording_process
|
self.recording_process = recording_process
|
||||||
recording_process.start()
|
recording_process.start()
|
||||||
@ -255,13 +250,9 @@ class FrigateApp:
|
|||||||
):
|
):
|
||||||
return
|
return
|
||||||
|
|
||||||
embedding_process = util.Process(
|
embedding_process = EmbeddingProcess(
|
||||||
target=manage_embeddings,
|
self.config,
|
||||||
name="embeddings_manager",
|
self.embeddings_metrics,
|
||||||
args=(
|
|
||||||
self.config,
|
|
||||||
self.embeddings_metrics,
|
|
||||||
),
|
|
||||||
)
|
)
|
||||||
embedding_process.daemon = True
|
embedding_process.daemon = True
|
||||||
self.embedding_process = embedding_process
|
self.embedding_process = embedding_process
|
||||||
@ -420,12 +411,7 @@ class FrigateApp:
|
|||||||
self.detected_frames_processor.start()
|
self.detected_frames_processor.start()
|
||||||
|
|
||||||
def start_video_output_processor(self) -> None:
|
def start_video_output_processor(self) -> None:
|
||||||
output_processor = util.Process(
|
output_processor = OutputProcess(self.config)
|
||||||
target=output_frames,
|
|
||||||
name="output_processor",
|
|
||||||
args=(self.config,),
|
|
||||||
)
|
|
||||||
output_processor.daemon = True
|
|
||||||
self.output_processor = output_processor
|
self.output_processor = output_processor
|
||||||
output_processor.start()
|
output_processor.start()
|
||||||
logger.info(f"Output process started: {output_processor.pid}")
|
logger.info(f"Output process started: {output_processor.pid}")
|
||||||
|
|||||||
@ -3,16 +3,12 @@
|
|||||||
import base64
|
import base64
|
||||||
import json
|
import json
|
||||||
import logging
|
import logging
|
||||||
import multiprocessing as mp
|
|
||||||
import os
|
import os
|
||||||
import signal
|
|
||||||
import threading
|
import threading
|
||||||
from types import FrameType
|
from typing import Any, Union
|
||||||
from typing import Any, Optional, Union
|
|
||||||
|
|
||||||
import regex
|
import regex
|
||||||
from pathvalidate import ValidationError, sanitize_filename
|
from pathvalidate import ValidationError, sanitize_filename
|
||||||
from setproctitle import setproctitle
|
|
||||||
|
|
||||||
from frigate.comms.embeddings_updater import EmbeddingsRequestEnum, EmbeddingsRequestor
|
from frigate.comms.embeddings_updater import EmbeddingsRequestEnum, EmbeddingsRequestor
|
||||||
from frigate.config import FrigateConfig
|
from frigate.config import FrigateConfig
|
||||||
@ -20,9 +16,9 @@ from frigate.const import CONFIG_DIR, FACE_DIR
|
|||||||
from frigate.data_processing.types import DataProcessorMetrics
|
from frigate.data_processing.types import DataProcessorMetrics
|
||||||
from frigate.db.sqlitevecq import SqliteVecQueueDatabase
|
from frigate.db.sqlitevecq import SqliteVecQueueDatabase
|
||||||
from frigate.models import Event
|
from frigate.models import Event
|
||||||
|
from frigate.util import Process as FrigateProcess
|
||||||
from frigate.util.builtin import serialize
|
from frigate.util.builtin import serialize
|
||||||
from frigate.util.classification import kickoff_model_training
|
from frigate.util.classification import kickoff_model_training
|
||||||
from frigate.util.services import listen
|
|
||||||
|
|
||||||
from .maintainer import EmbeddingMaintainer
|
from .maintainer import EmbeddingMaintainer
|
||||||
from .util import ZScoreNormalization
|
from .util import ZScoreNormalization
|
||||||
@ -30,25 +26,20 @@ from .util import ZScoreNormalization
|
|||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
def manage_embeddings(config: FrigateConfig, metrics: DataProcessorMetrics) -> None:
|
class EmbeddingProcess(FrigateProcess):
|
||||||
stop_event = mp.Event()
|
def __init__(self, config: FrigateConfig, metrics: DataProcessorMetrics) -> None:
|
||||||
|
super().__init__(name="frigate.embeddings_manager", daemon=True)
|
||||||
|
self.config = config
|
||||||
|
self.metrics = metrics
|
||||||
|
|
||||||
def receiveSignal(signalNumber: int, frame: Optional[FrameType]) -> None:
|
def run(self) -> None:
|
||||||
stop_event.set()
|
self.pre_run_setup()
|
||||||
|
maintainer = EmbeddingMaintainer(
|
||||||
signal.signal(signal.SIGTERM, receiveSignal)
|
self.config,
|
||||||
signal.signal(signal.SIGINT, receiveSignal)
|
self.metrics,
|
||||||
|
self.stop_event,
|
||||||
threading.current_thread().name = "process:embeddings_manager"
|
)
|
||||||
setproctitle("frigate.embeddings_manager")
|
maintainer.start()
|
||||||
listen()
|
|
||||||
|
|
||||||
maintainer = EmbeddingMaintainer(
|
|
||||||
config,
|
|
||||||
metrics,
|
|
||||||
stop_event,
|
|
||||||
)
|
|
||||||
maintainer.start()
|
|
||||||
|
|
||||||
|
|
||||||
class EmbeddingsContext:
|
class EmbeddingsContext:
|
||||||
|
|||||||
@ -2,14 +2,11 @@
|
|||||||
|
|
||||||
import datetime
|
import datetime
|
||||||
import logging
|
import logging
|
||||||
import multiprocessing as mp
|
|
||||||
import os
|
import os
|
||||||
import shutil
|
import shutil
|
||||||
import signal
|
|
||||||
import threading
|
import threading
|
||||||
from wsgiref.simple_server import make_server
|
from wsgiref.simple_server import make_server
|
||||||
|
|
||||||
from setproctitle import setproctitle
|
|
||||||
from ws4py.server.wsgirefserver import (
|
from ws4py.server.wsgirefserver import (
|
||||||
WebSocketWSGIHandler,
|
WebSocketWSGIHandler,
|
||||||
WebSocketWSGIRequestHandler,
|
WebSocketWSGIRequestHandler,
|
||||||
@ -17,6 +14,7 @@ from ws4py.server.wsgirefserver import (
|
|||||||
)
|
)
|
||||||
from ws4py.server.wsgiutils import WebSocketWSGIApplication
|
from ws4py.server.wsgiutils import WebSocketWSGIApplication
|
||||||
|
|
||||||
|
import frigate.util as util
|
||||||
from frigate.comms.detections_updater import DetectionSubscriber, DetectionTypeEnum
|
from frigate.comms.detections_updater import DetectionSubscriber, DetectionTypeEnum
|
||||||
from frigate.comms.ws import WebSocket
|
from frigate.comms.ws import WebSocket
|
||||||
from frigate.config import FrigateConfig
|
from frigate.config import FrigateConfig
|
||||||
@ -73,189 +71,193 @@ def check_disabled_camera_update(
|
|||||||
birdseye.all_cameras_disabled()
|
birdseye.all_cameras_disabled()
|
||||||
|
|
||||||
|
|
||||||
def output_frames(
|
class OutputProcess(util.Process):
|
||||||
config: FrigateConfig,
|
def __init__(self, config: FrigateConfig) -> None:
|
||||||
):
|
super().__init__(name="frigate.output", daemon=True)
|
||||||
threading.current_thread().name = "output"
|
self.config = config
|
||||||
setproctitle("frigate.output")
|
|
||||||
|
|
||||||
stop_event = mp.Event()
|
def run(self) -> None:
|
||||||
|
self.pre_run_setup()
|
||||||
|
|
||||||
def receiveSignal(signalNumber, frame):
|
frame_manager = SharedMemoryFrameManager()
|
||||||
stop_event.set()
|
|
||||||
|
|
||||||
signal.signal(signal.SIGTERM, receiveSignal)
|
# start a websocket server on 8082
|
||||||
signal.signal(signal.SIGINT, receiveSignal)
|
WebSocketWSGIHandler.http_version = "1.1"
|
||||||
|
websocket_server = make_server(
|
||||||
frame_manager = SharedMemoryFrameManager()
|
"127.0.0.1",
|
||||||
|
8082,
|
||||||
# start a websocket server on 8082
|
server_class=WSGIServer,
|
||||||
WebSocketWSGIHandler.http_version = "1.1"
|
handler_class=WebSocketWSGIRequestHandler,
|
||||||
websocket_server = make_server(
|
app=WebSocketWSGIApplication(handler_cls=WebSocket),
|
||||||
"127.0.0.1",
|
|
||||||
8082,
|
|
||||||
server_class=WSGIServer,
|
|
||||||
handler_class=WebSocketWSGIRequestHandler,
|
|
||||||
app=WebSocketWSGIApplication(handler_cls=WebSocket),
|
|
||||||
)
|
|
||||||
websocket_server.initialize_websockets_manager()
|
|
||||||
websocket_thread = threading.Thread(target=websocket_server.serve_forever)
|
|
||||||
|
|
||||||
detection_subscriber = DetectionSubscriber(DetectionTypeEnum.video)
|
|
||||||
config_subscriber = CameraConfigUpdateSubscriber(
|
|
||||||
config,
|
|
||||||
config.cameras,
|
|
||||||
[
|
|
||||||
CameraConfigUpdateEnum.add,
|
|
||||||
CameraConfigUpdateEnum.birdseye,
|
|
||||||
CameraConfigUpdateEnum.enabled,
|
|
||||||
CameraConfigUpdateEnum.record,
|
|
||||||
],
|
|
||||||
)
|
|
||||||
|
|
||||||
jsmpeg_cameras: dict[str, JsmpegCamera] = {}
|
|
||||||
birdseye: Birdseye | None = None
|
|
||||||
preview_recorders: dict[str, PreviewRecorder] = {}
|
|
||||||
preview_write_times: dict[str, float] = {}
|
|
||||||
failed_frame_requests: dict[str, int] = {}
|
|
||||||
last_disabled_cam_check = datetime.datetime.now().timestamp()
|
|
||||||
|
|
||||||
move_preview_frames("cache")
|
|
||||||
|
|
||||||
for camera, cam_config in config.cameras.items():
|
|
||||||
if not cam_config.enabled_in_config:
|
|
||||||
continue
|
|
||||||
|
|
||||||
jsmpeg_cameras[camera] = JsmpegCamera(cam_config, stop_event, websocket_server)
|
|
||||||
preview_recorders[camera] = PreviewRecorder(cam_config)
|
|
||||||
preview_write_times[camera] = 0
|
|
||||||
|
|
||||||
if config.birdseye.enabled:
|
|
||||||
birdseye = Birdseye(config, stop_event, websocket_server)
|
|
||||||
|
|
||||||
websocket_thread.start()
|
|
||||||
|
|
||||||
while not stop_event.is_set():
|
|
||||||
# check if there is an updated config
|
|
||||||
updates = config_subscriber.check_for_updates()
|
|
||||||
|
|
||||||
if "add" in updates:
|
|
||||||
for camera in updates["add"]:
|
|
||||||
jsmpeg_cameras[camera] = JsmpegCamera(
|
|
||||||
cam_config, stop_event, websocket_server
|
|
||||||
)
|
|
||||||
preview_recorders[camera] = PreviewRecorder(cam_config)
|
|
||||||
preview_write_times[camera] = 0
|
|
||||||
|
|
||||||
(topic, data) = detection_subscriber.check_for_update(timeout=1)
|
|
||||||
now = datetime.datetime.now().timestamp()
|
|
||||||
|
|
||||||
if now - last_disabled_cam_check > 5:
|
|
||||||
# check disabled cameras every 5 seconds
|
|
||||||
last_disabled_cam_check = now
|
|
||||||
check_disabled_camera_update(
|
|
||||||
config, birdseye, preview_recorders, preview_write_times
|
|
||||||
)
|
|
||||||
|
|
||||||
if not topic:
|
|
||||||
continue
|
|
||||||
|
|
||||||
(
|
|
||||||
camera,
|
|
||||||
frame_name,
|
|
||||||
frame_time,
|
|
||||||
current_tracked_objects,
|
|
||||||
motion_boxes,
|
|
||||||
_,
|
|
||||||
) = data
|
|
||||||
|
|
||||||
if not config.cameras[camera].enabled:
|
|
||||||
continue
|
|
||||||
|
|
||||||
frame = frame_manager.get(frame_name, config.cameras[camera].frame_shape_yuv)
|
|
||||||
|
|
||||||
if frame is None:
|
|
||||||
logger.debug(f"Failed to get frame {frame_name} from SHM")
|
|
||||||
failed_frame_requests[camera] = failed_frame_requests.get(camera, 0) + 1
|
|
||||||
|
|
||||||
if failed_frame_requests[camera] > config.cameras[camera].detect.fps:
|
|
||||||
logger.warning(
|
|
||||||
f"Failed to retrieve many frames for {camera} from SHM, consider increasing SHM size if this continues."
|
|
||||||
)
|
|
||||||
|
|
||||||
continue
|
|
||||||
else:
|
|
||||||
failed_frame_requests[camera] = 0
|
|
||||||
|
|
||||||
# send frames for low fps recording
|
|
||||||
preview_recorders[camera].write_data(
|
|
||||||
current_tracked_objects, motion_boxes, frame_time, frame
|
|
||||||
)
|
)
|
||||||
preview_write_times[camera] = frame_time
|
websocket_server.initialize_websockets_manager()
|
||||||
|
websocket_thread = threading.Thread(target=websocket_server.serve_forever)
|
||||||
|
|
||||||
# send camera frame to ffmpeg process if websockets are connected
|
detection_subscriber = DetectionSubscriber(DetectionTypeEnum.video)
|
||||||
if any(
|
config_subscriber = CameraConfigUpdateSubscriber(
|
||||||
ws.environ["PATH_INFO"].endswith(camera) for ws in websocket_server.manager
|
self.config,
|
||||||
):
|
self.config.cameras,
|
||||||
# write to the converter for the camera if clients are listening to the specific camera
|
[
|
||||||
jsmpeg_cameras[camera].write_frame(frame.tobytes())
|
CameraConfigUpdateEnum.add,
|
||||||
|
CameraConfigUpdateEnum.birdseye,
|
||||||
|
CameraConfigUpdateEnum.enabled,
|
||||||
|
CameraConfigUpdateEnum.record,
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
||||||
# send output data to birdseye if websocket is connected or restreaming
|
jsmpeg_cameras: dict[str, JsmpegCamera] = {}
|
||||||
if config.birdseye.enabled and (
|
birdseye: Birdseye | None = None
|
||||||
config.birdseye.restream
|
preview_recorders: dict[str, PreviewRecorder] = {}
|
||||||
or any(
|
preview_write_times: dict[str, float] = {}
|
||||||
ws.environ["PATH_INFO"].endswith("birdseye")
|
failed_frame_requests: dict[str, int] = {}
|
||||||
for ws in websocket_server.manager
|
last_disabled_cam_check = datetime.datetime.now().timestamp()
|
||||||
|
|
||||||
|
move_preview_frames("cache")
|
||||||
|
|
||||||
|
for camera, cam_config in self.config.cameras.items():
|
||||||
|
if not cam_config.enabled_in_config:
|
||||||
|
continue
|
||||||
|
|
||||||
|
jsmpeg_cameras[camera] = JsmpegCamera(
|
||||||
|
cam_config, self.stop_event, websocket_server
|
||||||
)
|
)
|
||||||
):
|
preview_recorders[camera] = PreviewRecorder(cam_config)
|
||||||
birdseye.write_data(
|
preview_write_times[camera] = 0
|
||||||
|
|
||||||
|
if self.config.birdseye.enabled:
|
||||||
|
birdseye = Birdseye(self.config, self.stop_event, websocket_server)
|
||||||
|
|
||||||
|
websocket_thread.start()
|
||||||
|
|
||||||
|
while not self.stop_event.is_set():
|
||||||
|
# check if there is an updated config
|
||||||
|
updates = config_subscriber.check_for_updates()
|
||||||
|
|
||||||
|
if "add" in updates:
|
||||||
|
for camera in updates["add"]:
|
||||||
|
jsmpeg_cameras[camera] = JsmpegCamera(
|
||||||
|
cam_config, self.stop_event, websocket_server
|
||||||
|
)
|
||||||
|
preview_recorders[camera] = PreviewRecorder(cam_config)
|
||||||
|
preview_write_times[camera] = 0
|
||||||
|
|
||||||
|
(topic, data) = detection_subscriber.check_for_update(timeout=1)
|
||||||
|
now = datetime.datetime.now().timestamp()
|
||||||
|
|
||||||
|
if now - last_disabled_cam_check > 5:
|
||||||
|
# check disabled cameras every 5 seconds
|
||||||
|
last_disabled_cam_check = now
|
||||||
|
check_disabled_camera_update(
|
||||||
|
self.config, birdseye, preview_recorders, preview_write_times
|
||||||
|
)
|
||||||
|
|
||||||
|
if not topic:
|
||||||
|
continue
|
||||||
|
|
||||||
|
(
|
||||||
camera,
|
camera,
|
||||||
|
frame_name,
|
||||||
|
frame_time,
|
||||||
current_tracked_objects,
|
current_tracked_objects,
|
||||||
motion_boxes,
|
motion_boxes,
|
||||||
frame_time,
|
_,
|
||||||
frame,
|
) = data
|
||||||
|
|
||||||
|
if not self.config.cameras[camera].enabled:
|
||||||
|
continue
|
||||||
|
|
||||||
|
frame = frame_manager.get(
|
||||||
|
frame_name, self.config.cameras[camera].frame_shape_yuv
|
||||||
)
|
)
|
||||||
|
|
||||||
frame_manager.close(frame_name)
|
if frame is None:
|
||||||
|
logger.debug(f"Failed to get frame {frame_name} from SHM")
|
||||||
|
failed_frame_requests[camera] = failed_frame_requests.get(camera, 0) + 1
|
||||||
|
|
||||||
move_preview_frames("clips")
|
if (
|
||||||
|
failed_frame_requests[camera]
|
||||||
|
> self.config.cameras[camera].detect.fps
|
||||||
|
):
|
||||||
|
logger.warning(
|
||||||
|
f"Failed to retrieve many frames for {camera} from SHM, consider increasing SHM size if this continues."
|
||||||
|
)
|
||||||
|
|
||||||
while True:
|
continue
|
||||||
(topic, data) = detection_subscriber.check_for_update(timeout=0)
|
else:
|
||||||
|
failed_frame_requests[camera] = 0
|
||||||
|
|
||||||
if not topic:
|
# send frames for low fps recording
|
||||||
break
|
preview_recorders[camera].write_data(
|
||||||
|
current_tracked_objects, motion_boxes, frame_time, frame
|
||||||
|
)
|
||||||
|
preview_write_times[camera] = frame_time
|
||||||
|
|
||||||
(
|
# send camera frame to ffmpeg process if websockets are connected
|
||||||
camera,
|
if any(
|
||||||
frame_name,
|
ws.environ["PATH_INFO"].endswith(camera)
|
||||||
frame_time,
|
for ws in websocket_server.manager
|
||||||
current_tracked_objects,
|
):
|
||||||
motion_boxes,
|
# write to the converter for the camera if clients are listening to the specific camera
|
||||||
regions,
|
jsmpeg_cameras[camera].write_frame(frame.tobytes())
|
||||||
) = data
|
|
||||||
|
|
||||||
frame = frame_manager.get(frame_name, config.cameras[camera].frame_shape_yuv)
|
# send output data to birdseye if websocket is connected or restreaming
|
||||||
frame_manager.close(frame_name)
|
if self.config.birdseye.enabled and (
|
||||||
|
self.config.birdseye.restream
|
||||||
|
or any(
|
||||||
|
ws.environ["PATH_INFO"].endswith("birdseye")
|
||||||
|
for ws in websocket_server.manager
|
||||||
|
)
|
||||||
|
):
|
||||||
|
birdseye.write_data(
|
||||||
|
camera,
|
||||||
|
current_tracked_objects,
|
||||||
|
motion_boxes,
|
||||||
|
frame_time,
|
||||||
|
frame,
|
||||||
|
)
|
||||||
|
|
||||||
detection_subscriber.stop()
|
frame_manager.close(frame_name)
|
||||||
|
|
||||||
for jsmpeg in jsmpeg_cameras.values():
|
move_preview_frames("clips")
|
||||||
jsmpeg.stop()
|
|
||||||
|
|
||||||
for preview in preview_recorders.values():
|
while True:
|
||||||
preview.stop()
|
(topic, data) = detection_subscriber.check_for_update(timeout=0)
|
||||||
|
|
||||||
if birdseye is not None:
|
if not topic:
|
||||||
birdseye.stop()
|
break
|
||||||
|
|
||||||
config_subscriber.stop()
|
(
|
||||||
websocket_server.manager.close_all()
|
camera,
|
||||||
websocket_server.manager.stop()
|
frame_name,
|
||||||
websocket_server.manager.join()
|
frame_time,
|
||||||
websocket_server.shutdown()
|
current_tracked_objects,
|
||||||
websocket_thread.join()
|
motion_boxes,
|
||||||
logger.info("exiting output process...")
|
regions,
|
||||||
|
) = data
|
||||||
|
|
||||||
|
frame = frame_manager.get(
|
||||||
|
frame_name, self.config.cameras[camera].frame_shape_yuv
|
||||||
|
)
|
||||||
|
frame_manager.close(frame_name)
|
||||||
|
|
||||||
|
detection_subscriber.stop()
|
||||||
|
|
||||||
|
for jsmpeg in jsmpeg_cameras.values():
|
||||||
|
jsmpeg.stop()
|
||||||
|
|
||||||
|
for preview in preview_recorders.values():
|
||||||
|
preview.stop()
|
||||||
|
|
||||||
|
if birdseye is not None:
|
||||||
|
birdseye.stop()
|
||||||
|
|
||||||
|
config_subscriber.stop()
|
||||||
|
websocket_server.manager.close_all()
|
||||||
|
websocket_server.manager.stop()
|
||||||
|
websocket_server.manager.join()
|
||||||
|
websocket_server.shutdown()
|
||||||
|
websocket_thread.join()
|
||||||
|
logger.info("exiting output process...")
|
||||||
|
|
||||||
|
|
||||||
def move_preview_frames(loc: str):
|
def move_preview_frames(loc: str):
|
||||||
|
|||||||
@ -1,50 +1,40 @@
|
|||||||
"""Run recording maintainer and cleanup."""
|
"""Run recording maintainer and cleanup."""
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
import multiprocessing as mp
|
|
||||||
import signal
|
|
||||||
import threading
|
|
||||||
from types import FrameType
|
|
||||||
from typing import Optional
|
|
||||||
|
|
||||||
from playhouse.sqliteq import SqliteQueueDatabase
|
from playhouse.sqliteq import SqliteQueueDatabase
|
||||||
from setproctitle import setproctitle
|
|
||||||
|
|
||||||
from frigate.config import FrigateConfig
|
from frigate.config import FrigateConfig
|
||||||
from frigate.models import Recordings, ReviewSegment
|
from frigate.models import Recordings, ReviewSegment
|
||||||
from frigate.record.maintainer import RecordingMaintainer
|
from frigate.record.maintainer import RecordingMaintainer
|
||||||
from frigate.util.services import listen
|
from frigate.util import Process as FrigateProcess
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
def manage_recordings(config: FrigateConfig) -> None:
|
class RecordProcess(FrigateProcess):
|
||||||
stop_event = mp.Event()
|
def __init__(self, config: FrigateConfig) -> None:
|
||||||
|
super().__init__(name="frigate.recording_manager", daemon=True)
|
||||||
|
self.config = config
|
||||||
|
|
||||||
def receiveSignal(signalNumber: int, frame: Optional[FrameType]) -> None:
|
def run(self) -> None:
|
||||||
stop_event.set()
|
self.pre_run_setup()
|
||||||
|
db = SqliteQueueDatabase(
|
||||||
|
self.config.database.path,
|
||||||
|
pragmas={
|
||||||
|
"auto_vacuum": "FULL", # Does not defragment database
|
||||||
|
"cache_size": -512 * 1000, # 512MB of cache
|
||||||
|
"synchronous": "NORMAL", # Safe when using WAL https://www.sqlite.org/pragma.html#pragma_synchronous
|
||||||
|
},
|
||||||
|
timeout=max(
|
||||||
|
60, 10 * len([c for c in self.config.cameras.values() if c.enabled])
|
||||||
|
),
|
||||||
|
)
|
||||||
|
models = [ReviewSegment, Recordings]
|
||||||
|
db.bind(models)
|
||||||
|
|
||||||
signal.signal(signal.SIGTERM, receiveSignal)
|
maintainer = RecordingMaintainer(
|
||||||
signal.signal(signal.SIGINT, receiveSignal)
|
self.config,
|
||||||
|
self.stop_event,
|
||||||
threading.current_thread().name = "process:recording_manager"
|
)
|
||||||
setproctitle("frigate.recording_manager")
|
maintainer.start()
|
||||||
listen()
|
|
||||||
|
|
||||||
db = SqliteQueueDatabase(
|
|
||||||
config.database.path,
|
|
||||||
pragmas={
|
|
||||||
"auto_vacuum": "FULL", # Does not defragment database
|
|
||||||
"cache_size": -512 * 1000, # 512MB of cache
|
|
||||||
"synchronous": "NORMAL", # Safe when using WAL https://www.sqlite.org/pragma.html#pragma_synchronous
|
|
||||||
},
|
|
||||||
timeout=max(60, 10 * len([c for c in config.cameras.values() if c.enabled])),
|
|
||||||
)
|
|
||||||
models = [ReviewSegment, Recordings]
|
|
||||||
db.bind(models)
|
|
||||||
|
|
||||||
maintainer = RecordingMaintainer(
|
|
||||||
config,
|
|
||||||
stop_event,
|
|
||||||
)
|
|
||||||
maintainer.start()
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user