mirror of
https://github.com/blakeblackshear/frigate.git
synced 2024-11-21 19:07:46 +01:00
Convert preview player to use html5 video (#10016)
* Convert preview player to use html5 * Cleanup * Increase padding and use constant * Firefox doesn't support high fps either * Cleanup * no need to special case firefox
This commit is contained in:
parent
7ccc7fb393
commit
4a7c159a44
@ -1,7 +1,5 @@
|
||||
import VideoPlayer from "./VideoPlayer";
|
||||
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
|
||||
import { useApiHost } from "@/api";
|
||||
import Player from "video.js/dist/types/player";
|
||||
import { formatUnixTimestampToDateTime, isCurrentHour } from "@/utils/dateUtil";
|
||||
import { ReviewSegment } from "@/types/review";
|
||||
import { Slider } from "../ui/slider";
|
||||
@ -169,6 +167,7 @@ export default function PreviewThumbnailPlayer({
|
||||
);
|
||||
}
|
||||
|
||||
const PREVIEW_PADDING = 16;
|
||||
type PreviewContentProps = {
|
||||
review: ReviewSegment;
|
||||
relevantPreview: Preview | undefined;
|
||||
@ -181,15 +180,69 @@ function PreviewContent({
|
||||
setProgress,
|
||||
setReviewed,
|
||||
}: PreviewContentProps) {
|
||||
const playerRef = useRef<Player | null>(null);
|
||||
const playerRef = useRef<HTMLVideoElement | null>(null);
|
||||
|
||||
// keep track of playback state
|
||||
|
||||
const playerStartTime = useMemo(() => {
|
||||
if (!relevantPreview) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// start with a bit of padding
|
||||
return Math.max(0, review.start_time - relevantPreview.start - 8);
|
||||
return Math.max(0, review.start_time - relevantPreview.start - PREVIEW_PADDING);
|
||||
}, []);
|
||||
const [lastPercent, setLastPercent] = useState(0.0);
|
||||
|
||||
// initialize player correctly
|
||||
|
||||
useEffect(() => {
|
||||
if (!playerRef.current) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (isSafari) {
|
||||
playerRef.current.pause();
|
||||
setManualPlayback(true);
|
||||
} else {
|
||||
playerRef.current.currentTime = playerStartTime;
|
||||
playerRef.current.playbackRate = 8;
|
||||
}
|
||||
}, [playerRef]);
|
||||
|
||||
// time progress update
|
||||
|
||||
const onProgress = useCallback(() => {
|
||||
if (!setProgress) {
|
||||
return;
|
||||
}
|
||||
|
||||
const playerProgress =
|
||||
(playerRef.current?.currentTime || 0) - playerStartTime;
|
||||
|
||||
// end with a bit of padding
|
||||
const playerDuration = review.end_time - review.start_time + PREVIEW_PADDING;
|
||||
const playerPercent = (playerProgress / playerDuration) * 100;
|
||||
|
||||
if (
|
||||
setReviewed &&
|
||||
!review.has_been_reviewed &&
|
||||
lastPercent < 50 &&
|
||||
playerPercent > 50
|
||||
) {
|
||||
setReviewed();
|
||||
}
|
||||
|
||||
setLastPercent(playerPercent);
|
||||
|
||||
if (playerPercent > 100) {
|
||||
playerRef.current?.pause();
|
||||
setManualPlayback(false);
|
||||
setProgress(100.0);
|
||||
} else {
|
||||
setProgress(playerPercent);
|
||||
}
|
||||
}, [setProgress, lastPercent]);
|
||||
|
||||
// manual playback
|
||||
// safari is incapable of playing at a speed > 2x
|
||||
@ -204,7 +257,7 @@ function PreviewContent({
|
||||
let counter = 0;
|
||||
const intervalId: NodeJS.Timeout = setInterval(() => {
|
||||
if (playerRef.current) {
|
||||
playerRef.current.currentTime(playerStartTime + counter);
|
||||
playerRef.current.currentTime = playerStartTime + counter;
|
||||
counter += 1;
|
||||
}
|
||||
}, 125);
|
||||
@ -215,77 +268,17 @@ function PreviewContent({
|
||||
|
||||
if (relevantPreview) {
|
||||
return (
|
||||
<VideoPlayer
|
||||
options={{
|
||||
preload: "auto",
|
||||
autoplay: true,
|
||||
controls: false,
|
||||
muted: true,
|
||||
fluid: true,
|
||||
aspectRatio: "16:9",
|
||||
loadingSpinner: false,
|
||||
sources: relevantPreview
|
||||
? [
|
||||
{
|
||||
src: `${relevantPreview.src}`,
|
||||
type: "video/mp4",
|
||||
},
|
||||
]
|
||||
: [],
|
||||
}}
|
||||
seekOptions={{}}
|
||||
onReady={(player) => {
|
||||
playerRef.current = player;
|
||||
|
||||
if (!relevantPreview) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (isSafari) {
|
||||
player.pause();
|
||||
setManualPlayback(true);
|
||||
} else {
|
||||
player.currentTime(playerStartTime);
|
||||
player.playbackRate(8);
|
||||
}
|
||||
|
||||
let lastPercent = 0;
|
||||
player.on("timeupdate", () => {
|
||||
if (!setProgress) {
|
||||
return;
|
||||
}
|
||||
|
||||
const playerProgress =
|
||||
(player.currentTime() || 0) - playerStartTime;
|
||||
|
||||
// end with a bit of padding
|
||||
const playerDuration = review.end_time - review.start_time + 8;
|
||||
const playerPercent = (playerProgress / playerDuration) * 100;
|
||||
|
||||
if (
|
||||
setReviewed &&
|
||||
!review.has_been_reviewed &&
|
||||
lastPercent < 50 &&
|
||||
playerPercent > 50
|
||||
) {
|
||||
setReviewed();
|
||||
}
|
||||
|
||||
lastPercent = playerPercent;
|
||||
|
||||
if (playerPercent > 100) {
|
||||
playerRef.current?.pause();
|
||||
setManualPlayback(false);
|
||||
setProgress(100.0);
|
||||
} else {
|
||||
setProgress(playerPercent);
|
||||
}
|
||||
});
|
||||
}}
|
||||
onDispose={() => {
|
||||
playerRef.current = null;
|
||||
}}
|
||||
/>
|
||||
<video
|
||||
ref={playerRef}
|
||||
className="w-full h-full aspect-video bg-black"
|
||||
autoPlay
|
||||
playsInline
|
||||
preload="auto"
|
||||
muted
|
||||
onTimeUpdate={onProgress}
|
||||
>
|
||||
<source src={relevantPreview.src} type={relevantPreview.type} />
|
||||
</video>
|
||||
);
|
||||
} else if (isCurrentHour(review.start_time)) {
|
||||
return (
|
||||
@ -373,10 +366,6 @@ function PreviewContextItems({
|
||||
setReviewed,
|
||||
}: PreviewContextItemsProps) {
|
||||
const exportReview = useCallback(() => {
|
||||
console.log(
|
||||
"trying to export to " +
|
||||
`export/${review.camera}/start/${review.start_time}/end/${review.end_time}`
|
||||
);
|
||||
axios.post(
|
||||
`export/${review.camera}/start/${review.start_time}/end/${review.end_time}`,
|
||||
{ playback: "realtime" }
|
||||
|
Loading…
Reference in New Issue
Block a user