Compare commits

..

No commits in common. "d830d47c9b7246baee758855b181cfb740130f7d" and "a47be12ac54ac6613ab72715c7c1b12e753f2a90" have entirely different histories.

8 changed files with 36 additions and 137 deletions

View File

@ -14,8 +14,6 @@ services:
dockerfile: docker/main/Dockerfile dockerfile: docker/main/Dockerfile
# Use target devcontainer-trt for TensorRT dev # Use target devcontainer-trt for TensorRT dev
target: devcontainer target: devcontainer
cache_from:
- ghcr.io/blakeblackshear/frigate:cache-amd64
## Uncomment this block for nvidia gpu support ## Uncomment this block for nvidia gpu support
# deploy: # deploy:
# resources: # resources:

View File

@ -52,14 +52,6 @@ RUN --mount=type=tmpfs,target=/tmp --mount=type=tmpfs,target=/var/cache/apt \
--mount=type=cache,target=/root/.ccache \ --mount=type=cache,target=/root/.ccache \
/deps/build_sqlite_vec.sh /deps/build_sqlite_vec.sh
# Build intel-media-driver from source against bookworm's system libva so it
# works with Debian 12's glibc/libstdc++ (pre-built noble/trixie packages
# require glibc 2.38 which is not available on bookworm).
FROM base AS intel-media-driver
ARG DEBIAN_FRONTEND
RUN --mount=type=bind,source=docker/main/build_intel_media_driver.sh,target=/deps/build_intel_media_driver.sh \
/deps/build_intel_media_driver.sh
FROM scratch AS go2rtc FROM scratch AS go2rtc
ARG TARGETARCH ARG TARGETARCH
WORKDIR /rootfs/usr/local/go2rtc/bin WORKDIR /rootfs/usr/local/go2rtc/bin
@ -208,7 +200,6 @@ RUN --mount=type=bind,source=docker/main/install_hailort.sh,target=/deps/install
FROM scratch AS deps-rootfs FROM scratch AS deps-rootfs
COPY --from=nginx /usr/local/nginx/ /usr/local/nginx/ COPY --from=nginx /usr/local/nginx/ /usr/local/nginx/
COPY --from=sqlite-vec /usr/local/lib/ /usr/local/lib/ COPY --from=sqlite-vec /usr/local/lib/ /usr/local/lib/
COPY --from=intel-media-driver /rootfs/ /
COPY --from=go2rtc /rootfs/ / COPY --from=go2rtc /rootfs/ /
COPY --from=libusb-build /usr/local/lib /usr/local/lib COPY --from=libusb-build /usr/local/lib /usr/local/lib
COPY --from=tempio /rootfs/ / COPY --from=tempio /rootfs/ /

View File

