From 38e098ca31d21320bb4d0574d876e660582613d9 Mon Sep 17 00:00:00 2001 From: Nicolas Mowen Date: Mon, 6 Jan 2025 17:38:46 -0600 Subject: [PATCH 1/9] Remove extra data except from keypackets when using qsv (#15865) --- frigate/ffmpeg_presets.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/frigate/ffmpeg_presets.py b/frigate/ffmpeg_presets.py index 1a3d4408f..c2dc09d1f 100644 --- a/frigate/ffmpeg_presets.py +++ b/frigate/ffmpeg_presets.py @@ -71,8 +71,8 @@ PRESETS_HW_ACCEL_DECODE = { "preset-rpi-64-h264": "-c:v:1 h264_v4l2m2m", "preset-rpi-64-h265": "-c:v:1 hevc_v4l2m2m", FFMPEG_HWACCEL_VAAPI: f"-hwaccel_flags allow_profile_mismatch -hwaccel vaapi -hwaccel_device {_gpu_selector.get_selected_gpu()} -hwaccel_output_format vaapi", - "preset-intel-qsv-h264": f"-hwaccel qsv -qsv_device {_gpu_selector.get_selected_gpu()} -hwaccel_output_format qsv -c:v h264_qsv", - "preset-intel-qsv-h265": f"-load_plugin hevc_hw -hwaccel qsv -qsv_device {_gpu_selector.get_selected_gpu()} -hwaccel_output_format qsv -c:v hevc_qsv", + "preset-intel-qsv-h264": f"-hwaccel qsv -qsv_device {_gpu_selector.get_selected_gpu()} -hwaccel_output_format qsv -c:v h264_qsv -bsf:v dump_extra", # https://trac.ffmpeg.org/ticket/9766#comment:17 + "preset-intel-qsv-h265": f"-load_plugin hevc_hw -hwaccel qsv -qsv_device {_gpu_selector.get_selected_gpu()} -hwaccel_output_format qsv -c:v hevc_qsv -bsf:v dump_extra", # https://trac.ffmpeg.org/ticket/9766#comment:17 FFMPEG_HWACCEL_NVIDIA: "-hwaccel cuda -hwaccel_output_format cuda", "preset-jetson-h264": "-c:v h264_nvmpi -resize {1}x{2}", "preset-jetson-h265": "-c:v hevc_nvmpi -resize {1}x{2}", From 4fc9106c17cb6784d5f532f7279d9a53f5474c39 Mon Sep 17 00:00:00 2001 From: Nicolas Mowen Date: Tue, 7 Jan 2025 17:02:32 -0600 Subject: [PATCH 2/9] Update for correct audio requirements (#15882) --- docs/docs/configuration/live.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/docs/configuration/live.md b/docs/docs/configuration/live.md index 25bf7537c..6d63744cc 100644 --- a/docs/docs/configuration/live.md +++ b/docs/docs/configuration/live.md @@ -29,7 +29,7 @@ The default video and audio codec on your camera may not always be compatible wi ### Audio Support -MSE Requires AAC audio, WebRTC requires PCMU/PCMA, or opus audio. If you want to support both MSE and WebRTC then your restream config needs to make sure both are enabled. +MSE Requires PCMA/PCMU or AAC audio, WebRTC requires PCMA/PCMU or opus audio. If you want to support both MSE and WebRTC then your restream config needs to make sure both are enabled. ```yaml go2rtc: From d57a61b50f1b250637b0669586325492a105b1a9 Mon Sep 17 00:00:00 2001 From: Nicolas Mowen Date: Tue, 7 Jan 2025 20:59:37 -0700 Subject: [PATCH 3/9] Simplify model config (#15881) * Add migration to migrate to model_path * Simplify model config * Cleanup docs * Set config version * Formatting * Fix tests --- docs/docs/configuration/index.md | 3 +- docs/docs/configuration/object_detectors.md | 10 +++--- docs/docs/configuration/reference.md | 2 +- frigate/config/config.py | 38 ++++++++------------- frigate/detectors/detector_config.py | 3 ++ frigate/test/test_config.py | 4 +-- frigate/util/config.py | 24 ++++++++++++- 7 files changed, 50 insertions(+), 34 deletions(-) diff --git a/docs/docs/configuration/index.md b/docs/docs/configuration/index.md index a0b58558d..a60da3499 100644 --- a/docs/docs/configuration/index.md +++ b/docs/docs/configuration/index.md @@ -203,14 +203,13 @@ detectors: ov: type: openvino device: AUTO - model: - path: /openvino-model/ssdlite_mobilenet_v2.xml model: width: 300 height: 300 input_tensor: nhwc input_pixel_format: bgr + path: /openvino-model/ssdlite_mobilenet_v2.xml labelmap_path: /openvino-model/coco_91cl_bkgr.txt record: diff --git a/docs/docs/configuration/object_detectors.md b/docs/docs/configuration/object_detectors.md index e06baaad5..3e03daab3 100644 --- a/docs/docs/configuration/object_detectors.md +++ b/docs/docs/configuration/object_detectors.md @@ -144,7 +144,7 @@ detectors: #### SSDLite MobileNet v2 -An OpenVINO model is provided in the container at `/openvino-model/ssdlite_mobilenet_v2.xml` and is used by this detector type by default. The model comes from Intel's Open Model Zoo [SSDLite MobileNet V2](https://github.com/openvinotoolkit/open_model_zoo/tree/master/models/public/ssdlite_mobilenet_v2) and is converted to an FP16 precision IR model. +An OpenVINO model is provided in the container at `/openvino-model/ssdlite_mobilenet_v2.xml` and is used by this detector type by default. The model comes from Intel's Open Model Zoo [SSDLite MobileNet V2](https://github.com/openvinotoolkit/open_model_zoo/tree/master/models/public/ssdlite_mobilenet_v2) and is converted to an FP16 precision IR model. Use the model configuration shown below when using the OpenVINO detector with the default OpenVINO model: @@ -506,11 +506,12 @@ detectors: cpu1: type: cpu num_threads: 3 - model: - path: "/custom_model.tflite" cpu2: type: cpu num_threads: 3 + +model: + path: "/custom_model.tflite" ``` When using CPU detectors, you can add one CPU detector per camera. Adding more detectors than the number of cameras should not improve performance. @@ -637,8 +638,6 @@ detectors: hailo8l: type: hailo8l device: PCIe - model: - path: /config/model_cache/h8l_cache/ssd_mobilenet_v1.hef model: width: 300 @@ -646,4 +645,5 @@ model: input_tensor: nhwc input_pixel_format: bgr model_type: ssd + path: /config/model_cache/h8l_cache/ssd_mobilenet_v1.hef ``` diff --git a/docs/docs/configuration/reference.md b/docs/docs/configuration/reference.md index 7f3164369..0c2dbdd12 100644 --- a/docs/docs/configuration/reference.md +++ b/docs/docs/configuration/reference.md @@ -52,7 +52,7 @@ detectors: # Required: name of the detector detector_name: # Required: type of the detector - # Frigate provided types include 'cpu', 'edgetpu', 'openvino' and 'tensorrt' (default: shown below) + # Frigate provides many types, see https://docs.frigate.video/configuration/object_detectors for more details (default: shown below) # Additional detector types can also be plugged in. # Detectors may require additional configuration. # Refer to the Detectors configuration page for more information. diff --git a/frigate/config/config.py b/frigate/config/config.py index 770588b93..43db89b4f 100644 --- a/frigate/config/config.py +++ b/frigate/config/config.py @@ -594,35 +594,27 @@ class FrigateConfig(FrigateBaseModel): if isinstance(detector, dict) else detector.model_dump(warnings="none") ) - detector_config: DetectorConfig = adapter.validate_python(model_dict) - if detector_config.model is None: - detector_config.model = self.model.model_copy() - else: - path = detector_config.model.path - detector_config.model = self.model.model_copy() - detector_config.model.path = path + detector_config: BaseDetectorConfig = adapter.validate_python(model_dict) - if "path" not in model_dict or len(model_dict.keys()) > 1: - logger.warning( - "Customizing more than a detector model path is unsupported." - ) + # users should not set model themselves + if detector_config.model: + detector_config.model = None - merged_model = deep_merge( - detector_config.model.model_dump(exclude_unset=True, warnings="none"), - self.model.model_dump(exclude_unset=True, warnings="none"), - ) + model_config = self.model.model_dump(exclude_unset=True, warnings="none") - if "path" not in merged_model: + if detector_config.model_path: + model_config["path"] = detector_config.model_path + + if "path" not in model_config: if detector_config.type == "cpu": - merged_model["path"] = "/cpu_model.tflite" + model_config["path"] = "/cpu_model.tflite" elif detector_config.type == "edgetpu": - merged_model["path"] = "/edgetpu_model.tflite" + model_config["path"] = "/edgetpu_model.tflite" - detector_config.model = ModelConfig.model_validate(merged_model) - detector_config.model.check_and_load_plus_model( - self.plus_api, detector_config.type - ) - detector_config.model.compute_model_hash() + model = ModelConfig.model_validate(model_config) + model.check_and_load_plus_model(self.plus_api, detector_config.type) + model.compute_model_hash() + detector_config.model = model self.detectors[key] = detector_config return self diff --git a/frigate/detectors/detector_config.py b/frigate/detectors/detector_config.py index 45875e2e6..452f1feed 100644 --- a/frigate/detectors/detector_config.py +++ b/frigate/detectors/detector_config.py @@ -194,6 +194,9 @@ class BaseDetectorConfig(BaseModel): model: Optional[ModelConfig] = Field( default=None, title="Detector specific model configuration." ) + model_path: Optional[str] = Field( + default=None, title="Detector specific model path." + ) model_config = ConfigDict( extra="allow", arbitrary_types_allowed=True, protected_namespaces=() ) diff --git a/frigate/test/test_config.py b/frigate/test/test_config.py index 143609386..e6cb1274e 100644 --- a/frigate/test/test_config.py +++ b/frigate/test/test_config.py @@ -75,11 +75,11 @@ class TestConfig(unittest.TestCase): "detectors": { "cpu": { "type": "cpu", - "model": {"path": "/cpu_model.tflite"}, + "model_path": "/cpu_model.tflite", }, "edgetpu": { "type": "edgetpu", - "model": {"path": "/edgetpu_model.tflite"}, + "model_path": "/edgetpu_model.tflite", }, "openvino": { "type": "openvino", diff --git a/frigate/util/config.py b/frigate/util/config.py index 6bdbc0430..bb050b5b6 100644 --- a/frigate/util/config.py +++ b/frigate/util/config.py @@ -13,7 +13,7 @@ from frigate.util.services import get_video_properties logger = logging.getLogger(__name__) -CURRENT_CONFIG_VERSION = "0.15-0" +CURRENT_CONFIG_VERSION = "0.15-1" DEFAULT_CONFIG_FILE = "/config/config.yml" @@ -77,6 +77,13 @@ def migrate_frigate_config(config_file: str): yaml.dump(new_config, f) previous_version = "0.15-0" + if previous_version < "0.15-1": + logger.info(f"Migrating frigate config from {previous_version} to 0.15-1...") + new_config = migrate_015_1(config) + with open(config_file, "w") as f: + yaml.dump(new_config, f) + previous_version = "0.15-1" + logger.info("Finished frigate config migration...") @@ -267,6 +274,21 @@ def migrate_015_0(config: dict[str, dict[str, any]]) -> dict[str, dict[str, any] return new_config +def migrate_015_1(config: dict[str, dict[str, any]]) -> dict[str, dict[str, any]]: + """Handle migrating frigate config to 0.15-1""" + new_config = config.copy() + + for detector, detector_config in config.get("detectors", {}).items(): + path = detector_config.get("model", {}).get("path") + + if path: + new_config["detectors"][detector]["model_path"] = path + del new_config["detectors"][detector]["model"] + + new_config["version"] = "0.15-1" + return new_config + + def get_relative_coordinates( mask: Optional[Union[str, list]], frame_shape: tuple[int, int] ) -> Union[str, list]: From b265b6b190efd4e6252450eb240a46cc6544b169 Mon Sep 17 00:00:00 2001 From: Nicolas Mowen Date: Wed, 8 Jan 2025 16:17:57 -0700 Subject: [PATCH 4/9] Catch case where user has multiple of the same kind of GPU (#15903) --- frigate/util/services.py | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/frigate/util/services.py b/frigate/util/services.py index 9ee6da999..2fd701298 100644 --- a/frigate/util/services.py +++ b/frigate/util/services.py @@ -390,12 +390,22 @@ def try_get_info(f, h, default="N/A"): def get_nvidia_gpu_stats() -> dict[int, dict]: + names: dict[str, int] = {} results = {} try: nvml.nvmlInit() deviceCount = nvml.nvmlDeviceGetCount() for i in range(deviceCount): handle = nvml.nvmlDeviceGetHandleByIndex(i) + gpu_name = nvml.nvmlDeviceGetName(handle) + + # handle case where user has multiple of same GPU + if gpu_name in names: + names[gpu_name] += 1 + gpu_name += f" ({names.get(gpu_name)})" + else: + names[gpu_name] = 1 + meminfo = try_get_info(nvml.nvmlDeviceGetMemoryInfo, handle) util = try_get_info(nvml.nvmlDeviceGetUtilizationRates, handle) enc = try_get_info(nvml.nvmlDeviceGetEncoderUtilization, handle) @@ -423,7 +433,7 @@ def get_nvidia_gpu_stats() -> dict[int, dict]: dec_util = -1 results[i] = { - "name": nvml.nvmlDeviceGetName(handle), + "name": gpu_name, "gpu": gpu_util, "mem": gpu_mem_util, "enc": enc_util, From 0c4ea504d8e0c3d1b68987b07cd9a4819d24d8b6 Mon Sep 17 00:00:00 2001 From: Nicolas Mowen Date: Wed, 8 Jan 2025 16:19:04 -0700 Subject: [PATCH 5/9] Update proxmox docs to align with proxmox recommendation of running in VM. (#15904) --- docs/docs/frigate/installation.md | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/docs/docs/frigate/installation.md b/docs/docs/frigate/installation.md index ede0fa897..4a28623a5 100644 --- a/docs/docs/frigate/installation.md +++ b/docs/docs/frigate/installation.md @@ -305,8 +305,15 @@ To install make sure you have the [community app plugin here](https://forums.unr ## Proxmox -It is recommended to run Frigate in LXC, rather than in a VM, for maximum performance. The setup can be complex so be prepared to read the Proxmox and LXC documentation. Suggestions include: +[According to Proxmox documentation](https://pve.proxmox.com/pve-docs/pve-admin-guide.html#chapter_pct) it is recommended that you run application containers like Frigate inside a Proxmox QEMU VM. This will give you all the advantages of application containerization, while also providing the benefits that VMs offer, such as strong isolation from the host and the ability to live-migrate, which otherwise isn’t possible with containers. +:::warning + +If you choose to run Frigate via LXC in Proxmox the setup can be complex so be prepared to read the Proxmox and LXC documentation, Frigate does not officially support running inside of an LXC. + +::: + + Suggestions include: - For Intel-based hardware acceleration, to allow access to the `/dev/dri/renderD128` device with major number 226 and minor number 128, add the following lines to the `/etc/pve/lxc/.conf` LXC configuration: - `lxc.cgroup2.devices.allow: c 226:128 rwm` - `lxc.mount.entry: /dev/dri/renderD128 dev/dri/renderD128 none bind,optional,create=file` From c1dede9369b00bd9e29a7c71fd2608aed52780de Mon Sep 17 00:00:00 2001 From: Josh Hawkins <32435876+hawkeye217@users.noreply.github.com> Date: Thu, 9 Jan 2025 10:31:16 -0600 Subject: [PATCH 6/9] Clarify reolink doorbell two way talk requirements (#15915) * Clarify reolink doorbell two way talk requirements * relative paths * move to live section * fix link --- docs/docs/configuration/camera_specific.md | 4 +++- docs/docs/configuration/live.md | 10 ++++++++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/docs/docs/configuration/camera_specific.md b/docs/docs/configuration/camera_specific.md index 072c20bb5..774754b9a 100644 --- a/docs/docs/configuration/camera_specific.md +++ b/docs/docs/configuration/camera_specific.md @@ -156,7 +156,9 @@ cameras: #### Reolink Doorbell -The reolink doorbell supports 2-way audio via go2rtc and other applications. It is important that the http-flv stream is still used for stability, a secondary rtsp stream can be added that will be using for the two way audio only. +The reolink doorbell supports two way audio via go2rtc and other applications. It is important that the http-flv stream is still used for stability, a secondary rtsp stream can be added that will be using for the two way audio only. + +Ensure HTTP is enabled in the camera's advanced network settings. To use two way talk with Frigate, see the [Live view documentation](/configuration/live#two-way-talk). ```yaml go2rtc: diff --git a/docs/docs/configuration/live.md b/docs/docs/configuration/live.md index 6d63744cc..22789181a 100644 --- a/docs/docs/configuration/live.md +++ b/docs/docs/configuration/live.md @@ -138,3 +138,13 @@ services: ::: See [go2rtc WebRTC docs](https://github.com/AlexxIT/go2rtc/tree/v1.8.3#module-webrtc) for more information about this. + +### Two way talk + +For devices that support two way talk, Frigate can be configured to use the feature from the camera's Live view in the Web UI. You should: + +- Set up go2rtc with [WebRTC](#webrtc-extra-configuration). +- Ensure you access Frigate via https (may require [opening port 8971](/frigate/installation/#ports)). +- For the Home Assistant Frigate card, [follow the docs](https://github.com/dermotduffy/frigate-hass-card?tab=readme-ov-file#using-2-way-audio) for the correct source. + +To use the Reolink Doorbell with two way talk, you should use the [recommended Reolink configuration](/configuration/camera_specific#reolink-doorbell) From b8a74793ca35ccfca0dbca64d3a0414888debe0a Mon Sep 17 00:00:00 2001 From: Josh Hawkins <32435876+hawkeye217@users.noreply.github.com> Date: Thu, 9 Jan 2025 10:55:08 -0600 Subject: [PATCH 7/9] Clarify motion recording (#15917) * Clarify motion recording * move to troubleshooting --- docs/docs/troubleshooting/recordings.md | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/docs/docs/troubleshooting/recordings.md b/docs/docs/troubleshooting/recordings.md index 611ba45e2..667ea1e8f 100644 --- a/docs/docs/troubleshooting/recordings.md +++ b/docs/docs/troubleshooting/recordings.md @@ -3,7 +3,15 @@ id: recordings title: Troubleshooting Recordings --- -### WARNING : Unable to keep up with recording segments in cache for camera. Keeping the 5 most recent segments out of 6 and discarding the rest... +## I have Frigate configured for motion recording only, but it still seems to be recording even with no motion. Why? + +You'll want to: + +- Make sure your camera's timestamp is masked out with a motion mask. Even if there is no motion occurring in your scene, your motion settings may be sensitive enough to count your timestamp as motion. +- If you have audio detection enabled, keep in mind that audio that is heard above `min_volume` is considered motion. +- [Tune your motion detection settings](/configuration/motion_detection) either by editing your config file or by using the UI's Motion Tuner. + +## I see the message: WARNING : Unable to keep up with recording segments in cache for camera. Keeping the 5 most recent segments out of 6 and discarding the rest... This error can be caused by a number of different issues. The first step in troubleshooting is to enable debug logging for recording. This will enable logging showing how long it takes for recordings to be moved from RAM cache to the disk. @@ -40,6 +48,7 @@ On linux, some helpful tools/commands in diagnosing would be: On modern linux kernels, the system will utilize some swap if enabled. Setting vm.swappiness=1 no longer means that the kernel will only swap in order to avoid OOM. To prevent any swapping inside a container, set allocations memory and memory+swap to be the same and disable swapping by setting the following docker/podman run parameters: **Compose example** + ```yaml version: "3.9" services: @@ -54,6 +63,7 @@ services: ``` **Run command example** + ``` --memory= --memory-swap= --memory-swappiness=0 ``` From c4727f19e14ab138872247bb1f85f79a36eeb6ce Mon Sep 17 00:00:00 2001 From: Blake Blackshear Date: Sat, 11 Jan 2025 08:04:11 -0600 Subject: [PATCH 8/9] Simplify plus submit (#15941) * remove unused annotate file * improve plus error messages * formatting --- benchmark.py | 2 +- frigate/comms/webpush.py | 2 +- frigate/config/camera/zone.py | 2 +- frigate/detectors/plugins/tensorrt.py | 18 +++++++++--------- frigate/plus.py | 15 ++++----------- frigate/ptz/autotrack.py | 14 +++++++------- frigate/record/maintainer.py | 2 +- frigate/review/maintainer.py | 4 ++-- frigate/service_manager/multiprocessing.py | 3 +-- frigate/track/tracked_object.py | 2 +- frigate/util/config.py | 4 ++-- process_clip.py | 6 +++--- 12 files changed, 33 insertions(+), 41 deletions(-) diff --git a/benchmark.py b/benchmark.py index 5c0c68419..7db09a5d7 100755 --- a/benchmark.py +++ b/benchmark.py @@ -61,7 +61,7 @@ def start(id, num_detections, detection_queue, event): object_detector.cleanup() print(f"{id} - Processed for {duration:.2f} seconds.") print(f"{id} - FPS: {object_detector.fps.eps():.2f}") - print(f"{id} - Average frame processing time: {mean(frame_times)*1000:.2f}ms") + print(f"{id} - Average frame processing time: {mean(frame_times) * 1000:.2f}ms") ###### diff --git a/frigate/comms/webpush.py b/frigate/comms/webpush.py index 602f8d11e..abfd52d19 100644 --- a/frigate/comms/webpush.py +++ b/frigate/comms/webpush.py @@ -151,7 +151,7 @@ class WebPushClient(Communicator): # type: ignore[misc] camera: str = payload["after"]["camera"] title = f"{', '.join(sorted_objects).replace('_', ' ').title()}{' was' if state == 'end' else ''} detected in {', '.join(payload['after']['data']['zones']).replace('_', ' ').title()}" message = f"Detected on {camera.replace('_', ' ').title()}" - image = f'{payload["after"]["thumb_path"].replace("/media/frigate", "")}' + image = f"{payload['after']['thumb_path'].replace('/media/frigate', '')}" # if event is ongoing open to live view otherwise open to recordings view direct_url = f"/review?id={reviewId}" if state == "end" else f"/#{camera}" diff --git a/frigate/config/camera/zone.py b/frigate/config/camera/zone.py index 65b34a049..37fc1b744 100644 --- a/frigate/config/camera/zone.py +++ b/frigate/config/camera/zone.py @@ -85,7 +85,7 @@ class ZoneConfig(BaseModel): if explicit: self.coordinates = ",".join( [ - f'{round(int(p.split(",")[0]) / frame_shape[1], 3)},{round(int(p.split(",")[1]) / frame_shape[0], 3)}' + f"{round(int(p.split(',')[0]) / frame_shape[1], 3)},{round(int(p.split(',')[1]) / frame_shape[0], 3)}" for p in coordinates ] ) diff --git a/frigate/detectors/plugins/tensorrt.py b/frigate/detectors/plugins/tensorrt.py index 380fa9107..de5459c6d 100644 --- a/frigate/detectors/plugins/tensorrt.py +++ b/frigate/detectors/plugins/tensorrt.py @@ -219,19 +219,19 @@ class TensorRtDetector(DetectionApi): ] def __init__(self, detector_config: TensorRTDetectorConfig): - assert ( - TRT_SUPPORT - ), f"TensorRT libraries not found, {DETECTOR_KEY} detector not present" + assert TRT_SUPPORT, ( + f"TensorRT libraries not found, {DETECTOR_KEY} detector not present" + ) (cuda_err,) = cuda.cuInit(0) - assert ( - cuda_err == cuda.CUresult.CUDA_SUCCESS - ), f"Failed to initialize cuda {cuda_err}" + assert cuda_err == cuda.CUresult.CUDA_SUCCESS, ( + f"Failed to initialize cuda {cuda_err}" + ) err, dev_count = cuda.cuDeviceGetCount() logger.debug(f"Num Available Devices: {dev_count}") - assert ( - detector_config.device < dev_count - ), f"Invalid TensorRT Device Config. Device {detector_config.device} Invalid." + assert detector_config.device < dev_count, ( + f"Invalid TensorRT Device Config. Device {detector_config.device} Invalid." + ) err, self.cu_ctx = cuda.cuCtxCreate( cuda.CUctx_flags.CU_CTX_MAP_HOST, detector_config.device ) diff --git a/frigate/plus.py b/frigate/plus.py index 83203356c..758089b85 100644 --- a/frigate/plus.py +++ b/frigate/plus.py @@ -68,11 +68,13 @@ class PlusApi: or self._token_data["expires"] - datetime.datetime.now().timestamp() < 60 ): if self.key is None: - raise Exception("Plus API not activated") + raise Exception( + "Plus API key not set. See https://docs.frigate.video/integrations/plus#set-your-api-key" + ) parts = self.key.split(":") r = requests.get(f"{self.host}/v1/auth/token", auth=(parts[0], parts[1])) if not r.ok: - raise Exception("Unable to refresh API token") + raise Exception(f"Unable to refresh API token: {r.text}") self._token_data = r.json() def _get_authorization_header(self) -> dict: @@ -116,15 +118,6 @@ class PlusApi: logger.error(f"Failed to upload original: {r.status_code} {r.text}") raise Exception(r.text) - # resize and submit annotate - files = {"file": get_jpg_bytes(image, 640, 70)} - data = presigned_urls["annotate"]["fields"] - data["content-type"] = "image/jpeg" - r = requests.post(presigned_urls["annotate"]["url"], files=files, data=data) - if not r.ok: - logger.error(f"Failed to upload annotate: {r.status_code} {r.text}") - raise Exception(r.text) - # resize and submit thumbnail files = {"file": get_jpg_bytes(image, 200, 70)} data = presigned_urls["thumbnail"]["fields"] diff --git a/frigate/ptz/autotrack.py b/frigate/ptz/autotrack.py index 9f7f5f1b8..fc6284f40 100644 --- a/frigate/ptz/autotrack.py +++ b/frigate/ptz/autotrack.py @@ -135,7 +135,7 @@ class PtzMotionEstimator: try: logger.debug( - f"{camera}: Motion estimator transformation: {self.coord_transformations.rel_to_abs([[0,0]])}" + f"{camera}: Motion estimator transformation: {self.coord_transformations.rel_to_abs([[0, 0]])}" ) except Exception: pass @@ -471,7 +471,7 @@ class PtzAutoTracker: self.onvif.get_camera_status(camera) logger.info( - f"Calibration for {camera} in progress: {round((step/num_steps)*100)}% complete" + f"Calibration for {camera} in progress: {round((step / num_steps) * 100)}% complete" ) self.calibrating[camera] = False @@ -690,7 +690,7 @@ class PtzAutoTracker: f"{camera}: Predicted movement time: {self._predict_movement_time(camera, pan, tilt)}" ) logger.debug( - f"{camera}: Actual movement time: {self.ptz_metrics[camera].stop_time.value-self.ptz_metrics[camera].start_time.value}" + f"{camera}: Actual movement time: {self.ptz_metrics[camera].stop_time.value - self.ptz_metrics[camera].start_time.value}" ) # save metrics for better estimate calculations @@ -983,10 +983,10 @@ class PtzAutoTracker: logger.debug(f"{camera}: Zoom test: at max zoom: {at_max_zoom}") logger.debug(f"{camera}: Zoom test: at min zoom: {at_min_zoom}") logger.debug( - f'{camera}: Zoom test: zoom in hysteresis limit: {zoom_in_hysteresis} value: {AUTOTRACKING_ZOOM_IN_HYSTERESIS} original: {self.tracked_object_metrics[camera]["original_target_box"]} max: {self.tracked_object_metrics[camera]["max_target_box"]} target: {calculated_target_box if calculated_target_box else self.tracked_object_metrics[camera]["target_box"]}' + f"{camera}: Zoom test: zoom in hysteresis limit: {zoom_in_hysteresis} value: {AUTOTRACKING_ZOOM_IN_HYSTERESIS} original: {self.tracked_object_metrics[camera]['original_target_box']} max: {self.tracked_object_metrics[camera]['max_target_box']} target: {calculated_target_box if calculated_target_box else self.tracked_object_metrics[camera]['target_box']}" ) logger.debug( - f'{camera}: Zoom test: zoom out hysteresis limit: {zoom_out_hysteresis} value: {AUTOTRACKING_ZOOM_OUT_HYSTERESIS} original: {self.tracked_object_metrics[camera]["original_target_box"]} max: {self.tracked_object_metrics[camera]["max_target_box"]} target: {calculated_target_box if calculated_target_box else self.tracked_object_metrics[camera]["target_box"]}' + f"{camera}: Zoom test: zoom out hysteresis limit: {zoom_out_hysteresis} value: {AUTOTRACKING_ZOOM_OUT_HYSTERESIS} original: {self.tracked_object_metrics[camera]['original_target_box']} max: {self.tracked_object_metrics[camera]['max_target_box']} target: {calculated_target_box if calculated_target_box else self.tracked_object_metrics[camera]['target_box']}" ) # Zoom in conditions (and) @@ -1069,7 +1069,7 @@ class PtzAutoTracker: pan = ((centroid_x / camera_width) - 0.5) * 2 tilt = (0.5 - (centroid_y / camera_height)) * 2 - logger.debug(f'{camera}: Original box: {obj.obj_data["box"]}') + logger.debug(f"{camera}: Original box: {obj.obj_data['box']}") logger.debug(f"{camera}: Predicted box: {tuple(predicted_box)}") logger.debug( f"{camera}: Velocity: {tuple(np.round(average_velocity).flatten().astype(int))}" @@ -1179,7 +1179,7 @@ class PtzAutoTracker: ) zoom = (ratio - 1) / (ratio + 1) logger.debug( - f'{camera}: limit: {self.tracked_object_metrics[camera]["max_target_box"]}, ratio: {ratio} zoom calculation: {zoom}' + f"{camera}: limit: {self.tracked_object_metrics[camera]['max_target_box']}, ratio: {ratio} zoom calculation: {zoom}" ) if not result: # zoom out with special condition if zooming out because of velocity, edges, etc. diff --git a/frigate/record/maintainer.py b/frigate/record/maintainer.py index 269735670..a4c23763d 100644 --- a/frigate/record/maintainer.py +++ b/frigate/record/maintainer.py @@ -449,7 +449,7 @@ class RecordingMaintainer(threading.Thread): return None else: logger.debug( - f"Copied {file_path} in {datetime.datetime.now().timestamp()-start_frame} seconds." + f"Copied {file_path} in {datetime.datetime.now().timestamp() - start_frame} seconds." ) try: diff --git a/frigate/review/maintainer.py b/frigate/review/maintainer.py index 8aa0f65e0..b4edb035b 100644 --- a/frigate/review/maintainer.py +++ b/frigate/review/maintainer.py @@ -256,7 +256,7 @@ class ReviewSegmentMaintainer(threading.Thread): elif object["sub_label"][0] in self.config.model.all_attributes: segment.detections[object["id"]] = object["sub_label"][0] else: - segment.detections[object["id"]] = f'{object["label"]}-verified' + segment.detections[object["id"]] = f"{object['label']}-verified" segment.sub_labels[object["id"]] = object["sub_label"][0] # if object is alert label @@ -352,7 +352,7 @@ class ReviewSegmentMaintainer(threading.Thread): elif object["sub_label"][0] in self.config.model.all_attributes: detections[object["id"]] = object["sub_label"][0] else: - detections[object["id"]] = f'{object["label"]}-verified' + detections[object["id"]] = f"{object['label']}-verified" sub_labels[object["id"]] = object["sub_label"][0] # if object is alert label diff --git a/frigate/service_manager/multiprocessing.py b/frigate/service_manager/multiprocessing.py index d0b169275..87bb4ffee 100644 --- a/frigate/service_manager/multiprocessing.py +++ b/frigate/service_manager/multiprocessing.py @@ -72,8 +72,7 @@ class BaseServiceProcess(Service, ABC): running = False except TimeoutError: self.manager.logger.warning( - f"{self.name} is still running after " - f"{timeout} seconds. Killing." + f"{self.name} is still running after {timeout} seconds. Killing." ) if running: diff --git a/frigate/track/tracked_object.py b/frigate/track/tracked_object.py index 3280965da..3da2a5e04 100644 --- a/frigate/track/tracked_object.py +++ b/frigate/track/tracked_object.py @@ -339,7 +339,7 @@ class TrackedObject: box[2], box[3], self.obj_data["label"], - f"{int(self.thumbnail_data['score']*100)}% {int(self.thumbnail_data['area'])}", + f"{int(self.thumbnail_data['score'] * 100)}% {int(self.thumbnail_data['area'])}", thickness=thickness, color=color, ) diff --git a/frigate/util/config.py b/frigate/util/config.py index bb050b5b6..d456c7557 100644 --- a/frigate/util/config.py +++ b/frigate/util/config.py @@ -314,7 +314,7 @@ def get_relative_coordinates( continue rel_points.append( - f"{round(x / frame_shape[1], 3)},{round(y / frame_shape[0], 3)}" + f"{round(x / frame_shape[1], 3)},{round(y / frame_shape[0], 3)}" ) relative_masks.append(",".join(rel_points)) @@ -337,7 +337,7 @@ def get_relative_coordinates( return [] rel_points.append( - f"{round(x / frame_shape[1], 3)},{round(y / frame_shape[0], 3)}" + f"{round(x / frame_shape[1], 3)},{round(y / frame_shape[0], 3)}" ) mask = ",".join(rel_points) diff --git a/process_clip.py b/process_clip.py index 54bbf0c1e..7ef9f4c75 100644 --- a/process_clip.py +++ b/process_clip.py @@ -208,7 +208,7 @@ class ProcessClip: box[2], box[3], obj["id"], - f"{int(obj['score']*100)}% {int(obj['area'])}", + f"{int(obj['score'] * 100)}% {int(obj['area'])}", thickness=thickness, color=color, ) @@ -227,7 +227,7 @@ class ProcessClip: ) cv2.imwrite( - f"{os.path.join(debug_path, os.path.basename(self.clip_path))}.{int(frame_time*1000000)}.jpg", + f"{os.path.join(debug_path, os.path.basename(self.clip_path))}.{int(frame_time * 1000000)}.jpg", current_frame, ) @@ -290,7 +290,7 @@ def process(path, label, output, debug_path): 1 for result in results if result[1]["true_positive_objects"] > 0 ) print( - f"Objects were detected in {positive_count}/{len(results)}({positive_count/len(results)*100:.2f}%) clip(s)." + f"Objects were detected in {positive_count}/{len(results)}({positive_count / len(results) * 100:.2f}%) clip(s)." ) if output: From 173b7aa308963a9f33b921d636a346141c853449 Mon Sep 17 00:00:00 2001 From: Nicolas Mowen Date: Sat, 11 Jan 2025 07:47:45 -0700 Subject: [PATCH 9/9] Handle case where user has multiple manual events on same camera (#15943) --- frigate/review/maintainer.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/frigate/review/maintainer.py b/frigate/review/maintainer.py index b4edb035b..c99479a67 100644 --- a/frigate/review/maintainer.py +++ b/frigate/review/maintainer.py @@ -527,7 +527,9 @@ class ReviewSegmentMaintainer(threading.Thread): if event_id in self.indefinite_events[camera]: self.indefinite_events[camera].pop(event_id) - current_segment.last_update = manual_info["end_time"] + + if len(self.indefinite_events[camera]) == 0: + current_segment.last_update = manual_info["end_time"] else: logger.error( f"Event with ID {event_id} has a set duration and can not be ended manually."