From 966970c2564887026acb6c0acc28767663941960 Mon Sep 17 00:00:00 2001 From: fwastring Date: Sun, 29 Mar 2026 15:17:22 +0200 Subject: [PATCH] added hardware encoding --- maskiner/laptop/configuration.nix | 14 ++- moduler/services/webcam-rtsp/default.nix | 127 +++++++++++++++++++++-- 2 files changed, 131 insertions(+), 10 deletions(-) diff --git a/maskiner/laptop/configuration.nix b/maskiner/laptop/configuration.nix index 68cfa67..52f931f 100644 --- a/maskiner/laptop/configuration.nix +++ b/maskiner/laptop/configuration.nix @@ -32,14 +32,24 @@ in frontcam = { device = "/dev/v4l/by-id/usb-Generic_HD_WebCam_200901010001-video-index0"; rtspUrl = "rtsp://192.168.1.143:8554/frontcam"; - framerate = 15; + framerate = 12; videoSize = "1280x720"; + useVaapi = true; + vaapiQp = 26; + bitrateKbps = 900; + maxrateKbps = 1100; + bufsizeKbps = 1800; }; webcam = { device = "/dev/v4l/by-id/usb-GENERAL_GENERAL_WEBCAM-video-index0"; rtspUrl = "rtsp://192.168.1.143:8554/webcam"; - framerate = 15; + framerate = 12; videoSize = "1280x720"; + useVaapi = true; + vaapiQp = 26; + bitrateKbps = 900; + maxrateKbps = 1100; + bufsizeKbps = 1800; }; }; }; diff --git a/moduler/services/webcam-rtsp/default.nix b/moduler/services/webcam-rtsp/default.nix index baf46ed..9db91ae 100644 --- a/moduler/services/webcam-rtsp/default.nix +++ b/moduler/services/webcam-rtsp/default.nix @@ -18,6 +18,13 @@ let rtspUrl = cfg.rtspUrl; framerate = cfg.framerate; videoSize = cfg.videoSize; + preset = cfg.preset; + bitrateKbps = cfg.bitrateKbps; + maxrateKbps = cfg.maxrateKbps; + bufsizeKbps = cfg.bufsizeKbps; + useVaapi = cfg.useVaapi; + vaapiDevice = cfg.vaapiDevice; + vaapiQp = cfg.vaapiQp; }; }; @@ -47,6 +54,51 @@ in default = "1280x720"; description = "Input video size for the webcam stream."; }; + preset = mkOption { + type = types.enum [ + "ultrafast" + "superfast" + "veryfast" + "faster" + "fast" + "medium" + "slow" + "slower" + "veryslow" + ]; + default = "veryfast"; + description = "x264 preset used for software encoding."; + }; + bitrateKbps = mkOption { + type = types.nullOr types.int; + default = null; + description = "Target bitrate in kbps. Set to null for CRF-like unconstrained output."; + }; + maxrateKbps = mkOption { + type = types.nullOr types.int; + default = null; + description = "Maximum bitrate in kbps. Defaults to bitrateKbps when unset."; + }; + bufsizeKbps = mkOption { + type = types.nullOr types.int; + default = null; + description = "Rate-control buffer in kbps. Defaults to 2x bitrateKbps when unset."; + }; + useVaapi = mkOption { + type = types.bool; + default = false; + description = "Use VAAPI hardware encoding (h264_vaapi) instead of libx264."; + }; + vaapiDevice = mkOption { + type = types.str; + default = "/dev/dri/renderD128"; + description = "VAAPI render device path used when useVaapi = true."; + }; + vaapiQp = mkOption { + type = types.int; + default = 24; + description = "VAAPI quality parameter (lower means better quality, higher CPU/bitrate)."; + }; streams = mkOption { type = types.attrsOf ( types.submodule { @@ -69,6 +121,51 @@ in default = "1280x720"; description = "Input video size for this stream."; }; + preset = mkOption { + type = types.enum [ + "ultrafast" + "superfast" + "veryfast" + "faster" + "fast" + "medium" + "slow" + "slower" + "veryslow" + ]; + default = "veryfast"; + description = "x264 preset used for software encoding."; + }; + bitrateKbps = mkOption { + type = types.nullOr types.int; + default = null; + description = "Target bitrate in kbps. Set to null for unconstrained output."; + }; + maxrateKbps = mkOption { + type = types.nullOr types.int; + default = null; + description = "Maximum bitrate in kbps. Defaults to bitrateKbps when unset."; + }; + bufsizeKbps = mkOption { + type = types.nullOr types.int; + default = null; + description = "Rate-control buffer in kbps. Defaults to 2x bitrateKbps when unset."; + }; + useVaapi = mkOption { + type = types.bool; + default = false; + description = "Use VAAPI hardware encoding (h264_vaapi) instead of libx264."; + }; + vaapiDevice = mkOption { + type = types.str; + default = "/dev/dri/renderD128"; + description = "VAAPI render device path used when useVaapi = true."; + }; + vaapiQp = mkOption { + type = types.int; + default = 24; + description = "VAAPI quality parameter for h264_vaapi."; + }; }; } ); @@ -81,6 +178,27 @@ in config = mkIf cfg.enable { systemd.services = mapAttrs' ( streamName: streamCfg: + let + maxrateKbps = + if streamCfg.maxrateKbps != null then streamCfg.maxrateKbps else streamCfg.bitrateKbps; + bufsizeKbps = + if streamCfg.bufsizeKbps != null then + streamCfg.bufsizeKbps + else if streamCfg.bitrateKbps != null then + streamCfg.bitrateKbps * 2 + else + null; + rateControlArgs = + if streamCfg.bitrateKbps != null then + "-b:v ${toString streamCfg.bitrateKbps}k -maxrate ${toString maxrateKbps}k -bufsize ${toString bufsizeKbps}k" + else + ""; + videoCodecArgs = + if streamCfg.useVaapi then + "-vaapi_device ${streamCfg.vaapiDevice} -vf format=nv12,hwupload -c:v h264_vaapi -qp ${toString streamCfg.vaapiQp}" + else + "-vcodec libx264 -tune zerolatency -preset ${streamCfg.preset}"; + in nameValuePair "webcam-rtsp-publisher-${sanitizeName streamName}" { description = "Publish webcam stream '${streamName}' to MediaMTX over RTSP"; wantedBy = [ "multi-user.target" ]; @@ -91,14 +209,7 @@ in Type = "simple"; Restart = "always"; RestartSec = "2"; - ExecStart = '' - ${pkgs.ffmpeg}/bin/ffmpeg \ - -hide_banner -loglevel warning \ - -f v4l2 -framerate ${toString streamCfg.framerate} -video_size ${streamCfg.videoSize} \ - -i ${streamCfg.device} \ - -vcodec libx264 -tune zerolatency -preset veryfast \ - -f rtsp ${streamCfg.rtspUrl} - ''; + ExecStart = "${pkgs.ffmpeg}/bin/ffmpeg -hide_banner -loglevel warning -f v4l2 -framerate ${toString streamCfg.framerate} -video_size ${streamCfg.videoSize} -i ${streamCfg.device} ${videoCodecArgs} ${rateControlArgs} -f rtsp ${streamCfg.rtspUrl}"; }; } ) effectiveStreams;