Skip to content

Commit

Permalink
frigate: coral tpu support, audio model, nvidia ffmpeg hwaccel, other…
Browse files Browse the repository at this point in the history
… fixes (#357717)
  • Loading branch information
mweinelt authored Nov 23, 2024
2 parents 21e00d7 + 591ebd3 commit 7eb0c19
Show file tree
Hide file tree
Showing 7 changed files with 154 additions and 9 deletions.
2 changes: 2 additions & 0 deletions nixos/doc/manual/release-notes/rl-2411.section.md
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,8 @@

## New Modules {#sec-release-24.11-new-modules}

- [Coral](https://coral.ai/), hardware support for Coral.ai Edge TPU devices. Available as [hardware.coral.usb.enable](#opt-hardware.coral.usb.enable) and [hardware.coral.pcie.enable](#opt-hardware.coral.pcie.enable).

- [Cyrus IMAP](https://github.com/cyrusimap/cyrus-imapd), an email, contacts and calendar server. Available as [services.cyrus-imap](#opt-services.cyrus-imap.enable) service.

- [TaskChampion Sync-Server](https://github.com/GothenburgBitFactory/taskchampion-sync-server), a [Taskwarrior 3](https://taskwarrior.org/docs/upgrade-3/) sync server. Available as [services.taskchampion-sync-server](#opt-services.taskchampion-sync-server.enable).
Expand Down
38 changes: 38 additions & 0 deletions nixos/modules/hardware/coral.nix
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
{
config,
lib,
pkgs,
...
}:

let
inherit (lib)
mkEnableOption
mkIf
mkMerge
;

cfg = config.hardware.coral;
in

{
options.hardware.coral = {
usb.enable = mkEnableOption "Coral USB support";
pcie.enable = mkEnableOption "Coral PCIe support";
};

config = mkMerge [
(mkIf (cfg.usb.enable || cfg.pcie.enable) {
users.groups.coral = { };
})
(mkIf cfg.usb.enable {
services.udev.packages = with pkgs; [ libedgetpu ];
})
(mkIf cfg.pcie.enable {
boot.extraModulePackages = with config.boot.kernelPackages; [ gasket ];
services.udev.extraRules = ''
SUBSYSTEM=="apex",MODE="0660",GROUP="coral"
'';
})
];
}
1 change: 1 addition & 0 deletions nixos/modules/module-list.nix
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@
./hardware/bladeRF.nix
./hardware/brillo.nix
./hardware/ckb-next.nix
./hardware/coral.nix
./hardware/corectrl.nix
./hardware/cpu/amd-microcode.nix
./hardware/cpu/amd-sev.nix
Expand Down
74 changes: 68 additions & 6 deletions nixos/modules/services/video/frigate.nix
Original file line number Diff line number Diff line change
Expand Up @@ -6,19 +6,28 @@

let
inherit (lib)
literalExpression
any
attrValues
converge
elem
filterAttrsRecursive
hasPrefix
makeLibraryPath
match
mkDefault
mkEnableOption
mkPackageOption
mkIf
mkOption
optionalAttrs
optionals
types;

cfg = config.services.frigate;

format = pkgs.formats.yaml { };

filteredConfig = lib.converge (lib.filterAttrsRecursive (_: v: ! lib.elem v [ null ])) cfg.settings;
filteredConfig = converge (filterAttrsRecursive (_: v: ! elem v [ null ])) cfg.settings;

cameraFormat = with types; submodule {
freeformType = format.type;
Expand Down Expand Up @@ -94,6 +103,15 @@ let
proxy_connect_timeout 360;
'';

# Discover configured detectors for acceleration support
detectors = attrValues cfg.settings.detectors or {};
withCoralUSB = any (d: d.type == "edgetpu" && hasPrefix "usb" d.device or "") detectors;
withCoralPCI = any (d: d.type == "edgetpu" && hasPrefix "pci" d.device or "") detectors;
withCoral = withCoralPCI || withCoralUSB;

# Provide ffmpeg-full for NVIDIA hardware acceleration
ffmpegArgs = cfg.settings.ffmpeg.hwaccel_args or "";
ffmpeg' = if match "/nvidia/" ffmpegArgs != null then pkgs.ffmpeg-full else pkgs.ffmpeg-headless;
in

{
Expand All @@ -114,6 +132,27 @@ in
'';
};

vaapiDriver = mkOption {
type = nullOr (enum [ "i965" "iHD" "nouveau" "vdpau" "nvidia" "radeonsi" ]);
default = null;
example = "radeonsi";
description = ''
Force usage of a particular VA-API driver for video acceleration. Use together with `settings.ffmpeg.hwaccel_args`.
Setting this *is not required* for VA-API to work, but it can help steer VA-API towards the correct card if you have multiple.
:::{.note}
For VA-API to work you must enable {option}`hardware.graphics.enable` (sufficient for AMDGPU) and pass for example
`pkgs.intel-media-driver` (required for Intel 5th Gen. and newer) into {option}`hardware.graphics.extraPackages`.
:::
See also:
- https://docs.frigate.video/configuration/hardware_acceleration
- https://docs.frigate.video/configuration/ffmpeg_presets#hwaccel-presets
'';
};

settings = mkOption {
type = submodule {
freeformType = format.type;
Expand Down Expand Up @@ -171,7 +210,6 @@ in
set-misc
vod
];
recommendedProxySettings = mkDefault true;
recommendedGzipSettings = mkDefault true;
mapHashBucketSize = mkDefault 128;
upstreams = {
Expand Down Expand Up @@ -202,6 +240,7 @@ in
# auth_location.conf
"/auth" = {
proxyPass = "http://frigate-api/auth";
recommendedProxySettings = true;
extraConfig = ''
internal;
Expand Down Expand Up @@ -306,18 +345,21 @@ in
};
"/ws" = {
proxyPass = "http://frigate-mqtt-ws/";
recommendedProxySettings = true;
proxyWebsockets = true;
extraConfig = nginxAuthRequest + nginxProxySettings;
};
"/live/jsmpeg" = {
proxyPass = "http://frigate-jsmpeg/";
recommendedProxySettings = true;
proxyWebsockets = true;
extraConfig = nginxAuthRequest + nginxProxySettings;
};
# frigate lovelace card uses this path
"/live/mse/api/ws" = {
proxyPass = "http://frigate-go2rtc/api/ws";
proxyWebsockets = true;
recommendedProxySettings = true;
extraConfig = nginxAuthRequest + nginxProxySettings + ''
limit_except GET {
deny all;
Expand All @@ -327,6 +369,7 @@ in
"/live/webrtc/api/ws" = {
proxyPass = "http://frigate-go2rtc/api/ws";
proxyWebsockets = true;
recommendedProxySettings = true;
extraConfig = nginxAuthRequest + nginxProxySettings + ''
limit_except GET {
deny all;
Expand All @@ -336,6 +379,7 @@ in
# pass through go2rtc player
"/live/webrtc/webrtc.html" = {
proxyPass = "http://frigate-go2rtc/webrtc.html";
recommendedProxySettings = true;
extraConfig = nginxAuthRequest + nginxProxySettings + ''
limit_except GET {
deny all;
Expand All @@ -345,6 +389,7 @@ in
# frontend uses this to fetch the version
"/api/go2rtc/api" = {
proxyPass = "http://frigate-go2rtc/api";
recommendedProxySettings = true;
extraConfig = nginxAuthRequest + nginxProxySettings + ''
limit_except GET {
deny all;
Expand All @@ -355,6 +400,7 @@ in
"/api/go2rtc/webrtc" = {
proxyPass = "http://frigate-go2rtc/api/webrtc";
proxyWebsockets = true;
recommendedProxySettings = true;
extraConfig = nginxAuthRequest + nginxProxySettings + ''
limit_except GET {
deny all;
Expand All @@ -363,12 +409,14 @@ in
};
"~* /api/.*\.(jpg|jpeg|png|webp|gif)$" = {
proxyPass = "http://frigate-api";
recommendedProxySettings = true;
extraConfig = nginxAuthRequest + nginxProxySettings + ''
rewrite ^/api/(.*)$ $1 break;
'';
};
"/api/" = {
proxyPass = "http://frigate-api/";
recommendedProxySettings = true;
extraConfig = nginxAuthRequest + nginxProxySettings + ''
add_header Cache-Control "no-store";
expires off;
Expand Down Expand Up @@ -492,6 +540,11 @@ in
"frigate"
];

hardware.coral = {
usb.enable = mkDefault withCoralUSB;
pcie.enable = mkDefault withCoralPCI;
};

users.users.frigate = {
isSystemUser = true;
group = "frigate";
Expand All @@ -510,26 +563,35 @@ in
CONFIG_FILE = format.generate "frigate.yml" filteredConfig;
HOME = "/var/lib/frigate";
PYTHONPATH = cfg.package.pythonPath;
} // optionalAttrs (cfg.vaapiDriver != null) {
LIBVA_DRIVER_NAME = cfg.vaapiDriver;
} // optionalAttrs withCoral {
LD_LIBRARY_PATH = makeLibraryPath (with pkgs; [ libedgetpu ]);
};
path = with pkgs; [
# unfree:
# config.boot.kernelPackages.nvidiaPackages.latest.bin
ffmpeg-headless
ffmpeg'
libva-utils
procps
radeontop
] ++ lib.optionals (!stdenv.hostPlatform.isAarch64) [
] ++ optionals (!stdenv.hostPlatform.isAarch64) [
# not available on aarch64-linux
intel-gpu-tools
];
serviceConfig = {
ExecStartPre = "-rm /var/cache/frigate/*.mp4";
ExecStartPre = pkgs.writeShellScript "frigate-clear-cache" ''
rm --recursive --force /var/cache/frigate/*
'';
ExecStart = "${cfg.package.python.interpreter} -m frigate";
Restart = "on-failure";
SyslogIdentifier = "frigate";

User = "frigate";
Group = "frigate";
SupplementaryGroups = [ "render" ] ++ optionals withCoral [ "coral" ];

AmbientCapabilities = optionals (elem cfg.vaapiDriver [ "i965" "iHD" ]) [ "CAP_PERFMON" ]; # for intel_gpu_top

UMask = "0027";

Expand Down
19 changes: 18 additions & 1 deletion pkgs/by-name/fr/frigate/package.nix
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,12 @@ let
};
};

# Tensorflow audio model
tflite_audio_model = fetchurl {
url = "https://www.kaggle.com/api/v1/models/google/yamnet/tfLite/classification-tflite/1/download";
hash = "sha256-G5cbITJ2AnOl+49dxQToZ4OyeFO7MTXVVa4G8eHjZfM=";
};

# Tensorflow Lite models
# https://github.com/blakeblackshear/frigate/blob/v0.13.0/docker/main/Dockerfile#L96-L97
tflite_cpu_model = fetchurl {
Expand Down Expand Up @@ -72,14 +78,22 @@ python.pkgs.buildPythonApplication rec {
substituteInPlace frigate/detectors/detector_config.py \
--replace-fail "/labelmap.txt" "${placeholder "out"}/share/frigate/labelmap.txt"
substituteInPlace frigate/output/birdseye.py \
--replace-fail "/opt/frigate/" "${placeholder "out"}/${python.sitePackages}/"
# work around onvif-zeep idiosyncrasy
substituteInPlace frigate/ptz/onvif.py \
--replace-fail dist-packages site-packages
# provide default paths for models and maps that are shipped with frigate
substituteInPlace frigate/config.py \
--replace-fail "/cpu_model.tflite" "${tflite_cpu_model}" \
--replace-fail "/edgetpu_model.tflite" "${tflite_edgetpu_model}"
substituteInPlace frigate/events/audio.py \
--replace-fail "/cpu_audio_model.tflite" "${placeholder "out"}/share/frigate/cpu_audio_model.tflite" \
--replace-fail "/audio-labelmap.txt" "${placeholder "out"}/share/frigate/audio-labelmap.txt"
substituteInPlace frigate/test/test_config.py \
--replace-fail "(MODEL_CACHE_DIR" "('/build/model_cache'" \
--replace-fail "/config/model_cache" "/build/model_cache"
Expand Down Expand Up @@ -131,7 +145,10 @@ python.pkgs.buildPythonApplication rec {
cp -R frigate/* $out/${python.sitePackages}/frigate/
mkdir -p $out/share/frigate
cp -R {migrations,labelmap.txt} $out/share/frigate/
cp -R {migrations,labelmap.txt,audio-labelmap.txt} $out/share/frigate/
tar --extract --gzip --file ${tflite_audio_model}
cp --no-preserve=mode ./1.tflite $out/share/frigate/cpu_audio_model.tflite
cp --no-preserve=mode ${openvino_model} $out/share/frigate/coco_91cl_bkgr.txt
sed -i 's/truck/car/g' $out/share/frigate/coco_91cl_bkgr.txt
Expand Down
6 changes: 6 additions & 0 deletions pkgs/by-name/li/libedgetpu/package.nix
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,12 @@ stdenv.mkDerivation {
})
];

postPatch = ''
# Use dedicated group for coral devices
substituteInPlace debian/edgetpu-accelerator.rules \
--replace-fail "plugdev" "coral"
'';

makeFlags = [
"-f"
"makefile_build/Makefile"
Expand Down
23 changes: 21 additions & 2 deletions pkgs/os-specific/linux/gasket/default.nix
Original file line number Diff line number Diff line change
@@ -1,4 +1,10 @@
{ stdenv, lib, fetchFromGitHub, kernel }:
{
stdenv,
lib,
fetchFromGitHub,
fetchpatch2,
kernel
}:

stdenv.mkDerivation rec {
pname = "gasket";
Expand All @@ -11,6 +17,20 @@ stdenv.mkDerivation rec {
sha256 = "O17+msok1fY5tdX1DvqYVw6plkUDF25i8sqwd6mxYf8=";
};

patches = [
(fetchpatch2 {
# https://github.com/google/gasket-driver/issues/36
# https://github.com/google/gasket-driver/pull/35
name = "linux-6.12-compat.patch";
url = "https://github.com/google/gasket-driver/commit/4b2a1464f3b619daaf0f6c664c954a42c4b7ce00.patch";
hash = "sha256-UOoOSEnpUMa4QXWVFpGFxBoF5szXaLEfcWtfKatO5XY=";
})
];

postPatch = ''
cd src
'';

makeFlags = kernel.makeFlags ++ [
"-C"
"${kernel.dev}/lib/modules/${kernel.modDirVersion}/build"
Expand All @@ -21,7 +41,6 @@ stdenv.mkDerivation rec {
installFlags = [ "INSTALL_MOD_PATH=${placeholder "out"}" ];
installTargets = [ "modules_install" ];

sourceRoot = "${src.name}/src";
hardeningDisable = [ "pic" "format" ];
nativeBuildInputs = kernel.moduleBuildDependencies;

Expand Down

0 comments on commit 7eb0c19

Please sign in to comment.