mirror of
https://github.com/blakeblackshear/frigate.git
synced 2025-12-31 09:28:16 -05:00
Compare commits
1 Commits
dev
...
llc_to_inc
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3a71931595 |
2
LICENSE
2
LICENSE
@@ -1,6 +1,6 @@
|
||||
The MIT License
|
||||
|
||||
Copyright (c) 2025 Frigate LLC (Frigate™)
|
||||
Copyright (c) 2026 Frigate, Inc. (Frigate™)
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
|
||||
@@ -40,7 +40,7 @@ If you would like to make a donation to support development, please use [Github
|
||||
This project is licensed under the **MIT License**.
|
||||
|
||||
- **Code:** The source code, configuration files, and documentation in this repository are available under the [MIT License](LICENSE). You are free to use, modify, and distribute the code as long as you include the original copyright notice.
|
||||
- **Trademarks:** The "Frigate" name, the "Frigate NVR" brand, and the Frigate logo are **trademarks of Frigate LLC** and are **not** covered by the MIT License.
|
||||
- **Trademarks:** The "Frigate" name, the "Frigate NVR" brand, and the Frigate logo are **trademarks of Frigate, Inc.** and are **not** covered by the MIT License.
|
||||
|
||||
Please see our [Trademark Policy](TRADEMARK.md) for details on acceptable use of our brand assets.
|
||||
|
||||
@@ -80,4 +80,4 @@ We use [Weblate](https://hosted.weblate.org/projects/frigate-nvr/) to support la
|
||||
|
||||
---
|
||||
|
||||
**Copyright © 2025 Frigate LLC.**
|
||||
**Copyright © 2026 Frigate, Inc.**
|
||||
|
||||
@@ -41,7 +41,7 @@
|
||||
|
||||
**代码部分**:本代码库中的源代码、配置文件和文档均遵循 [MIT 许可证](LICENSE)。您可以自由使用、修改和分发这些代码,但必须保留原始版权声明。
|
||||
|
||||
**商标部分**:“Frigate”名称、“Frigate NVR”品牌以及 Frigate 的 Logo 为 **Frigate LLC 的商标**,**不在** MIT 许可证覆盖范围内。
|
||||
**商标部分**:“Frigate”名称、“Frigate NVR”品牌以及 Frigate 的 Logo 为 **Frigate, Inc. 的商标**,**不在** MIT 许可证覆盖范围内。
|
||||
有关品牌资产的规范使用详情,请参阅我们的[《商标政策》](TRADEMARK.md)。
|
||||
|
||||
## 截图
|
||||
@@ -87,4 +87,4 @@ Bilibili:https://space.bilibili.com/3546894915602564
|
||||
|
||||
---
|
||||
|
||||
**Copyright © 2025 Frigate LLC.**
|
||||
**Copyright © 2026 Frigate, Inc.**
|
||||
|
||||
@@ -6,7 +6,7 @@ This document outlines the policy regarding the use of the trademarks associated
|
||||
|
||||
## 1. Our Trademarks
|
||||
|
||||
The following terms and visual assets are trademarks (the "Marks") of **Frigate LLC**:
|
||||
The following terms and visual assets are trademarks (the "Marks") of **Frigate, Inc.**:
|
||||
|
||||
- **Frigate™**
|
||||
- **Frigate NVR™**
|
||||
@@ -14,7 +14,7 @@ The following terms and visual assets are trademarks (the "Marks") of **Frigate
|
||||
- **The Frigate Logo**
|
||||
|
||||
**Note on Common Law Rights:**
|
||||
Frigate LLC asserts all common law rights in these Marks. The absence of a federal registration symbol (®) does not constitute a waiver of our intellectual property rights.
|
||||
Frigate, Inc. asserts all common law rights in these Marks. The absence of a federal registration symbol (®) does not constitute a waiver of our intellectual property rights.
|
||||
|
||||
## 2. Interaction with the MIT License
|
||||
|
||||
@@ -25,7 +25,7 @@ The software in this repository is licensed under the [MIT License](LICENSE).
|
||||
- The **Code** is free to use, modify, and distribute under the MIT terms.
|
||||
- The **Brand (Trademarks)** is **NOT** licensed under MIT.
|
||||
|
||||
You may not use the Marks in any way that is not explicitly permitted by this policy or by written agreement with Frigate LLC.
|
||||
You may not use the Marks in any way that is not explicitly permitted by this policy or by written agreement with Frigate, Inc.
|
||||
|
||||
## 3. Acceptable Use
|
||||
|
||||
@@ -40,7 +40,7 @@ You may use the Marks without prior written permission in the following specific
|
||||
You may **NOT** use the Marks in the following ways:
|
||||
|
||||
- **Commercial Products:** You may not use "Frigate" in the name of a commercial product, service, or app (e.g., selling an app named _"Frigate Viewer"_ is prohibited).
|
||||
- **Implying Affiliation:** You may not use the Marks in a way that suggests your project is official, sponsored by, or endorsed by Frigate LLC.
|
||||
- **Implying Affiliation:** You may not use the Marks in a way that suggests your project is official, sponsored by, or endorsed by Frigate, Inc.
|
||||
- **Confusing Forks:** If you fork this repository to create a derivative work, you **must** remove the Frigate logo and rename your project to avoid user confusion. You cannot distribute a modified version of the software under the name "Frigate".
|
||||
- **Domain Names:** You may not register domain names containing "Frigate" that are likely to confuse users (e.g., `frigate-official-support.com`).
|
||||
|
||||
|
||||
@@ -188,10 +188,10 @@ go2rtc:
|
||||
# example for connectin to a Reolink camera that supports two way talk
|
||||
your_reolink_camera_twt:
|
||||
- "ffmpeg:http://reolink_ip/flv?port=1935&app=bcs&stream=channel0_main.bcs&user=username&password=password#video=copy#audio=copy#audio=opus"
|
||||
- "rtsp://username:password@reolink_ip/Preview_01_sub"
|
||||
- "rtsp://username:password@reolink_ip/Preview_01_sub
|
||||
your_reolink_camera_twt_sub:
|
||||
- "ffmpeg:http://reolink_ip/flv?port=1935&app=bcs&stream=channel0_ext.bcs&user=username&password=password"
|
||||
- "rtsp://username:password@reolink_ip/Preview_01_sub"
|
||||
- "rtsp://username:password@reolink_ip/Preview_01_sub
|
||||
# example for connecting to a Reolink NVR
|
||||
your_reolink_camera_via_nvr:
|
||||
- "ffmpeg:http://reolink_nvr_ip/flv?port=1935&app=bcs&stream=channel3_main.bcs&user=username&password=password" # channel numbers are 0-15
|
||||
@@ -227,12 +227,6 @@ cameras:
|
||||
|
||||
### Unifi Protect Cameras
|
||||
|
||||
:::note
|
||||
|
||||
Unifi G5s cameras and newer need a Unifi Protect server to enable rtsps stream, it's not posible to enable it in standalone mode.
|
||||
|
||||
:::
|
||||
|
||||
Unifi protect cameras require the rtspx stream to be used with go2rtc.
|
||||
To utilize a Unifi protect camera, modify the rtsps link to begin with rtspx.
|
||||
Additionally, remove the "?enableSrtp" from the end of the Unifi link.
|
||||
@@ -258,10 +252,6 @@ ffmpeg:
|
||||
|
||||
TP-Link VIGI cameras need some adjustments to the main stream settings on the camera itself to avoid issues. The stream needs to be configured as `H264` with `Smart Coding` set to `off`. Without these settings you may have problems when trying to watch recorded footage. For example Firefox will stop playback after a few seconds and show the following error message: `The media playback was aborted due to a corruption problem or because the media used features your browser did not support.`.
|
||||
|
||||
### Wyze Wireless Cameras
|
||||
|
||||
Some community members have found better performance on Wyze cameras by using an alternative firmware known as [Thingino](https://thingino.com/).
|
||||
|
||||
## USB Cameras (aka Webcams)
|
||||
|
||||
To use a USB camera (webcam) with Frigate, the recommendation is to use go2rtc's [FFmpeg Device](https://github.com/AlexxIT/go2rtc?tab=readme-ov-file#source-ffmpeg-device) support:
|
||||
|
||||
@@ -94,19 +94,18 @@ This list of working and non-working PTZ cameras is based on user feedback. If y
|
||||
The FeatureList on the [ONVIF Conformant Products Database](https://www.onvif.org/conformant-products/) can provide a starting point to determine a camera's compatibility with Frigate's autotracking. Look to see if a camera lists `PTZRelative`, `PTZRelativePanTilt` and/or `PTZRelativeZoom`. These features are required for autotracking, but some cameras still fail to respond even if they claim support. If they are missing, autotracking will not work (though basic PTZ in the WebUI might). Avoid cameras with no database entry unless they are confirmed as working below.
|
||||
|
||||
| Brand or specific camera | PTZ Controls | Autotracking | Notes |
|
||||
| ---------------------------- | :----------: | :----------: | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| ---------------------------- | :----------: | :----------: | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --- |
|
||||
| Amcrest | ✅ | ✅ | ⛔️ Generally, Amcrest should work, but some older models (like the common IP2M-841) don't support autotracking |
|
||||
| Amcrest ASH21 | ✅ | ❌ | ONVIF service port: 80 |
|
||||
| Amcrest IP4M-S2112EW-AI | ✅ | ❌ | FOV relative movement not supported. |
|
||||
| Amcrest IP5M-1190EW | ✅ | ❌ | ONVIF Port: 80. FOV relative movement not supported. |
|
||||
| Annke CZ504 | ✅ | ✅ | Annke support provide specific firmware ([V5.7.1 build 250227](https://github.com/pierrepinon/annke_cz504/raw/refs/heads/main/digicap_V5-7-1_build_250227.dav)) to fix issue with ONVIF "TranslationSpaceFov" |
|
||||
| Axis Q-6155E | ✅ | ❌ | ONVIF service port: 80; Camera does not support MoveStatus. |
|
||||
| Ctronics PTZ | ✅ | ❌ | |
|
||||
| Dahua | ✅ | ✅ | Some low-end Dahuas (lite series, picoo series (commonly), among others) have been reported to not support autotracking. These models usually don't have a four digit model number with chassis prefix and options postfix (e.g. DH-P5AE-PV vs DH-SD49825GB-HNR). |
|
||||
| Dahua DH-SD2A500HB | ✅ | ❌ | |
|
||||
| Dahua DH-SD49825GB-HNR | ✅ | ✅ | |
|
||||
| Dahua DH-P5AE-PV | ❌ | ❌ | |
|
||||
| Foscam | ✅ | ❌ | In general support PTZ, but not relative move. There are no official ONVIF certifications and tests available on the ONVIF Conformant Products Database |
|
||||
| Foscam | ✅ | ❌ | In general support PTZ, but not relative move. There are no official ONVIF certifications and tests available on the ONVIF Conformant Products Database | |
|
||||
| Foscam R5 | ✅ | ❌ | |
|
||||
| Foscam SD4 | ✅ | ❌ | |
|
||||
| Hanwha XNP-6550RH | ✅ | ❌ | |
|
||||
|
||||
@@ -39,7 +39,7 @@ For object classification:
|
||||
|
||||
:::note
|
||||
|
||||
A tracked object can only have a single sub label. If you are using Triggers or Face Recognition and you configure an object classification model for `person` using the sub label type, your sub label may not be assigned correctly as it depends on which enrichment completes its analysis first. This could also occur with `car` objects that are assigned a sub label for a delivery carrier. Consider using the `attribute` type instead.
|
||||
A tracked object can only have a single sub label. If you are using Triggers or Face Recognition and you configure an object classification model for `person` using the sub label type, your sub label may not be assigned correctly as it depends on which enrichment completes its analysis first. Consider using the `attribute` type instead.
|
||||
|
||||
:::
|
||||
|
||||
|
||||
@@ -48,29 +48,15 @@ Using Ollama on CPU is not recommended, high inference times make using Generati
|
||||
|
||||
:::
|
||||
|
||||
[Ollama](https://ollama.com/) allows you to self-host large language models and keep everything running locally. It is highly recommended to host this server on a machine with an Nvidia graphics card, or on a Apple silicon Mac for best performance.
|
||||
[Ollama](https://ollama.com/) allows you to self-host large language models and keep everything running locally. It provides a nice API over [llama.cpp](https://github.com/ggerganov/llama.cpp). It is highly recommended to host this server on a machine with an Nvidia graphics card, or on a Apple silicon Mac for best performance.
|
||||
|
||||
Most of the 7b parameter 4-bit vision models will fit inside 8GB of VRAM. There is also a [Docker container](https://hub.docker.com/r/ollama/ollama) available.
|
||||
|
||||
Parallel requests also come with some caveats. You will need to set `OLLAMA_NUM_PARALLEL=1` and choose a `OLLAMA_MAX_QUEUE` and `OLLAMA_MAX_LOADED_MODELS` values that are appropriate for your hardware and preferences. See the [Ollama documentation](https://docs.ollama.com/faq#how-does-ollama-handle-concurrent-requests).
|
||||
|
||||
### Model Types: Instruct vs Thinking
|
||||
|
||||
Most vision-language models are available as **instruct** models, which are fine-tuned to follow instructions and respond concisely to prompts. However, some models (such as certain Qwen-VL or minigpt variants) offer both **instruct** and **thinking** versions.
|
||||
|
||||
- **Instruct models** are always recommended for use with Frigate. These models generate direct, relevant, actionable descriptions that best fit Frigate's object and event summary use case.
|
||||
- **Thinking models** are fine-tuned for more free-form, open-ended, and speculative outputs, which are typically not concise and may not provide the practical summaries Frigate expects. For this reason, Frigate does **not** recommend or support using thinking models.
|
||||
|
||||
Some models are labeled as **hybrid** (capable of both thinking and instruct tasks). In these cases, Frigate will always use instruct-style prompts and specifically disables thinking-mode behaviors to ensure concise, useful responses.
|
||||
|
||||
**Recommendation:**
|
||||
Always select the `-instruct` or documented instruct/tagged variant of any model you use in your Frigate configuration. If in doubt, refer to your model provider’s documentation or model library for guidance on the correct model variant to use.
|
||||
|
||||
|
||||
Parallel requests also come with some caveats. You will need to set `OLLAMA_NUM_PARALLEL=1` and choose a `OLLAMA_MAX_QUEUE` and `OLLAMA_MAX_LOADED_MODELS` values that are appropriate for your hardware and preferences. See the [Ollama documentation](https://github.com/ollama/ollama/blob/main/docs/faq.md#how-does-ollama-handle-concurrent-requests).
|
||||
|
||||
### Supported Models
|
||||
|
||||
You must use a vision capable model with Frigate. Current model variants can be found [in their model library](https://ollama.com/search?c=vision). Note that Frigate will not automatically download the model you specify in your config, you must download the model to your local instance of Ollama first i.e. by running `ollama pull qwen3-vl:2b-instruct` on your Ollama server/Docker container. Note that the model specified in Frigate's config must match the downloaded model tag.
|
||||
You must use a vision capable model with Frigate. Current model variants can be found [in their model library](https://ollama.com/library). Note that Frigate will not automatically download the model you specify in your config, you must download the model to your local instance of Ollama first i.e. by running `ollama pull llava:7b` on your Ollama server/Docker container. Note that the model specified in Frigate's config must match the downloaded model tag.
|
||||
|
||||
:::note
|
||||
|
||||
|
||||
@@ -5,61 +5,76 @@ title: Video Decoding
|
||||
|
||||
# Video Decoding
|
||||
|
||||
It is highly recommended to use an integrated or discrete GPU for hardware acceleration video decoding in Frigate.
|
||||
It is highly recommended to use a GPU for hardware acceleration video decoding in Frigate. Some types of hardware acceleration are detected and used automatically, but you may need to update your configuration to enable hardware accelerated decoding in ffmpeg.
|
||||
|
||||
Some types of hardware acceleration are detected and used automatically, but you may need to update your configuration to enable hardware accelerated decoding in ffmpeg. To verify that hardware acceleration is working:
|
||||
- Check the logs: A message will either say that hardware acceleration was automatically detected, or there will be a warning that no hardware acceleration was automatically detected
|
||||
- If hardware acceleration is specified in the config, verification can be done by ensuring the logs are free from errors. There is no CPU fallback for hardware acceleration.
|
||||
Depending on your system, these parameters may not be compatible. More information on hardware accelerated decoding for ffmpeg can be found here: https://trac.ffmpeg.org/wiki/HWAccelIntro
|
||||
|
||||
:::info
|
||||
|
||||
Frigate supports presets for optimal hardware accelerated video decoding:
|
||||
## Raspberry Pi 3/4
|
||||
|
||||
**AMD**
|
||||
Ensure you increase the allocated RAM for your GPU to at least 128 (`raspi-config` > Performance Options > GPU Memory).
|
||||
If you are using the HA Add-on, you may need to use the full access variant and turn off _Protection mode_ for hardware acceleration.
|
||||
|
||||
- [AMD](#amd-based-cpus): Frigate can utilize modern AMD integrated GPUs and AMD discrete GPUs to accelerate video decoding.
|
||||
```yaml
|
||||
# if you want to decode a h264 stream
|
||||
ffmpeg:
|
||||
hwaccel_args: preset-rpi-64-h264
|
||||
|
||||
**Intel**
|
||||
# if you want to decode a h265 (hevc) stream
|
||||
ffmpeg:
|
||||
hwaccel_args: preset-rpi-64-h265
|
||||
```
|
||||
|
||||
- [Intel](#intel-based-cpus): Frigate can utilize most Intel integrated GPUs and Arc GPUs to accelerate video decoding.
|
||||
:::note
|
||||
|
||||
**Nvidia GPU**
|
||||
If running Frigate through Docker, you either need to run in privileged mode or
|
||||
map the `/dev/video*` devices to Frigate. With Docker Compose add:
|
||||
|
||||
- [Nvidia GPU](#nvidia-gpus): Frigate can utilize most modern Nvidia GPUs to accelerate video decoding.
|
||||
```yaml
|
||||
services:
|
||||
frigate:
|
||||
...
|
||||
devices:
|
||||
- /dev/video11:/dev/video11
|
||||
```
|
||||
|
||||
**Raspberry Pi 3/4**
|
||||
Or with `docker run`:
|
||||
|
||||
- [Raspberry Pi](#raspberry-pi-34): Frigate can utilize the media engine in the Raspberry Pi 3 and 4 to slightly accelerate video decoding.
|
||||
```bash
|
||||
docker run -d \
|
||||
--name frigate \
|
||||
...
|
||||
--device /dev/video11 \
|
||||
ghcr.io/blakeblackshear/frigate:stable
|
||||
```
|
||||
|
||||
**Nvidia Jetson**
|
||||
`/dev/video11` is the correct device (on Raspberry Pi 4B). You can check
|
||||
by running the following and looking for `H264`:
|
||||
|
||||
- [Jetson](#nvidia-jetson): Frigate can utilize the media engine in Jetson hardware to accelerate video decoding.
|
||||
```bash
|
||||
for d in /dev/video*; do
|
||||
echo -e "---\n$d"
|
||||
v4l2-ctl --list-formats-ext -d $d
|
||||
done
|
||||
```
|
||||
|
||||
**Rockchip**
|
||||
|
||||
- [RKNN](#rockchip-platform): Frigate can utilize the media engine in RockChip SOCs to accelerate video decoding.
|
||||
|
||||
**Other Hardware**
|
||||
|
||||
Depending on your system, these presets may not be compatible, and you may need to use manual hwaccel args to take advantage of your hardware. More information on hardware accelerated decoding for ffmpeg can be found here: https://trac.ffmpeg.org/wiki/HWAccelIntro
|
||||
Or map in all the `/dev/video*` devices.
|
||||
|
||||
:::
|
||||
|
||||
## Intel-based CPUs
|
||||
|
||||
Frigate can utilize most Intel integrated GPUs and Arc GPUs to accelerate video decoding.
|
||||
|
||||
:::info
|
||||
|
||||
**Recommended hwaccel Preset**
|
||||
|
||||
| CPU Generation | Intel Driver | Recommended Preset | Notes |
|
||||
| -------------- | ------------ | ------------------- | ------------------------------------------- |
|
||||
| gen1 - gen5 | i965 | preset-vaapi | qsv is not supported, may not support H.265 |
|
||||
| gen6 - gen7 | iHD | preset-vaapi | qsv is not supported |
|
||||
| gen8 - gen12 | iHD | preset-vaapi | preset-intel-qsv-\* can also be used |
|
||||
| gen13+ | iHD / Xe | preset-intel-qsv-\* | |
|
||||
| Intel Arc GPU | iHD / Xe | preset-intel-qsv-\* | |
|
||||
| CPU Generation | Intel Driver | Recommended Preset | Notes |
|
||||
| -------------- | ------------ | ------------------- | ------------------------------------ |
|
||||
| gen1 - gen5 | i965 | preset-vaapi | qsv is not supported |
|
||||
| gen6 - gen7 | iHD | preset-vaapi | qsv is not supported |
|
||||
| gen8 - gen12 | iHD | preset-vaapi | preset-intel-qsv-\* can also be used |
|
||||
| gen13+ | iHD / Xe | preset-intel-qsv-\* | |
|
||||
| Intel Arc GPU | iHD / Xe | preset-intel-qsv-\* | |
|
||||
|
||||
:::
|
||||
|
||||
@@ -180,9 +195,9 @@ telemetry:
|
||||
|
||||
If you are passing in a device path, make sure you've passed the device through to the container.
|
||||
|
||||
## AMD-based CPUs
|
||||
## AMD/ATI GPUs (Radeon HD 2000 and newer GPUs) via libva-mesa-driver
|
||||
|
||||
Frigate can utilize modern AMD integrated GPUs and AMD GPUs to accelerate video decoding using VAAPI.
|
||||
VAAPI supports automatic profile selection so it will work automatically with both H.264 and H.265 streams.
|
||||
|
||||
:::note
|
||||
|
||||
@@ -190,8 +205,6 @@ You need to change the driver to `radeonsi` by adding the following environment
|
||||
|
||||
:::
|
||||
|
||||
VAAPI supports automatic profile selection so it will work automatically with both H.264 and H.265 streams.
|
||||
|
||||
```yaml
|
||||
ffmpeg:
|
||||
hwaccel_args: preset-vaapi
|
||||
@@ -251,7 +264,7 @@ processes:
|
||||
|
||||
:::note
|
||||
|
||||
`nvidia-smi` will not show `ffmpeg` processes when run inside the container [due to docker limitations](https://github.com/NVIDIA/nvidia-docker/issues/179#issuecomment-645579458).
|
||||
`nvidia-smi` may not show `ffmpeg` processes when run inside the container [due to docker limitations](https://github.com/NVIDIA/nvidia-docker/issues/179#issuecomment-645579458).
|
||||
|
||||
:::
|
||||
|
||||
@@ -287,63 +300,12 @@ If you do not see these processes, check the `docker logs` for the container and
|
||||
|
||||
These instructions were originally based on the [Jellyfin documentation](https://jellyfin.org/docs/general/administration/hardware-acceleration.html#nvidia-hardware-acceleration-on-docker-linux).
|
||||
|
||||
## Raspberry Pi 3/4
|
||||
|
||||
Ensure you increase the allocated RAM for your GPU to at least 128 (`raspi-config` > Performance Options > GPU Memory).
|
||||
If you are using the HA Add-on, you may need to use the full access variant and turn off _Protection mode_ for hardware acceleration.
|
||||
|
||||
```yaml
|
||||
# if you want to decode a h264 stream
|
||||
ffmpeg:
|
||||
hwaccel_args: preset-rpi-64-h264
|
||||
|
||||
# if you want to decode a h265 (hevc) stream
|
||||
ffmpeg:
|
||||
hwaccel_args: preset-rpi-64-h265
|
||||
```
|
||||
|
||||
:::note
|
||||
|
||||
If running Frigate through Docker, you either need to run in privileged mode or
|
||||
map the `/dev/video*` devices to Frigate. With Docker Compose add:
|
||||
|
||||
```yaml
|
||||
services:
|
||||
frigate:
|
||||
...
|
||||
devices:
|
||||
- /dev/video11:/dev/video11
|
||||
```
|
||||
|
||||
Or with `docker run`:
|
||||
|
||||
```bash
|
||||
docker run -d \
|
||||
--name frigate \
|
||||
...
|
||||
--device /dev/video11 \
|
||||
ghcr.io/blakeblackshear/frigate:stable
|
||||
```
|
||||
|
||||
`/dev/video11` is the correct device (on Raspberry Pi 4B). You can check
|
||||
by running the following and looking for `H264`:
|
||||
|
||||
```bash
|
||||
for d in /dev/video*; do
|
||||
echo -e "---\n$d"
|
||||
v4l2-ctl --list-formats-ext -d $d
|
||||
done
|
||||
```
|
||||
|
||||
Or map in all the `/dev/video*` devices.
|
||||
|
||||
:::
|
||||
|
||||
# Community Supported
|
||||
|
||||
## NVIDIA Jetson
|
||||
## NVIDIA Jetson (Orin AGX, Orin NX, Orin Nano\*, Xavier AGX, Xavier NX, TX2, TX1, Nano)
|
||||
|
||||
A separate set of docker images is available for Jetson devices. They come with an `ffmpeg` build with codecs that use the Jetson's dedicated media engine. If your Jetson host is running Jetpack 6.0+ use the `stable-tensorrt-jp6` tagged image. Note that the Orin Nano has no video encoder, so frigate will use software encoding on this platform, but the image will still allow hardware decoding and tensorrt object detection.
|
||||
A separate set of docker images is available that is based on Jetpack/L4T. They come with an `ffmpeg` build
|
||||
with codecs that use the Jetson's dedicated media engine. If your Jetson host is running Jetpack 6.0+ use the `stable-tensorrt-jp6` tagged image. Note that the Orin Nano has no video encoder, so frigate will use software encoding on this platform, but the image will still allow hardware decoding and tensorrt object detection.
|
||||
|
||||
You will need to use the image with the nvidia container runtime:
|
||||
|
||||
|
||||
@@ -15,7 +15,7 @@ The jsmpeg live view will use more browser and client GPU resources. Using go2rt
|
||||
| ------ | ------------------------------------- | ---------- | ---------------------------- | --------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| jsmpeg | same as `detect -> fps`, capped at 10 | 720p | no | no | Resolution is configurable, but go2rtc is recommended if you want higher resolutions and better frame rates. jsmpeg is Frigate's default without go2rtc configured. |
|
||||
| mse | native | native | yes (depends on audio codec) | yes | iPhone requires iOS 17.1+, Firefox is h.264 only. This is Frigate's default when go2rtc is configured. |
|
||||
| webrtc | native | native | yes (depends on audio codec) | yes | Requires extra configuration. Frigate attempts to use WebRTC when MSE fails or when using a camera's two-way talk feature. |
|
||||
| webrtc | native | native | yes (depends on audio codec) | yes | Requires extra configuration, doesn't support h.265. Frigate attempts to use WebRTC when MSE fails or when using a camera's two-way talk feature. |
|
||||
|
||||
### Camera Settings Recommendations
|
||||
|
||||
@@ -127,8 +127,7 @@ WebRTC works by creating a TCP or UDP connection on port `8555`. However, it req
|
||||
```
|
||||
|
||||
- For access through Tailscale, the Frigate system's Tailscale IP must be added as a WebRTC candidate. Tailscale IPs all start with `100.`, and are reserved within the `100.64.0.0/10` CIDR block.
|
||||
|
||||
- Note that some browsers may not support H.265 (HEVC). You can check your browser's current version for H.265 compatibility [here](https://github.com/AlexxIT/go2rtc?tab=readme-ov-file#codecs-madness).
|
||||
- Note that WebRTC does not support H.265.
|
||||
|
||||
:::tip
|
||||
|
||||
|
||||
@@ -157,7 +157,7 @@ A TensorFlow Lite model is provided in the container at `/edgetpu_model.tflite`
|
||||
|
||||
#### YOLOv9
|
||||
|
||||
YOLOv9 models that are compiled for TensorFlow Lite and properly quantized are supported, but not included by default. [Download the model](https://github.com/dbro/frigate-detector-edgetpu-yolo9/releases/download/v1.0/yolov9-s-relu6-best_320_int8_edgetpu.tflite), bind mount the file into the container, and provide the path with `model.path`. Note that the linked model requires a 17-label [labelmap file](https://raw.githubusercontent.com/dbro/frigate-detector-edgetpu-yolo9/refs/heads/main/labels-coco17.txt) that includes only 17 COCO classes.
|
||||
[YOLOv9](https://github.com/dbro/frigate-detector-edgetpu-yolo9/releases/download/v1.0/yolov9-s-relu6-best_320_int8_edgetpu.tflite) models that are compiled for Tensorflow Lite and properly quantized are supported, but not included by default. To provide your own model, bind mount the file into the container and provide the path with `model.path`. Note that the model may require a custom label file (eg. [use this 17 label file](https://raw.githubusercontent.com/dbro/frigate-detector-edgetpu-yolo9/refs/heads/main/labels-coco17.txt) for the model linked above.)
|
||||
|
||||
<details>
|
||||
<summary>YOLOv9 Setup & Config</summary>
|
||||
@@ -178,7 +178,7 @@ model:
|
||||
labelmap_path: /config/labels-coco17.txt
|
||||
```
|
||||
|
||||
Note that due to hardware limitations of the Coral, the labelmap is a subset of the COCO labels and includes only 17 object classes.
|
||||
Note that the labelmap uses a subset of the complete COCO label set that has only 17 objects.
|
||||
|
||||
</details>
|
||||
|
||||
@@ -477,7 +477,7 @@ After placing the downloaded onnx model in your config/model_cache folder, you c
|
||||
detectors:
|
||||
ov:
|
||||
type: openvino
|
||||
device: CPU
|
||||
device: GPU
|
||||
|
||||
model:
|
||||
model_type: dfine
|
||||
@@ -569,10 +569,10 @@ When using Docker Compose:
|
||||
```yaml
|
||||
services:
|
||||
frigate:
|
||||
...
|
||||
devices:
|
||||
- /dev/dri
|
||||
- /dev/kfd
|
||||
---
|
||||
devices:
|
||||
- /dev/dri
|
||||
- /dev/kfd
|
||||
```
|
||||
|
||||
For reference on recommended settings see [running ROCm/pytorch in Docker](https://rocm.docs.amd.com/projects/install-on-linux/en/develop/how-to/3rd-party/pytorch-install.html#using-docker-with-pytorch-pre-installed).
|
||||
@@ -600,9 +600,9 @@ When using Docker Compose:
|
||||
```yaml
|
||||
services:
|
||||
frigate:
|
||||
...
|
||||
environment:
|
||||
HSA_OVERRIDE_GFX_VERSION: "10.0.0"
|
||||
|
||||
environment:
|
||||
HSA_OVERRIDE_GFX_VERSION: "10.0.0"
|
||||
```
|
||||
|
||||
Figuring out what version you need can be complicated as you can't tell the chipset name and driver from the AMD brand name.
|
||||
@@ -1508,17 +1508,17 @@ COPY --from=build /dfine/output/dfine_${MODEL_SIZE}_obj2coco.onnx /dfine-${MODEL
|
||||
EOF
|
||||
```
|
||||
|
||||
### Downloading RF-DETR Model
|
||||
### Download RF-DETR Model
|
||||
|
||||
RF-DETR can be exported as ONNX by running the command below. You can copy and paste the whole thing to your terminal and execute, altering `MODEL_SIZE=Nano` in the first line to `Nano`, `Small`, or `Medium` size.
|
||||
|
||||
```sh
|
||||
docker build . --build-arg MODEL_SIZE=Nano --rm --output . -f- <<'EOF'
|
||||
docker build . --build-arg MODEL_SIZE=Nano --output . -f- <<'EOF'
|
||||
FROM python:3.11 AS build
|
||||
RUN apt-get update && apt-get install --no-install-recommends -y libgl1 && rm -rf /var/lib/apt/lists/*
|
||||
COPY --from=ghcr.io/astral-sh/uv:0.8.0 /uv /bin/
|
||||
WORKDIR /rfdetr
|
||||
RUN uv pip install --system rfdetr[onnxexport] torch==2.8.0 onnx==1.19.1 onnxscript
|
||||
RUN uv pip install --system rfdetr[onnxexport] torch==2.8.0 onnxscript
|
||||
ARG MODEL_SIZE
|
||||
RUN python3 -c "from rfdetr import RFDETR${MODEL_SIZE}; x = RFDETR${MODEL_SIZE}(resolution=320); x.export(simplify=True)"
|
||||
FROM scratch
|
||||
|
||||
@@ -11,7 +11,7 @@ This adds features including the ability to deep link directly into the app.
|
||||
|
||||
In order to install Frigate as a PWA, the following requirements must be met:
|
||||
|
||||
- Frigate must be accessed via a secure context (localhost, secure https, VPN, etc.)
|
||||
- Frigate must be accessed via a secure context (localhost, secure https, etc.)
|
||||
- On Android, Firefox, Chrome, Edge, Opera, and Samsung Internet Browser all support installing PWAs.
|
||||
- On iOS 16.4 and later, PWAs can be installed from the Share menu in Safari, Chrome, Edge, Firefox, and Orion.
|
||||
|
||||
@@ -22,7 +22,3 @@ Installation varies slightly based on the device that is being used:
|
||||
- Desktop: Use the install button typically found in right edge of the address bar
|
||||
- Android: Use the `Install as App` button in the more options menu for Chrome, and the `Add app to Home screen` button for Firefox
|
||||
- iOS: Use the `Add to Homescreen` button in the share menu
|
||||
|
||||
## Usage
|
||||
|
||||
Once setup, the Frigate app can be used wherever it has access to Frigate. This means it can be setup as local-only, VPN-only, or fully accessible depending on your needs.
|
||||
|
||||
@@ -20,7 +20,7 @@ Here are some of the cameras I recommend:
|
||||
- <a href="https://amzn.to/4fwoNWA" target="_blank" rel="nofollow noopener sponsored">Loryta(Dahua) IPC-T549M-ALED-S3</a> (affiliate link)
|
||||
- <a href="https://amzn.to/3YXpcMw" target="_blank" rel="nofollow noopener sponsored">Loryta(Dahua) IPC-T54IR-AS</a> (affiliate link)
|
||||
- <a href="https://amzn.to/3AvBHoY" target="_blank" rel="nofollow noopener sponsored">Amcrest IP5M-T1179EW-AI-V3</a> (affiliate link)
|
||||
- <a href="https://www.bhphotovideo.com/c/product/1705511-REG/hikvision_colorvu_ds_2cd2387g2p_lsu_sl_8mp_network.html" target="_blank" rel="nofollow noopener">HIKVISION DS-2CD2387G2P-LSU/SL ColorVu 8MP Panoramic Turret IP Camera</a> (affiliate link)
|
||||
- <a href="https://amzn.to/4ltOpaC" target="_blank" rel="nofollow noopener sponsored">HIKVISION DS-2CD2387G2P-LSU/SL ColorVu 8MP Panoramic Turret IP Camera</a> (affiliate link)
|
||||
|
||||
I may earn a small commission for my endorsement, recommendation, testimonial, or link to any products or services from this website.
|
||||
|
||||
@@ -38,11 +38,9 @@ If the EQ13 is out of stock, the link below may take you to a suggested alternat
|
||||
|
||||
:::
|
||||
|
||||
| Name | Capabilities | Notes |
|
||||
| ------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------- | --------------------------------------------------- |
|
||||
| Beelink EQ13 (<a href="https://amzn.to/4jn2qVr" target="_blank" rel="nofollow noopener sponsored">Amazon</a>) | Can run object detection on several 1080p cameras with low-medium activity | Dual gigabit NICs for easy isolated camera network. |
|
||||
| Intel 1120p ([Amazon](https://www.amazon.com/Beelink-i3-1220P-Computer-Display-Gigabit/dp/B0DDCKT9YP) | Can handle a large number of 1080p cameras with high activity | |
|
||||
| Intel 125H ([Amazon](https://www.amazon.com/MINISFORUM-Pro-125H-Barebone-Computer-HDMI2-1/dp/B0FH21FSZM) | Can handle a significant number of 1080p cameras with high activity | Includes NPU for more efficient detection in 0.17+ |
|
||||
| Name | Coral Inference Speed | Coral Compatibility | Notes |
|
||||
| ------------------------------------------------------------------------------------------------------------- | --------------------- | ------------------- | ----------------------------------------------------------------------------------------- |
|
||||
| Beelink EQ13 (<a href="https://amzn.to/4jn2qVr" target="_blank" rel="nofollow noopener sponsored">Amazon</a>) | 5-10ms | USB | Dual gigabit NICs for easy isolated camera network. Easily handles several 1080p cameras. |
|
||||
|
||||
## Detectors
|
||||
|
||||
@@ -127,16 +125,10 @@ In real-world deployments, even with multiple cameras running concurrently, Frig
|
||||
|
||||
### Google Coral TPU
|
||||
|
||||
:::warning
|
||||
|
||||
The Coral is no longer recommended for new Frigate installations, except in deployments with particularly low power requirements or hardware incapable of utilizing alternative AI accelerators for object detection. Instead, we suggest using one of the numerous other supported object detectors. Frigate will continue to provide support for the Coral TPU for as long as practicably possible given its still one of the most power-efficient devices for executing object detection models.
|
||||
|
||||
:::
|
||||
|
||||
Frigate supports both the USB and M.2 versions of the Google Coral.
|
||||
|
||||
- The USB version is compatible with the widest variety of hardware and does not require a driver on the host machine. However, it does lack the automatic throttling features of the other versions.
|
||||
- The PCIe and M.2 versions require installation of a driver on the host. https://github.com/jnicolson/gasket-builder should be used.
|
||||
- The PCIe and M.2 versions require installation of a driver on the host. Follow the instructions for your version from https://coral.ai
|
||||
|
||||
A single Coral can handle many cameras using the default model and will be sufficient for the majority of users. You can calculate the maximum performance of your Coral based on the inference speed reported by Frigate. With an inference speed of 10, your Coral will top out at `1000/10=100`, or 100 frames per second. If your detection fps is regularly getting close to that, you should first consider tuning motion masks. If those are already properly configured, a second Coral may be needed.
|
||||
|
||||
|
||||
@@ -94,10 +94,6 @@ $ python -c 'print("{:.2f}MB".format(((1280 * 720 * 1.5 * 20 + 270480) / 1048576
|
||||
|
||||
The shm size cannot be set per container for Home Assistant add-ons. However, this is probably not required since by default Home Assistant Supervisor allocates `/dev/shm` with half the size of your total memory. If your machine has 8GB of memory, chances are that Frigate will have access to up to 4GB without any additional configuration.
|
||||
|
||||
## Extra Steps for Specific Hardware
|
||||
|
||||
The following sections contain additional setup steps that are only required if you are using specific hardware. If you are not using any of these hardware types, you can skip to the [Docker](#docker) installation section.
|
||||
|
||||
### Raspberry Pi 3/4
|
||||
|
||||
By default, the Raspberry Pi limits the amount of memory available to the GPU. In order to use ffmpeg hardware acceleration, you must increase the available memory by setting `gpu_mem` to the maximum recommended value in `config.txt` as described in the [official docs](https://www.raspberrypi.org/documentation/computers/config_txt.html#memory-options).
|
||||
@@ -110,107 +106,14 @@ The Hailo-8 and Hailo-8L AI accelerators are available in both M.2 and HAT form
|
||||
|
||||
#### Installation
|
||||
|
||||
:::warning
|
||||
For Raspberry Pi 5 users with the AI Kit, installation is straightforward. Simply follow this [guide](https://www.raspberrypi.com/documentation/accessories/ai-kit.html#ai-kit-installation) to install the driver and software.
|
||||
|
||||
The Raspberry Pi kernel includes an older version of the Hailo driver that is incompatible with Frigate. You **must** follow the installation steps below to install the correct driver version, and you **must** disable the built-in kernel driver as described in step 1.
|
||||
For other installations, follow these steps for installation:
|
||||
|
||||
:::
|
||||
|
||||
1. **Disable the built-in Hailo driver (Raspberry Pi only)**:
|
||||
|
||||
:::note
|
||||
|
||||
If you are **not** using a Raspberry Pi, skip this step and proceed directly to step 2.
|
||||
|
||||
:::
|
||||
|
||||
If you are using a Raspberry Pi, you need to blacklist the built-in kernel Hailo driver to prevent conflicts. First, check if the driver is currently loaded:
|
||||
|
||||
```bash
|
||||
lsmod | grep hailo
|
||||
```
|
||||
|
||||
If it shows `hailo_pci`, unload it:
|
||||
|
||||
```bash
|
||||
sudo rmmod hailo_pci
|
||||
```
|
||||
|
||||
Now blacklist the driver to prevent it from loading on boot:
|
||||
|
||||
```bash
|
||||
echo "blacklist hailo_pci" | sudo tee /etc/modprobe.d/blacklist-hailo_pci.conf
|
||||
```
|
||||
|
||||
Update initramfs to ensure the blacklist takes effect:
|
||||
|
||||
```bash
|
||||
sudo update-initramfs -u
|
||||
```
|
||||
|
||||
Reboot your Raspberry Pi:
|
||||
|
||||
```bash
|
||||
sudo reboot
|
||||
```
|
||||
|
||||
After rebooting, verify the built-in driver is not loaded:
|
||||
|
||||
```bash
|
||||
lsmod | grep hailo
|
||||
```
|
||||
|
||||
This command should return no results. If it still shows `hailo_pci`, the blacklist did not take effect properly and you may need to check for other Hailo packages installed via apt that are loading the driver.
|
||||
|
||||
2. **Run the installation script**:
|
||||
|
||||
Download the installation script:
|
||||
|
||||
```bash
|
||||
wget https://raw.githubusercontent.com/blakeblackshear/frigate/dev/docker/hailo8l/user_installation.sh
|
||||
```
|
||||
|
||||
Make it executable:
|
||||
|
||||
```bash
|
||||
sudo chmod +x user_installation.sh
|
||||
```
|
||||
|
||||
Run the script:
|
||||
|
||||
```bash
|
||||
./user_installation.sh
|
||||
```
|
||||
|
||||
The script will:
|
||||
|
||||
- Install necessary build dependencies
|
||||
- Clone and build the Hailo driver from the official repository
|
||||
- Install the driver
|
||||
- Download and install the required firmware
|
||||
- Set up udev rules
|
||||
|
||||
3. **Reboot your system**:
|
||||
|
||||
After the script completes successfully, reboot to load the firmware:
|
||||
|
||||
```bash
|
||||
sudo reboot
|
||||
```
|
||||
|
||||
4. **Verify the installation**:
|
||||
|
||||
After rebooting, verify that the Hailo device is available:
|
||||
|
||||
```bash
|
||||
ls -l /dev/hailo0
|
||||
```
|
||||
|
||||
You should see the device listed. You can also verify the driver is loaded:
|
||||
|
||||
```bash
|
||||
lsmod | grep hailo_pci
|
||||
```
|
||||
1. Install the driver from the [Hailo GitHub repository](https://github.com/hailo-ai/hailort-drivers). A convenient script for Linux is available to clone the repository, build the driver, and install it.
|
||||
2. Copy or download [this script](https://github.com/blakeblackshear/frigate/blob/dev/docker/hailo8l/user_installation.sh).
|
||||
3. Ensure it has execution permissions with `sudo chmod +x user_installation.sh`
|
||||
4. Run the script with `./user_installation.sh`
|
||||
|
||||
#### Setup
|
||||
|
||||
@@ -399,7 +302,7 @@ services:
|
||||
shm_size: "512mb" # update for your cameras based on calculation above
|
||||
devices:
|
||||
- /dev/bus/usb:/dev/bus/usb # Passes the USB Coral, needs to be modified for other versions
|
||||
- /dev/apex_0:/dev/apex_0 # Passes a PCIe Coral, follow driver instructions here https://github.com/jnicolson/gasket-builder
|
||||
- /dev/apex_0:/dev/apex_0 # Passes a PCIe Coral, follow driver instructions here https://coral.ai/docs/m2/get-started/#2a-on-linux
|
||||
- /dev/video11:/dev/video11 # For Raspberry Pi 4B
|
||||
- /dev/dri/renderD128:/dev/dri/renderD128 # AMD / Intel GPU, needs to be updated for your hardware
|
||||
- /dev/accel:/dev/accel # Intel NPU
|
||||
|
||||
@@ -202,7 +202,7 @@ services:
|
||||
...
|
||||
devices:
|
||||
- /dev/bus/usb:/dev/bus/usb # passes the USB Coral, needs to be modified for other versions
|
||||
- /dev/apex_0:/dev/apex_0 # passes a PCIe Coral, follow driver instructions here https://github.com/jnicolson/gasket-builder
|
||||
- /dev/apex_0:/dev/apex_0 # passes a PCIe Coral, follow driver instructions here https://coral.ai/docs/m2/get-started/#2a-on-linux
|
||||
...
|
||||
```
|
||||
|
||||
|
||||
@@ -68,7 +68,8 @@ The USB Coral can become stuck and need to be restarted, this can happen for a n
|
||||
|
||||
The most common reason for the PCIe Coral not being detected is that the driver has not been installed. This process varies based on what OS and kernel that is being run.
|
||||
|
||||
- In most cases https://github.com/jnicolson/gasket-builder can be used to build and install the latest version of the driver.
|
||||
- In most cases [the Coral docs](https://coral.ai/docs/m2/get-started/#2-install-the-pcie-driver-and-edge-tpu-runtime) show how to install the driver for the PCIe based Coral.
|
||||
- For some newer Linux distros (for example, Ubuntu 22.04+), https://github.com/jnicolson/gasket-builder can be used to build and install the latest version of the driver.
|
||||
|
||||
## Attempting to load TPU as pci & Fatal Python error: Illegal instruction
|
||||
|
||||
|
||||
@@ -170,7 +170,7 @@ const config: Config = {
|
||||
],
|
||||
},
|
||||
],
|
||||
copyright: `Copyright © ${new Date().getFullYear()} Frigate LLC`,
|
||||
copyright: `Copyright © ${new Date().getFullYear()} Frigate, Inc.`,
|
||||
},
|
||||
},
|
||||
plugins: [
|
||||
|
||||
10
docs/static/img/branding/LICENSE.md
vendored
10
docs/static/img/branding/LICENSE.md
vendored
@@ -1,12 +1,12 @@
|
||||
# COPYRIGHT AND TRADEMARK NOTICE
|
||||
|
||||
The images, logos, and icons contained in this directory (the "Brand Assets") are
|
||||
proprietary to Frigate LLC and are NOT covered by the MIT License governing the
|
||||
proprietary to Frigate, Inc. and are NOT covered by the MIT License governing the
|
||||
rest of this repository.
|
||||
|
||||
1. TRADEMARK STATUS
|
||||
The "Frigate" name and the accompanying logo are common law trademarks™ of
|
||||
Frigate LLC. Frigate LLC reserves all rights to these marks.
|
||||
Frigate, Inc. Frigate, Inc. reserves all rights to these marks.
|
||||
|
||||
2. LIMITED PERMISSION FOR USE
|
||||
Permission is hereby granted to display these Brand Assets strictly for the
|
||||
@@ -17,9 +17,9 @@ rest of this repository.
|
||||
3. RESTRICTIONS
|
||||
You may NOT:
|
||||
a. Use these Brand Assets to represent a derivative work (fork) as an official
|
||||
product of Frigate LLC.
|
||||
product of Frigate, Inc.
|
||||
b. Use these Brand Assets in a way that implies endorsement, sponsorship, or
|
||||
commercial affiliation with Frigate LLC.
|
||||
commercial affiliation with Frigate, Inc.
|
||||
c. Modify or alter the Brand Assets.
|
||||
|
||||
If you fork this repository with the intent to distribute a modified or competing
|
||||
@@ -27,4 +27,4 @@ version of the software, you must replace these Brand Assets with your own
|
||||
original content.
|
||||
|
||||
ALL RIGHTS RESERVED.
|
||||
Copyright (c) 2025 Frigate LLC.
|
||||
Copyright (c) 2026 Frigate, Inc.
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
# COPYRIGHT AND TRADEMARK NOTICE
|
||||
|
||||
The images, logos, and icons contained in this directory (the "Brand Assets") are
|
||||
proprietary to Frigate LLC and are NOT covered by the MIT License governing the
|
||||
proprietary to Frigate, Inc. and are NOT covered by the MIT License governing the
|
||||
rest of this repository.
|
||||
|
||||
1. TRADEMARK STATUS
|
||||
The "Frigate" name and the accompanying logo are common law trademarks™ of
|
||||
Frigate LLC. Frigate LLC reserves all rights to these marks.
|
||||
Frigate, Inc. Frigate, Inc. reserves all rights to these marks.
|
||||
|
||||
2. LIMITED PERMISSION FOR USE
|
||||
Permission is hereby granted to display these Brand Assets strictly for the
|
||||
@@ -17,9 +17,9 @@ rest of this repository.
|
||||
3. RESTRICTIONS
|
||||
You may NOT:
|
||||
a. Use these Brand Assets to represent a derivative work (fork) as an official
|
||||
product of Frigate LLC.
|
||||
product of Frigate, Inc.
|
||||
b. Use these Brand Assets in a way that implies endorsement, sponsorship, or
|
||||
commercial affiliation with Frigate LLC.
|
||||
commercial affiliation with Frigate, Inc.
|
||||
c. Modify or alter the Brand Assets.
|
||||
|
||||
If you fork this repository with the intent to distribute a modified or competing
|
||||
@@ -30,4 +30,4 @@ For full usage guidelines, strictly see the TRADEMARK.md file in the
|
||||
repository root.
|
||||
|
||||
ALL RIGHTS RESERVED.
|
||||
Copyright (c) 2025 Frigate LLC.
|
||||
Copyright (c) 2026 Frigate, Inc.
|
||||
|
||||
@@ -9,11 +9,7 @@
|
||||
"empty": {
|
||||
"alert": "There are no alerts to review",
|
||||
"detection": "There are no detections to review",
|
||||
"motion": "No motion data found",
|
||||
"recordingsDisabled": {
|
||||
"title": "Recordings must be enabled",
|
||||
"description": "Review items can only be created for a camera when recordings are enabled for that camera."
|
||||
}
|
||||
"motion": "No motion data found"
|
||||
},
|
||||
"timeline": "Timeline",
|
||||
"timeline.aria": "Select timeline",
|
||||
|
||||
@@ -166,9 +166,6 @@
|
||||
"tips": {
|
||||
"descriptionSaved": "Successfully saved description",
|
||||
"saveDescriptionFailed": "Failed to update the description: {{errorMessage}}"
|
||||
},
|
||||
"title": {
|
||||
"label": "Title"
|
||||
}
|
||||
},
|
||||
"itemMenu": {
|
||||
|
||||
@@ -2,18 +2,15 @@ import React from "react";
|
||||
import { Button } from "../ui/button";
|
||||
import Heading from "../ui/heading";
|
||||
import { Link } from "react-router-dom";
|
||||
import { cn } from "@/lib/utils";
|
||||
|
||||
type EmptyCardProps = {
|
||||
className?: string;
|
||||
icon: React.ReactNode;
|
||||
title: string;
|
||||
description?: string;
|
||||
description: string;
|
||||
buttonText?: string;
|
||||
link?: string;
|
||||
};
|
||||
export function EmptyCard({
|
||||
className,
|
||||
icon,
|
||||
title,
|
||||
description,
|
||||
@@ -21,12 +18,10 @@ export function EmptyCard({
|
||||
link,
|
||||
}: EmptyCardProps) {
|
||||
return (
|
||||
<div className={cn("flex flex-col items-center gap-2", className)}>
|
||||
<div className="flex flex-col items-center gap-2">
|
||||
{icon}
|
||||
<Heading as="h4">{title}</Heading>
|
||||
{description && (
|
||||
<div className="mb-3 text-secondary-foreground">{description}</div>
|
||||
)}
|
||||
<div className="mb-3 text-secondary-foreground">{description}</div>
|
||||
{buttonText?.length && (
|
||||
<Button size="sm" variant="select">
|
||||
<Link to={link ?? "#"}>{buttonText}</Link>
|
||||
|
||||
@@ -39,7 +39,6 @@ import { Trans, useTranslation } from "react-i18next";
|
||||
import { cn } from "@/lib/utils";
|
||||
import { LuCircle } from "react-icons/lu";
|
||||
import { MdAutoAwesome } from "react-icons/md";
|
||||
import { GenAISummaryDialog } from "../overlay/chip/GenAISummaryChip";
|
||||
|
||||
type ReviewCardProps = {
|
||||
event: ReviewSegment;
|
||||
@@ -220,14 +219,12 @@ export default function ReviewCard({
|
||||
/>
|
||||
</div>
|
||||
{event.data.metadata?.title && (
|
||||
<GenAISummaryDialog review={event}>
|
||||
<div className="flex items-center gap-1.5 rounded bg-secondary/50 hover:underline">
|
||||
<MdAutoAwesome className="size-3 shrink-0 text-primary" />
|
||||
<span className="truncate text-xs text-primary">
|
||||
{event.data.metadata.title}
|
||||
</span>
|
||||
</div>
|
||||
</GenAISummaryDialog>
|
||||
<div className="flex items-center gap-1.5 rounded bg-secondary/50">
|
||||
<MdAutoAwesome className="size-3 shrink-0 text-primary" />
|
||||
<span className="truncate text-xs text-primary">
|
||||
{event.data.metadata.title}
|
||||
</span>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -195,7 +195,7 @@ export default function SearchResultActions({
|
||||
</ContextMenu>
|
||||
) : (
|
||||
<>
|
||||
<DropdownMenu modal={false}>
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<BlurredIconButton aria-label={t("itemMenu.more.aria")}>
|
||||
<FiMoreVertical className="size-5" />
|
||||
|
||||
@@ -6,15 +6,16 @@ import {
|
||||
ThreatLevel,
|
||||
THREAT_LEVEL_LABELS,
|
||||
} from "@/types/review";
|
||||
import React, { useEffect, useMemo, useState } from "react";
|
||||
import { useEffect, useMemo, useState } from "react";
|
||||
import { isDesktop } from "react-device-detect";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { MdAutoAwesome } from "react-icons/md";
|
||||
|
||||
type GenAISummaryChipProps = {
|
||||
review?: ReviewSegment;
|
||||
onClick: () => void;
|
||||
};
|
||||
export function GenAISummaryChip({ review }: GenAISummaryChipProps) {
|
||||
export function GenAISummaryChip({ review, onClick }: GenAISummaryChipProps) {
|
||||
const [isVisible, setIsVisible] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
@@ -28,6 +29,7 @@ export function GenAISummaryChip({ review }: GenAISummaryChipProps) {
|
||||
isVisible ? "translate-y-0 opacity-100" : "-translate-y-4 opacity-0",
|
||||
isDesktop ? "bg-card" : "bg-secondary-foreground",
|
||||
)}
|
||||
onClick={onClick}
|
||||
>
|
||||
<MdAutoAwesome className="shrink-0" />
|
||||
<span className="truncate">{review?.data.metadata?.title}</span>
|
||||
@@ -38,12 +40,10 @@ export function GenAISummaryChip({ review }: GenAISummaryChipProps) {
|
||||
type GenAISummaryDialogProps = {
|
||||
review?: ReviewSegment;
|
||||
onOpen?: (open: boolean) => void;
|
||||
children: React.ReactNode;
|
||||
};
|
||||
export function GenAISummaryDialog({
|
||||
review,
|
||||
onOpen,
|
||||
children,
|
||||
}: GenAISummaryDialogProps) {
|
||||
const { t } = useTranslation(["views/explore"]);
|
||||
|
||||
@@ -104,7 +104,7 @@ export function GenAISummaryDialog({
|
||||
return (
|
||||
<Overlay open={open} onOpenChange={setOpen}>
|
||||
<Trigger asChild>
|
||||
<div>{children}</div>
|
||||
<GenAISummaryChip review={review} onClick={() => setOpen(true)} />
|
||||
</Trigger>
|
||||
<Content
|
||||
className={cn(
|
||||
@@ -115,10 +115,6 @@ export function GenAISummaryDialog({
|
||||
)}
|
||||
>
|
||||
{t("aiAnalysis.title")}
|
||||
<div className="text-sm text-primary/40">
|
||||
{t("details.title.label")}
|
||||
</div>
|
||||
<div className="text-sm">{aiAnalysis.title}</div>
|
||||
<div className="text-sm text-primary/40">
|
||||
{t("details.description.label")}
|
||||
</div>
|
||||
|
||||
@@ -25,13 +25,10 @@ import { Tooltip, TooltipContent, TooltipTrigger } from "../ui/tooltip";
|
||||
import { Link } from "react-router-dom";
|
||||
import { Switch } from "@/components/ui/switch";
|
||||
import { useUserPersistence } from "@/hooks/use-user-persistence";
|
||||
import { isDesktop, isIOS, isMobile } from "react-device-detect";
|
||||
import { isDesktop } from "react-device-detect";
|
||||
import { resolveZoneName } from "@/hooks/use-zone-friendly-name";
|
||||
import { PiSlidersHorizontalBold } from "react-icons/pi";
|
||||
import { MdAutoAwesome } from "react-icons/md";
|
||||
import { isPWA } from "@/utils/isPWA";
|
||||
import { isInIframe } from "@/utils/isIFrame";
|
||||
import { GenAISummaryDialog } from "../overlay/chip/GenAISummaryChip";
|
||||
|
||||
type DetailStreamProps = {
|
||||
reviewItems?: ReviewSegment[];
|
||||
@@ -103,25 +100,7 @@ export default function DetailStream({
|
||||
}
|
||||
}, [reviewItems, activeReviewId, effectiveTime]);
|
||||
|
||||
// Initial scroll to active review (runs immediately when user selects, not during playback)
|
||||
useEffect(() => {
|
||||
if (!scrollRef.current || !activeReviewId || userInteracting || isPlaying)
|
||||
return;
|
||||
|
||||
const element = scrollRef.current.querySelector(
|
||||
`[data-review-id="${activeReviewId}"]`,
|
||||
) as HTMLElement;
|
||||
|
||||
if (element) {
|
||||
setProgrammaticScroll();
|
||||
scrollIntoView(element, {
|
||||
scrollMode: "if-needed",
|
||||
behavior: isMobile && isIOS && !isPWA && isInIframe ? "auto" : "smooth",
|
||||
});
|
||||
}
|
||||
}, [activeReviewId, setProgrammaticScroll, userInteracting, isPlaying]);
|
||||
|
||||
// Auto-scroll to current time during playback
|
||||
// Auto-scroll to current time
|
||||
useEffect(() => {
|
||||
if (!scrollRef.current || userInteracting || !isPlaying) return;
|
||||
// Prefer the review whose range contains the effectiveTime. If none
|
||||
@@ -166,8 +145,7 @@ export default function DetailStream({
|
||||
setProgrammaticScroll();
|
||||
scrollIntoView(element, {
|
||||
scrollMode: "if-needed",
|
||||
behavior:
|
||||
isMobile && isIOS && !isPWA && isInIframe ? "auto" : "smooth",
|
||||
behavior: "smooth",
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -439,18 +417,7 @@ function ReviewGroup({
|
||||
{review.data.metadata.title}
|
||||
</TooltipContent>
|
||||
</Tooltip>
|
||||
<GenAISummaryDialog
|
||||
review={review}
|
||||
onOpen={(open) => {
|
||||
if (open) {
|
||||
onSeek(review.start_time, false);
|
||||
}
|
||||
}}
|
||||
>
|
||||
<span className="truncate hover:underline">
|
||||
{review.data.metadata.title}
|
||||
</span>
|
||||
</GenAISummaryDialog>
|
||||
<span className="truncate">{review.data.metadata.title}</span>
|
||||
</div>
|
||||
)}
|
||||
<div className="flex flex-row items-center gap-1.5">
|
||||
@@ -815,27 +782,21 @@ function LifecycleItem({
|
||||
<div className="flex flex-col gap-1">
|
||||
<div className="flex items-start gap-1">
|
||||
<span className="text-muted-foreground">
|
||||
{t("trackingDetails.lifecycleItemDesc.header.score", {
|
||||
ns: "views/explore",
|
||||
})}
|
||||
{t("trackingDetails.lifecycleItemDesc.header.score")}
|
||||
</span>
|
||||
<span className="font-medium text-foreground">{score}</span>
|
||||
</div>
|
||||
|
||||
<div className="flex items-start gap-1">
|
||||
<span className="text-muted-foreground">
|
||||
{t("trackingDetails.lifecycleItemDesc.header.ratio", {
|
||||
ns: "views/explore",
|
||||
})}
|
||||
{t("trackingDetails.lifecycleItemDesc.header.ratio")}
|
||||
</span>
|
||||
<span className="font-medium text-foreground">{ratio}</span>
|
||||
</div>
|
||||
|
||||
<div className="flex items-start gap-1">
|
||||
<span className="text-muted-foreground">
|
||||
{t("trackingDetails.lifecycleItemDesc.header.area", {
|
||||
ns: "views/explore",
|
||||
})}{" "}
|
||||
{t("trackingDetails.lifecycleItemDesc.header.area")}{" "}
|
||||
{attributeAreaPx !== undefined &&
|
||||
attributeAreaPct !== undefined && (
|
||||
<span className="text-muted-foreground">
|
||||
@@ -845,7 +806,7 @@ function LifecycleItem({
|
||||
</span>
|
||||
{areaPx !== undefined && areaPct !== undefined ? (
|
||||
<span className="font-medium text-foreground">
|
||||
{areaPx} {t("information.pixels", { ns: "common" })}{" "}
|
||||
{areaPx} {t("pixels", { ns: "common" })}{" "}
|
||||
<span className="text-secondary-foreground">·</span>{" "}
|
||||
{areaPct}%
|
||||
</span>
|
||||
@@ -858,9 +819,7 @@ function LifecycleItem({
|
||||
attributeAreaPct !== undefined && (
|
||||
<div className="flex items-start gap-1">
|
||||
<span className="text-muted-foreground">
|
||||
{t("trackingDetails.lifecycleItemDesc.header.area", {
|
||||
ns: "views/explore",
|
||||
})}{" "}
|
||||
{t("trackingDetails.lifecycleItemDesc.header.area")}{" "}
|
||||
{attributeAreaPx !== undefined &&
|
||||
attributeAreaPct !== undefined && (
|
||||
<span className="text-muted-foreground">
|
||||
@@ -869,8 +828,7 @@ function LifecycleItem({
|
||||
)}
|
||||
</span>
|
||||
<span className="font-medium text-foreground">
|
||||
{attributeAreaPx}{" "}
|
||||
{t("information.pixels", { ns: "common" })}{" "}
|
||||
{attributeAreaPx} {t("pixels", { ns: "common" })}{" "}
|
||||
<span className="text-secondary-foreground">·</span>{" "}
|
||||
{attributeAreaPct}%
|
||||
</span>
|
||||
|
||||
@@ -111,7 +111,7 @@ export function MotionReviewTimeline({
|
||||
|
||||
const getRecordingAvailability = useCallback(
|
||||
(time: number): boolean | undefined => {
|
||||
if (noRecordingRanges == undefined) return undefined;
|
||||
if (!noRecordingRanges?.length) return undefined;
|
||||
|
||||
return !noRecordingRanges.some(
|
||||
(range) => time >= range.start_time && time < range.end_time,
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
export type EmptyCardData = {
|
||||
title: string;
|
||||
description?: string;
|
||||
};
|
||||
@@ -79,6 +79,9 @@ i18n
|
||||
parseMissingKeyHandler: (key: string) => {
|
||||
const parts = key.split(".");
|
||||
|
||||
// eslint-disable-next-line no-console
|
||||
console.warn(`Missing translation key: ${key}`);
|
||||
|
||||
if (parts[0] === "time" && parts[1]?.includes("formattedTimestamp")) {
|
||||
// Extract the format type from the last part (12hour, 24hour)
|
||||
const formatType = parts[parts.length - 1];
|
||||
|
||||
@@ -56,8 +56,6 @@ import { GiSoundWaves } from "react-icons/gi";
|
||||
import useKeyboardListener from "@/hooks/use-keyboard-listener";
|
||||
import { useTimelineZoom } from "@/hooks/use-timeline-zoom";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { EmptyCard } from "@/components/card/EmptyCard";
|
||||
import { EmptyCardData } from "@/types/card";
|
||||
|
||||
type EventViewProps = {
|
||||
reviewItems?: SegmentedReviewData;
|
||||
@@ -134,24 +132,6 @@ export default function EventView({
|
||||
}
|
||||
}, [filter, showReviewed, reviewSummary]);
|
||||
|
||||
const emptyCardData: EmptyCardData = useMemo(() => {
|
||||
if (
|
||||
!config ||
|
||||
Object.values(config.cameras).find(
|
||||
(cam) => cam.record.enabled_in_config,
|
||||
) != undefined
|
||||
) {
|
||||
return {
|
||||
title: t("empty." + severity.replace(/_/g, " ")),
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
title: t("empty.recordingsDisabled.title"),
|
||||
description: t("empty.recordingsDisabled.description"),
|
||||
};
|
||||
}, [config, severity, t]);
|
||||
|
||||
// review interaction
|
||||
|
||||
const [selectedReviews, setSelectedReviews] = useState<ReviewSegment[]>([]);
|
||||
@@ -432,7 +412,6 @@ export default function EventView({
|
||||
timeRange={timeRange}
|
||||
startTime={startTime}
|
||||
loading={severity != severityToggle}
|
||||
emptyCardData={emptyCardData}
|
||||
markItemAsReviewed={markItemAsReviewed}
|
||||
markAllItemsAsReviewed={markAllItemsAsReviewed}
|
||||
onSelectReview={onSelectReview}
|
||||
@@ -451,7 +430,6 @@ export default function EventView({
|
||||
startTime={startTime}
|
||||
filter={filter}
|
||||
motionOnly={motionOnly}
|
||||
emptyCardData={emptyCardData}
|
||||
onOpenRecording={onOpenRecording}
|
||||
/>
|
||||
)}
|
||||
@@ -477,7 +455,6 @@ type DetectionReviewProps = {
|
||||
timeRange: { before: number; after: number };
|
||||
startTime?: number;
|
||||
loading: boolean;
|
||||
emptyCardData: EmptyCardData;
|
||||
markItemAsReviewed: (review: ReviewSegment) => void;
|
||||
markAllItemsAsReviewed: (currentItems: ReviewSegment[]) => void;
|
||||
onSelectReview: (
|
||||
@@ -501,7 +478,6 @@ function DetectionReview({
|
||||
timeRange,
|
||||
startTime,
|
||||
loading,
|
||||
emptyCardData,
|
||||
markItemAsReviewed,
|
||||
markAllItemsAsReviewed,
|
||||
onSelectReview,
|
||||
@@ -761,12 +737,10 @@ function DetectionReview({
|
||||
)}
|
||||
|
||||
{!loading && currentItems?.length === 0 && (
|
||||
<EmptyCard
|
||||
className="y-translate-1/2 absolute left-[50%] top-[50%] -translate-x-1/2"
|
||||
title={emptyCardData.title}
|
||||
description={emptyCardData.description}
|
||||
icon={<LuFolderCheck className="size-16" />}
|
||||
/>
|
||||
<div className="absolute left-1/2 top-1/2 flex -translate-x-1/2 -translate-y-1/2 flex-col items-center justify-center text-center">
|
||||
<LuFolderCheck className="size-16" />
|
||||
{t("empty." + severity.replace(/_/g, " "))}
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div
|
||||
@@ -901,7 +875,6 @@ type MotionReviewProps = {
|
||||
startTime?: number;
|
||||
filter?: ReviewFilter;
|
||||
motionOnly?: boolean;
|
||||
emptyCardData: EmptyCardData;
|
||||
onOpenRecording: (data: RecordingStartingPoint) => void;
|
||||
};
|
||||
function MotionReview({
|
||||
@@ -912,9 +885,9 @@ function MotionReview({
|
||||
startTime,
|
||||
filter,
|
||||
motionOnly = false,
|
||||
emptyCardData,
|
||||
onOpenRecording,
|
||||
}: MotionReviewProps) {
|
||||
const { t } = useTranslation(["views/events"]);
|
||||
const segmentDuration = 30;
|
||||
const { data: config } = useSWR<FrigateConfig>("config");
|
||||
|
||||
@@ -1107,12 +1080,9 @@ function MotionReview({
|
||||
|
||||
if (motionData?.length === 0) {
|
||||
return (
|
||||
<div className="absolute left-1/2 top-1/2 -translate-x-1/2 -translate-y-1/2">
|
||||
<EmptyCard
|
||||
title={emptyCardData.title}
|
||||
description={emptyCardData.description}
|
||||
icon={<LuFolderX className="size-16" />}
|
||||
/>
|
||||
<div className="absolute left-1/2 top-1/2 flex -translate-x-1/2 -translate-y-1/2 flex-col items-center justify-center text-center">
|
||||
<LuFolderX className="size-16" />
|
||||
{t("empty.motion")}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -66,10 +66,7 @@ import {
|
||||
import { CameraNameLabel } from "@/components/camera/FriendlyNameLabel";
|
||||
import { useAllowedCameras } from "@/hooks/use-allowed-cameras";
|
||||
import { DetailStreamProvider } from "@/context/detail-stream-context";
|
||||
import {
|
||||
GenAISummaryDialog,
|
||||
GenAISummaryChip,
|
||||
} from "@/components/overlay/chip/GenAISummaryChip";
|
||||
import { GenAISummaryDialog } from "@/components/overlay/chip/GenAISummaryChip";
|
||||
|
||||
const DATA_REFRESH_TIME = 600000; // 10 minutes
|
||||
|
||||
@@ -312,18 +309,10 @@ export function RecordingView({
|
||||
currentTimeRange.after <= currentTime &&
|
||||
currentTimeRange.before >= currentTime
|
||||
) {
|
||||
if (mainControllerRef.current != undefined) {
|
||||
let shouldPlayback = true;
|
||||
|
||||
if (timelineType == "detail") {
|
||||
shouldPlayback = mainControllerRef.current.isPlaying();
|
||||
}
|
||||
|
||||
mainControllerRef.current.seekToTimestamp(
|
||||
currentTime,
|
||||
shouldPlayback,
|
||||
);
|
||||
}
|
||||
mainControllerRef.current?.seekToTimestamp(
|
||||
currentTime,
|
||||
mainControllerRef.current.isPlaying(),
|
||||
);
|
||||
} else {
|
||||
updateSelectedSegment(currentTime, true);
|
||||
}
|
||||
@@ -742,9 +731,7 @@ export function RecordingView({
|
||||
<GenAISummaryDialog
|
||||
review={activeReviewItem}
|
||||
onOpen={onAnalysisOpen}
|
||||
>
|
||||
<GenAISummaryChip review={activeReviewItem} />
|
||||
</GenAISummaryDialog>
|
||||
/>
|
||||
)}
|
||||
|
||||
<DynamicVideoPlayer
|
||||
@@ -1002,9 +989,7 @@ function Timeline({
|
||||
)}
|
||||
>
|
||||
{isMobile && timelineType == "timeline" && (
|
||||
<GenAISummaryDialog review={activeReviewItem} onOpen={onAnalysisOpen}>
|
||||
<GenAISummaryChip review={activeReviewItem} />
|
||||
</GenAISummaryDialog>
|
||||
<GenAISummaryDialog review={activeReviewItem} onOpen={onAnalysisOpen} />
|
||||
)}
|
||||
|
||||
{timelineType != "detail" && (
|
||||
|
||||
Reference in New Issue
Block a user