mirror of
				https://github.com/blakeblackshear/frigate.git
				synced 2025-10-27 10:52:11 +01:00 
			
		
		
		
	Enable temporary caching of camera images to improve responsiveness of UI (#15614)
This commit is contained in:
		
							parent
							
								
									69a2f948f2
								
							
						
					
					
						commit
						baa068acdf
					
				@ -20,6 +20,7 @@ class MediaLatestFrameQueryParams(BaseModel):
 | 
			
		||||
    regions: Optional[int] = None
 | 
			
		||||
    quality: Optional[int] = 70
 | 
			
		||||
    height: Optional[int] = None
 | 
			
		||||
    store: Optional[int] = None
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class MediaEventsSnapshotQueryParams(BaseModel):
 | 
			
		||||
 | 
			
		||||
@ -182,11 +182,16 @@ def latest_frame(
 | 
			
		||||
 | 
			
		||||
        frame = cv2.resize(frame, dsize=(width, height), interpolation=cv2.INTER_AREA)
 | 
			
		||||
 | 
			
		||||
        ret, img = cv2.imencode(f".{extension}", frame, quality_params)
 | 
			
		||||
        _, img = cv2.imencode(f".{extension}", frame, quality_params)
 | 
			
		||||
        return Response(
 | 
			
		||||
            content=img.tobytes(),
 | 
			
		||||
            media_type=f"image/{mime_type}",
 | 
			
		||||
            headers={"Content-Type": f"image/{mime_type}", "Cache-Control": "no-store"},
 | 
			
		||||
            headers={
 | 
			
		||||
                "Content-Type": f"image/{mime_type}",
 | 
			
		||||
                "Cache-Control": "no-store"
 | 
			
		||||
                if not params.store
 | 
			
		||||
                else "private, max-age=60",
 | 
			
		||||
            },
 | 
			
		||||
        )
 | 
			
		||||
    elif camera_name == "birdseye" and request.app.frigate_config.birdseye.restream:
 | 
			
		||||
        frame = cv2.cvtColor(
 | 
			
		||||
@ -199,11 +204,16 @@ def latest_frame(
 | 
			
		||||
 | 
			
		||||
        frame = cv2.resize(frame, dsize=(width, height), interpolation=cv2.INTER_AREA)
 | 
			
		||||
 | 
			
		||||
        ret, img = cv2.imencode(f".{extension}", frame, quality_params)
 | 
			
		||||
        _, img = cv2.imencode(f".{extension}", frame, quality_params)
 | 
			
		||||
        return Response(
 | 
			
		||||
            content=img.tobytes(),
 | 
			
		||||
            media_type=f"image/{mime_type}",
 | 
			
		||||
            headers={"Content-Type": f"image/{mime_type}", "Cache-Control": "no-store"},
 | 
			
		||||
            headers={
 | 
			
		||||
                "Content-Type": f"image/{mime_type}",
 | 
			
		||||
                "Cache-Control": "no-store"
 | 
			
		||||
                if not params.store
 | 
			
		||||
                else "private, max-age=60",
 | 
			
		||||
            },
 | 
			
		||||
        )
 | 
			
		||||
    else:
 | 
			
		||||
        return JSONResponse(
 | 
			
		||||
 | 
			
		||||
@ -1,4 +1,4 @@
 | 
			
		||||
import { useCallback, useEffect, useRef, useState } from "react";
 | 
			
		||||
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
 | 
			
		||||
import CameraImage from "./CameraImage";
 | 
			
		||||
 | 
			
		||||
type AutoUpdatingCameraImageProps = {
 | 
			
		||||
@ -8,6 +8,7 @@ type AutoUpdatingCameraImageProps = {
 | 
			
		||||
  className?: string;
 | 
			
		||||
  cameraClasses?: string;
 | 
			
		||||
  reloadInterval?: number;
 | 
			
		||||
  periodicCache?: boolean;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const MIN_LOAD_TIMEOUT_MS = 200;
 | 
			
		||||
@ -19,6 +20,7 @@ export default function AutoUpdatingCameraImage({
 | 
			
		||||
  className,
 | 
			
		||||
  cameraClasses,
 | 
			
		||||
  reloadInterval = MIN_LOAD_TIMEOUT_MS,
 | 
			
		||||
  periodicCache = false,
 | 
			
		||||
}: AutoUpdatingCameraImageProps) {
 | 
			
		||||
  const [key, setKey] = useState(Date.now());
 | 
			
		||||
  const [fps, setFps] = useState<string>("0");
 | 
			
		||||
@ -42,6 +44,8 @@ export default function AutoUpdatingCameraImage({
 | 
			
		||||
  }, [reloadInterval]);
 | 
			
		||||
 | 
			
		||||
  const handleLoad = useCallback(() => {
 | 
			
		||||
    setIsCached(true);
 | 
			
		||||
 | 
			
		||||
    if (reloadInterval == -1) {
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
@ -66,12 +70,28 @@ export default function AutoUpdatingCameraImage({
 | 
			
		||||
    // eslint-disable-next-line react-hooks/exhaustive-deps
 | 
			
		||||
  }, [key, setFps]);
 | 
			
		||||
 | 
			
		||||
  // periodic cache to reduce loading indicator
 | 
			
		||||
 | 
			
		||||
  const [isCached, setIsCached] = useState(false);
 | 
			
		||||
 | 
			
		||||
  const cacheKey = useMemo(() => {
 | 
			
		||||
    let baseParam = "";
 | 
			
		||||
 | 
			
		||||
    if (periodicCache && !isCached) {
 | 
			
		||||
      baseParam = "store=1";
 | 
			
		||||
    } else {
 | 
			
		||||
      baseParam = `cache=${key}`;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return `${baseParam}${searchParams ? `&${searchParams}` : ""}`;
 | 
			
		||||
  }, [isCached, periodicCache, key, searchParams]);
 | 
			
		||||
 | 
			
		||||
  return (
 | 
			
		||||
    <div className={className}>
 | 
			
		||||
      <CameraImage
 | 
			
		||||
        camera={camera}
 | 
			
		||||
        onload={handleLoad}
 | 
			
		||||
        searchParams={`cache=${key}${searchParams ? `&${searchParams}` : ""}`}
 | 
			
		||||
        searchParams={cacheKey}
 | 
			
		||||
        className={cameraClasses}
 | 
			
		||||
      />
 | 
			
		||||
      {showFps ? <span className="text-xs">Displaying at {fps}fps</span> : null}
 | 
			
		||||
 | 
			
		||||
@ -294,10 +294,11 @@ export default function LivePlayer({
 | 
			
		||||
      >
 | 
			
		||||
        <AutoUpdatingCameraImage
 | 
			
		||||
          className="size-full"
 | 
			
		||||
          cameraClasses="relative size-full flex justify-center"
 | 
			
		||||
          camera={cameraConfig.name}
 | 
			
		||||
          showFps={false}
 | 
			
		||||
          reloadInterval={stillReloadInterval}
 | 
			
		||||
          cameraClasses="relative size-full flex justify-center"
 | 
			
		||||
          periodicCache
 | 
			
		||||
        />
 | 
			
		||||
      </div>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user