@ -1,48 +0,0 @@
#!/bin/bash
set -euxo pipefail
# Intel media driver is x86_64-only. Create empty rootfs on other arches so
# the downstream COPY --from has a valid source.
if [ "$(uname -m)" != "x86_64" ]; then
mkdir -p /rootfs
exit 0
fi
MEDIA_DRIVER_VERSION="intel-media-25.2.6"
GMMLIB_VERSION="intel-gmmlib-22.7.2"
apt-get -qq update
apt-get -qq install -y wget gnupg ca-certificates cmake g++ make pkg-config
# Use Intel's jammy repo for newer libva-dev (2.22) which provides the
# VVC/VVC-decode headers required by media-driver 25.x
wget -qO - https://repositories.intel.com/gpu/intel-graphics.key | gpg --yes --dearmor --output /usr/share/keyrings/intel-graphics.gpg
echo "deb [arch=amd64 signed-by=/usr/share/keyrings/intel-graphics.gpg] https://repositories.intel.com/gpu/ubuntu jammy client" > /etc/apt/sources.list.d/intel-gpu-jammy.list
apt-get -qq update
apt-get -qq install -y libva-dev
# Build gmmlib (required by media-driver)
wget -qO gmmlib.tar.gz "https://github.com/intel/gmmlib/archive/refs/tags/${GMMLIB_VERSION}.tar.gz"
mkdir /tmp/gmmlib
tar -xf gmmlib.tar.gz -C /tmp/gmmlib --strip-components 1
cmake -S /tmp/gmmlib -B /tmp/gmmlib/build -DCMAKE_BUILD_TYPE=Release
make -C /tmp/gmmlib/build -j"$(nproc)"
make -C /tmp/gmmlib/build install
# Build intel-media-driver
wget -qO media-driver.tar.gz "https://github.com/intel/media-driver/archive/refs/tags/${MEDIA_DRIVER_VERSION}.tar.gz"
mkdir /tmp/media-driver
tar -xf media-driver.tar.gz -C /tmp/media-driver --strip-components 1
cmake -S /tmp/media-driver -B /tmp/media-driver/build \
-DCMAKE_BUILD_TYPE=Release \
-DENABLE_KERNELS=ON \
-DENABLE_NONFREE_KERNELS=ON \
-DCMAKE_INSTALL_PREFIX=/usr \
-DCMAKE_INSTALL_LIBDIR=/usr/lib/x86_64-linux-gnu \
-DCMAKE_C_FLAGS="-Wno-error" \
-DCMAKE_CXX_FLAGS="-Wno-error"
make -C /tmp/media-driver/build -j"$(nproc)"
# Install driver to rootfs for COPY --from
make -C /tmp/media-driver/build install DESTDIR=/rootfs

View File

@ -91,10 +91,8 @@ if [[ "${TARGETARCH}" == "amd64" ]]; then
wget -qO - https://repositories.intel.com/gpu/intel-graphics.key | gpg --yes --dearmor --output /usr/share/keyrings/intel-graphics.gpg wget -qO - https://repositories.intel.com/gpu/intel-graphics.key | gpg --yes --dearmor --output /usr/share/keyrings/intel-graphics.gpg
echo "deb [arch=amd64 signed-by=/usr/share/keyrings/intel-graphics.gpg] https://repositories.intel.com/gpu/ubuntu jammy client" | tee /etc/apt/sources.list.d/intel-gpu-jammy.list echo "deb [arch=amd64 signed-by=/usr/share/keyrings/intel-graphics.gpg] https://repositories.intel.com/gpu/ubuntu jammy client" | tee /etc/apt/sources.list.d/intel-gpu-jammy.list
apt-get -qq update apt-get -qq update
# intel-media-va-driver-non-free is built from source in the
# intel-media-driver Dockerfile stage for Battlemage (Xe2) support
apt-get -qq install --no-install-recommends --no-install-suggests -y \ apt-get -qq install --no-install-recommends --no-install-suggests -y \
libmfx1 libmfxgen1 libvpl2 intel-media-va-driver-non-free libmfx1 libmfxgen1 libvpl2
apt-get -qq install -y ocl-icd-libopencl1 apt-get -qq install -y ocl-icd-libopencl1

View File

@ -59,14 +59,13 @@ Frigate can utilize most Intel integrated GPUs and Arc GPUs to accelerate video
**Recommended hwaccel Preset** **Recommended hwaccel Preset**
| CPU Generation | Intel Driver | Recommended Preset | Notes | | CPU Generation | Intel Driver | Recommended Preset | Notes |
| ------------------ | ------------ | ------------------- | ------------------------------------------- | | -------------- | ------------ | ------------------- | ------------------------------------------- |
| gen1 - gen5 | i965 | preset-vaapi | qsv is not supported, may not support H.265 | | gen1 - gen5 | i965 | preset-vaapi | qsv is not supported, may not support H.265 |
| gen6 - gen7 | iHD | 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 | | gen8 - gen12 | iHD | preset-vaapi | preset-intel-qsv-\* can also be used |
| gen13+ | iHD / Xe | preset-intel-qsv-\* | | | gen13+ | iHD / Xe | preset-intel-qsv-\* | |
| Intel Arc A-series | iHD / Xe | preset-intel-qsv-\* | | | Intel Arc GPU | iHD / Xe | preset-intel-qsv-\* | |
| Intel Arc B-series | iHD / Xe | preset-intel-qsv-\* | Requires host kernel 6.12+ |
::: :::

