From 1188d87588d5e9aef35c4311c70e08542942edf7 Mon Sep 17 00:00:00 2001 From: Josh Hawkins <32435876+hawkeye217@users.noreply.github.com> Date: Mon, 9 Mar 2026 16:50:46 -0500 Subject: [PATCH] Save detect dimensions to config on add camera wizard save (#22349) * add util for optimal detect resolution * add detect to type * save optimal detect resolution to config on wizard save * use const --- .../settings/CameraWizardDialog.tsx | 24 +++++++++- web/src/types/cameraWizard.ts | 4 ++ web/src/utils/cameraUtil.ts | 45 +++++++++++++++++++ 3 files changed, 72 insertions(+), 1 deletion(-) diff --git a/web/src/components/settings/CameraWizardDialog.tsx b/web/src/components/settings/CameraWizardDialog.tsx index 5846fd9a2..74969290a 100644 --- a/web/src/components/settings/CameraWizardDialog.tsx +++ b/web/src/components/settings/CameraWizardDialog.tsx @@ -20,7 +20,10 @@ import type { CameraConfigData, ConfigSetBody, } from "@/types/cameraWizard"; -import { processCameraName } from "@/utils/cameraUtil"; +import { + processCameraName, + calculateDetectDimensions, +} from "@/utils/cameraUtil"; import { cn } from "@/lib/utils"; type WizardState = { @@ -203,6 +206,25 @@ export default function CameraWizardDialog({ }, }; + // Calculate detect dimensions from the detect stream's probed resolution + const detectStream = wizardData.streams.find((stream) => + stream.roles.includes("detect"), + ); + if (detectStream?.testResult?.resolution) { + const [streamWidth, streamHeight] = detectStream.testResult.resolution + .split("x") + .map(Number); + if (streamWidth > 0 && streamHeight > 0) { + const detectDimensions = calculateDetectDimensions( + streamWidth, + streamHeight, + ); + if (detectDimensions) { + configData.cameras[finalCameraName].detect = detectDimensions; + } + } + } + // Add live.streams configuration for go2rtc streams if (wizardData.streams && wizardData.streams.length > 0) { configData.cameras[finalCameraName].live = { diff --git a/web/src/types/cameraWizard.ts b/web/src/types/cameraWizard.ts index 4048303cb..20e843635 100644 --- a/web/src/types/cameraWizard.ts +++ b/web/src/types/cameraWizard.ts @@ -162,6 +162,10 @@ export type CameraConfigData = { input_args?: string; }[]; }; + detect?: { + width: number; + height: number; + }; live?: { streams: Record; }; diff --git a/web/src/utils/cameraUtil.ts b/web/src/utils/cameraUtil.ts index 543605ad0..07295d73c 100644 --- a/web/src/utils/cameraUtil.ts +++ b/web/src/utils/cameraUtil.ts @@ -115,6 +115,51 @@ export type CameraAudioFeatures = { * @param requireSecureContext - If true, two-way audio requires secure context (default: true) * @returns CameraAudioFeatures object with detected capabilities */ +/** + * Calculates optimal detect dimensions from stream resolution. + * + * Scales dimensions to an efficient size for object detection while + * preserving the stream's aspect ratio. Does not upscale. + * + * @param streamWidth - Native stream width in pixels + * @param streamHeight - Native stream height in pixels + * @returns Detect dimensions with even values, or null if inputs are invalid + */ + +// Target size for the smaller dimension (width or height) for detect streams +export const DETECT_TARGET_PX = 720; + +export function calculateDetectDimensions( + streamWidth: number, + streamHeight: number, +): { width: number; height: number } | null { + if ( + !Number.isFinite(streamWidth) || + !Number.isFinite(streamHeight) || + streamWidth <= 0 || + streamHeight <= 0 + ) { + return null; + } + + const smallerDim = Math.min(streamWidth, streamHeight); + const target = Math.min(DETECT_TARGET_PX, smallerDim); + const scale = target / smallerDim; + + let width = Math.round(streamWidth * scale); + let height = Math.round(streamHeight * scale); + + // Round down to even numbers (required for video processing) + width = width - (width % 2); + height = height - (height % 2); + + if (width < 2 || height < 2) { + return null; + } + + return { width, height }; +} + export function detectCameraAudioFeatures( metadata: LiveStreamMetadata | null | undefined, requireSecureContext: boolean = true,