Bladeren bron

move width/height/fps under detect and make required

also resizes the output from ffmpeg to specified size
Blake Blackshear 3 jaren geleden
bovenliggende
commit
f3a1c1de0a

+ 18 - 19
docs/docs/configuration/cameras.md

@@ -32,9 +32,10 @@ cameras:
           roles:
             - clips
             - record
-    width: 1280
-    height: 720
-    fps: 5
+    detect:
+      width: 1280
+      height: 720
+      fps: 5
 ```
 
 ## Masks & Zones
@@ -280,14 +281,20 @@ cameras:
       # Optional: camera specific output args (default: inherit)
       output_args:
 
-    # Required: width of the frame for the input with the detect role
-    width: 1280
-    # Required: height of the frame for the input with the detect role
-    height: 720
-    # Optional: desired fps for your camera for the input with the detect role
-    # NOTE: Recommended value of 5. Ideally, try and reduce your FPS on the camera.
-    #       Frigate will attempt to autodetect if not specified.
-    fps: 5
+    # Required: Camera level detect settings
+    detect:
+      # Required: width of the frame for the input with the detect role
+      width: 1280
+      # Required: height of the frame for the input with the detect role
+      height: 720
+      # Required: desired fps for your camera for the input with the detect role
+      # NOTE: Recommended value of 5. Ideally, try and reduce your FPS on the camera.
+      fps: 5
+      # Optional: enables detection for the camera (default: True)
+      # This value can be set via MQTT and will be updated in startup based on retained value
+      enabled: True
+      # Optional: Number of frames without a detection before frigate considers an object to be gone. (default: 5x the frame rate)
+      max_disappeared: 25
 
     # Optional: camera level motion config
     motion:
@@ -319,14 +326,6 @@ cameras:
             max_area: 100000
             threshold: 0.7
 
-    # Optional: Camera level detect settings
-    detect:
-      # Optional: enables detection for the camera (default: True)
-      # This value can be set via MQTT and will be updated in startup based on retained value
-      enabled: True
-      # Optional: Number of frames without a detection before frigate considers an object to be gone. (default: 5x the frame rate)
-      max_disappeared: 25
-
     # Optional: save clips configuration
     clips:
       # Required: enables clips for the camera (default: shown below)

+ 8 - 6
docs/docs/configuration/index.md

@@ -20,9 +20,10 @@ cameras:
           roles:
             - detect
             - rtmp
-    width: 1280
-    height: 720
-    fps: 5
+    detect:
+      width: 1280
+      height: 720
+      fps: 5
 ```
 
 ## Required
@@ -76,9 +77,10 @@ cameras:
           roles:
             - detect
             - rtmp