View File

@ -146,11 +146,17 @@ A single Coral can handle many cameras using the default model and will be suffi
The OpenVINO detector type is able to run on: The OpenVINO detector type is able to run on:
- 6th Gen Intel Platforms and newer that have an iGPU - 6th Gen Intel Platforms and newer that have an iGPU
- x86 hosts with an Intel Arc GPU (including Arc A-series and B-series Battlemage) - x86 hosts with an Intel Arc GPU
- Intel NPUs - Intel NPUs
- Most modern AMD CPUs (though this is officially not supported by Intel) - Most modern AMD CPUs (though this is officially not supported by Intel)
- x86 & Arm64 hosts via CPU (generally not recommended) - x86 & Arm64 hosts via CPU (generally not recommended)
:::note
Intel B-series (Battlemage) GPUs are not officially supported with Frigate 0.17, though a user has [provided steps to rebuild the Frigate container](https://github.com/blakeblackshear/frigate/discussions/21257) with support for them.
:::
More information is available [in the detector docs](/configuration/object_detectors#openvino-detector) More information is available [in the detector docs](/configuration/object_detectors#openvino-detector)
Inference speeds vary greatly depending on the CPU or GPU used, some known examples of GPU inference times are below: Inference speeds vary greatly depending on the CPU or GPU used, some known examples of GPU inference times are below:

View File

@ -372,7 +372,6 @@ class RecordingMaintainer(threading.Thread):
) )
record_config = self.config.cameras[camera].record record_config = self.config.cameras[camera].record
segment_stats: SegmentInfo | None = None
highest = None highest = None
if record_config.continuous.days > 0: if record_config.continuous.days > 0:
@ -402,19 +401,9 @@ class RecordingMaintainer(threading.Thread):
if highest == "continuous" if highest == "continuous"
else RetainModeEnum.motion else RetainModeEnum.motion
) )
segment_stats = self.segment_stats(camera, start_time, end_time) return await self.move_segment(
camera, start_time, end_time, duration, cache_path, record_mode
# Here we only check if we should move the segment based on non-object recording retention )
# we will always want to check for overlapping review items below before dropping the segment
if not segment_stats.should_discard_segment(record_mode):
return await self.move_segment(
camera,
start_time,
end_time,
duration,
cache_path,
segment_stats,
)
# we fell through the continuous / motion check, so we need to check the review items # we fell through the continuous / motion check, so we need to check the review items
# if the cached segment overlaps with the review items: # if the cached segment overlaps with the review items:
@ -446,24 +435,15 @@ class RecordingMaintainer(threading.Thread):
if review.severity == "alert" if review.severity == "alert"
else record_config.detections.retain.mode else record_config.detections.retain.mode
) )
# move from cache to recordings immediately
if segment_stats is None: return await self.move_segment(
segment_stats = self.segment_stats(camera, start_time, end_time) camera,
start_time,
if not segment_stats.should_discard_segment(record_mode): end_time,
# move from cache to recordings immediately duration,
return await self.move_segment( cache_path,
camera, record_mode,
start_time, )
end_time,
duration,
cache_path,
segment_stats,
)
else:
self.drop_segment(cache_path)
return None
# if it doesn't overlap with an review item, go ahead and drop the segment # if it doesn't overlap with an review item, go ahead and drop the segment
# if it ends more than the configured pre_capture for the camera # if it ends more than the configured pre_capture for the camera
# BUT only if continuous/motion is NOT enabled (otherwise wait for processing) # BUT only if continuous/motion is NOT enabled (otherwise wait for processing)
@ -475,7 +455,6 @@ class RecordingMaintainer(threading.Thread):
retain_cutoff = datetime.datetime.fromtimestamp( retain_cutoff = datetime.datetime.fromtimestamp(
most_recently_processed_frame_time - record_config.event_pre_capture most_recently_processed_frame_time - record_config.event_pre_capture
).astimezone(datetime.timezone.utc) ).astimezone(datetime.timezone.utc)
if end_time < retain_cutoff: if end_time < retain_cutoff:
self.drop_segment(cache_path) self.drop_segment(cache_path)
@ -599,8 +578,15 @@ class RecordingMaintainer(threading.Thread):
end_time: datetime.datetime, end_time: datetime.datetime,
duration: float, duration: float,
cache_path: str, cache_path: str,
segment_info: SegmentInfo, store_mode: RetainModeEnum,
) -> Optional[dict[str, Any]]: ) -> Optional[dict[str, Any]]:
segment_info = self.segment_stats(camera, start_time, end_time)
# check if the segment shouldn't be stored
if segment_info.should_discard_segment(store_mode):
self.drop_segment(cache_path)
return None
# directory will be in utc due to start_time being in utc # directory will be in utc due to start_time being in utc
directory = os.path.join( directory = os.path.join(
RECORD_DIR, RECORD_DIR,

View File

@ -24,7 +24,6 @@ import {
import EventView from "@/views/events/EventView"; import EventView from "@/views/events/EventView";
import MotionSearchView from "@/views/motion-search/MotionSearchView"; import MotionSearchView from "@/views/motion-search/MotionSearchView";
import { RecordingView } from "@/views/recording/RecordingView"; import { RecordingView } from "@/views/recording/RecordingView";
import { useFrigateReviews } from "@/api/ws";
import axios from "axios"; import axios from "axios";
import { useCallback, useEffect, useMemo, useState } from "react"; import { useCallback, useEffect, useMemo, useState } from "react";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
@ -327,29 +326,6 @@ export default function Events() {
}; };
}, [reviews]); }, [reviews]);
// update review items in place when a review segment ends
const reviewUpdate = useFrigateReviews();
const [endedReviews, setEndedReviews] = useState(
new Map<string, ReviewSegment>(),
);
useEffect(() => {
if (reviewUpdate?.type === "end") {
updateSegments(
(data) => {
if (!data) return data;
return data.map((seg) =>
seg.id === reviewUpdate.after.id ? reviewUpdate.after : seg,
);
},
{ revalidate: false, populateCache: true },
);
setEndedReviews((prev) =>
new Map(prev).set(reviewUpdate.after.id, reviewUpdate.after),
);
}
}, [reviewUpdate, updateSegments]);
const currentItems = useMemo(() => { const currentItems = useMemo(() => {
if (!reviewItems || !severity) { if (!reviewItems || !severity) {
return null; return null;
@ -376,13 +352,6 @@ export default function Events() {
// eslint-disable-next-line react-hooks/exhaustive-deps // eslint-disable-next-line react-hooks/exhaustive-deps
}, [severity, reviewFilter, showReviewed, reviewItems?.all.length]); }, [severity, reviewFilter, showReviewed, reviewItems?.all.length]);
// overlay end_time updates onto currentItems without re-running
// the has_been_reviewed filter, so hover-reviewed items stay visible
const displayItems = useMemo(() => {
if (!currentItems || endedReviews.size === 0) return currentItems;
return currentItems.map((seg) => endedReviews.get(seg.id) ?? seg);
}, [currentItems, endedReviews]);
// review summary // review summary
const { data: reviewSummary, mutate: updateSummary } = useSWR<ReviewSummary>( const { data: reviewSummary, mutate: updateSummary } = useSWR<ReviewSummary>(
@ -634,7 +603,7 @@ export default function Events() {
) : ( ) : (
<EventView <EventView
reviewItems={reviewItems} reviewItems={reviewItems}
currentReviewItems={displayItems} currentReviewItems={currentItems}
reviewSummary={reviewSummary} reviewSummary={reviewSummary}
recordingsSummary={recordingsSummary} recordingsSummary={recordingsSummary}
relevantPreviews={allPreviews} relevantPreviews={allPreviews}