mirror of
https://github.com/blakeblackshear/frigate.git
synced 2026-05-09 15:05:26 +03:00
Compare commits
5 Commits
a47be12ac5
...
d830d47c9b
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d830d47c9b | ||
|
|
3e85b18ee3 | ||
|
|
2ffe47511a | ||
|
|
82e14d71fb | ||
|
|
15ac76f20d |
@ -14,6 +14,8 @@ 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:
|
||||||
|
|||||||
@ -52,6 +52,14 @@ 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
|
||||||
@ -200,6 +208,7 @@ 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/ /
|
||||||
|
|||||||
48
docker/main/build_intel_media_driver.sh
Executable file
48
docker/main/build_intel_media_driver.sh
Executable file
@ -0,0 +1,48 @@
|
|||||||
|
#!/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
|
||||||
@ -91,8 +91,10 @@ 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 \
|
||||||
intel-media-va-driver-non-free libmfx1 libmfxgen1 libvpl2
|
libmfx1 libmfxgen1 libvpl2
|
||||||
|
|
||||||
apt-get -qq install -y ocl-icd-libopencl1
|
apt-get -qq install -y ocl-icd-libopencl1
|
||||||
|
|
||||||
|
|||||||
@ -59,13 +59,14 @@ 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 GPU | iHD / Xe | preset-intel-qsv-\* | |
|
| Intel Arc A-series | iHD / Xe | preset-intel-qsv-\* | |
|
||||||
|
| Intel Arc B-series | iHD / Xe | preset-intel-qsv-\* | Requires host kernel 6.12+ |
|
||||||
|
|
||||||
:::
|
:::
|
||||||
|
|
||||||
|
|||||||
@ -146,17 +146,11 @@ 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
|
- x86 hosts with an Intel Arc GPU (including Arc A-series and B-series Battlemage)
|
||||||
- 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:
|
||||||
|
|||||||
@ -372,6 +372,7 @@ 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:
|
||||||
@ -401,9 +402,19 @@ class RecordingMaintainer(threading.Thread):
|
|||||||
if highest == "continuous"
|
if highest == "continuous"
|
||||||
else RetainModeEnum.motion
|
else RetainModeEnum.motion
|
||||||
)
|
)
|
||||||
return await self.move_segment(
|
segment_stats = self.segment_stats(camera, start_time, end_time)
|
||||||
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:
|
||||||
@ -435,15 +446,24 @@ 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
|
|
||||||
return await self.move_segment(
|
if segment_stats is None:
|
||||||
camera,
|
segment_stats = self.segment_stats(camera, start_time, end_time)
|
||||||
start_time,
|
|
||||||
end_time,
|
if not segment_stats.should_discard_segment(record_mode):
|
||||||
duration,
|
# move from cache to recordings immediately
|
||||||
cache_path,
|
return await self.move_segment(
|
||||||
record_mode,
|
camera,
|
||||||
)
|
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)
|
||||||
@ -455,6 +475,7 @@ 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)
|
||||||
|
|
||||||
@ -578,15 +599,8 @@ class RecordingMaintainer(threading.Thread):
|
|||||||
end_time: datetime.datetime,
|
end_time: datetime.datetime,
|
||||||
duration: float,
|
duration: float,
|
||||||
cache_path: str,
|
cache_path: str,
|
||||||
store_mode: RetainModeEnum,
|
segment_info: SegmentInfo,
|
||||||
) -> 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,
|
||||||
|
|||||||
@ -24,6 +24,7 @@ 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";
|
||||||
@ -326,6 +327,29 @@ 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;
|
||||||
@ -352,6 +376,13 @@ 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>(
|
||||||
@ -603,7 +634,7 @@ export default function Events() {
|
|||||||
) : (
|
) : (
|
||||||
<EventView
|
<EventView
|
||||||
reviewItems={reviewItems}
|
reviewItems={reviewItems}
|
||||||
currentReviewItems={currentItems}
|
currentReviewItems={displayItems}
|
||||||
reviewSummary={reviewSummary}
|
reviewSummary={reviewSummary}
|
||||||
recordingsSummary={recordingsSummary}
|
recordingsSummary={recordingsSummary}
|
||||||
relevantPreviews={allPreviews}
|
relevantPreviews={allPreviews}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user