-    width: 1280
-    height: 720
-    fps: 5
+    detect:
+      width: 1280
+      height: 720
+      fps: 5
 ```
 
 ## Optional

+ 20 - 17
frigate/config.py

@@ -151,6 +151,9 @@ class RuntimeMotionConfig(MotionConfig):
 
 
 class DetectConfig(BaseModel):
+    height: int = Field(title="Height of the stream for the detect role.")
+    width: int = Field(title="Width of the stream for the detect role.")
+    fps: int = Field(title="Number of frames per second to process through detection.")
     enabled: bool = Field(default=True, title="Detection Enabled.")
     max_disappeared: Optional[int] = Field(
         title="Maximum number of frames the object can dissapear before detection ends."
@@ -435,11 +438,6 @@ class CameraLiveConfig(BaseModel):
 class CameraConfig(BaseModel):
     name: Optional[str] = Field(title="Camera name.")
     ffmpeg: CameraFfmpegConfig = Field(title="FFmpeg configuration for the camera.")
-    height: int = Field(title="Height of the stream for the detect role.")
-    width: int = Field(title="Width of the stream for the detect role.")
-    fps: Optional[int] = Field(
-        title="Number of frames per second to process through Frigate."
-    )
     best_image_timeout: int = Field(
         default=60,
         title="How long to wait for the image with the highest confidence score.",
@@ -465,7 +463,7 @@ class CameraConfig(BaseModel):
         default_factory=ObjectConfig, title="Object configuration."
     )
     motion: Optional[MotionConfig] = Field(title="Motion detection configuration.")
-    detect: Optional[DetectConfig] = Field(title="Object detection configuration.")
+    detect: DetectConfig = Field(title="Object detection configuration.")
     timestamp_style: TimestampStyleConfig = Field(
         default_factory=TimestampStyleConfig, title="Timestamp style configuration."
     )
@@ -483,11 +481,11 @@ class CameraConfig(BaseModel):
 
     @property
     def frame_shape(self) -> Tuple[int, int]:
-        return self.height, self.width
+        return self.detect.height, self.detect.width
 
     @property
     def frame_shape_yuv(self) -> Tuple[int, int]:
-        return self.height * 3 // 2, self.width
+        return self.detect.height * 3 // 2, self.detect.width
 
     @property
     def ffmpeg_cmds(self) -> List[Dict[str, List[str]]]:
@@ -508,9 +506,17 @@ class CameraConfig(BaseModel):
                 if isinstance(self.ffmpeg.output_args.detect, list)
                 else self.ffmpeg.output_args.detect.split(" ")
             )
-            ffmpeg_output_args = detect_args + ffmpeg_output_args + ["pipe:"]
-            if self.fps:
-                ffmpeg_output_args = ["-r", str(self.fps)] + ffmpeg_output_args
+            ffmpeg_output_args = (
+                [
+                    "-r",
+                    str(self.detect.fps),
+                    "-s",
+                    f"{self.detect.width}x{self.detect.height}",
+                ]
+                + detect_args
+                + ffmpeg_output_args
+                + ["pipe:"]
+            )
         if "rtmp" in ffmpeg_input.roles and self.rtmp.enabled:
             rtmp_args = (
                 self.ffmpeg.output_args.rtmp
@@ -735,12 +741,9 @@ class FrigateConfig(BaseModel):
                 )
 
             # Default detect configuration
-            max_disappeared = (camera_config.fps or 5) * 5
-            if camera_config.detect:
-                if camera_config.detect.max_disappeared is None:
-                    camera_config.detect.max_disappeared = max_disappeared
-            else:
-                camera_config.detect = DetectConfig(max_disappeared=max_disappeared)
+            max_disappeared = camera_config.detect.fps * 5
+            if camera_config.detect.max_disappeared is None:
+                camera_config.detect.max_disappeared = max_disappeared
 
             # Default live configuration
             if camera_config.live is None:

+ 121 - 49
frigate/test/test_config.py

@@ -18,8 +18,11 @@ class TestConfig(unittest.TestCase):
                             {"path": "rtsp://10.0.0.1:554/video", "roles": ["detect"]}
                         ]
                     },
-                    "height": 1080,
-                    "width": 1920,
+                    "detect": {
+                        "height": 1080,
+                        "width": 1920,
+                        "fps": 5,
+                    },
                 }
             },
         }
@@ -42,8 +45,11 @@ class TestConfig(unittest.TestCase):
                             {"path": "rtsp://10.0.0.1:554/video", "roles": ["detect"]}
                         ]
                     },
-                    "height": 1080,
-                    "width": 1920,
+                    "detect": {
+                        "height": 1080,
+                        "width": 1920,
+                        "fps": 5,
+                    },
                 }
             },
         }
@@ -60,8 +66,11 @@ class TestConfig(unittest.TestCase):
                             {"path": "rtsp://10.0.0.1:554/video", "roles": ["detect"]}
                         ]
                     },
-                    "height": 1080,
-                    "width": 1920,
+                    "detect": {
+                        "height": 1080,
+                        "width": 1920,
+                        "fps": 5,
+                    },
                 }
             },
         }
@@ -82,8 +91,11 @@ class TestConfig(unittest.TestCase):
                             {"path": "rtsp://10.0.0.1:554/video", "roles": ["detect"]}
                         ]
                     },
-                    "height": 1080,
-                    "width": 1920,
+                    "detect": {
+                        "height": 1080,
+                        "width": 1920,
+                        "fps": 5,
+                    },
                     "objects": {"track": ["cat"]},
                 }
             },
@@ -105,8 +117,11 @@ class TestConfig(unittest.TestCase):
                             {"path": "rtsp://10.0.0.1:554/video", "roles": ["detect"]}
                         ]
                     },
-                    "height": 1080,
-                    "width": 1920,
+                    "detect": {
+                        "height": 1080,
+                        "width": 1920,
+                        "fps": 5,
+                    },
                 }
             },
         }
@@ -130,8 +145,11 @@ class TestConfig(unittest.TestCase):
                             {"path": "rtsp://10.0.0.1:554/video", "roles": ["detect"]}
                         ]
                     },
-                    "height": 1080,
-                    "width": 1920,
+                    "detect": {
+                        "height": 1080,
+                        "width": 1920,
+                        "fps": 5,
+                    },
                 }
             },
         }
@@ -152,8 +170,11 @@ class TestConfig(unittest.TestCase):
                             {"path": "rtsp://10.0.0.1:554/video", "roles": ["detect"]}
                         ]
                     },
-                    "height": 1080,
-                    "width": 1920,
+                    "detect": {
+                        "height": 1080,
+                        "width": 1920,
+                        "fps": 5,
+                    },
                     "objects": {
                         "track": ["person", "dog"],
                         "filters": {"dog": {"threshold": 0.7}},
@@ -179,8 +200,11 @@ class TestConfig(unittest.TestCase):
                             {"path": "rtsp://10.0.0.1:554/video", "roles": ["detect"]}
                         ]
                     },
-                    "height": 1080,
-                    "width": 1920,
+                    "detect": {
+                        "height": 1080,
+                        "width": 1920,
+                        "fps": 5,
+                    },
                     "objects": {
                         "mask": "0,0,1,1,0,1",
                         "filters": {"dog": {"mask": "1,1,1,1,1,1"}},
@@ -210,8 +234,11 @@ class TestConfig(unittest.TestCase):
                             },
                         ]
                     },
-                    "height": 1080,
-                    "width": 1920,
+                    "detect": {
+                        "height": 1080,
+                        "width": 1920,
+                        "fps": 5,
+                    },
                 }
             },
         }
@@ -233,8 +260,11 @@ class TestConfig(unittest.TestCase):
                             {"path": "rtsp://10.0.0.1:554/video", "roles": ["detect"]}
                         ]
                     },
-                    "height": 1080,
-                    "width": 1920,
+                    "detect": {
+                        "height": 1080,
+                        "width": 1920,
+                        "fps": 5,
+                    },
                     "objects": {
                         "track": ["person", "dog"],
                         "filters": {"dog": {"threshold": 0.7}},
@@ -260,8 +290,11 @@ class TestConfig(unittest.TestCase):
                         ],
                         "input_args": ["-re"],
                     },
-                    "height": 1080,
-                    "width": 1920,
+                    "detect": {
+                        "height": 1080,
+                        "width": 1920,
+                        "fps": 5,
+                    },
                     "objects": {
                         "track": ["person", "dog"],
                         "filters": {"dog": {"threshold": 0.7}},
@@ -292,8 +325,11 @@ class TestConfig(unittest.TestCase):
                         ],
                         "input_args": "test3",
                     },
-                    "height": 1080,
-                    "width": 1920,
+                    "detect": {
+                        "height": 1080,
+                        "width": 1920,
+                        "fps": 5,
+                    },
                     "objects": {
                         "track": ["person", "dog"],
                         "filters": {"dog": {"threshold": 0.7}},
@@ -321,8 +357,11 @@ class TestConfig(unittest.TestCase):
                             {"path": "rtsp://10.0.0.1:554/video", "roles": ["detect"]}
                         ]
                     },
-                    "height": 1080,
-                    "width": 1920,
+                    "detect": {
+                        "height": 1080,
+                        "width": 1920,
+                        "fps": 5,
+                    },
                 }
             },
         }
@@ -344,8 +383,11 @@ class TestConfig(unittest.TestCase):
                             {"path": "rtsp://10.0.0.1:554/video2", "roles": ["detect"]},
                         ]
                     },
-                    "height": 1080,
-                    "width": 1920,
+                    "detect": {
+                        "height": 1080,
+                        "width": 1920,
+                        "fps": 5,
+                    },
                 }
             },
         }
@@ -362,8 +404,11 @@ class TestConfig(unittest.TestCase):
                             {"path": "rtsp://10.0.0.1:554/video", "roles": ["detect"]}
                         ]
                     },
-                    "height": 1080,
-                    "width": 1920,
+                    "detect": {
+                        "height": 1080,
+                        "width": 1920,
+                        "fps": 5,
+                    },
                     "zones": {"back": {"coordinates": "1,1,1,1,1,1"}},
                 }
             },
@@ -381,8 +426,11 @@ class TestConfig(unittest.TestCase):
                             {"path": "rtsp://10.0.0.1:554/video", "roles": ["detect"]}
                         ]
                     },
-                    "height": 1080,
-                    "width": 1920,
+                    "detect": {
+                        "height": 1080,
+                        "width": 1920,
+                        "fps": 5,
+                    },
                     "zones": {"test": {"coordinates": "1,1,1,1,1,1"}},
                 }
             },
@@ -408,8 +456,11 @@ class TestConfig(unittest.TestCase):
                             {"path": "rtsp://10.0.0.1:554/video", "roles": ["detect"]}
                         ]
                     },
-                    "height": 1080,
-                    "width": 1920,
+                    "detect": {
+                        "height": 1080,
+                        "width": 1920,
+                        "fps": 5,
+                    },
                     "clips": {"enabled": True},
                 }
             },
@@ -436,8 +487,11 @@ class TestConfig(unittest.TestCase):
                             {"path": "rtsp://10.0.0.1:554/record", "roles": ["record"]},
                         ]
                     },
-                    "height": 1080,
-                    "width": 1920,
+                    "detect": {
+                        "height": 1080,
+                        "width": 1920,
+                        "fps": 5,
+                    },
                 }
             },
         }
@@ -463,9 +517,12 @@ class TestConfig(unittest.TestCase):
                             },
                         ]
                     },
-                    "height": 1080,
-                    "width": 1920,
-                    "detect": {"enabled": True},
+                    "detect": {
+                        "enabled": True,
+                        "height": 1080,
+                        "width": 1920,
+                        "fps": 5,
+                    },
                 }
             },
         }
@@ -490,8 +547,11 @@ class TestConfig(unittest.TestCase):
                             },
                         ]
                     },
-                    "height": 480,
-                    "width": 640,
+                    "detect": {
+                        "height": 1080,
+                        "width": 1920,
+                        "fps": 5,
+                    },
                 }
             },
         }
@@ -516,8 +576,11 @@ class TestConfig(unittest.TestCase):
                             },
                         ]
                     },
-                    "height": 1080,
-                    "width": 1920,
+                    "detect": {
+                        "height": 1080,
+                        "width": 1920,
+                        "fps": 5,
+                    },
                 }
             },
         }
@@ -543,8 +606,11 @@ class TestConfig(unittest.TestCase):
                             },
                         ]
                     },
-                    "height": 1080,
-                    "width": 1920,
+                    "detect": {
+                        "height": 1080,
+                        "width": 1920,
+                        "fps": 5,
+                    },
                 }
             },
         }
@@ -569,8 +635,11 @@ class TestConfig(unittest.TestCase):
                             },
                         ]
                     },
-                    "height": 1080,
-                    "width": 1920,
+                    "detect": {
+                        "height": 1080,
+                        "width": 1920,
+                        "fps": 5,
+                    },
                 }
             },
         }
@@ -596,8 +665,11 @@ class TestConfig(unittest.TestCase):
                             },
                         ]
                     },
-                    "height": 1080,
-                    "width": 1920,
+                    "detect": {
+                        "height": 1080,
+                        "width": 1920,
+                        "fps": 5,
+                    },
                 }
             },
         }

+ 2 - 1
web/src/components/CameraImage.jsx

@@ -12,7 +12,8 @@ export default function CameraImage({ camera, onload, searchParams = '', stretch
   const canvasRef = useRef(null);
   const [{ width: availableWidth }] = useResizeObserver(containerRef);
 
-  const { name, width, height } = config.cameras[camera];
+  const { name } = config.cameras[camera];
+  const { width, height } = config.cameras[camera].detect;
   const aspectRatio = width / height;
 
   const scaledHeight = useMemo(() => {

+ 1 - 1
web/src/components/__tests__/CameraImage.test.jsx

@@ -7,7 +7,7 @@ import { render, screen } from '@testing-library/preact';
 describe('CameraImage', () => {
   beforeEach(() => {
     jest.spyOn(Api, 'useConfig').mockImplementation(() => {
-      return { data: { cameras: { front: { name: 'front', width: 1280, height: 720 } } } };
+      return { data: { cameras: { front: { name: 'front', detect: { width: 1280, height: 720 } } } } };
     });
     jest.spyOn(Api, 'useApiHost').mockReturnValue('http://base-url.local:5000');
     jest.spyOn(Hooks, 'useResizeObserver').mockImplementation(() => [{ width: 0 }]);

+ 5 - 2
web/src/routes/CameraMap.jsx

@@ -15,13 +15,16 @@ export default function CameraMasks({ camera, url }) {
 
   const cameraConfig = config.cameras[camera];
   const {
-    width,
-    height,
     motion: { mask: motionMask },
     objects: { filters: objectFilters },
     zones,
   } = cameraConfig;
 
+  const {
+    width,
+    height,
+  } = cameraConfig.detect;
+
   const [{ width: scaledWidth }] = useResizeObserver(imageRef);
   const imageScale = scaledWidth / width;