* Use full resolution aspect for main camera style in history view

* Only check for offline cameras after 60s of uptime

* only call onPlaying when loadeddata is fired or after timeout

* revert to inline funcs

* Portal frigate plus alert dialog

* remove duplicated logic

* increase onplaying timeout

* Use a ref instead of a state and clear timeout in AutoUpdatingCameraImage

* default to the selected month for selectedDay

* Use buffered time instead of timeout

* Use default cursor when not editing polygons
This commit is contained in:
Josh Hawkins
2024-07-08 08:14:10 -05:00
committed by GitHub
parent 2ea1d34f4f
commit 0ce596ec8f
13 changed files with 127 additions and 73 deletions

View File

@@ -40,6 +40,7 @@ type HlsVideoPlayerProps = {
setFullResolution?: React.Dispatch<React.SetStateAction<VideoResolutionType>>;
onUploadFrame?: (playTime: number) => Promise<AxiosResponse> | undefined;
toggleFullscreen?: () => void;
containerRef?: React.MutableRefObject<HTMLDivElement | null>;
};
export default function HlsVideoPlayer({
videoRef,
@@ -54,6 +55,7 @@ export default function HlsVideoPlayer({
setFullResolution,
onUploadFrame,
toggleFullscreen,
containerRef,
}: HlsVideoPlayerProps) {
const { data: config } = useSWR<FrigateConfig>("config");
@@ -225,6 +227,7 @@ export default function HlsVideoPlayer({
}}
fullscreen={fullscreen}
toggleFullscreen={toggleFullscreen}
containerRef={containerRef}
/>
<TransformComponent
wrapperStyle={{

View File

@@ -256,9 +256,10 @@ export default function LivePlayer({
)}
<div
className={`absolute inset-0 w-full ${
showStillWithoutActivity && !liveReady ? "visible" : "invisible"
}`}
className={cn(
"absolute inset-0 w-full",
showStillWithoutActivity && !liveReady ? "visible" : "invisible",
)}
>
<AutoUpdatingCameraImage
className="size-full"

View File

@@ -297,6 +297,11 @@ function MSEPlayer({
};
};
const getBufferedTime = (video: HTMLVideoElement | null) => {
if (!video || video.buffered.length === 0) return 0;
return video.buffered.end(video.buffered.length - 1) - video.currentTime;
};
useEffect(() => {
if (!playbackEnabled) {
return;
@@ -385,9 +390,15 @@ function MSEPlayer({
muted={!audioEnabled}
onPause={() => videoRef.current?.play()}
onProgress={() => {
if (!isPlaying) {
// if we have > 3 seconds of buffered data and we're still not playing,
// something might be wrong - maybe codec issue, no audio, etc
// so mark the player as playing so that error handlers will fire
if (
!isPlaying &&
playbackEnabled &&
getBufferedTime(videoRef.current) > 3
) {
setIsPlaying(true);
handleLoadedMetadata?.();
onPlaying?.();
}
if (onError != undefined) {

View File

@@ -71,6 +71,7 @@ type VideoControlsProps = {
onSetPlaybackRate: (rate: number) => void;
onUploadFrame?: () => void;
toggleFullscreen?: () => void;
containerRef?: React.MutableRefObject<HTMLDivElement | null>;
};
export default function VideoControls({
className,
@@ -91,10 +92,11 @@ export default function VideoControls({
onSetPlaybackRate,
onUploadFrame,
toggleFullscreen,
containerRef,
}: VideoControlsProps) {
// layout
const containerRef = useRef<HTMLDivElement | null>(null);
const controlsContainerRef = useRef<HTMLDivElement | null>(null);
// controls
@@ -197,7 +199,7 @@ export default function VideoControls({
MIN_ITEMS_WRAP &&
"min-w-[75%] flex-wrap",
)}
ref={containerRef}
ref={controlsContainerRef}
>
{video && features.volume && (
<div className="flex cursor-pointer items-center justify-normal gap-2">
@@ -247,7 +249,7 @@ export default function VideoControls({
>
<DropdownMenuTrigger>{`${playbackRate}x`}</DropdownMenuTrigger>
<DropdownMenuContent
portalProps={{ container: containerRef.current }}
portalProps={{ container: controlsContainerRef.current }}
>
<DropdownMenuRadioGroup
onValueChange={(rate) => onSetPlaybackRate(parseFloat(rate))}
@@ -281,6 +283,7 @@ export default function VideoControls({
}
}}
onUploadFrame={onUploadFrame}
containerRef={containerRef}
/>
)}
{features.fullscreen && toggleFullscreen && (
@@ -297,12 +300,14 @@ type FrigatePlusUploadButtonProps = {
onOpen: () => void;
onClose: () => void;
onUploadFrame: () => void;
containerRef?: React.MutableRefObject<HTMLDivElement | null>;
};
function FrigatePlusUploadButton({
video,
onOpen,
onClose,
onUploadFrame,
containerRef,
}: FrigatePlusUploadButtonProps) {
const [videoImg, setVideoImg] = useState<string>();
@@ -336,7 +341,10 @@ function FrigatePlusUploadButton({
}}
/>
</AlertDialogTrigger>
<AlertDialogContent className="md:max-w-2xl lg:max-w-3xl xl:max-w-4xl">
<AlertDialogContent
portalProps={{ container: containerRef?.current }}
className="md:max-w-2xl lg:max-w-3xl xl:max-w-4xl"
>
<AlertDialogHeader>
<AlertDialogTitle>Submit this frame to Frigate+?</AlertDialogTitle>
</AlertDialogHeader>

View File

@@ -30,6 +30,7 @@ type DynamicVideoPlayerProps = {
onClipEnded?: () => void;
setFullResolution: React.Dispatch<React.SetStateAction<VideoResolutionType>>;
toggleFullscreen: () => void;
containerRef?: React.MutableRefObject<HTMLDivElement | null>;
};
export default function DynamicVideoPlayer({
className,
@@ -45,6 +46,7 @@ export default function DynamicVideoPlayer({
onClipEnded,
setFullResolution,
toggleFullscreen,
containerRef,
}: DynamicVideoPlayerProps) {
const apiHost = useApiHost();
const { data: config } = useSWR<FrigateConfig>("config");
@@ -208,6 +210,7 @@ export default function DynamicVideoPlayer({
setFullResolution={setFullResolution}
onUploadFrame={onUploadFrameToPlus}
toggleFullscreen={toggleFullscreen}
containerRef={containerRef}
/>
<PreviewPlayer
className={cn(