mirror of
https://github.com/blakeblackshear/frigate.git
synced 2025-08-04 13:47:37 +02:00
Fix birdseye crash when dynamically adding a camera (#18821)
This commit is contained in:
parent
20dac9d05e
commit
55c6008ff0
@ -423,6 +423,7 @@ class FrigateApp:
|
|||||||
self.camera_metrics,
|
self.camera_metrics,
|
||||||
self.ptz_metrics,
|
self.ptz_metrics,
|
||||||
self.stop_event,
|
self.stop_event,
|
||||||
|
self.metrics_manager,
|
||||||
)
|
)
|
||||||
self.camera_maintainer.start()
|
self.camera_maintainer.start()
|
||||||
|
|
||||||
|
@ -6,7 +6,7 @@ import os
|
|||||||
import shutil
|
import shutil
|
||||||
import threading
|
import threading
|
||||||
from multiprocessing import Queue
|
from multiprocessing import Queue
|
||||||
from multiprocessing.managers import DictProxy
|
from multiprocessing.managers import DictProxy, SyncManager
|
||||||
from multiprocessing.synchronize import Event as MpEvent
|
from multiprocessing.synchronize import Event as MpEvent
|
||||||
|
|
||||||
from frigate.camera import CameraMetrics, PTZMetrics
|
from frigate.camera import CameraMetrics, PTZMetrics
|
||||||
@ -35,6 +35,7 @@ class CameraMaintainer(threading.Thread):
|
|||||||
camera_metrics: DictProxy,
|
camera_metrics: DictProxy,
|
||||||
ptz_metrics: dict[str, PTZMetrics],
|
ptz_metrics: dict[str, PTZMetrics],
|
||||||
stop_event: MpEvent,
|
stop_event: MpEvent,
|
||||||
|
metrics_manager: SyncManager,
|
||||||
):
|
):
|
||||||
super().__init__(name="camera_processor")
|
super().__init__(name="camera_processor")
|
||||||
self.config = config
|
self.config = config
|
||||||
@ -56,6 +57,7 @@ class CameraMaintainer(threading.Thread):
|
|||||||
self.shm_count = self.__calculate_shm_frame_count()
|
self.shm_count = self.__calculate_shm_frame_count()
|
||||||
self.camera_processes: dict[str, mp.Process] = {}
|
self.camera_processes: dict[str, mp.Process] = {}
|
||||||
self.capture_processes: dict[str, mp.Process] = {}
|
self.capture_processes: dict[str, mp.Process] = {}
|
||||||
|
self.metrics_manager = metrics_manager
|
||||||
|
|
||||||
def __init_historical_regions(self) -> None:
|
def __init_historical_regions(self) -> None:
|
||||||
# delete region grids for removed or renamed cameras
|
# delete region grids for removed or renamed cameras
|
||||||
@ -128,7 +130,7 @@ class CameraMaintainer(threading.Thread):
|
|||||||
return
|
return
|
||||||
|
|
||||||
if runtime:
|
if runtime:
|
||||||
self.camera_metrics[name] = CameraMetrics()
|
self.camera_metrics[name] = CameraMetrics(self.metrics_manager)
|
||||||
self.ptz_metrics[name] = PTZMetrics(autotracker_enabled=False)
|
self.ptz_metrics[name] = PTZMetrics(autotracker_enabled=False)
|
||||||
self.region_grids[name] = get_camera_regions_grid(
|
self.region_grids[name] = get_camera_regions_grid(
|
||||||
name,
|
name,
|
||||||
|
@ -319,7 +319,16 @@ class BirdsEyeFrameManager:
|
|||||||
self.frame[:] = self.blank_frame
|
self.frame[:] = self.blank_frame
|
||||||
|
|
||||||
self.cameras = {}
|
self.cameras = {}
|
||||||
for camera, settings in self.config.cameras.items():
|
for camera in self.config.cameras.keys():
|
||||||
|
self.add_camera(camera)
|
||||||
|
|
||||||
|
self.camera_layout = []
|
||||||
|
self.active_cameras = set()
|
||||||
|
self.last_output_time = 0.0
|
||||||
|
|
||||||
|
def add_camera(self, cam: str):
|
||||||
|
"""Add a camera to self.cameras with the correct structure."""
|
||||||
|
settings = self.config.cameras[cam]
|
||||||
# precalculate the coordinates for all the channels
|
# precalculate the coordinates for all the channels
|
||||||
y, u1, u2, v1, v2 = get_yuv_crop(
|
y, u1, u2, v1, v2 = get_yuv_crop(
|
||||||
settings.frame_shape_yuv,
|
settings.frame_shape_yuv,
|
||||||
@ -330,8 +339,11 @@ class BirdsEyeFrameManager:
|
|||||||
settings.frame_shape[0],
|
settings.frame_shape[0],
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
self.cameras[camera] = {
|
self.cameras[cam] = {
|
||||||
"dimensions": [settings.detect.width, settings.detect.height],
|
"dimensions": [
|
||||||
|
settings.detect.width,
|
||||||
|
settings.detect.height,
|
||||||
|
],
|
||||||
"last_active_frame": 0.0,
|
"last_active_frame": 0.0,
|
||||||
"current_frame": 0.0,
|
"current_frame": 0.0,
|
||||||
"layout_frame": 0.0,
|
"layout_frame": 0.0,
|
||||||
@ -344,9 +356,10 @@ class BirdsEyeFrameManager:
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
self.camera_layout = []
|
def remove_camera(self, cam: str):
|
||||||
self.active_cameras = set()
|
"""Remove a camera from self.cameras."""
|
||||||
self.last_output_time = 0.0
|
if cam in self.cameras:
|
||||||
|
del self.cameras[cam]
|
||||||
|
|
||||||
def clear_frame(self):
|
def clear_frame(self):
|
||||||
logger.debug("Clearing the birdseye frame")
|
logger.debug("Clearing the birdseye frame")
|
||||||
@ -774,7 +787,7 @@ class Birdseye:
|
|||||||
self.broadcaster = BroadcastThread(
|
self.broadcaster = BroadcastThread(
|
||||||
"birdseye", self.converter, websocket_server, stop_event
|
"birdseye", self.converter, websocket_server, stop_event
|
||||||
)
|
)
|
||||||
self.birdseye_manager = BirdsEyeFrameManager(config, stop_event)
|
self.birdseye_manager = BirdsEyeFrameManager(self.config, stop_event)
|
||||||
self.frame_manager = SharedMemoryFrameManager()
|
self.frame_manager = SharedMemoryFrameManager()
|
||||||
self.stop_event = stop_event
|
self.stop_event = stop_event
|
||||||
self.requestor = InterProcessRequestor()
|
self.requestor = InterProcessRequestor()
|
||||||
@ -804,6 +817,16 @@ class Birdseye:
|
|||||||
self.birdseye_manager.clear_frame()
|
self.birdseye_manager.clear_frame()
|
||||||
self.__send_new_frame()
|
self.__send_new_frame()
|
||||||
|
|
||||||
|
def add_camera(self, camera: str) -> None:
|
||||||
|
"""Add a camera to the birdseye manager."""
|
||||||
|
self.birdseye_manager.add_camera(camera)
|
||||||
|
logger.debug(f"Added camera {camera} to birdseye")
|
||||||
|
|
||||||
|
def remove_camera(self, camera: str) -> None:
|
||||||
|
"""Remove a camera from the birdseye manager."""
|
||||||
|
self.birdseye_manager.remove_camera(camera)
|
||||||
|
logger.debug(f"Removed camera {camera} from birdseye")
|
||||||
|
|
||||||
def write_data(
|
def write_data(
|
||||||
self,
|
self,
|
||||||
camera: str,
|
camera: str,
|
||||||
|
@ -133,7 +133,7 @@ class OutputProcess(FrigateProcess):
|
|||||||
# check if there is an updated config
|
# check if there is an updated config
|
||||||
updates = config_subscriber.check_for_updates()
|
updates = config_subscriber.check_for_updates()
|
||||||
|
|
||||||
if "add" in updates:
|
if CameraConfigUpdateEnum.add in updates:
|
||||||
for camera in updates["add"]:
|
for camera in updates["add"]:
|
||||||
jsmpeg_cameras[camera] = JsmpegCamera(
|
jsmpeg_cameras[camera] = JsmpegCamera(
|
||||||
cam_config, self.stop_event, websocket_server
|
cam_config, self.stop_event, websocket_server
|
||||||
@ -141,6 +141,12 @@ class OutputProcess(FrigateProcess):
|
|||||||
preview_recorders[camera] = PreviewRecorder(cam_config)
|
preview_recorders[camera] = PreviewRecorder(cam_config)
|
||||||
preview_write_times[camera] = 0
|
preview_write_times[camera] = 0
|
||||||
|
|
||||||
|
if (
|
||||||
|
self.config.birdseye.enabled
|
||||||
|
and self.config.cameras[camera].birdseye.enabled
|
||||||
|
):
|
||||||
|
birdseye.add_camera(camera)
|
||||||
|
|
||||||
(topic, data) = detection_subscriber.check_for_update(timeout=1)
|
(topic, data) = detection_subscriber.check_for_update(timeout=1)
|
||||||
now = datetime.datetime.now().timestamp()
|
now = datetime.datetime.now().timestamp()
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user