mirror of
https://github.com/blakeblackshear/frigate.git
synced 2024-11-21 19:07:46 +01:00
Live view tweaks and jsmpeg bugfix (#11584)
* live view tweaks and jsmpeg bugfix * use container aspect in check
This commit is contained in:
parent
6913cc6abc
commit
4165639308
@ -77,7 +77,7 @@ export default function JSMpegPlayer({
|
|||||||
const video = new JSMpeg.VideoElement(
|
const video = new JSMpeg.VideoElement(
|
||||||
playerRef.current,
|
playerRef.current,
|
||||||
url,
|
url,
|
||||||
{ canvas: "#video-canvas" },
|
{ canvas: `#${camera}-canvas` },
|
||||||
{ protocols: [], audio: false, videoBufferSize: 1024 * 1024 * 4 },
|
{ protocols: [], audio: false, videoBufferSize: 1024 * 1024 * 4 },
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -90,13 +90,13 @@ export default function JSMpegPlayer({
|
|||||||
playerRef.current = null;
|
playerRef.current = null;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}, [url]);
|
}, [url, camera]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={className} ref={internalContainerRef}>
|
<div className={className} ref={internalContainerRef}>
|
||||||
<div ref={playerRef} className="jsmpeg">
|
<div ref={playerRef} className="jsmpeg">
|
||||||
<canvas
|
<canvas
|
||||||
id="video-canvas"
|
id={`${camera}-canvas`}
|
||||||
style={{
|
style={{
|
||||||
width: scaledWidth ?? width,
|
width: scaledWidth ?? width,
|
||||||
height: scaledHeight ?? height,
|
height: scaledHeight ?? height,
|
||||||
|
@ -4,8 +4,9 @@ import BirdseyeLivePlayer from "@/components/player/BirdseyeLivePlayer";
|
|||||||
import { Button } from "@/components/ui/button";
|
import { Button } from "@/components/ui/button";
|
||||||
import { TooltipProvider } from "@/components/ui/tooltip";
|
import { TooltipProvider } from "@/components/ui/tooltip";
|
||||||
import { useResizeObserver } from "@/hooks/resize-observer";
|
import { useResizeObserver } from "@/hooks/resize-observer";
|
||||||
|
import { useFullscreen } from "@/hooks/use-fullscreen";
|
||||||
import { FrigateConfig } from "@/types/frigateConfig";
|
import { FrigateConfig } from "@/types/frigateConfig";
|
||||||
import { useEffect, useMemo, useRef, useState } from "react";
|
import { useMemo, useRef } from "react";
|
||||||
import {
|
import {
|
||||||
isDesktop,
|
isDesktop,
|
||||||
isMobile,
|
isMobile,
|
||||||
@ -29,25 +30,10 @@ export default function LiveBirdseyeView() {
|
|||||||
|
|
||||||
// fullscreen state
|
// fullscreen state
|
||||||
|
|
||||||
useEffect(() => {
|
const { fullscreen, toggleFullscreen } = useFullscreen(mainRef);
|
||||||
if (mainRef.current == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const listener = () => {
|
|
||||||
setFullscreen(document.fullscreenElement != null);
|
|
||||||
};
|
|
||||||
document.addEventListener("fullscreenchange", listener);
|
|
||||||
|
|
||||||
return () => {
|
|
||||||
document.removeEventListener("fullscreenchange", listener);
|
|
||||||
};
|
|
||||||
}, [mainRef]);
|
|
||||||
|
|
||||||
// playback state
|
// playback state
|
||||||
|
|
||||||
const [fullscreen, setFullscreen] = useState(false);
|
|
||||||
|
|
||||||
const cameraAspectRatio = useMemo(() => {
|
const cameraAspectRatio = useMemo(() => {
|
||||||
if (!config) {
|
if (!config) {
|
||||||
return 16 / 9;
|
return 16 / 9;
|
||||||
@ -96,15 +82,23 @@ export default function LiveBirdseyeView() {
|
|||||||
return windowWidth / windowHeight;
|
return windowWidth / windowHeight;
|
||||||
}, [windowWidth, windowHeight]);
|
}, [windowWidth, windowHeight]);
|
||||||
|
|
||||||
|
const containerAspectRatio = useMemo(() => {
|
||||||
|
if (!containerRef.current) {
|
||||||
|
return windowAspectRatio;
|
||||||
|
}
|
||||||
|
|
||||||
|
return containerRef.current.clientWidth / containerRef.current.clientHeight;
|
||||||
|
}, [windowAspectRatio, containerRef]);
|
||||||
|
|
||||||
const aspectRatio = useMemo<number>(() => {
|
const aspectRatio = useMemo<number>(() => {
|
||||||
if (isMobile || fullscreen) {
|
if (isMobile || fullscreen) {
|
||||||
return cameraAspectRatio;
|
return cameraAspectRatio;
|
||||||
} else {
|
} else {
|
||||||
return windowAspectRatio < cameraAspectRatio
|
return containerAspectRatio < cameraAspectRatio
|
||||||
? windowAspectRatio - 0.05
|
? containerAspectRatio
|
||||||
: cameraAspectRatio - 0.03;
|
: cameraAspectRatio;
|
||||||
}
|
}
|
||||||
}, [cameraAspectRatio, windowAspectRatio, fullscreen]);
|
}, [cameraAspectRatio, containerAspectRatio, fullscreen]);
|
||||||
|
|
||||||
if (!config) {
|
if (!config) {
|
||||||
return <ActivityIndicator />;
|
return <ActivityIndicator />;
|
||||||
@ -149,13 +143,7 @@ export default function LiveBirdseyeView() {
|
|||||||
Icon={fullscreen ? FaCompress : FaExpand}
|
Icon={fullscreen ? FaCompress : FaExpand}
|
||||||
isActive={fullscreen}
|
isActive={fullscreen}
|
||||||
title={fullscreen ? "Close" : "Fullscreen"}
|
title={fullscreen ? "Close" : "Fullscreen"}
|
||||||
onClick={() => {
|
onClick={toggleFullscreen}
|
||||||
if (fullscreen) {
|
|
||||||
document.exitFullscreen();
|
|
||||||
} else {
|
|
||||||
mainRef.current?.requestFullscreen();
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</TooltipProvider>
|
</TooltipProvider>
|
||||||
|
@ -73,6 +73,7 @@ import {
|
|||||||
import { useNavigate } from "react-router-dom";
|
import { useNavigate } from "react-router-dom";
|
||||||
import { TransformWrapper, TransformComponent } from "react-zoom-pan-pinch";
|
import { TransformWrapper, TransformComponent } from "react-zoom-pan-pinch";
|
||||||
import useSWR from "swr";
|
import useSWR from "swr";
|
||||||
|
import { useFullscreen } from "@/hooks/use-fullscreen";
|
||||||
|
|
||||||
type LiveCameraViewProps = {
|
type LiveCameraViewProps = {
|
||||||
config?: FrigateConfig;
|
config?: FrigateConfig;
|
||||||
@ -177,19 +178,7 @@ export default function LiveCameraView({
|
|||||||
|
|
||||||
// fullscreen / pip state
|
// fullscreen / pip state
|
||||||
|
|
||||||
useEffect(() => {
|
const { fullscreen, toggleFullscreen } = useFullscreen(mainRef);
|
||||||
if (mainRef.current == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const fsListener = () => {
|
|
||||||
setFullscreen(document.fullscreenElement != null);
|
|
||||||
};
|
|
||||||
document.addEventListener("fullscreenchange", fsListener);
|
|
||||||
|
|
||||||
return () => {
|
|
||||||
document.removeEventListener("fullscreenchange", fsListener);
|
|
||||||
};
|
|
||||||
}, [mainRef]);
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setPip(document.pictureInPictureElement != null);
|
setPip(document.pictureInPictureElement != null);
|
||||||
@ -201,7 +190,6 @@ export default function LiveCameraView({
|
|||||||
|
|
||||||
const [audio, setAudio] = useState(false);
|
const [audio, setAudio] = useState(false);
|
||||||
const [mic, setMic] = useState(false);
|
const [mic, setMic] = useState(false);
|
||||||
const [fullscreen, setFullscreen] = useState(false);
|
|
||||||
const [pip, setPip] = useState(false);
|
const [pip, setPip] = useState(false);
|
||||||
|
|
||||||
const [fullResolution, setFullResolution] = useState<VideoResolutionType>({
|
const [fullResolution, setFullResolution] = useState<VideoResolutionType>({
|
||||||
@ -209,37 +197,6 @@ export default function LiveCameraView({
|
|||||||
height: 0,
|
height: 0,
|
||||||
});
|
});
|
||||||
|
|
||||||
const growClassName = useMemo(() => {
|
|
||||||
let aspect;
|
|
||||||
if (fullResolution.width && fullResolution.height) {
|
|
||||||
aspect = fullResolution.width / fullResolution.height;
|
|
||||||
} else {
|
|
||||||
aspect = camera.detect.width / camera.detect.height;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isMobile) {
|
|
||||||
if (isPortrait) {
|
|
||||||
return "absolute left-2 right-2 top-[50%] -translate-y-[50%]";
|
|
||||||
} else {
|
|
||||||
if (aspect > 1.5) {
|
|
||||||
return "p-2 absolute left-0 top-[50%] -translate-y-[50%]";
|
|
||||||
} else {
|
|
||||||
return "p-2 absolute top-2 bottom-2 left-[50%] -translate-x-[50%]";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (fullscreen) {
|
|
||||||
if (aspect > 1.5) {
|
|
||||||
return "absolute inset-x-2 top-[50%] -translate-y-[50%]";
|
|
||||||
} else {
|
|
||||||
return "absolute inset-y-2 left-[50%] -translate-x-[50%]";
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return "absolute top-2 bottom-2 left-[50%] -translate-x-[50%]";
|
|
||||||
}
|
|
||||||
}, [camera, fullscreen, isPortrait, fullResolution]);
|
|
||||||
|
|
||||||
const preferredLiveMode = useMemo(() => {
|
const preferredLiveMode = useMemo(() => {
|
||||||
if (isSafari || mic) {
|
if (isSafari || mic) {
|
||||||
return "webrtc";
|
return "webrtc";
|
||||||
@ -252,6 +209,14 @@ export default function LiveCameraView({
|
|||||||
return windowWidth / windowHeight;
|
return windowWidth / windowHeight;
|
||||||
}, [windowWidth, windowHeight]);
|
}, [windowWidth, windowHeight]);
|
||||||
|
|
||||||
|
const containerAspectRatio = useMemo(() => {
|
||||||
|
if (!containerRef.current) {
|
||||||
|
return windowAspectRatio;
|
||||||
|
}
|
||||||
|
|
||||||
|
return containerRef.current.clientWidth / containerRef.current.clientHeight;
|
||||||
|
}, [windowAspectRatio, containerRef]);
|
||||||
|
|
||||||
const cameraAspectRatio = useMemo(() => {
|
const cameraAspectRatio = useMemo(() => {
|
||||||
if (fullResolution.width && fullResolution.height) {
|
if (fullResolution.width && fullResolution.height) {
|
||||||
return fullResolution.width / fullResolution.height;
|
return fullResolution.width / fullResolution.height;
|
||||||
@ -264,11 +229,42 @@ export default function LiveCameraView({
|
|||||||
if (isMobile || fullscreen) {
|
if (isMobile || fullscreen) {
|
||||||
return cameraAspectRatio;
|
return cameraAspectRatio;
|
||||||
} else {
|
} else {
|
||||||
return windowAspectRatio < cameraAspectRatio
|
return containerAspectRatio < cameraAspectRatio
|
||||||
? windowAspectRatio - 0.05
|
? containerAspectRatio
|
||||||
: cameraAspectRatio - 0.03;
|
: cameraAspectRatio;
|
||||||
}
|
}
|
||||||
}, [cameraAspectRatio, windowAspectRatio, fullscreen]);
|
}, [cameraAspectRatio, containerAspectRatio, fullscreen]);
|
||||||
|
|
||||||
|
const growClassName = useMemo(() => {
|
||||||
|
let aspect;
|
||||||
|
if (fullResolution.width && fullResolution.height) {
|
||||||
|
aspect = fullResolution.width / fullResolution.height;
|
||||||
|
} else {
|
||||||
|
aspect = camera.detect.width / camera.detect.height;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isMobile) {
|
||||||
|
if (isPortrait) {
|
||||||
|
return "absolute left-0.5 right-0.5 top-[50%] -translate-y-[50%]";
|
||||||
|
} else {
|
||||||
|
if (aspect > containerAspectRatio) {
|
||||||
|
return "p-2 absolute left-0 top-[50%] -translate-y-[50%]";
|
||||||
|
} else {
|
||||||
|
return "p-2 absolute top-0.5 bottom-0.5 left-[50%] -translate-x-[50%]";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fullscreen) {
|
||||||
|
if (aspect > containerAspectRatio) {
|
||||||
|
return "absolute inset-x-2 top-[50%] -translate-y-[50%]";
|
||||||
|
} else {
|
||||||
|
return "absolute inset-y-2 left-[50%] -translate-x-[50%]";
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return "absolute top-0.5 bottom-0.5 left-[50%] -translate-x-[50%]";
|
||||||
|
}
|
||||||
|
}, [camera, fullscreen, isPortrait, fullResolution, containerAspectRatio]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<TransformWrapper minScale={1.0}>
|
<TransformWrapper minScale={1.0}>
|
||||||
@ -333,13 +329,7 @@ export default function LiveCameraView({
|
|||||||
Icon={fullscreen ? FaCompress : FaExpand}
|
Icon={fullscreen ? FaCompress : FaExpand}
|
||||||
isActive={fullscreen}
|
isActive={fullscreen}
|
||||||
title={fullscreen ? "Close" : "Fullscreen"}
|
title={fullscreen ? "Close" : "Fullscreen"}
|
||||||
onClick={() => {
|
onClick={toggleFullscreen}
|
||||||
if (fullscreen) {
|
|
||||||
document.exitFullscreen();
|
|
||||||
} else {
|
|
||||||
mainRef.current?.requestFullscreen();
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
{!isIOS && (
|
{!isIOS && (
|
||||||
|
Loading…
Reference in New Issue
Block a user