From 47cbeeef9589d16cdc65fe9a035b49876a7668a7 Mon Sep 17 00:00:00 2001 From: Graham Barber Date: Wed, 21 Oct 2026 22:40:00 -0700 Subject: [PATCH] obelisk: fix Vesktop webcam capture with a stride-aware bridge --- hosts/obelisk/hardware.nix | 55 +++++++++++++++++++-- modules/home/puregarlic/desktop/default.nix | 6 ++- 2 files changed, 57 insertions(+), 4 deletions(-) diff --git a/hosts/obelisk/hardware.nix b/hosts/obelisk/hardware.nix index c829e13..ffb3e4a 100644 --- a/hosts/obelisk/hardware.nix +++ b/hosts/obelisk/hardware.nix @@ -1,4 +1,4 @@ -{ inputs, lib, pkgs, modulesPath, ... }: +{ config, inputs, lib, pkgs, modulesPath, ... }: { imports = @@ -18,8 +18,57 @@ boot.initrd.availableKernelModules = [ "usb_storage" ]; boot.initrd.kernelModules = [ ]; - boot.kernelModules = [ ]; - boot.extraModulePackages = [ ]; + boot.kernelModules = [ "v4l2loopback" ]; + boot.extraModulePackages = [ + (pkgs.runCommand "v4l2loopback-modules" { } '' + for modules in ${config.boot.kernelPackages.v4l2loopback}/lib/modules/*; do + destination="$out/lib/modules/$(basename "$modules")" + mkdir -p "$destination" + cp -r "$modules/updates" "$destination/" + done + '') + ]; + boot.extraModprobeConfig = '' + options v4l2loopback video_nr=10 card_label="FaceTime HD (compat)" exclusive_caps=1 + ''; + + systemd.user.services.webcam-bridge = { + description = "Stride-aware FaceTime camera bridge"; + serviceConfig.ExecStart = lib.getExe (pkgs.writeShellApplication { + name = "webcam-bridge"; + runtimeInputs = [ pkgs.coreutils pkgs.gawk pkgs.v4l-utils pkgs.ffmpeg ]; + text = '' + camera="" + for device in /sys/class/video4linux/video*; do + if [[ "$(< "$device/name")" == "apple-isp" ]]; then + camera="/dev/''${device##*/}" + break + fi + done + if [[ -z "$camera" ]]; then + printf 'FaceTime HD Camera not found\n' >&2 + exit 1 + fi + + format=$(v4l2-ctl --device="$camera" \ + --set-fmt-video=width=1280,height=720,pixelformat=NV12 \ + --get-fmt-video) + dimensions=$(awk -F: '/Width\/Height/ { gsub(/[[:space:]]/, "", $2); sub(/\//, "x", $2); print $2 }' <<< "$format") + stride=$(awk -F: '/Bytes per Line/ { gsub(/[[:space:]]/, "", $2); print $2 }' <<< "$format") + if [[ ! "$dimensions" =~ ^[0-9]+x[0-9]+$ || ! "$stride" =~ ^[0-9]+$ ]]; then + printf 'Could not read camera dimensions and stride\n' >&2 + exit 1 + fi + + v4l2-ctl --device="$camera" --silent --stream-mmap=4 --stream-to=- | + ffmpeg -hide_banner -loglevel warning \ + -f rawvideo -pixel_format nv12 -video_size "$dimensions" \ + -stride "$stride,$stride" -framerate 30 -i pipe:0 \ + -an -vf format=yuyv422 -c:v rawvideo -pix_fmt yuyv422 \ + -f v4l2 /dev/video10 + ''; + }); + }; fileSystems."/" = { device = "/dev/disk/by-uuid/481919ac-eec0-4739-8980-7dbbb9b45342"; diff --git a/modules/home/puregarlic/desktop/default.nix b/modules/home/puregarlic/desktop/default.nix index 8f24cf6..62e8da1 100644 --- a/modules/home/puregarlic/desktop/default.nix +++ b/modules/home/puregarlic/desktop/default.nix @@ -53,7 +53,11 @@ programs.zed-editor.enable = true; stylix.targets.zed.enable = true; - programs.vesktop.enable = true; + programs.vesktop = { + enable = true; + mutableSettings = true; + vencord.mutableSettings = true; + }; programs.alacritty = { enable = true; -- knotmirror 0.0.1