mirror of
https://github.com/blakeblackshear/frigate.git
synced 2026-10-07 15:22:48 +03:00
use resolved camera config in object processor to avoid race on replay stop (#24450)
CI / AMD64 Build (push) Canceled after 0s
CI / ARM Build (push) Canceled after 0s
CI / Jetson Jetpack 6 (push) Canceled after 0s
CI / Assemble and push default build (push) Canceled after 0s
CI / AMD64 Extra Build (push) Canceled after 0s
CI / ARM Extra Build (push) Canceled after 0s
CI / Synaptics Build (push) Canceled after 0s
CI / AMD64 Build (push) Canceled after 0s
CI / ARM Build (push) Canceled after 0s
CI / Jetson Jetpack 6 (push) Canceled after 0s
CI / Assemble and push default build (push) Canceled after 0s
CI / AMD64 Extra Build (push) Canceled after 0s
CI / ARM Extra Build (push) Canceled after 0s
CI / Synaptics Build (push) Canceled after 0s
This commit is contained in:
@@ -103,12 +103,13 @@ class CameraActivityManager:
|
|||||||
all_objects: list[dict[str, Any]] = []
|
all_objects: list[dict[str, Any]] = []
|
||||||
|
|
||||||
for camera in new_activity.keys():
|
for camera in new_activity.keys():
|
||||||
if camera not in self.config.cameras:
|
camera_config = self.config.cameras.get(camera)
|
||||||
|
if camera_config is None:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
# handle cameras that were added dynamically
|
# handle cameras that were added dynamically
|
||||||
if camera not in self.camera_all_object_counts:
|
if camera not in self.camera_all_object_counts:
|
||||||
self.__init_camera(self.config.cameras[camera])
|
self.__init_camera(camera_config)
|
||||||
|
|
||||||
new_objects = new_activity[camera].get("objects", [])
|
new_objects = new_activity[camera].get("objects", [])
|
||||||
all_objects.extend(new_objects)
|
all_objects.extend(new_objects)
|
||||||
@@ -233,12 +234,13 @@ class AudioActivityManager:
|
|||||||
now = datetime.datetime.now().timestamp()
|
now = datetime.datetime.now().timestamp()
|
||||||
|
|
||||||
for camera in new_activity.keys():
|
for camera in new_activity.keys():
|
||||||
if camera not in self.config.cameras:
|
camera_config = self.config.cameras.get(camera)
|
||||||
|
if camera_config is None:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
# handle cameras that were added dynamically
|
# handle cameras that were added dynamically
|
||||||
if camera not in self.current_audio_detections:
|
if camera not in self.current_audio_detections:
|
||||||
self.__init_camera(self.config.cameras[camera])
|
self.__init_camera(camera_config)
|
||||||
|
|
||||||
new_detections = new_activity[camera].get("detections", [])
|
new_detections = new_activity[camera].get("detections", [])
|
||||||
if self.compare_audio_activity(camera, new_detections, now):
|
if self.compare_audio_activity(camera, new_detections, now):
|
||||||
|
|||||||
@@ -352,8 +352,9 @@ def stats_snapshot(
|
|||||||
total_camera_fps = total_process_fps = total_skipped_fps = total_detection_fps = 0
|
total_camera_fps = total_process_fps = total_skipped_fps = total_detection_fps = 0
|
||||||
|
|
||||||
stats["cameras"] = {}
|
stats["cameras"] = {}
|
||||||
for name, camera_stats in camera_metrics.items():
|
for name, camera_stats in list(camera_metrics.items()):
|
||||||
if name not in config.cameras:
|
camera_config = config.cameras.get(name)
|
||||||
|
if camera_config is None:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
total_camera_fps += camera_stats.camera_fps.value
|
total_camera_fps += camera_stats.camera_fps.value
|
||||||
@@ -370,7 +371,7 @@ def stats_snapshot(
|
|||||||
# Calculate connection quality based on current state
|
# Calculate connection quality based on current state
|
||||||
# This is computed at stats-collection time so offline cameras
|
# This is computed at stats-collection time so offline cameras
|
||||||
# correctly show as unusable rather than excellent
|
# correctly show as unusable rather than excellent
|
||||||
expected_fps = config.cameras[name].detect.fps
|
expected_fps = camera_config.detect.fps
|
||||||
current_fps = camera_stats.camera_fps.value
|
current_fps = camera_stats.camera_fps.value
|
||||||
reconnects = camera_stats.reconnects_last_hour.value
|
reconnects = camera_stats.reconnects_last_hour.value
|
||||||
stalls = camera_stats.stalls_last_hour.value
|
stalls = camera_stats.stalls_last_hour.value
|
||||||
@@ -398,7 +399,7 @@ def stats_snapshot(
|
|||||||
"process_fps": round(camera_stats.process_fps.value, 2),
|
"process_fps": round(camera_stats.process_fps.value, 2),
|
||||||
"skipped_fps": round(camera_stats.skipped_fps.value, 2),
|
"skipped_fps": round(camera_stats.skipped_fps.value, 2),
|
||||||
"detection_fps": round(camera_stats.detection_fps.value, 2),
|
"detection_fps": round(camera_stats.detection_fps.value, 2),
|
||||||
"detection_enabled": config.cameras[name].detect.enabled,
|
"detection_enabled": camera_config.detect.enabled,
|
||||||
"pid": pid,
|
"pid": pid,
|
||||||
"capture_pid": capture_pid,
|
"capture_pid": capture_pid,
|
||||||
"ffmpeg_pid": ffmpeg_pid,
|
"ffmpeg_pid": ffmpeg_pid,
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ from frigate.comms.event_metadata_updater import (
|
|||||||
from frigate.comms.events_updater import EventEndSubscriber, EventUpdatePublisher
|
from frigate.comms.events_updater import EventEndSubscriber, EventUpdatePublisher
|
||||||
from frigate.comms.inter_process import InterProcessRequestor
|
from frigate.comms.inter_process import InterProcessRequestor
|
||||||
from frigate.config import (
|
from frigate.config import (
|
||||||
|
CameraConfig,
|
||||||
CameraMqttConfig,
|
CameraMqttConfig,
|
||||||
FrigateConfig,
|
FrigateConfig,
|
||||||
RecordConfig,
|
RecordConfig,
|
||||||
@@ -128,8 +129,10 @@ class TrackedObjectProcessor(threading.Thread):
|
|||||||
)
|
)
|
||||||
|
|
||||||
def update(camera: str, obj: TrackedObject, frame_name: str) -> None:
|
def update(camera: str, obj: TrackedObject, frame_name: str) -> None:
|
||||||
obj.has_snapshot = self.should_save_snapshot(camera, obj)
|
obj.has_snapshot = self.should_save_snapshot(
|
||||||
obj.has_clip = self.should_retain_recording(camera, obj)
|
camera_state.camera_config, obj
|
||||||
|
)
|
||||||
|
obj.has_clip = self.should_retain_recording(camera_state.camera_config, obj)
|
||||||
after = obj.to_dict()
|
after = obj.to_dict()
|
||||||
message = {
|
message = {
|
||||||
"before": obj.previous,
|
"before": obj.previous,
|
||||||
@@ -153,8 +156,10 @@ class TrackedObjectProcessor(threading.Thread):
|
|||||||
|
|
||||||
def end(camera: str, obj: TrackedObject, frame_name: str) -> None:
|
def end(camera: str, obj: TrackedObject, frame_name: str) -> None:
|
||||||
# populate has_snapshot
|
# populate has_snapshot
|
||||||
obj.has_snapshot = self.should_save_snapshot(camera, obj)
|
obj.has_snapshot = self.should_save_snapshot(
|
||||||
obj.has_clip = self.should_retain_recording(camera, obj)
|
camera_state.camera_config, obj
|
||||||
|
)
|
||||||
|
obj.has_clip = self.should_retain_recording(camera_state.camera_config, obj)
|
||||||
|
|
||||||
# write thumbnail to disk if it will be saved as an event
|
# write thumbnail to disk if it will be saved as an event
|
||||||
if obj.has_snapshot or obj.has_clip:
|
if obj.has_snapshot or obj.has_clip:
|
||||||
@@ -184,8 +189,8 @@ class TrackedObjectProcessor(threading.Thread):
|
|||||||
)
|
)
|
||||||
|
|
||||||
def snapshot(camera: str, obj: TrackedObject) -> bool:
|
def snapshot(camera: str, obj: TrackedObject) -> bool:
|
||||||
mqtt_config: CameraMqttConfig = self.config.cameras[camera].mqtt
|
mqtt_config: CameraMqttConfig = camera_state.camera_config.mqtt
|
||||||
if mqtt_config.enabled and self.should_mqtt_snapshot(camera, obj):
|
if mqtt_config.enabled and self.should_mqtt_snapshot(mqtt_config, obj):
|
||||||
jpg_bytes, _ = obj.get_img_bytes(
|
jpg_bytes, _ = obj.get_img_bytes(
|
||||||
ext="jpg",
|
ext="jpg",
|
||||||
timestamp=mqtt_config.timestamp,
|
timestamp=mqtt_config.timestamp,
|
||||||
@@ -238,11 +243,13 @@ class TrackedObjectProcessor(threading.Thread):
|
|||||||
camera_state.on("camera_activity", camera_activity)
|
camera_state.on("camera_activity", camera_activity)
|
||||||
self.camera_states[camera] = camera_state
|
self.camera_states[camera] = camera_state
|
||||||
|
|
||||||
def should_save_snapshot(self, camera: str, obj: TrackedObject) -> bool:
|
def should_save_snapshot(
|
||||||
|
self, camera_config: CameraConfig, obj: TrackedObject
|
||||||
|
) -> bool:
|
||||||
if obj.false_positive:
|
if obj.false_positive:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
snapshot_config: SnapshotsConfig = self.config.cameras[camera].snapshots
|
snapshot_config: SnapshotsConfig = camera_config.snapshots
|
||||||
|
|
||||||
if not snapshot_config.enabled:
|
if not snapshot_config.enabled:
|
||||||
return False
|
return False
|
||||||
@@ -261,11 +268,13 @@ class TrackedObjectProcessor(threading.Thread):
|
|||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def should_retain_recording(self, camera: str, obj: TrackedObject) -> bool:
|
def should_retain_recording(
|
||||||
|
self, camera_config: CameraConfig, obj: TrackedObject
|
||||||
|
) -> bool:
|
||||||
if obj.false_positive:
|
if obj.false_positive:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
record_config: RecordConfig = self.config.cameras[camera].record
|
record_config: RecordConfig = camera_config.record
|
||||||
|
|
||||||
# Recording is disabled
|
# Recording is disabled
|
||||||
if not record_config.enabled:
|
if not record_config.enabled:
|
||||||
@@ -281,13 +290,15 @@ class TrackedObjectProcessor(threading.Thread):
|
|||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def should_mqtt_snapshot(self, camera: str, obj: TrackedObject) -> bool:
|
def should_mqtt_snapshot(
|
||||||
|
self, mqtt_config: CameraMqttConfig, obj: TrackedObject
|
||||||
|
) -> bool:
|
||||||
# object never changed position
|
# object never changed position
|
||||||
if obj.is_stationary():
|
if obj.is_stationary():
|
||||||
return False
|
return False
|
||||||
|
|
||||||
# if there are required zones and there is no overlap
|
# if there are required zones and there is no overlap
|
||||||
required_zones = self.config.cameras[camera].mqtt.required_zones
|
required_zones = mqtt_config.required_zones
|
||||||
if len(required_zones) > 0 and not set(obj.entered_zones) & set(required_zones):
|
if len(required_zones) > 0 and not set(obj.entered_zones) & set(required_zones):
|
||||||
logger.debug(
|
logger.debug(
|
||||||
f"Not sending mqtt for {obj.obj_data['id']} because it did not enter required zones"
|
f"Not sending mqtt for {obj.obj_data['id']} because it did not enter required zones"
|
||||||
@@ -297,7 +308,11 @@ class TrackedObjectProcessor(threading.Thread):
|
|||||||
return True
|
return True
|
||||||
|
|
||||||
def update_mqtt_motion(
|
def update_mqtt_motion(
|
||||||
self, camera: str, frame_time: float, motion_boxes: list
|
self,
|
||||||
|
camera: str,
|
||||||
|
camera_config: CameraConfig,
|
||||||
|
frame_time: float,
|
||||||
|
motion_boxes: list,
|
||||||
) -> None:
|
) -> None:
|
||||||
# publish if motion is currently being detected
|
# publish if motion is currently being detected
|
||||||
if motion_boxes:
|
if motion_boxes:
|
||||||
@@ -312,7 +327,7 @@ class TrackedObjectProcessor(threading.Thread):
|
|||||||
# always updated latest motion
|
# always updated latest motion
|
||||||
self.last_motion_detected[camera] = frame_time
|
self.last_motion_detected[camera] = frame_time
|
||||||
elif self.last_motion_detected.get(camera, 0) > 0:
|
elif self.last_motion_detected.get(camera, 0) > 0:
|
||||||
mqtt_delay = self.config.cameras[camera].motion.mqtt_off_delay
|
mqtt_delay = camera_config.motion.mqtt_off_delay
|
||||||
|
|
||||||
# If no motion, make sure the off_delay has passed
|
# If no motion, make sure the off_delay has passed
|
||||||
if frame_time - self.last_motion_detected.get(camera, 0) >= mqtt_delay:
|
if frame_time - self.last_motion_detected.get(camera, 0) >= mqtt_delay:
|
||||||
@@ -783,7 +798,7 @@ class TrackedObjectProcessor(threading.Thread):
|
|||||||
frame_name, frame_time, current_tracked_objects, motion_boxes, regions
|
frame_name, frame_time, current_tracked_objects, motion_boxes, regions
|
||||||
)
|
)
|
||||||
|
|
||||||
self.update_mqtt_motion(camera, frame_time, motion_boxes)
|
self.update_mqtt_motion(camera, camera_config, frame_time, motion_boxes)
|
||||||
|
|
||||||
tracked_objects = [
|
tracked_objects = [
|
||||||
o.to_dict() for o in camera_state.tracked_objects.values()
|
o.to_dict() for o in camera_state.tracked_objects.values()
|
||||||
|
|||||||
Reference in New Issue
Block a user