diff --git a/nixos/doc/manual/release-notes/rl-2305.section.md b/nixos/doc/manual/release-notes/rl-2305.section.md index f5082bf226d7..c2c9f2d1a251 100644 --- a/nixos/doc/manual/release-notes/rl-2305.section.md +++ b/nixos/doc/manual/release-notes/rl-2305.section.md @@ -101,6 +101,10 @@ In addition to numerous new and upgraded packages, this release has the followin - [ReGreet](https://github.com/rharish101/ReGreet), a clean and customizable greeter for greetd. Available as [programs.regreet](#opt-programs.regreet.enable). +- [v4l2-relayd](https://git.launchpad.net/v4l2-relayd), a streaming relay for v4l2loopback using gstreamer. Available as [services.v4l2-relayd](#opt-services.v4l2-relayd.instances._name_.enable). + +- [hardware.ipu6](#opt-hardware.ipu6.enable) adds support for ipu6 based webcams on intel tiger lake and alder lake. + ## Backward Incompatibilities {#sec-release-23.05-incompatibilities} diff --git a/nixos/modules/hardware/video/webcam/ipu6.nix b/nixos/modules/hardware/video/webcam/ipu6.nix new file mode 100644 index 000000000000..8a9b88f9e550 --- /dev/null +++ b/nixos/modules/hardware/video/webcam/ipu6.nix @@ -0,0 +1,57 @@ +{ config, lib, pkgs, ... }: +let + + inherit (lib) mkDefault mkEnableOption mkIf mkOption optional types; + + cfg = config.hardware.ipu6; + +in +{ + + options.hardware.ipu6 = { + + enable = mkEnableOption (lib.mdDoc "ipu6 kernel module"); + + platform = mkOption { + type = types.enum [ "ipu6" "ipu6ep" ]; + description = lib.mdDoc '' + Choose the version for your hardware platform. + + Use `ipu6` for Tiger Lake and `ipu6ep` for Alder Lake respectively. + ''; + }; + + }; + + config = mkIf cfg.enable { + + boot.extraModulePackages = with config.boot.kernelPackages; [ + ipu6-drivers + ]; + + hardware.firmware = with pkgs; [ ] + ++ optional (cfg.platform == "ipu6") ipu6-camera-bin + ++ optional (cfg.platform == "ipu6ep") ipu6ep-camera-bin; + + services.udev.extraRules = '' + SUBSYSTEM=="intel-ipu6-psys", MODE="0660", GROUP="video" + ''; + + services.v4l2-relayd.instances.ipu6 = { + enable = mkDefault true; + + cardLabel = mkDefault "Intel MIPI Camera"; + + extraPackages = with pkgs.gst_all_1; [ ] + ++ optional (cfg.platform == "ipu6") icamerasrc-ipu6 + ++ optional (cfg.platform == "ipu6ep") icamerasrc-ipu6ep; + + input = { + pipeline = "icamerasrc"; + format = mkIf (cfg.platform == "ipu6ep") (mkDefault "NV12"); + }; + }; + + }; + +} diff --git a/nixos/modules/module-list.nix b/nixos/modules/module-list.nix index ed6c12197668..cc464c18ca55 100644 --- a/nixos/modules/module-list.nix +++ b/nixos/modules/module-list.nix @@ -99,6 +99,7 @@ ./hardware/video/switcheroo-control.nix ./hardware/video/uvcvideo/default.nix ./hardware/video/webcam/facetimehd.nix + ./hardware/video/webcam/ipu6.nix ./hardware/wooting.nix ./hardware/xone.nix ./hardware/xpadneo.nix @@ -1130,6 +1131,7 @@ ./services/video/replay-sorcery.nix ./services/video/rtsp-simple-server.nix ./services/video/unifi-video.nix + ./services/video/v4l2-relayd.nix ./services/wayland/cage.nix ./services/web-apps/akkoma.nix ./services/web-apps/alps.nix diff --git a/nixos/modules/services/video/v4l2-relayd.nix b/nixos/modules/services/video/v4l2-relayd.nix new file mode 100644 index 000000000000..2a9dbe00158f --- /dev/null +++ b/nixos/modules/services/video/v4l2-relayd.nix @@ -0,0 +1,199 @@ +{ config, lib, pkgs, utils, ... }: +let + + inherit (lib) attrValues concatStringsSep filterAttrs length listToAttrs literalExpression + makeSearchPathOutput mkEnableOption mkIf mkOption nameValuePair optionals types; + inherit (utils) escapeSystemdPath; + + cfg = config.services.v4l2-relayd; + + kernelPackages = config.boot.kernelPackages; + + gst = (with pkgs.gst_all_1; [ + gst-plugins-bad + gst-plugins-base + gst-plugins-good + gstreamer.out + ]); + + instanceOpts = { name, ... }: { + options = { + enable = mkEnableOption (lib.mdDoc "this v4l2-relayd instance"); + + name = mkOption { + type = types.str; + default = name; + description = lib.mdDoc '' + The name of the instance. + ''; + }; + + cardLabel = mkOption { + type = types.str; + description = lib.mdDoc '' + The name the camera will show up as. + ''; + }; + + extraPackages = mkOption { + type = with types; listOf package; + default = [ ]; + description = lib.mdDoc '' + Extra packages to add to {env}`GST_PLUGIN_PATH` for the instance. + ''; + }; + + input = { + pipeline = mkOption { + type = types.str; + description = lib.mdDoc '' + The gstreamer-pipeline to use for the input-stream. + ''; + }; + + format = mkOption { + type = types.str; + default = "YUY2"; + description = lib.mdDoc '' + The video-format to read from input-stream. + ''; + }; + + width = mkOption { + type = types.ints.positive; + default = 1280; + description = lib.mdDoc '' + The width to read from input-stream. + ''; + }; + + height = mkOption { + type = types.ints.positive; + default = 720; + description = lib.mdDoc '' + The height to read from input-stream. + ''; + }; + + framerate = mkOption { + type = types.ints.positive; + default = 30; + description = lib.mdDoc '' + The framerate to read from input-stream. + ''; + }; + }; + + output = { + format = mkOption { + type = types.str; + default = "YUY2"; + description = lib.mdDoc '' + The video-format to write to output-stream. + ''; + }; + }; + + }; + }; + +in +{ + + options.services.v4l2-relayd = { + + instances = mkOption { + type = with types; attrsOf (submodule instanceOpts); + default = { }; + example = literalExpression '' + { + example = { + cardLabel = "Example card"; + input.pipeline = "videotestsrc"; + }; + } + ''; + description = lib.mdDoc '' + v4l2-relayd instances to be created. + ''; + }; + + }; + + config = + let + + mkInstanceService = instance: { + description = "Streaming relay for v4l2loopback using GStreamer"; + + after = [ "modprobe@v4l2loopback.service" "systemd-logind.service" ]; + wantedBy = [ "multi-user.target" ]; + + serviceConfig = { + Type = "simple"; + Restart = "always"; + PrivateNetwork = true; + PrivateTmp = true; + LimitNPROC = 1; + }; + + environment = { + GST_PLUGIN_PATH = makeSearchPathOutput "lib" "lib/gstreamer-1.0" (gst ++ instance.extraPackages); + V4L2_DEVICE_FILE = "/run/v4l2-relayd-${instance.name}/device"; + }; + + script = + let + appsrcOptions = concatStringsSep "," [ + "caps=video/x-raw" + "format=${instance.input.format}" + "width=${toString instance.input.width}" + "height=${toString instance.input.height}" + "framerate=${toString instance.input.framerate}/1" + ]; + + outputPipeline = [ + "appsrc name=appsrc ${appsrcOptions}" + "videoconvert" + ] ++ optionals (instance.input.format != instance.output.format) [ + "video/x-raw,format=${instance.output.format}" + "queue" + ] ++ [ "v4l2sink name=v4l2sink device=$(cat $V4L2_DEVICE_FILE)" ]; + in + '' + exec ${pkgs.v4l2-relayd}/bin/v4l2-relayd -i "${instance.input.pipeline}" -o "${concatStringsSep " ! " outputPipeline}" + ''; + + preStart = '' + mkdir -p $(dirname $V4L2_DEVICE_FILE) + ${kernelPackages.v4l2loopback.bin}/bin/v4l2loopback-ctl add -x 1 -n "${instance.cardLabel}" > $V4L2_DEVICE_FILE + ''; + + postStop = '' + ${kernelPackages.v4l2loopback.bin}/bin/v4l2loopback-ctl delete $(cat $V4L2_DEVICE_FILE) + rm -rf $(dirname $V4L2_DEVICE_FILE) + ''; + }; + + mkInstanceServices = instances: listToAttrs (map + (instance: + nameValuePair "v4l2-relayd-${escapeSystemdPath instance.name}" (mkInstanceService instance) + ) + instances); + + enabledInstances = attrValues (filterAttrs (n: v: v.enable) cfg.instances); + + in + { + + boot = mkIf ((length enabledInstances) > 0) { + extraModulePackages = [ kernelPackages.v4l2loopback ]; + kernelModules = [ "v4l2loopback" ]; + }; + + systemd.services = mkInstanceServices enabledInstances; + + }; + + meta.maintainers = with lib.maintainers; [ betaboon ]; +} diff --git a/pkgs/os-specific/linux/v4l2-relayd/default.nix b/pkgs/os-specific/linux/v4l2-relayd/default.nix index 293210fa9f57..a089ce8c77f8 100644 --- a/pkgs/os-specific/linux/v4l2-relayd/default.nix +++ b/pkgs/os-specific/linux/v4l2-relayd/default.nix @@ -2,27 +2,14 @@ , stdenv , fetchgit , autoreconfHook -, coreutils , glib -, gnugrep , gst_all_1 -, icamerasrc , libtool -, makeWrapper , pkg-config , which }: -let - gst = [ - gst_all_1.gstreamer.out - gst_all_1.gst-plugins-bad - gst_all_1.gst-plugins-base - gst_all_1.gst-plugins-good - icamerasrc - ]; -in stdenv.mkDerivation rec { - pname = "v4l2-relayd-${icamerasrc.ipuVersion}"; + pname = "v4l2-relayd"; version = "0.1.3"; src = fetchgit { @@ -38,39 +25,18 @@ stdenv.mkDerivation rec { nativeBuildInputs = [ autoreconfHook libtool - makeWrapper pkg-config which ]; buildInputs = [ glib - ] ++ gst; + gst_all_1.gstreamer + gst_all_1.gst-plugins-base + ]; preConfigure = "./autogen.sh --prefix=$out"; - postInstall = '' - mkdir -p $out/lib/systemd/system $out/etc/default - cp data/systemd/v4l2-relayd.service $out/lib/systemd/system - cp data/etc/default/v4l2-relayd $out/etc/default - - substituteInPlace $out/lib/systemd/system/v4l2-relayd.service \ - --replace grep ${gnugrep}/bin/grep \ - --replace cut ${coreutils}/bin/cut \ - --replace /usr/bin/test ${coreutils}/bin/test \ - --replace /usr/bin/v4l2-relayd $out/bin/v4l2-relayd \ - --replace /etc/default $out/etc/default \ - --replace "DeviceAllow=char-video4linux" "" - - substituteInPlace $out/etc/default/v4l2-relayd \ - --replace 'FORMAT=YUY2' 'FORMAT=NV12' \ - --replace 'CARD_LABEL="Virtual Camera"' 'CARD_LABEL="Intel MIPI Camera"' \ - --replace 'VIDEOSRC="videotestsrc"' 'VIDEOSRC="icamerasrc"' - - wrapProgram $out/bin/v4l2-relayd \ - --prefix GST_PLUGIN_PATH : ${lib.makeSearchPathOutput "lib" "lib/gstreamer-1.0" gst} - ''; - meta = with lib; { description = "Streaming relay for v4l2loopback using GStreamer"; homepage = "https://git.launchpad.net/v4l2-relayd"; diff --git a/pkgs/top-level/all-packages.nix b/pkgs/top-level/all-packages.nix index 6d69f89767c8..bd017547d99a 100644 --- a/pkgs/top-level/all-packages.nix +++ b/pkgs/top-level/all-packages.nix @@ -27431,12 +27431,7 @@ with pkgs; v4l-utils = qt5.callPackage ../os-specific/linux/v4l-utils { }; - v4l2-relayd-ipu6 = callPackage ../os-specific/linux/v4l2-relayd { - icamerasrc = gst_all_1.icamerasrc-ipu6; - }; - v4l2-relayd-ipu6ep = callPackage ../os-specific/linux/v4l2-relayd { - icamerasrc = gst_all_1.icamerasrc-ipu6ep; - }; + v4l2-relayd = callPackage ../os-specific/linux/v4l2-relayd { }; vendir = callPackage ../development/tools/vendir { };