From 717517aeb50edbf8da477738d5d612f88060e0ab Mon Sep 17 00:00:00 2001 From: Nicolas Mowen Date: Sun, 18 May 2025 17:23:01 -0600 Subject: [PATCH] Misc fixes (#18289) * Fix key not moved * Account for HLS start offset when seeking and calculating update time --- web/src/components/player/HlsVideoPlayer.tsx | 36 ++++++++++++++----- .../player/dynamic/DynamicVideoController.ts | 5 +++ .../player/dynamic/DynamicVideoPlayer.tsx | 14 ++++++++ web/src/views/recording/RecordingView.tsx | 3 +- 4 files changed, 48 insertions(+), 10 deletions(-) diff --git a/web/src/components/player/HlsVideoPlayer.tsx b/web/src/components/player/HlsVideoPlayer.tsx index 1350a70b1..775159dc1 100644 --- a/web/src/components/player/HlsVideoPlayer.tsx +++ b/web/src/components/player/HlsVideoPlayer.tsx @@ -37,6 +37,7 @@ type HlsVideoPlayerProps = { supportsFullscreen: boolean; fullscreen: boolean; frigateControls?: boolean; + inpointOffset?: number; onClipEnded?: () => void; onPlayerLoaded?: () => void; onTimeUpdate?: (time: number) => void; @@ -55,6 +56,7 @@ export default function HlsVideoPlayer({ supportsFullscreen, fullscreen, frigateControls = true, + inpointOffset = 0, onClipEnded, onPlayerLoaded, onTimeUpdate, @@ -187,6 +189,16 @@ export default function HlsVideoPlayer({ }; }, [videoRef, controlsOpen]); + const getVideoTime = useCallback(() => { + const currentTime = videoRef.current?.currentTime; + + if (!currentTime) { + return undefined; + } + + return currentTime + inpointOffset; + }, [videoRef, inpointOffset]); + return ( { - const currentTime = videoRef.current?.currentTime; + const currentTime = getVideoTime(); if (!videoRef.current || !currentTime) { return; @@ -234,8 +246,10 @@ export default function HlsVideoPlayer({ } }} onUploadFrame={async () => { - if (videoRef.current && onUploadFrame) { - const resp = await onUploadFrame(videoRef.current.currentTime); + const frameTime = getVideoTime(); + + if (frameTime && onUploadFrame) { + const resp = await onUploadFrame(frameTime); if (resp && resp.status == 200) { toast.success(t("toast.success.submittedFrigatePlus"), { @@ -335,11 +349,17 @@ export default function HlsVideoPlayer({ } } }} - onTimeUpdate={() => - onTimeUpdate && videoRef.current - ? onTimeUpdate(videoRef.current.currentTime) - : undefined - } + onTimeUpdate={() => { + if (!onTimeUpdate) { + return; + } + + const frameTime = getVideoTime(); + + if (frameTime) { + onTimeUpdate(frameTime); + } + }} onLoadedData={() => { onPlayerLoaded?.(); handleLoadedMetadata(); diff --git a/web/src/components/player/dynamic/DynamicVideoController.ts b/web/src/components/player/dynamic/DynamicVideoController.ts index 63686b84e..a820c8aae 100644 --- a/web/src/components/player/dynamic/DynamicVideoController.ts +++ b/web/src/components/player/dynamic/DynamicVideoController.ts @@ -17,6 +17,7 @@ export class DynamicVideoController { // playback private recordings: Recording[] = []; private timeRange: TimeRange = { after: 0, before: 0 }; + private inpointOffset: number = 0; private annotationOffset: number; private timeToStart: number | undefined = undefined; @@ -41,6 +42,7 @@ export class DynamicVideoController { newPlayback(newPlayback: DynamicPlayback) { this.recordings = newPlayback.recordings; this.timeRange = newPlayback.timeRange; + this.inpointOffset = this.timeRange.after - this.recordings[0].start_time; if (this.timeToStart) { this.seekToTimestamp(this.timeToStart); @@ -92,6 +94,9 @@ export class DynamicVideoController { return true; }); + // adjust for HLS inpoint offset + seekSeconds -= this.inpointOffset; + if (seekSeconds != 0) { this.playerController.currentTime = seekSeconds; diff --git a/web/src/components/player/dynamic/DynamicVideoPlayer.tsx b/web/src/components/player/dynamic/DynamicVideoPlayer.tsx index 05521ea3b..be7221906 100644 --- a/web/src/components/player/dynamic/DynamicVideoPlayer.tsx +++ b/web/src/components/player/dynamic/DynamicVideoPlayer.tsx @@ -197,6 +197,19 @@ export default function DynamicVideoPlayer({ // eslint-disable-next-line react-hooks/exhaustive-deps }, [controller, recordings]); + /** the HLS endpoint returns the vod segments with the first + * segment of the hour trimmed, meaning it will start at + * the beginning of the hour, cutting off any difference + * that the segment has. + */ + const inpointOffset = useMemo(() => { + if (!recordingParams || !recordings) { + return 0; + } + + return recordingParams.after - recordings[0].start_time; + }, [recordingParams, recordings]); + return ( <> +