diff --git a/docs/docs/configuration/record.md b/docs/docs/configuration/record.md index 043a9d0af..614beafed 100644 --- a/docs/docs/configuration/record.md +++ b/docs/docs/configuration/record.md @@ -281,31 +281,52 @@ Using Frigate UI, Home Assistant, or MQTT, cameras can be automated to only reco Footage can be exported from Frigate by right-clicking (desktop) or long pressing (mobile) on a review item in the Review pane or by clicking the Export button in the History view. Exported footage is then organized and searchable through the Export view, accessible from the main navigation bar. -### Time-lapse export +### Custom export with FFmpeg arguments -Time lapse exporting is available only via the [HTTP API](../integrations/api/export-recording-export-camera-name-start-start-time-end-end-time-post.api.mdx). +For advanced use cases, the [custom export HTTP API](../integrations/api/export-recording-custom-export-custom-camera-name-start-start-time-end-end-time-post.api.mdx) lets you pass custom FFmpeg arguments when exporting a recording: -When exporting a time-lapse the default speed-up is 25x with 30 FPS. This means that every 25 seconds of (real-time) recording is condensed into 1 second of time-lapse video (always without audio) with a smoothness of 30 FPS. - -To configure the speed-up factor, the frame rate and further custom settings, use the `timelapse_args` parameter. The below configuration example would change the time-lapse speed to 60x (for fitting 1 hour of recording into 1 minute of time-lapse) with 25 FPS: - -```yaml {3-4} -record: - enabled: True - export: - timelapse_args: "-vf setpts=PTS/60 -r 25" +``` +POST /export/custom/{camera_name}/start/{start_time}/end/{end_time} ``` -:::tip +The request body accepts `ffmpeg_input_args` and `ffmpeg_output_args` to control encoding, frame rate, filters, and other FFmpeg options. If neither is provided, Frigate defaults to time-lapse output settings (25x speed, 30 FPS). -When using `hwaccel_args`, hardware encoding is used for timelapse generation. This setting can be overridden for a specific camera (e.g., when camera resolution exceeds hardware encoder limits); set the camera-level export hwaccel_args with the appropriate settings. Using an unrecognized value or empty string will fall back to software encoding (libx264). +The following example exports a time-lapse at 60x speed with 25 FPS: + +```json +{ + "name": "Front Door Time-lapse", + "ffmpeg_output_args": "-vf setpts=PTS/60 -r 25" +} +``` + +#### CPU fallback + +If hardware acceleration is configured and the export fails (e.g., the GPU is unavailable), set `cpu_fallback: true` in the request body to automatically retry using software encoding. + +```json +{ + "name": "My Export", + "ffmpeg_output_args": "-c:v libx264 -crf 23", + "cpu_fallback": true +} +``` + +:::note + +Non-admin users are restricted from using FFmpeg arguments that can access the filesystem (e.g., `-filter_complex`, file paths, and protocol references). Admin users have full control over FFmpeg arguments. ::: :::tip -The encoder determines its own behavior so the resulting file size may be undesirably large. -To reduce the output file size the ffmpeg parameter `-qp n` can be utilized (where `n` stands for the value of the quantisation parameter). The value can be adjusted to get an acceptable tradeoff between quality and file size for the given scenario. +When `hwaccel_args` is configured, hardware encoding is used for exports. This can be overridden per camera (e.g., when camera resolution exceeds hardware encoder limits) by setting a camera-level `hwaccel_args`. Using an unrecognized value or empty string falls back to software encoding (libx264). + +::: + +:::tip + +To reduce output file size, add the FFmpeg parameter `-qp n` to `ffmpeg_output_args` (where `n` is the quantization parameter). Adjust the value to balance quality and file size for your scenario. ::: diff --git a/docs/docs/troubleshooting/recordings.md b/docs/docs/troubleshooting/recordings.md index b1f180a82..2425e653a 100644 --- a/docs/docs/troubleshooting/recordings.md +++ b/docs/docs/troubleshooting/recordings.md @@ -80,3 +80,85 @@ Some users found that mounting a drive via `fstab` with the `sync` option caused #### Copy Times < 1 second If the storage is working quickly then this error may be caused by CPU load on the machine being too high for Frigate to have the resources to keep up. Try temporarily shutting down other services to see if the issue improves. + +## I see the message: WARNING : Too many unprocessed recording segments in cache for camera. This likely indicates an issue with the detect stream... + +This warning means that the detect stream for the affected camera has fallen behind or stopped processing frames. Frigate's recording cache holds segments waiting to be analyzed by the detector — when more than 6 segments pile up without being processed, Frigate discards the oldest ones to prevent the cache from filling up. + +:::warning + +This error is a **symptom**, not the root cause. The actual cause is always logged **before** these messages start appearing. You must review the full logs from Frigate startup through the first occurrence of this warning to identify the real issue. + +::: + +### Step 1: Get the full logs + +Collect complete Frigate logs from startup through the first occurrence of the error. Look for errors or warnings that appear **before** the "Too many unprocessed" messages begin — that is where the root cause will be found. + +### Step 2: Check the cache directory + +Exec into the Frigate container and inspect the recording cache: + +``` +docker exec -it frigate ls -la /tmp/cache +``` + +Each camera should have a small number of `.mp4` segment files. If one camera has significantly more files than others, that camera is the source of the problem. A problem with a single camera can cascade and cause all cameras to show this error. + +### Step 3: Verify segment duration + +Recording segments should be approximately 10 seconds long. Run `ffprobe` on segments in the cache to check: + +``` +docker exec -it frigate ffprobe -v error -show_entries format=duration -of default=noprint_wrappers=1 /tmp/cache/@.mp4 +``` + +If segments are only ~1 second instead of ~10 seconds, the camera is sending corrupt timestamp data, causing segments to be split too frequently and filling the cache 10x faster than expected. + +**Common causes of short segments:** + +- **"Smart Codec" or "Smart+" enabled on the camera** — These features dynamically change encoding parameters mid-stream, which corrupts timestamps. Disable them in your camera's settings. +- **Changing codec, bitrate, or resolution mid-stream** — Any encoding changes during an active stream can cause unpredictable segment splitting. +- **Camera firmware bugs** — Check for firmware updates from your camera manufacturer. + +### Step 4: Check for a stuck detector + +If the detect stream is not processing frames, segments will accumulate. Common causes: + +- **Detection resolution too high** — Use a substream for detection, not the full resolution main stream. +- **Detection FPS too high** — 5 fps is the recommended maximum for detection. +- **Model too large** — Use smaller model variants (e.g., YOLO `s` or `t` size, not `e` or `x`). Use 320x320 input size rather than 640x640 unless you have a powerful dedicated detector. +- **Virtualization** — Running Frigate in a VM (especially Proxmox) can cause the detector to hang or stall. This is a known issue with GPU/TPU passthrough in virtualized environments and is not something Frigate can fix. Running Frigate in Docker on bare metal is recommended. + +### Step 5: Check for GPU hangs + +On the host machine, check `dmesg` for GPU-related errors: + +``` +dmesg | grep -i -E "gpu|drm|reset|hang" +``` + +Messages like `trying reset from guc_exec_queue_timedout_job` or similar GPU reset/hang messages indicate a driver or hardware issue. Ensure your kernel and GPU drivers (especially Intel) are up to date. + +### Step 6: Verify hardware acceleration configuration + +An incorrect `hwaccel_args` preset can cause ffmpeg to fail silently or consume excessive CPU, starving the detector of resources. + +- After upgrading Frigate, verify your preset matches your hardware (e.g., `preset-intel-qsv-h264` instead of the deprecated `preset-vaapi`). +- For h265 cameras, use the corresponding h265 preset (e.g., `preset-intel-qsv-h265`). +- Note that `hwaccel_args` are only relevant for the detect stream — Frigate does not decode the record stream. + +### Step 7: Verify go2rtc stream configuration + +Ensure that the ffmpeg source names in your go2rtc configuration match the correct camera stream. A misconfigured stream name (e.g., copying a config from one camera to another without updating the stream reference) will cause the wrong stream to be used or the stream to fail entirely. + +### Step 8: Check system resources + +If none of the above apply, the issue may be a general resource constraint. Monitor the following on your host: + +- **CPU usage** — An overloaded CPU can prevent the detector from keeping up. +- **RAM and swap** — Excessive swapping dramatically slows all I/O operations. +- **Disk I/O** — Use `iotop` or `iostat` to check for saturation. +- **Storage space** — Verify you have free space on the Frigate storage volume (check the Storage page in the Frigate UI). + +Try temporarily disabling resource-intensive features like `genai` and `face_recognition` to see if the issue resolves. This can help isolate whether the detector is being starved of resources. diff --git a/web/src/components/Statusbar.tsx b/web/src/components/Statusbar.tsx index 18a0d9ee1..4e7c4053c 100644 --- a/web/src/components/Statusbar.tsx +++ b/web/src/components/Statusbar.tsx @@ -7,6 +7,7 @@ import useStats, { useAutoFrigateStats } from "@/hooks/use-stats"; import { cn } from "@/lib/utils"; import type { ProfilesApiResponse } from "@/types/profile"; import { getProfileColor } from "@/utils/profileColors"; +import { useIsAdmin } from "@/hooks/use-is-admin"; import { useContext, useEffect, useMemo } from "react"; import { useTranslation } from "react-i18next"; import useSWR from "swr"; @@ -18,6 +19,7 @@ import { Link } from "react-router-dom"; export default function Statusbar() { const { t } = useTranslation(["views/system"]); + const isAdmin = useIsAdmin(); const { messages, addMessage, clearMessages } = useContext( StatusBarMessagesContext, @@ -154,9 +156,23 @@ export default function Statusbar() { ); })} - {activeProfile && ( - -
+ {activeProfile && + (isAdmin ? ( + +
+ + + {activeProfile.friendlyName} + +
+ + ) : ( +
- - )} + ))}
{Object.entries(messages).length === 0 ? ( diff --git a/web/src/components/filter/CameraGroupSelector.tsx b/web/src/components/filter/CameraGroupSelector.tsx index c50abf692..5c092ac1f 100644 --- a/web/src/components/filter/CameraGroupSelector.tsx +++ b/web/src/components/filter/CameraGroupSelector.tsx @@ -89,6 +89,7 @@ export function CameraGroupSelector({ className }: CameraGroupSelectorProps) { const { t } = useTranslation(["components/camera"]); const { data: config } = useSWR("config"); const allowedCameras = useAllowedCameras(); + const hasFullCameraAccess = useHasFullCameraAccess(); const isAdmin = useIsAdmin(); // tooltip @@ -125,7 +126,7 @@ export function CameraGroupSelector({ className }: CameraGroupSelectorProps) { const allGroups = Object.entries(config.camera_groups); // If custom role, filter out groups where user has no accessible cameras - if (!isAdmin) { + if (!hasFullCameraAccess) { return allGroups .filter(([, groupConfig]) => { // Check if user has access to at least one camera in this group @@ -137,7 +138,7 @@ export function CameraGroupSelector({ className }: CameraGroupSelectorProps) { } return allGroups.sort((a, b) => a[1].order - b[1].order); - }, [config, allowedCameras, isAdmin]); + }, [config, allowedCameras, hasFullCameraAccess]); // add group diff --git a/web/src/pages/Events.tsx b/web/src/pages/Events.tsx index d3545f242..9f8dd4e44 100644 --- a/web/src/pages/Events.tsx +++ b/web/src/pages/Events.tsx @@ -334,7 +334,7 @@ export default function Events() { ); useEffect(() => { - if (reviewUpdate?.type === "end") { + if (reviewUpdate?.type === "end" && reviews) { updateSegments( (data) => { if (!data) return data; @@ -348,6 +348,9 @@ export default function Events() { new Map(prev).set(reviewUpdate.after.id, reviewUpdate.after), ); } + // reviews is intentionally excluded - only used to guard against + // updating the SWR cache before data has loaded + // eslint-disable-next-line react-hooks/exhaustive-deps }, [reviewUpdate, updateSegments]); const currentItems = useMemo(() => {