mirror of
https://github.com/blakeblackshear/frigate.git
synced 2026-05-01 11:07:41 +03:00
Move camera management fully to separate class
This commit is contained in:
parent
7085790dcd
commit
fa6f531e88
@ -36,7 +36,6 @@ from frigate.const import (
|
||||
FACE_DIR,
|
||||
MODEL_CACHE_DIR,
|
||||
RECORD_DIR,
|
||||
SHM_FRAMES_VAR,
|
||||
THUMB_DIR,
|
||||
)
|
||||
from frigate.data_processing.types import DataProcessorMetrics
|
||||
@ -70,8 +69,7 @@ from frigate.storage import StorageMaintainer
|
||||
from frigate.timeline import TimelineProcessor
|
||||
from frigate.track.object_processing import TrackedObjectProcessor
|
||||
from frigate.util.builtin import empty_and_close_queue
|
||||
from frigate.util.image import SharedMemoryFrameManager, UntrackedSharedMemory
|
||||
from frigate.util.object import get_camera_regions_grid
|
||||
from frigate.util.image import UntrackedSharedMemory
|
||||
from frigate.version import VERSION
|
||||
from frigate.watchdog import FrigateWatchdog
|
||||
|
||||
@ -101,8 +99,6 @@ class FrigateApp:
|
||||
self.ptz_metrics: dict[str, PTZMetrics] = {}
|
||||
self.processes: dict[str, int] = {}
|
||||
self.embeddings: Optional[EmbeddingsContext] = None
|
||||
self.region_grids: dict[str, list[list[dict[str, int]]]] = {}
|
||||
self.frame_manager = SharedMemoryFrameManager()
|
||||
self.config = config
|
||||
|
||||
def ensure_dirs(self) -> None:
|
||||
@ -423,20 +419,6 @@ class FrigateApp:
|
||||
output_processor.start()
|
||||
logger.info(f"Output process started: {output_processor.pid}")
|
||||
|
||||
def init_historical_regions(self) -> None:
|
||||
# delete region grids for removed or renamed cameras
|
||||
cameras = list(self.config.cameras.keys())
|
||||
Regions.delete().where(~(Regions.camera << cameras)).execute()
|
||||
|
||||
# create or update region grids for each camera
|
||||
for camera in self.config.cameras.values():
|
||||
assert camera.name is not None
|
||||
self.region_grids[camera.name] = get_camera_regions_grid(
|
||||
camera.name,
|
||||
camera.detect,
|
||||
max(self.config.model.width, self.config.model.height),
|
||||
)
|
||||
|
||||
def start_camera_processor(self) -> None:
|
||||
self.camera_maintainer = CameraMaintainer(self.config, self.stop_event)
|
||||
self.camera_maintainer.start()
|
||||
@ -499,45 +481,6 @@ class FrigateApp:
|
||||
self.frigate_watchdog = FrigateWatchdog(self.detectors, self.stop_event)
|
||||
self.frigate_watchdog.start()
|
||||
|
||||
def shm_frame_count(self) -> int:
|
||||
total_shm = round(shutil.disk_usage("/dev/shm").total / pow(2, 20), 1)
|
||||
|
||||
# required for log files + nginx cache
|
||||
min_req_shm = 40 + 10
|
||||
|
||||
if self.config.birdseye.restream:
|
||||
min_req_shm += 8
|
||||
|
||||
available_shm = total_shm - min_req_shm
|
||||
cam_total_frame_size = 0.0
|
||||
|
||||
for camera in self.config.cameras.values():
|
||||
if camera.enabled and camera.detect.width and camera.detect.height:
|
||||
cam_total_frame_size += round(
|
||||
(camera.detect.width * camera.detect.height * 1.5 + 270480)
|
||||
/ 1048576,
|
||||
1,
|
||||
)
|
||||
|
||||
if cam_total_frame_size == 0.0:
|
||||
return 0
|
||||
|
||||
shm_frame_count = min(
|
||||
int(os.environ.get(SHM_FRAMES_VAR, "50")),
|
||||
int(available_shm / (cam_total_frame_size)),
|
||||
)
|
||||
|
||||
logger.debug(
|
||||
f"Calculated total camera size {available_shm} / {cam_total_frame_size} :: {shm_frame_count} frames for each camera in SHM"
|
||||
)
|
||||
|
||||
if shm_frame_count < 20:
|
||||
logger.warning(
|
||||
f"The current SHM size of {total_shm}MB is too small, recommend increasing it to at least {round(min_req_shm + cam_total_frame_size * 20)}MB."
|
||||
)
|
||||
|
||||
return shm_frame_count
|
||||
|
||||
def init_auth(self) -> None:
|
||||
if self.config.auth.enabled:
|
||||
if User.select().count() == 0:
|
||||
@ -604,10 +547,8 @@ class FrigateApp:
|
||||
self.init_embeddings_client()
|
||||
self.start_video_output_processor()
|
||||
self.start_ptz_autotracker()
|
||||
self.init_historical_regions()
|
||||
self.start_detected_frames_processor()
|
||||
self.start_camera_processor()
|
||||
self.start_camera_capture_processes()
|
||||
self.start_audio_processor()
|
||||
self.start_storage_maintainer()
|
||||
self.start_stats_emitter()
|
||||
@ -706,7 +647,6 @@ class FrigateApp:
|
||||
self.event_metadata_updater.stop()
|
||||
self.inter_zmq_proxy.stop()
|
||||
|
||||
self.frame_manager.cleanup()
|
||||
while len(self.detection_shms) > 0:
|
||||
shm = self.detection_shms.pop()
|
||||
shm.close()
|
||||
|
||||
@ -1,23 +1,107 @@
|
||||
"""Create and maintain camera processes / management."""
|
||||
|
||||
import logging
|
||||
import os
|
||||
import shutil
|
||||
import threading
|
||||
from multiprocessing import Queue
|
||||
from multiprocessing.synchronize import Event as MpEvent
|
||||
|
||||
from frigate.camera import CameraMetrics, PTZMetrics
|
||||
from frigate.config import FrigateConfig
|
||||
from frigate.config.updater import GlobalConfigUpdateEnum, GlobalConfigUpdateSubscriber
|
||||
from frigate.const import SHM_FRAMES_VAR
|
||||
from frigate.models import Regions
|
||||
from frigate.util import Process as FrigateProcess
|
||||
from frigate.util.builtin import empty_and_close_queue
|
||||
from frigate.util.image import SharedMemoryFrameManager
|
||||
from frigate.util.object import get_camera_regions_grid
|
||||
from frigate.video import capture_camera, track_camera
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
|
||||
class CameraMaintainer(threading.Thread):
|
||||
def __init__(self, config: FrigateConfig, stop_event: MpEvent):
|
||||
def __init__(
|
||||
self,
|
||||
config: FrigateConfig,
|
||||
detection_queue: Queue,
|
||||
detection_out_events: dict[str, MpEvent],
|
||||
detected_frames_queue: Queue,
|
||||
camera_metrics: dict[str, CameraMetrics],
|
||||
ptz_metrics: dict[str, PTZMetrics],
|
||||
stop_event: MpEvent,
|
||||
):
|
||||
super().__init__(name="camera_processor")
|
||||
self.config = config
|
||||
self.detection_queue = detection_queue
|
||||
self.detection_out_events = detection_out_events
|
||||
self.detected_frames_queue = detected_frames_queue
|
||||
self.stop_event = stop_event
|
||||
self.camera_metrics = camera_metrics
|
||||
self.ptz_metrics = ptz_metrics
|
||||
self.frame_manager = SharedMemoryFrameManager()
|
||||
self.region_grids: dict[str, list[list[dict[str, int]]]] = {}
|
||||
self.update_subscriber = GlobalConfigUpdateSubscriber(
|
||||
[
|
||||
GlobalConfigUpdateEnum.add_camera,
|
||||
GlobalConfigUpdateEnum.debug_camera,
|
||||
GlobalConfigUpdateEnum.remove_camera,
|
||||
]
|
||||
)
|
||||
|
||||
def __init_historical_regions(self) -> None:
|
||||
# delete region grids for removed or renamed cameras
|
||||
cameras = list(self.config.cameras.keys())
|
||||
Regions.delete().where(~(Regions.camera << cameras)).execute()
|
||||
|
||||
# create or update region grids for each camera
|
||||
for camera in self.config.cameras.values():
|
||||
assert camera.name is not None
|
||||
self.region_grids[camera.name] = get_camera_regions_grid(
|
||||
camera.name,
|
||||
camera.detect,
|
||||
max(self.config.model.width, self.config.model.height),
|
||||
)
|
||||
|
||||
def __calculate_shm_frame_count(self) -> int:
|
||||
total_shm = round(shutil.disk_usage("/dev/shm").total / pow(2, 20), 1)
|
||||
|
||||
# required for log files + nginx cache
|
||||
min_req_shm = 40 + 10
|
||||
|
||||
if self.config.birdseye.restream:
|
||||
min_req_shm += 8
|
||||
|
||||
available_shm = total_shm - min_req_shm
|
||||
cam_total_frame_size = 0.0
|
||||
|
||||
for camera in self.config.cameras.values():
|
||||
if camera.enabled and camera.detect.width and camera.detect.height:
|
||||
cam_total_frame_size += round(
|
||||
(camera.detect.width * camera.detect.height * 1.5 + 270480)
|
||||
/ 1048576,
|
||||
1,
|
||||
)
|
||||
|
||||
if cam_total_frame_size == 0.0:
|
||||
return 0
|
||||
|
||||
shm_frame_count = min(
|
||||
int(os.environ.get(SHM_FRAMES_VAR, "50")),
|
||||
int(available_shm / (cam_total_frame_size)),
|
||||
)
|
||||
|
||||
logger.debug(
|
||||
f"Calculated total camera size {available_shm} / {cam_total_frame_size} :: {shm_frame_count} frames for each camera in SHM"
|
||||
)
|
||||
|
||||
if shm_frame_count < 20:
|
||||
logger.warning(
|
||||
f"The current SHM size of {total_shm}MB is too small, recommend increasing it to at least {round(min_req_shm + cam_total_frame_size * 20)}MB."
|
||||
)
|
||||
|
||||
return shm_frame_count
|
||||
|
||||
def __start_camera_processors(self) -> None:
|
||||
for name, config in self.config.cameras.items():
|
||||
@ -47,7 +131,7 @@ class CameraMaintainer(threading.Thread):
|
||||
logger.info(f"Camera processor started for {name}: {camera_process.pid}")
|
||||
|
||||
def __start_camera_capture(self) -> None:
|
||||
shm_frame_count = self.shm_frame_count()
|
||||
shm_frame_count = self.__calculate_shm_frame_count()
|
||||
|
||||
for name, config in self.config.cameras.items():
|
||||
if not self.config.cameras[name].enabled_in_config:
|
||||
@ -70,11 +154,22 @@ class CameraMaintainer(threading.Thread):
|
||||
logger.info(f"Capture process started for {name}: {capture_process.pid}")
|
||||
|
||||
def run(self):
|
||||
self.__init_historical_regions()
|
||||
|
||||
# start camera processes
|
||||
self.__start_camera_processors()
|
||||
self.__start_camera_capture()
|
||||
|
||||
while not self.stop_event.is_set():
|
||||
pass
|
||||
while not self.stop_event.wait(1):
|
||||
updates = self.update_subscriber.check_for_updates()
|
||||
|
||||
for update_type, update_payload in updates:
|
||||
if update_type == GlobalConfigUpdateEnum.add_camera:
|
||||
pass
|
||||
elif update_type == GlobalConfigUpdateEnum.debug_camera:
|
||||
pass
|
||||
elif update_type == GlobalConfigUpdateEnum.remove_camera:
|
||||
pass
|
||||
|
||||
# ensure the capture processes are done
|
||||
for camera, metrics in self.camera_metrics.items():
|
||||
@ -93,3 +188,5 @@ class CameraMaintainer(threading.Thread):
|
||||
camera_process.join()
|
||||
logger.info(f"Closing frame queue for {camera}")
|
||||
empty_and_close_queue(metrics.frame_queue)
|
||||
|
||||
self.frame_manager.cleanup()
|
||||
|
||||
@ -11,6 +11,7 @@ class GlobalConfigUpdateEnum(str, Enum):
|
||||
"""Supported global config update types."""
|
||||
|
||||
add_camera = "add_camera"
|
||||
debug_camera = "debug_camera"
|
||||
remove_camera = "remove_camera"
|
||||
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user