Motion review playback optimizations (#10659)

* handle motion timestamps with ranges

* check for overlaps when checking segment for events

* rename motion color vars to significant_motion for consistency

* safelist significant_motion

* rename vars for clarity and use timeout instead of interval
This commit is contained in:
Josh Hawkins
2024-03-24 21:37:44 -05:00
committed by GitHub
parent 24d29dd32c
commit 7b64091128
9 changed files with 163 additions and 129 deletions

View File

@@ -4,8 +4,6 @@ import {
useMotionActivity,
} from "@/api/ws";
import { CameraConfig } from "@/types/frigateConfig";
import { MotionData, ReviewSegment } from "@/types/review";
import { TimeRange } from "@/types/timeline";
import { useEffect, useMemo, useState } from "react";
type useCameraActivityReturn = {
@@ -68,57 +66,3 @@ export function useCameraActivity(
: false,
};
}
export function useCameraMotionTimestamps(
timeRange: TimeRange,
motionOnly: boolean,
events: ReviewSegment[],
motion: MotionData[],
) {
const timestamps = useMemo(() => {
const seekableTimestamps = [];
let lastEventIdx = 0;
let lastMotionIdx = 0;
for (let i = timeRange.after; i <= timeRange.before; i += 0.5) {
if (!motionOnly) {
seekableTimestamps.push(i);
} else {
const relevantEventIdx = events.findIndex((seg, segIdx) => {
if (segIdx < lastEventIdx) {
return false;
}
return seg.start_time <= i && seg.end_time >= i;
});
if (relevantEventIdx != -1) {
lastEventIdx = relevantEventIdx;
continue;
}
const relevantMotionIdx = motion.findIndex((mot, motIdx) => {
if (motIdx < lastMotionIdx) {
return false;
}
return mot.start_time <= i && mot.start_time + 15 >= i;
});
if (relevantMotionIdx == -1 || motion[relevantMotionIdx].motion == 0) {
if (relevantMotionIdx != -1) {
lastMotionIdx = relevantMotionIdx;
}
continue;
}
seekableTimestamps.push(i);
}
}
return seekableTimestamps;
}, [timeRange, motionOnly, events, motion]);
return timestamps;
}

View File

@@ -368,27 +368,10 @@ function useDraggableElement({
const alignedSegmentTime = alignStartDateToTimeline(draggableElementTime);
let segmentElement = timelineRef.current.querySelector(
const segmentElement = timelineRef.current.querySelector(
`[data-segment-id="${alignedSegmentTime}"]`,
);
if (!segmentElement) {
// segment not found, maybe we collapsed over a collapsible segment
let searchTime = alignedSegmentTime;
while (searchTime >= timelineStartAligned - timelineDuration) {
// Decrement currentTime by segmentDuration
searchTime -= segmentDuration;
segmentElement = timelineRef.current.querySelector(
`[data-segment-id="${searchTime}"]`,
);
if (segmentElement) {
// segmentElement found
break;
}
}
}
if (segmentElement) {
const timelineRect = timelineRef.current.getBoundingClientRect();
const timelineTopAbsolute = timelineRect.top;
@@ -422,6 +405,37 @@ function useDraggableElement({
segments,
]);
useEffect(() => {
if (timelineRef.current && draggableElementTime && timelineCollapsed) {
const alignedSegmentTime = alignStartDateToTimeline(draggableElementTime);
let segmentElement = timelineRef.current.querySelector(
`[data-segment-id="${alignedSegmentTime}"]`,
);
if (!segmentElement) {
// segment not found, maybe we collapsed over a collapsible segment
let searchTime = alignedSegmentTime;
while (searchTime >= timelineStartAligned - timelineDuration) {
searchTime -= segmentDuration;
segmentElement = timelineRef.current.querySelector(
`[data-segment-id="${searchTime}"]`,
);
if (segmentElement) {
// found, set time
if (setDraggableElementTime) {
setDraggableElementTime(searchTime);
}
break;
}
}
}
}
// we know that these deps are correct
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [timelineCollapsed]);
return { handleMouseDown, handleMouseUp, handleMouseMove };
}

View File

@@ -33,7 +33,7 @@ export const useMotionSegmentUtils = (
const interpolateMotionAudioData = useCallback(
(value: number, newMax: number): number => {
return Math.ceil((Math.abs(value) / 100.0) * newMax) || 1;
return Math.ceil((Math.abs(value) / 100.0) * newMax) || 0;
},
[],
);