Compare commits

...

6 Commits

Author SHA1 Message Date
Marc Altmann
3947e79086 update FFmpeg to ensure compatibility with newer kernels (#16027) 2025-01-18 05:48:28 -07:00
Nicolas Mowen
91ab1071d2 Update docs to make note of go2rtc port requirement (#16013) 2025-01-16 16:14:40 -07:00
Nicolas Mowen
409e911752 Update integration docs (#15967) 2025-01-13 08:50:44 -06:00
tpjanssen
9983bd8d92 Fix API latest image quality and API MIME types (#15964)
* Fix API latest image quality

* Fix mime types

* Code formatting + media_type fix
2025-01-13 07:46:46 -06:00
Nicolas Mowen
32c71c4108 Clean up handling of ffmpeg specific params (#15956) 2025-01-12 17:47:24 -06:00
Josh Hawkins
ef6952e3ea Fix display of save button in tracked object details pane (#15946) 2025-01-11 15:23:52 -06:00
6 changed files with 62 additions and 42 deletions

View File

@@ -22,6 +22,6 @@ ADD https://github.com/MarcA711/rknn-toolkit2/releases/download/v2.0.0/librknnrt
RUN rm -rf /usr/lib/btbn-ffmpeg/bin/ffmpeg RUN rm -rf /usr/lib/btbn-ffmpeg/bin/ffmpeg
RUN rm -rf /usr/lib/btbn-ffmpeg/bin/ffprobe RUN rm -rf /usr/lib/btbn-ffmpeg/bin/ffprobe
ADD --chmod=111 https://github.com/MarcA711/Rockchip-FFmpeg-Builds/releases/download/6.1-5/ffmpeg /usr/lib/ffmpeg/6.0/bin/ ADD --chmod=111 https://github.com/MarcA711/Rockchip-FFmpeg-Builds/releases/download/6.1-7/ffmpeg /usr/lib/ffmpeg/6.0/bin/
ADD --chmod=111 https://github.com/MarcA711/Rockchip-FFmpeg-Builds/releases/download/6.1-5/ffprobe /usr/lib/ffmpeg/6.0/bin/ ADD --chmod=111 https://github.com/MarcA711/Rockchip-FFmpeg-Builds/releases/download/6.1-7/ffprobe /usr/lib/ffmpeg/6.0/bin/
ENV PATH="/usr/lib/ffmpeg/6.0/bin/:${PATH}" ENV PATH="/usr/lib/ffmpeg/6.0/bin/:${PATH}"

View File

@@ -548,6 +548,8 @@ genai:
# Optional: Restream configuration # Optional: Restream configuration
# Uses https://github.com/AlexxIT/go2rtc (v1.9.2) # Uses https://github.com/AlexxIT/go2rtc (v1.9.2)
# NOTE: The default go2rtc API port (1984) must be used,
# changing this port for the integrated go2rtc instance is not supported.
go2rtc: go2rtc:
# Optional: Live stream configuration for WebUI. # Optional: Live stream configuration for WebUI.

View File

@@ -47,7 +47,7 @@ that card.
## Configuration ## Configuration
When configuring the integration, you will be asked for the `URL` of your Frigate instance which needs to be pointed at the internal unauthenticated port (`5000`) for your instance. This may look like `http://<host>:5000/`. When configuring the integration, you will be asked for the `URL` of your Frigate instance which can be pointed at the internal unauthenticated port (`5000`) or the authenticated port (`8971`) for your instance. This may look like `http://<host>:5000/`.
### Docker Compose Examples ### Docker Compose Examples
@@ -55,7 +55,7 @@ If you are running Home Assistant Core and Frigate with Docker Compose on the sa
#### Home Assistant running with host networking #### Home Assistant running with host networking
It is not recommended to run Frigate in host networking mode. In this example, you would use `http://172.17.0.1:5000` when configuring the integration. It is not recommended to run Frigate in host networking mode. In this example, you would use `http://172.17.0.1:5000` or `http://172.17.0.1:8971` when configuring the integration.
```yaml ```yaml
services: services:
@@ -75,7 +75,7 @@ services:
#### Home Assistant _not_ running with host networking or in a separate compose file #### Home Assistant _not_ running with host networking or in a separate compose file
In this example, you would use `http://frigate:5000` when configuring the integration. There is no need to map the port for the Frigate container. In this example, it is recommended to connect to the authenticated port, for example, `http://frigate:8971` when configuring the integration. There is no need to map the port for the Frigate container.
```yaml ```yaml
services: services:
@@ -103,14 +103,15 @@ If you are using HassOS with the addon, the URL should be one of the following d
| Frigate NVR (Full Access) | `http://ccab4aaf-frigate-fa:5000` | | Frigate NVR (Full Access) | `http://ccab4aaf-frigate-fa:5000` |
| Frigate NVR Beta | `http://ccab4aaf-frigate-beta:5000` | | Frigate NVR Beta | `http://ccab4aaf-frigate-beta:5000` |
| Frigate NVR Beta (Full Access) | `http://ccab4aaf-frigate-fa-beta:5000` | | Frigate NVR Beta (Full Access) | `http://ccab4aaf-frigate-fa-beta:5000` |
| Frigate NVR HailoRT Beta | `http://ccab4aaf-frigate-hailo-beta:5000` |
### Frigate running on a separate machine ### Frigate running on a separate machine
If you run Frigate on a separate device within your local network, Home Assistant will need access to port 5000. If you run Frigate on a separate device within your local network, Home Assistant will need access to port 8971.
#### Local network #### Local network
Use `http://<frigate_device_ip>:5000` as the URL for the integration. If you want to protect access to port 5000, you can use firewall rules to limit access to the device running Home Assistant. Use `http://<frigate_device_ip>:8971` as the URL for the integration so that authentication is required.
```yaml ```yaml
services: services:
@@ -118,7 +119,7 @@ services:
image: ghcr.io/blakeblackshear/frigate:stable image: ghcr.io/blakeblackshear/frigate:stable
... ...
ports: ports:
- "5000:5000" - "8971:8971"
... ...
``` ```
@@ -195,12 +196,30 @@ To load a snapshot for a tracked object:
https://HA_URL/api/frigate/notifications/<event-id>/snapshot.jpg https://HA_URL/api/frigate/notifications/<event-id>/snapshot.jpg
``` ```
To load a video clip of a tracked object: To load a video clip of a tracked object using an Android device:
``` ```
https://HA_URL/api/frigate/notifications/<event-id>/clip.mp4 https://HA_URL/api/frigate/notifications/<event-id>/clip.mp4
``` ```
To load a video clip of a tracked object using an iOS device:
```
https://HA_URL/api/frigate/notifications/<event-id>/master.m3u8
```
To load a preview gif of a tracked object:
```
https://HA_URL/api/frigate/notifications/<event-id>/event_preview.gif
```
To load a preview gif of a review item:
```
https://HA_URL/api/frigate/notifications/<review-id>/review_preview.gif
```
<a name="streams"></a> <a name="streams"></a>
## RTSP stream ## RTSP stream

View File

@@ -133,6 +133,15 @@ def latest_frame(
"regions": params.regions, "regions": params.regions,
} }
quality = params.quality quality = params.quality
mime_type = extension
if extension == "png":
quality_params = None
elif extension == "webp":
quality_params = [int(cv2.IMWRITE_WEBP_QUALITY), quality]
else:
quality_params = [int(cv2.IMWRITE_JPEG_QUALITY), quality]
mime_type = "jpeg"
if camera_name in request.app.frigate_config.cameras: if camera_name in request.app.frigate_config.cameras:
frame = frame_processor.get_current_frame(camera_name, draw_options) frame = frame_processor.get_current_frame(camera_name, draw_options)
@@ -173,13 +182,11 @@ def latest_frame(
frame = cv2.resize(frame, dsize=(width, height), interpolation=cv2.INTER_AREA) frame = cv2.resize(frame, dsize=(width, height), interpolation=cv2.INTER_AREA)
ret, img = cv2.imencode( ret, img = cv2.imencode(f".{extension}", frame, quality_params)
f".{extension}", frame, [int(cv2.IMWRITE_WEBP_QUALITY), quality]
)
return Response( return Response(
content=img.tobytes(), content=img.tobytes(),
media_type=f"image/{extension}", media_type=f"image/{mime_type}",
headers={"Content-Type": f"image/{extension}", "Cache-Control": "no-store"}, headers={"Content-Type": f"image/{mime_type}", "Cache-Control": "no-store"},
) )
elif camera_name == "birdseye" and request.app.frigate_config.birdseye.restream: elif camera_name == "birdseye" and request.app.frigate_config.birdseye.restream:
frame = cv2.cvtColor( frame = cv2.cvtColor(
@@ -192,13 +199,11 @@ def latest_frame(
frame = cv2.resize(frame, dsize=(width, height), interpolation=cv2.INTER_AREA) frame = cv2.resize(frame, dsize=(width, height), interpolation=cv2.INTER_AREA)
ret, img = cv2.imencode( ret, img = cv2.imencode(f".{extension}", frame, quality_params)
f".{extension}", frame, [int(cv2.IMWRITE_WEBP_QUALITY), quality]
)
return Response( return Response(
content=img.tobytes(), content=img.tobytes(),
media_type=f"image/{extension}", media_type=f"image/{mime_type}",
headers={"Content-Type": f"image/{extension}", "Cache-Control": "no-store"}, headers={"Content-Type": f"image/{mime_type}", "Cache-Control": "no-store"},
) )
else: else:
return JSONResponse( return JSONResponse(
@@ -241,6 +246,7 @@ def get_snapshot_from_recording(
recording: Recordings = recording_query.get() recording: Recordings = recording_query.get()
time_in_segment = frame_time - recording.start_time time_in_segment = frame_time - recording.start_time
codec = "png" if format == "png" else "mjpeg" codec = "png" if format == "png" else "mjpeg"
mime_type = "png" if format == "png" else "jpeg"
config: FrigateConfig = request.app.frigate_config config: FrigateConfig = request.app.frigate_config
image_data = get_image_from_recording( image_data = get_image_from_recording(
@@ -257,7 +263,7 @@ def get_snapshot_from_recording(
), ),
status_code=404, status_code=404,
) )
return Response(image_data, headers={"Content-Type": f"image/{format}"}) return Response(image_data, headers={"Content-Type": f"image/{mime_type}"})
except DoesNotExist: except DoesNotExist:
return JSONResponse( return JSONResponse(
content={ content={

View File

@@ -50,16 +50,9 @@ class LibvaGpuSelector:
return "" return ""
FPS_VFR_PARAM = ( LIBAV_VERSION = int(os.getenv("LIBAVFORMAT_VERSION_MAJOR", "59") or "59")
"-fps_mode vfr" FPS_VFR_PARAM = "-fps_mode vfr" if LIBAV_VERSION >= 59 else "-vsync 2"
if int(os.getenv("LIBAVFORMAT_VERSION_MAJOR", "59") or "59") >= 59 TIMEOUT_PARAM = "-timeout" if LIBAV_VERSION >= 59 else "-stimeout"
else "-vsync 2"
)
TIMEOUT_PARAM = (
"-timeout"
if int(os.getenv("LIBAVFORMAT_VERSION_MAJOR", "59") or "59") >= 59
else "-stimeout"
)
_gpu_selector = LibvaGpuSelector() _gpu_selector = LibvaGpuSelector()
_user_agent_args = [ _user_agent_args = [
@@ -71,8 +64,8 @@ PRESETS_HW_ACCEL_DECODE = {
"preset-rpi-64-h264": "-c:v:1 h264_v4l2m2m", "preset-rpi-64-h264": "-c:v:1 h264_v4l2m2m",
"preset-rpi-64-h265": "-c:v:1 hevc_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", 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 -bsf:v dump_extra", # https://trac.ffmpeg.org/ticket/9766#comment:17 "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' if LIBAV_VERSION >= 61 else ''}", # 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 "preset-intel-qsv-h265": f"-load_plugin hevc_hw -hwaccel qsv -qsv_device {_gpu_selector.get_selected_gpu()} -hwaccel_output_format qsv{' -bsf:v dump_extra' if LIBAV_VERSION >= 61 else ''}", # https://trac.ffmpeg.org/ticket/9766#comment:17
FFMPEG_HWACCEL_NVIDIA: "-hwaccel cuda -hwaccel_output_format cuda", FFMPEG_HWACCEL_NVIDIA: "-hwaccel cuda -hwaccel_output_format cuda",
"preset-jetson-h264": "-c:v h264_nvmpi -resize {1}x{2}", "preset-jetson-h264": "-c:v h264_nvmpi -resize {1}x{2}",
"preset-jetson-h265": "-c:v hevc_nvmpi -resize {1}x{2}", "preset-jetson-h265": "-c:v hevc_nvmpi -resize {1}x{2}",

View File

@@ -543,16 +543,16 @@ function ObjectDetailsTab({
)} )}
</div> </div>
)} )}
{(config?.cameras[search.camera].genai.enabled && search.end_time) || {((config?.cameras[search.camera].genai.enabled && search.end_time) ||
(!config?.cameras[search.camera].genai.enabled && ( !config?.cameras[search.camera].genai.enabled) && (
<Button <Button
variant="select" variant="select"
aria-label="Save" aria-label="Save"
onClick={updateDescription} onClick={updateDescription}
> >
Save Save
</Button> </Button>
))} )}
</div> </div>
</div> </div>
</div> </div>