mirror of
https://github.com/blakeblackshear/frigate.git
synced 2026-04-12 10:07:36 +03:00
use annotation offset
This commit is contained in:
parent
f673398053
commit
fcb28cf1c2
@ -2,6 +2,7 @@ import { useMemo, useCallback } from "react";
|
||||
import { ObjectLifecycleSequence, LifecycleClassType } from "@/types/timeline";
|
||||
import { FrigateConfig } from "@/types/frigateConfig";
|
||||
import useSWR from "swr";
|
||||
import { useActivityStream } from "@/contexts/ActivityStreamContext";
|
||||
import {
|
||||
Tooltip,
|
||||
TooltipContent,
|
||||
@ -32,6 +33,10 @@ export default function ObjectTrackOverlay({
|
||||
objectTimeline,
|
||||
}: ObjectTrackOverlayProps) {
|
||||
const { data: config } = useSWR<FrigateConfig>("config");
|
||||
const { annotationOffset } = useActivityStream();
|
||||
|
||||
// Offset currentTime by annotation offset for rendering
|
||||
const effectiveCurrentTime = currentTime - annotationOffset;
|
||||
|
||||
// Fetch the full event data to get saved path points
|
||||
const { data: eventData } = useSWR(["event_ids", { ids: selectedObjectId }]);
|
||||
@ -76,14 +81,14 @@ export default function ObjectTrackOverlay({
|
||||
const currentObjectZones = useMemo(() => {
|
||||
if (!objectTimeline) return [];
|
||||
|
||||
// Find the most recent timeline event at or before current time
|
||||
// Find the most recent timeline event at or before effective current time
|
||||
const relevantEvents = objectTimeline
|
||||
.filter((event) => event.timestamp <= currentTime)
|
||||
.filter((event) => event.timestamp <= effectiveCurrentTime)
|
||||
.sort((a, b) => b.timestamp - a.timestamp); // Most recent first
|
||||
|
||||
// Get zones from the most recent event
|
||||
return relevantEvents[0]?.data?.zones || [];
|
||||
}, [objectTimeline, currentTime]);
|
||||
}, [objectTimeline, effectiveCurrentTime]);
|
||||
|
||||
const zones = useMemo(() => {
|
||||
if (!config?.cameras?.[camera]?.zones || !currentObjectZones.length)
|
||||
@ -320,9 +325,12 @@ export default function ObjectTrackOverlay({
|
||||
{(() => {
|
||||
if (!objectTimeline) return null;
|
||||
|
||||
// Find the most recent timeline event at or before current time with a bounding box
|
||||
// Find the most recent timeline event at or before effective current time with a bounding box
|
||||
const relevantEvents = objectTimeline
|
||||
.filter((event) => event.timestamp <= currentTime && event.data.box)
|
||||
.filter(
|
||||
(event) =>
|
||||
event.timestamp <= effectiveCurrentTime && event.data.box,
|
||||
)
|
||||
.sort((a, b) => b.timestamp - a.timestamp); // Most recent first
|
||||
|
||||
const currentEvent = relevantEvents[0];
|
||||
|
||||
@ -15,9 +15,11 @@ export default function ActivityStream({
|
||||
currentTime,
|
||||
onSeek,
|
||||
}: ActivityStreamProps) {
|
||||
const { selectedObjectId } = useActivityStream();
|
||||
const { selectedObjectId, annotationOffset } = useActivityStream();
|
||||
const scrollRef = useRef<HTMLDivElement>(null);
|
||||
|
||||
const effectiveTime = currentTime + annotationOffset;
|
||||
|
||||
// group activities by timestamp (within 1 second resolution window)
|
||||
const groupedActivities = useMemo(() => {
|
||||
const groups: { [key: number]: ObjectLifecycleSequence[] } = {};
|
||||
@ -36,12 +38,13 @@ export default function ActivityStream({
|
||||
(a, b) => a.timestamp - b.timestamp,
|
||||
);
|
||||
return {
|
||||
timestamp: sortedActivities[0].timestamp, // use the earliest activity timestamp
|
||||
timestamp: sortedActivities[0].timestamp, // Original timestamp for display
|
||||
effectiveTimestamp: sortedActivities[0].timestamp + annotationOffset, // Adjusted for sorting/comparison
|
||||
activities: sortedActivities,
|
||||
};
|
||||
})
|
||||
.sort((a, b) => a.timestamp - b.timestamp);
|
||||
}, [timelineData]);
|
||||
}, [timelineData, annotationOffset]);
|
||||
|
||||
// Filter activities if object is selected
|
||||
const filteredGroups = useMemo(() => {
|
||||
@ -62,10 +65,10 @@ export default function ActivityStream({
|
||||
useEffect(() => {
|
||||
if (!scrollRef.current) return;
|
||||
|
||||
// Find the last group where timestamp <= currentTime
|
||||
// Find the last group where effectiveTimestamp <= currentTime + annotationOffset
|
||||
let currentGroupIndex = -1;
|
||||
for (let i = filteredGroups.length - 1; i >= 0; i--) {
|
||||
if (filteredGroups[i].timestamp <= currentTime) {
|
||||
if (filteredGroups[i].effectiveTimestamp <= effectiveTime) {
|
||||
currentGroupIndex = i;
|
||||
break;
|
||||
}
|
||||
@ -82,7 +85,7 @@ export default function ActivityStream({
|
||||
});
|
||||
}
|
||||
}
|
||||
}, [filteredGroups, currentTime]);
|
||||
}, [filteredGroups, effectiveTime, annotationOffset]);
|
||||
|
||||
return (
|
||||
<div
|
||||
@ -99,7 +102,7 @@ export default function ActivityStream({
|
||||
<ActivityGroup
|
||||
key={group.timestamp}
|
||||
group={group}
|
||||
isCurrent={group.timestamp <= currentTime}
|
||||
isCurrent={group.effectiveTimestamp <= currentTime}
|
||||
onSeek={onSeek}
|
||||
/>
|
||||
))
|
||||
@ -112,6 +115,7 @@ export default function ActivityStream({
|
||||
type ActivityGroupProps = {
|
||||
group: {
|
||||
timestamp: number;
|
||||
effectiveTimestamp: number;
|
||||
activities: ObjectLifecycleSequence[];
|
||||
};
|
||||
isCurrent: boolean;
|
||||
|
||||
@ -1,11 +1,14 @@
|
||||
import React, { createContext, useContext, useState, useMemo } from "react";
|
||||
import { ObjectLifecycleSequence } from "@/types/timeline";
|
||||
import { FrigateConfig } from "@/types/frigateConfig";
|
||||
import useSWR from "swr";
|
||||
|
||||
interface ActivityStreamContextType {
|
||||
selectedObjectId: string | undefined;
|
||||
selectedObjectTimeline: ObjectLifecycleSequence[] | undefined;
|
||||
currentTime: number;
|
||||
camera: string;
|
||||
annotationOffset: number;
|
||||
setSelectedObjectId: (id: string | undefined) => void;
|
||||
isActivityMode: boolean;
|
||||
}
|
||||
@ -33,6 +36,16 @@ export function ActivityStreamProvider({
|
||||
string | undefined
|
||||
>();
|
||||
|
||||
const { data: config } = useSWR<FrigateConfig>("config");
|
||||
|
||||
const annotationOffset = useMemo(() => {
|
||||
if (!config) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return (config.cameras[camera]?.detect?.annotation_offset || 0) / 1000; // Convert to seconds
|
||||
}, [config, camera]);
|
||||
|
||||
const selectedObjectTimeline = useMemo(() => {
|
||||
if (!selectedObjectId || !timelineData) return undefined;
|
||||
return timelineData.filter((item) => item.source_id === selectedObjectId);
|
||||
@ -43,6 +56,7 @@ export function ActivityStreamProvider({
|
||||
selectedObjectTimeline,
|
||||
currentTime,
|
||||
camera,
|
||||
annotationOffset,
|
||||
setSelectedObjectId,
|
||||
isActivityMode,
|
||||
};
|
||||
|
||||
Loading…
Reference in New Issue
Block a user