mirror of
https://github.com/blakeblackshear/frigate.git
synced 2026-04-05 22:57:40 +03:00
Merge pull request #60 from ibs0d/claude/fix-zoom-statistics-WFvOm
fix: exclude stats, spinner and motion dot from camera zoom transform
This commit is contained in:
commit
c3465dd611
@ -48,6 +48,9 @@ type LivePlayerProps = {
|
|||||||
pip?: boolean;
|
pip?: boolean;
|
||||||
autoLive?: boolean;
|
autoLive?: boolean;
|
||||||
showStats?: boolean;
|
showStats?: boolean;
|
||||||
|
onStatsUpdate?: (stats: PlayerStatsType) => void;
|
||||||
|
onLoadingChange?: (loading: boolean) => void;
|
||||||
|
onActiveMotionChange?: (active: boolean) => void;
|
||||||
onClick?: () => void;
|
onClick?: () => void;
|
||||||
setFullResolution?: React.Dispatch<React.SetStateAction<VideoResolutionType>>;
|
setFullResolution?: React.Dispatch<React.SetStateAction<VideoResolutionType>>;
|
||||||
onError?: (error: LivePlayerError) => void;
|
onError?: (error: LivePlayerError) => void;
|
||||||
@ -73,6 +76,9 @@ export default function LivePlayer({
|
|||||||
pip,
|
pip,
|
||||||
autoLive = true,
|
autoLive = true,
|
||||||
showStats = false,
|
showStats = false,
|
||||||
|
onStatsUpdate,
|
||||||
|
onLoadingChange,
|
||||||
|
onActiveMotionChange,
|
||||||
onClick,
|
onClick,
|
||||||
setFullResolution,
|
setFullResolution,
|
||||||
onError,
|
onError,
|
||||||
@ -105,6 +111,10 @@ export default function LivePlayer({
|
|||||||
droppedFrameRate: 0, // percentage
|
droppedFrameRate: 0, // percentage
|
||||||
});
|
});
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
onStatsUpdate?.(stats);
|
||||||
|
}, [stats, onStatsUpdate]);
|
||||||
|
|
||||||
// camera activity
|
// camera activity
|
||||||
|
|
||||||
const {
|
const {
|
||||||
@ -274,6 +284,42 @@ export default function LivePlayer({
|
|||||||
}
|
}
|
||||||
}, [liveReady, isReEnabling]);
|
}, [liveReady, isReEnabling]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!onLoadingChange) return;
|
||||||
|
const loading = !!(
|
||||||
|
cameraEnabled &&
|
||||||
|
!offline &&
|
||||||
|
(!showStillWithoutActivity || isReEnabling) &&
|
||||||
|
!liveReady
|
||||||
|
);
|
||||||
|
onLoadingChange(loading);
|
||||||
|
}, [
|
||||||
|
onLoadingChange,
|
||||||
|
cameraEnabled,
|
||||||
|
offline,
|
||||||
|
showStillWithoutActivity,
|
||||||
|
isReEnabling,
|
||||||
|
liveReady,
|
||||||
|
]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!onActiveMotionChange) return;
|
||||||
|
const motionVisible = !!(
|
||||||
|
autoLive &&
|
||||||
|
!offline &&
|
||||||
|
activeMotion &&
|
||||||
|
((showStillWithoutActivity && !liveReady) || liveReady)
|
||||||
|
);
|
||||||
|
onActiveMotionChange(motionVisible);
|
||||||
|
}, [
|
||||||
|
onActiveMotionChange,
|
||||||
|
autoLive,
|
||||||
|
offline,
|
||||||
|
activeMotion,
|
||||||
|
showStillWithoutActivity,
|
||||||
|
liveReady,
|
||||||
|
]);
|
||||||
|
|
||||||
if (!cameraConfig) {
|
if (!cameraConfig) {
|
||||||
return <ActivityIndicator />;
|
return <ActivityIndicator />;
|
||||||
}
|
}
|
||||||
@ -407,7 +453,8 @@ export default function LivePlayer({
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{cameraEnabled &&
|
{!onLoadingChange &&
|
||||||
|
cameraEnabled &&
|
||||||
!offline &&
|
!offline &&
|
||||||
(!showStillWithoutActivity || isReEnabling) &&
|
(!showStillWithoutActivity || isReEnabling) &&
|
||||||
!liveReady && <ActivityIndicator />}
|
!liveReady && <ActivityIndicator />}
|
||||||
@ -530,14 +577,15 @@ export default function LivePlayer({
|
|||||||
{cameraName}
|
{cameraName}
|
||||||
</Chip>
|
</Chip>
|
||||||
)}
|
)}
|
||||||
{autoLive &&
|
{!onActiveMotionChange &&
|
||||||
|
autoLive &&
|
||||||
!offline &&
|
!offline &&
|
||||||
activeMotion &&
|
activeMotion &&
|
||||||
((showStillWithoutActivity && !liveReady) || liveReady) && (
|
((showStillWithoutActivity && !liveReady) || liveReady) && (
|
||||||
<MdCircle className="mr-2 size-2 animate-pulse text-danger shadow-danger drop-shadow-md" />
|
<MdCircle className="mr-2 size-2 animate-pulse text-danger shadow-danger drop-shadow-md" />
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
{showStats && (
|
{showStats && !onStatsUpdate && (
|
||||||
<PlayerStats stats={stats} minimal={cameraRef !== undefined} />
|
<PlayerStats stats={stats} minimal={cameraRef !== undefined} />
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -23,9 +23,13 @@ import {
|
|||||||
AudioState,
|
AudioState,
|
||||||
LivePlayerMode,
|
LivePlayerMode,
|
||||||
LiveStreamMetadata,
|
LiveStreamMetadata,
|
||||||
|
PlayerStatsType,
|
||||||
StatsState,
|
StatsState,
|
||||||
VolumeState,
|
VolumeState,
|
||||||
} from "@/types/live";
|
} from "@/types/live";
|
||||||
|
import ActivityIndicator from "@/components/indicators/activity-indicator";
|
||||||
|
import { PlayerStats } from "@/components/player/PlayerStats";
|
||||||
|
import { MdCircle } from "react-icons/md";
|
||||||
import { Skeleton } from "@/components/ui/skeleton";
|
import { Skeleton } from "@/components/ui/skeleton";
|
||||||
|
|
||||||
import { isEqual } from "lodash";
|
import { isEqual } from "lodash";
|
||||||
@ -431,6 +435,15 @@ export default function DraggableGridLayout({
|
|||||||
const [cameraZoomStates, setCameraZoomStates] = useState<
|
const [cameraZoomStates, setCameraZoomStates] = useState<
|
||||||
Record<string, CameraZoomRuntimeTransform>
|
Record<string, CameraZoomRuntimeTransform>
|
||||||
>({});
|
>({});
|
||||||
|
const [cameraStatsData, setCameraStatsData] = useState<
|
||||||
|
Record<string, PlayerStatsType>
|
||||||
|
>({});
|
||||||
|
const [cameraLoadingStates, setCameraLoadingStates] = useState<
|
||||||
|
Record<string, boolean>
|
||||||
|
>({});
|
||||||
|
const [cameraMotionStates, setCameraMotionStates] = useState<
|
||||||
|
Record<string, boolean>
|
||||||
|
>({});
|
||||||
const cameraZoomViewportRefs = useRef<Record<string, HTMLDivElement | null>>(
|
const cameraZoomViewportRefs = useRef<Record<string, HTMLDivElement | null>>(
|
||||||
{},
|
{},
|
||||||
);
|
);
|
||||||
@ -808,7 +821,7 @@ export default function DraggableGridLayout({
|
|||||||
streamMetadata={streamMetadata}
|
streamMetadata={streamMetadata}
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
className="size-full overflow-hidden"
|
className="relative size-full overflow-hidden"
|
||||||
ref={(node) => {
|
ref={(node) => {
|
||||||
cameraZoomViewportRefs.current[camera.name] = node;
|
cameraZoomViewportRefs.current[camera.name] = node;
|
||||||
|
|
||||||
@ -855,7 +868,25 @@ export default function DraggableGridLayout({
|
|||||||
preferredLiveModes[camera.name] ?? "mse"
|
preferredLiveModes[camera.name] ?? "mse"
|
||||||
}
|
}
|
||||||
playInBackground={false}
|
playInBackground={false}
|
||||||
showStats={statsStates[camera.name] ?? true}
|
showStats={false}
|
||||||
|
onStatsUpdate={(stats) =>
|
||||||
|
setCameraStatsData((prev) => ({
|
||||||
|
...prev,
|
||||||
|
[camera.name]: stats,
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
onLoadingChange={(loading) =>
|
||||||
|
setCameraLoadingStates((prev) => ({
|
||||||
|
...prev,
|
||||||
|
[camera.name]: loading,
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
onActiveMotionChange={(active) =>
|
||||||
|
setCameraMotionStates((prev) => ({
|
||||||
|
...prev,
|
||||||
|
[camera.name]: active,
|
||||||
|
}))
|
||||||
|
}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
!isEditMode && onSelectCamera(camera.name);
|
!isEditMode && onSelectCamera(camera.name);
|
||||||
}}
|
}}
|
||||||
@ -875,6 +906,23 @@ export default function DraggableGridLayout({
|
|||||||
volume={volumeStates[camera.name]}
|
volume={volumeStates[camera.name]}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
{cameraLoadingStates[camera.name] && (
|
||||||
|
<div className="absolute inset-0 flex items-center justify-center">
|
||||||
|
<ActivityIndicator />
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
{statsStates[camera.name] &&
|
||||||
|
cameraStatsData[camera.name] && (
|
||||||
|
<PlayerStats
|
||||||
|
stats={cameraStatsData[camera.name]}
|
||||||
|
minimal={true}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
{cameraMotionStates[camera.name] && (
|
||||||
|
<div className="absolute right-2 top-2 z-40">
|
||||||
|
<MdCircle className="mr-2 size-2 animate-pulse text-danger shadow-danger drop-shadow-md" />
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
{isEditMode && showCircles && <CornerCircles />}
|
{isEditMode && showCircles && <CornerCircles />}
|
||||||
</GridLiveContextMenu>
|
</GridLiveContextMenu>
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user