From 2e04f2f152f591c6f7067e25bda101592f7c8b54 Mon Sep 17 00:00:00 2001 From: Josh Hawkins <32435876+hawkeye217@users.noreply.github.com> Date: Wed, 3 Jun 2026 14:38:38 -0500 Subject: [PATCH 1/5] serialize OpenVINO inference per process to prevent concurrent-inference segfault --- frigate/detectors/detection_runners.py | 32 +++++++++++++++++--------- 1 file changed, 21 insertions(+), 11 deletions(-) diff --git a/frigate/detectors/detection_runners.py b/frigate/detectors/detection_runners.py index c89cd8b44f..c6c9569da9 100644 --- a/frigate/detectors/detection_runners.py +++ b/frigate/detectors/detection_runners.py @@ -15,6 +15,9 @@ from frigate.util.rknn_converter import auto_convert_model, is_rknn_compatible logger = logging.getLogger(__name__) +# Process-wide lock serializing all OpenVINO compile/inference calls +_OPENVINO_LOCK = threading.Lock() + def is_arm64_platform() -> bool: """Check if we're running on an ARM platform.""" @@ -326,18 +329,23 @@ class OpenVINOModelRunner(BaseModelRunner): except Exception as e: logger.debug(f"NPU_TURBO not supported by driver: {e}") - # Compile model - self.compiled_model = self.ov_core.compile_model( - model=model_path, device_name=device - ) + # Compile model under the shared lock + with _OPENVINO_LOCK: + self.compiled_model = self.ov_core.compile_model( + model=model_path, device_name=device + ) + + # Create reusable inference request + self.infer_request = self.compiled_model.create_infer_request() - # Create reusable inference request - self.infer_request = self.compiled_model.create_infer_request() self.input_tensor: ov.Tensor | None = None - # Thread lock to prevent concurrent inference (needed for JinaV2 which shares - # one runner between text and vision embeddings called from different threads) - self._inference_lock = threading.Lock() + # Shared, process-wide lock serializing inference across all OpenVINO + # runners in this process. Needed both for the JinaV2 case (one runner + # shared between text and vision threads) and to prevent two *different* + # runners (e.g. an ArcFace face-model build thread and the LPR detector) + # from inferring concurrently and corrupting shared OpenVINO state. + self._inference_lock = _OPENVINO_LOCK if not self.complex_model: try: @@ -382,8 +390,10 @@ class OpenVINOModelRunner(BaseModelRunner): Returns: List of output tensors """ - # Lock prevents concurrent access to infer_request - # Needed for JinaV2: genai thread (text) + embeddings thread (vision) + # Shared lock serializes inference across every OpenVINO runner in this + # process — both the shared-runner JinaV2 case (genai text thread + + # embeddings vision thread) and distinct runners running on separate + # threads (e.g. the ArcFace face-model build vs the LPR detector). with self._inference_lock: from frigate.embeddings.types import EnrichmentModelTypeEnum From 94cd10d370f5ae42d78508d9377fb579147e5203 Mon Sep 17 00:00:00 2001 From: Josh Hawkins <32435876+hawkeye217@users.noreply.github.com> Date: Wed, 3 Jun 2026 14:43:00 -0500 Subject: [PATCH 2/5] clean up --- frigate/detectors/detection_runners.py | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/frigate/detectors/detection_runners.py b/frigate/detectors/detection_runners.py index c6c9569da9..ee465b3d51 100644 --- a/frigate/detectors/detection_runners.py +++ b/frigate/detectors/detection_runners.py @@ -340,13 +340,6 @@ class OpenVINOModelRunner(BaseModelRunner): self.input_tensor: ov.Tensor | None = None - # Shared, process-wide lock serializing inference across all OpenVINO - # runners in this process. Needed both for the JinaV2 case (one runner - # shared between text and vision threads) and to prevent two *different* - # runners (e.g. an ArcFace face-model build thread and the LPR detector) - # from inferring concurrently and corrupting shared OpenVINO state. - self._inference_lock = _OPENVINO_LOCK - if not self.complex_model: try: input_shape = self.compiled_model.inputs[0].get_shape() @@ -394,7 +387,7 @@ class OpenVINOModelRunner(BaseModelRunner): # process — both the shared-runner JinaV2 case (genai text thread + # embeddings vision thread) and distinct runners running on separate # threads (e.g. the ArcFace face-model build vs the LPR detector). - with self._inference_lock: + with _OPENVINO_LOCK: from frigate.embeddings.types import EnrichmentModelTypeEnum if self.model_type in [EnrichmentModelTypeEnum.arcface.value]: From 7109ee1c48afab5990299f28a5ffea9351d7748f Mon Sep 17 00:00:00 2001 From: Josh Hawkins <32435876+hawkeye217@users.noreply.github.com> Date: Wed, 3 Jun 2026 17:16:11 -0500 Subject: [PATCH 3/5] add max scaling meta to login page --- web/login.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/login.html b/web/login.html index fc0fb551e3..f83243d023 100644 --- a/web/login.html +++ b/web/login.html @@ -3,7 +3,7 @@ - + Frigate Date: Thu, 4 Jun 2026 06:21:23 -0500 Subject: [PATCH 4/5] add more detect section field messages --- web/public/locales/en/views/settings.json | 6 +- .../config-form/section-configs/detect.ts | 91 +++++++++++++++++-- 2 files changed, 88 insertions(+), 9 deletions(-) diff --git a/web/public/locales/en/views/settings.json b/web/public/locales/en/views/settings.json index 0c46aec581..a5edab9788 100644 --- a/web/public/locales/en/views/settings.json +++ b/web/public/locales/en/views/settings.json @@ -1908,7 +1908,11 @@ "fpsGreaterThanFive": "Setting the detect FPS higher than 5 is not recommended. Higher values may cause performance issues and will not provide any benefit.", "disabled": "Object detection is disabled. Snapshots, review items, and enrichments such as face recognition, license plate recognition, and Generative AI will not function.", "resolutionShouldBeMultipleOfFour": "For best results, detect width and height should be multiples of 4. Other even values may produce visual artifacts or slight distortion in the detect stream.", - "aspectRatioMismatch": "The width and height you've entered don't match the aspect ratio of your current detect resolution. This may produce a stretched or distorted image." + "aspectRatioMismatch": "The width and height you've entered don't match the aspect ratio of your current detect resolution. This may produce a stretched or distorted image.", + "maxFramesSet": "Setting max frames overrides default behavior and disables stationary object tracking. There are very few situations where this is needed, use with caution.", + "squareResolution": "A square detect resolution is unusual. The detect width and height should match your camera's aspect ratio (for example, 16:9), not the dimensions of the object detection model. A mismatched aspect ratio can stretch the image and reduce detection accuracy.", + "resolutionHigh": "This detect resolution is higher than recommended and may cause increased resource usage without improving detection accuracy. A detect resolution at or below 1080p is recommended for most cameras.", + "globalResolutionMultipleCameras": "A global detect resolution is set while multiple cameras are configured. Unless all cameras share the same resolution and aspect ratio, the detect width and height should be defined per camera to match each camera's native aspect ratio." }, "objects": { "genaiNoDescriptionsProvider": "You must configure a GenAI provider with the 'descriptions' role for descriptions to be generated." diff --git a/web/src/components/config-form/section-configs/detect.ts b/web/src/components/config-form/section-configs/detect.ts index 74d170edc6..9176c49a74 100644 --- a/web/src/components/config-form/section-configs/detect.ts +++ b/web/src/components/config-form/section-configs/detect.ts @@ -11,8 +11,12 @@ const detect: SectionConfigOverrides = { condition: (ctx) => ctx.level === "camera" && ctx.formData?.enabled === false, }, + ], + fieldMessages: [ { key: "detect-resolution-not-multiple-of-four", + field: "width", + position: "before", messageKey: "configMessages.detect.resolutionShouldBeMultipleOfFour", severity: "warning", condition: (ctx) => { @@ -23,8 +27,59 @@ const detect: SectionConfigOverrides = { return isEvenButNotFour(width) || isEvenButNotFour(height); }, }, + { + key: "detect-global-resolution-multiple-cameras", + field: "width", + position: "before", + messageKey: "configMessages.detect.globalResolutionMultipleCameras", + severity: "info", + condition: (ctx) => { + if (ctx.level !== "global") return false; + const width = ctx.formData?.width as number | null | undefined; + const height = ctx.formData?.height as number | null | undefined; + if (typeof width !== "number" && typeof height !== "number") { + return false; + } + const cameraCount = Object.keys(ctx.fullConfig?.cameras ?? {}).length; + return cameraCount > 1; + }, + }, + { + key: "detect-resolution-high", + field: "width", + position: "before", + messageKey: "configMessages.detect.resolutionHigh", + severity: "warning", + condition: (ctx) => { + const width = ctx.formData?.width as number | null | undefined; + const height = ctx.formData?.height as number | null | undefined; + if (typeof width !== "number" || typeof height !== "number") { + return false; + } + return Math.min(width, height) > 1080; + }, + }, + { + key: "detect-square-resolution", + field: "width", + position: "before", + messageKey: "configMessages.detect.squareResolution", + severity: "warning", + condition: (ctx) => { + const width = ctx.formData?.width as number | null | undefined; + const height = ctx.formData?.height as number | null | undefined; + return ( + typeof width === "number" && + typeof height === "number" && + width > 0 && + width === height + ); + }, + }, { key: "detect-aspect-ratio-mismatch", + field: "width", + position: "before", messageKey: "configMessages.detect.aspectRatioMismatch", severity: "warning", condition: (ctx) => { @@ -55,8 +110,6 @@ const detect: SectionConfigOverrides = { return Math.abs(newRatio - savedRatio) > 0.01; }, }, - ], - fieldMessages: [ { key: "fps-greater-than-five", field: "fps", @@ -71,6 +124,31 @@ const detect: SectionConfigOverrides = { return detectFps != null && streamFps != null && detectFps > 5; }, }, + { + key: "max-frames-set", + field: "stationary.max_frames", + messageKey: "configMessages.detect.maxFramesSet", + severity: "warning", + position: "after", + condition: (ctx) => { + const stationary = ctx.formData?.stationary as + | { + max_frames?: { + default?: number | null; + objects?: Record; + } | null; + } + | null + | undefined; + const maxFrames = stationary?.max_frames; + if (!maxFrames) return false; + return ( + typeof maxFrames.default === "number" || + (maxFrames.objects != null && + Object.keys(maxFrames.objects).length > 0) + ); + }, + }, ], fieldOrder: [ "enabled", @@ -81,9 +159,9 @@ const detect: SectionConfigOverrides = { "max_disappeared", "annotation_offset", "stationary", - "interval", - "threshold", - "max_frames", + "stationary.interval", + "stationary.threshold", + "stationary.max_frames", ], restartRequired: [], fieldGroups: { @@ -129,9 +207,6 @@ const detect: SectionConfigOverrides = { "max_disappeared", "annotation_offset", "stationary", - "interval", - "threshold", - "max_frames", ], advancedFields: [], }, From f6bd68e5ecbd976aae321327057a8e5c918738b8 Mon Sep 17 00:00:00 2001 From: Josh Hawkins <32435876+hawkeye217@users.noreply.github.com> Date: Thu, 4 Jun 2026 06:21:48 -0500 Subject: [PATCH 5/5] fix icon layout in settings field messages --- web/src/components/config-form/ConfigFieldMessage.tsx | 8 ++++---- web/src/components/config-form/ConfigMessageBanner.tsx | 6 +++--- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/web/src/components/config-form/ConfigFieldMessage.tsx b/web/src/components/config-form/ConfigFieldMessage.tsx index 5c0a5c5056..545d50ba7c 100644 --- a/web/src/components/config-form/ConfigFieldMessage.tsx +++ b/web/src/components/config-form/ConfigFieldMessage.tsx @@ -15,13 +15,13 @@ const severityVariantMap: Record< function SeverityIcon({ severity }: { severity: string }) { switch (severity) { case "info": - return ; + return ; case "warning": - return ; + return ; case "error": - return ; + return ; default: - return ; + return ; } } diff --git a/web/src/components/config-form/ConfigMessageBanner.tsx b/web/src/components/config-form/ConfigMessageBanner.tsx index 919d337c15..8e701947a0 100644 --- a/web/src/components/config-form/ConfigMessageBanner.tsx +++ b/web/src/components/config-form/ConfigMessageBanner.tsx @@ -18,11 +18,11 @@ const severityVariantMap: Record< function SeverityIcon({ severity }: { severity: MessageSeverity }) { switch (severity) { case "info": - return ; + return ; case "warning": - return ; + return ; case "error": - return ; + return ; } }