mirror of
				https://github.com/blakeblackshear/frigate.git
				synced 2025-10-27 10:52:11 +01:00 
			
		
		
		
	Live camera aspect ratio fixes (#10266)
* dynamically manage aspect ratio * full size * always use camera aspect ratio for mobile * no need for different handling for pano cams * don't set aspect ratio on fullscreen
This commit is contained in:
		
							parent
							
								
									7be2923d2d
								
							
						
					
					
						commit
						ed99be0856
					
				@ -93,7 +93,7 @@ export default function LivePlayer({
 | 
			
		||||
  if (liveMode == "webrtc") {
 | 
			
		||||
    player = (
 | 
			
		||||
      <WebRtcPlayer
 | 
			
		||||
        className={`rounded-2xl h-full ${liveReady ? "" : "hidden"}`}
 | 
			
		||||
        className={`rounded-2xl size-full ${liveReady ? "" : "hidden"}`}
 | 
			
		||||
        camera={cameraConfig.live.stream_name}
 | 
			
		||||
        playbackEnabled={cameraActive}
 | 
			
		||||
        audioEnabled={playAudio}
 | 
			
		||||
@ -104,7 +104,7 @@ export default function LivePlayer({
 | 
			
		||||
    if ("MediaSource" in window || "ManagedMediaSource" in window) {
 | 
			
		||||
      player = (
 | 
			
		||||
        <MSEPlayer
 | 
			
		||||
          className={`rounded-2xl h-full ${liveReady ? "" : "hidden"}`}
 | 
			
		||||
          className={`rounded-2xl size-full ${liveReady ? "" : "hidden"}`}
 | 
			
		||||
          camera={cameraConfig.name}
 | 
			
		||||
          playbackEnabled={cameraActive}
 | 
			
		||||
          audioEnabled={playAudio}
 | 
			
		||||
 | 
			
		||||
@ -1,7 +1,11 @@
 | 
			
		||||
import { MutableRefObject, useEffect, useMemo, useState } from "react";
 | 
			
		||||
 | 
			
		||||
export function useResizeObserver(...refs: MutableRefObject<Element | null>[]) {
 | 
			
		||||
  const [dimensions, setDimensions] = useState(
 | 
			
		||||
type RefType = MutableRefObject<Element | null> | Window;
 | 
			
		||||
 | 
			
		||||
export function useResizeObserver(...refs: RefType[]) {
 | 
			
		||||
  const [dimensions, setDimensions] = useState<
 | 
			
		||||
    { width: number; height: number; x: number; y: number }[]
 | 
			
		||||
  >(
 | 
			
		||||
    new Array(refs.length).fill({
 | 
			
		||||
      width: 0,
 | 
			
		||||
      height: 0,
 | 
			
		||||
@ -21,14 +25,18 @@ export function useResizeObserver(...refs: MutableRefObject<Element | null>[]) {
 | 
			
		||||
 | 
			
		||||
  useEffect(() => {
 | 
			
		||||
    refs.forEach((ref) => {
 | 
			
		||||
      if (ref.current) {
 | 
			
		||||
      if (ref instanceof Window) {
 | 
			
		||||
        resizeObserver.observe(document.body);
 | 
			
		||||
      } else if (ref.current) {
 | 
			
		||||
        resizeObserver.observe(ref.current);
 | 
			
		||||
      }
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    return () => {
 | 
			
		||||
      refs.forEach((ref) => {
 | 
			
		||||
        if (ref.current) {
 | 
			
		||||
        if (ref instanceof Window) {
 | 
			
		||||
          resizeObserver.unobserve(document.body);
 | 
			
		||||
        } else if (ref.current) {
 | 
			
		||||
          resizeObserver.unobserve(ref.current);
 | 
			
		||||
        }
 | 
			
		||||
      });
 | 
			
		||||
 | 
			
		||||
@ -15,6 +15,7 @@ import {
 | 
			
		||||
  DropdownMenuTrigger,
 | 
			
		||||
} from "@/components/ui/dropdown-menu";
 | 
			
		||||
import { TooltipProvider } from "@/components/ui/tooltip";
 | 
			
		||||
import { useResizeObserver } from "@/hooks/resize-observer";
 | 
			
		||||
import useKeyboardListener from "@/hooks/use-keyboard-listener";
 | 
			
		||||
import { CameraConfig } from "@/types/frigateConfig";
 | 
			
		||||
import { CameraPtzInfo } from "@/types/ptz";
 | 
			
		||||
@ -61,6 +62,8 @@ export default function LiveCameraView({ camera }: LiveCameraViewProps) {
 | 
			
		||||
  const navigate = useNavigate();
 | 
			
		||||
  const { isPortrait } = useMobileOrientation();
 | 
			
		||||
  const mainRef = useRef<HTMLDivElement | null>(null);
 | 
			
		||||
  const [{ width: windowWidth, height: windowHeight }] =
 | 
			
		||||
    useResizeObserver(window);
 | 
			
		||||
 | 
			
		||||
  // camera features
 | 
			
		||||
 | 
			
		||||
@ -105,7 +108,7 @@ export default function LiveCameraView({ camera }: LiveCameraViewProps) {
 | 
			
		||||
        return "absolute left-2 right-2 top-[50%] -translate-y-[50%]";
 | 
			
		||||
      } else {
 | 
			
		||||
        if (aspect > 16 / 9) {
 | 
			
		||||
          return "absolute left-12 top-[50%] -translate-y-[50%]";
 | 
			
		||||
          return "absolute left-0 top-[50%] -translate-y-[50%]";
 | 
			
		||||
        } else {
 | 
			
		||||
          return "absolute top-2 bottom-2 left-[50%] -translate-x-[50%]";
 | 
			
		||||
        }
 | 
			
		||||
@ -114,17 +117,33 @@ export default function LiveCameraView({ camera }: LiveCameraViewProps) {
 | 
			
		||||
 | 
			
		||||
    if (fullscreen) {
 | 
			
		||||
      if (aspect > 16 / 9) {
 | 
			
		||||
        return "absolute inset-x-0 top-[50%] -translate-y-[50%]";
 | 
			
		||||
        return "absolute inset-x-2 top-[50%] -translate-y-[50%]";
 | 
			
		||||
      } else {
 | 
			
		||||
        return "absolute inset-y-0 left-[50%] -translate-x-[50%]";
 | 
			
		||||
        return "absolute inset-y-2 left-[50%] -translate-x-[50%]";
 | 
			
		||||
      }
 | 
			
		||||
    } else if (aspect > 2) {
 | 
			
		||||
      return "absolute left-2 right-2 top-[50%] -translate-y-[50%]";
 | 
			
		||||
    } else {
 | 
			
		||||
      return "absolute top-2 bottom-2 left-[50%] -translate-x-[50%]";
 | 
			
		||||
    }
 | 
			
		||||
  }, [camera, fullscreen, isPortrait]);
 | 
			
		||||
 | 
			
		||||
  const windowAspectRatio = useMemo(() => {
 | 
			
		||||
    return windowWidth / windowHeight;
 | 
			
		||||
  }, [windowWidth, windowHeight]);
 | 
			
		||||
 | 
			
		||||
  const cameraAspectRatio = useMemo(() => {
 | 
			
		||||
    return camera.detect.width / camera.detect.height;
 | 
			
		||||
  }, [camera]);
 | 
			
		||||
 | 
			
		||||
  const aspectRatio = useMemo<number>(() => {
 | 
			
		||||
    if (isMobile || fullscreen) {
 | 
			
		||||
      return cameraAspectRatio;
 | 
			
		||||
    } else {
 | 
			
		||||
      return windowAspectRatio < cameraAspectRatio
 | 
			
		||||
        ? windowAspectRatio - 0.05
 | 
			
		||||
        : cameraAspectRatio - 0.03;
 | 
			
		||||
    }
 | 
			
		||||
  }, [cameraAspectRatio, windowAspectRatio, fullscreen]);
 | 
			
		||||
 | 
			
		||||
  return (
 | 
			
		||||
    <div
 | 
			
		||||
      ref={mainRef}
 | 
			
		||||
@ -216,14 +235,16 @@ export default function LiveCameraView({ camera }: LiveCameraViewProps) {
 | 
			
		||||
          </div>
 | 
			
		||||
        </TooltipProvider>
 | 
			
		||||
      </div>
 | 
			
		||||
      <div className="relative size-full">
 | 
			
		||||
      <div className="relative size-full p-2">
 | 
			
		||||
        <div
 | 
			
		||||
          className={growClassName}
 | 
			
		||||
          style={{ aspectRatio: camera.detect.width / camera.detect.height }}
 | 
			
		||||
          style={{
 | 
			
		||||
            aspectRatio: aspectRatio,
 | 
			
		||||
          }}
 | 
			
		||||
        >
 | 
			
		||||
          <LivePlayer
 | 
			
		||||
            key={camera.name}
 | 
			
		||||
            className={`size-full ${fullscreen ? "*:rounded-none" : ""}`}
 | 
			
		||||
            className={`${fullscreen ? "*:rounded-none" : ""}`}
 | 
			
		||||
            windowVisible
 | 
			
		||||
            showStillWithoutActivity={false}
 | 
			
		||||
            cameraConfig={camera}
 | 
			
		||||
 | 
			
		||||
@ -75,7 +75,7 @@ export default function LiveDashboardView({
 | 
			
		||||
  }, [visibilityListener]);
 | 
			
		||||
 | 
			
		||||
  return (
 | 
			
		||||
    <div className="size-full overflow-y-scroll px-2">
 | 
			
		||||
    <div className="size-full overflow-y-auto px-2">
 | 
			
		||||
      {isMobile && (
 | 
			
		||||
        <div className="relative h-9 flex items-center justify-between">
 | 
			
		||||
          <Logo className="absolute inset-y-0 inset-x-1/2 -translate-x-1/2 h-8" />
 | 
			
		||||
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user