fix(capture): pin NVENC to a GPU with ffmpeg -gpu N (privileged bypasses env)
NVIDIA_VISIBLE_DEVICES=1 was set but the sidecar still SAW /dev/nvidia0,1,2 and nvenc used GPU 0 — because capture sidecars run Privileged, which exposes every GPU device node regardless of NVIDIA_VISIBLE_DEVICES/DeviceRequests. Real fix: node-agent passes CAPTURE_GPU_INDEX to the sidecar and capture-manager adds ffmpeg '-gpu N' to the hevc_nvenc + h264_nvenc encoders, so each port's master+HLS encode is explicitly bound to its assigned L4. Spreads 8 ports across 3 cards.
This commit is contained in:
parent
15fab99d55
commit
80f157968f
2 changed files with 23 additions and 2 deletions
|
|
@ -181,8 +181,24 @@ function parseFps(framerate, fallback = 60) {
|
|||
return Number.isFinite(f) && f > 0 ? f : fallback;
|
||||
}
|
||||
|
||||
// Which physical GPU this sidecar's NVENC encodes should use. node-agent
|
||||
// round-robins capture ports across the host's GPUs and passes the index here.
|
||||
// We MUST select it explicitly with ffmpeg's `-gpu N` because the capture
|
||||
// sidecars run Privileged (so they see every /dev/nvidiaN regardless of
|
||||
// NVIDIA_VISIBLE_DEVICES) — without -gpu, nvenc defaults every session to GPU 0
|
||||
// and all 8 ports pile onto one card → it falls below realtime → video freezes.
|
||||
const CAPTURE_GPU_INDEX = (() => {
|
||||
const v = process.env.CAPTURE_GPU_INDEX;
|
||||
if (v == null || v === '' || v === 'all') return null;
|
||||
const n = parseInt(v, 10);
|
||||
return Number.isInteger(n) && n >= 0 ? n : null;
|
||||
})();
|
||||
// `-gpu N` must come BEFORE the input/encoder is initialized; ffmpeg accepts it
|
||||
// as an encoder option right after -c:v. Returns [] when no pin is configured.
|
||||
const nvencGpuSel = () => (CAPTURE_GPU_INDEX != null ? ['-gpu', String(CAPTURE_GPU_INDEX)] : []);
|
||||
|
||||
function hevcNvencArgs(framerate, growing) {
|
||||
const base = ['-c:v', 'hevc_nvenc', '-preset', 'p4', '-rc', 'vbr', '-profile:v', 'main10'];
|
||||
const base = ['-c:v', 'hevc_nvenc', ...nvencGpuSel(), '-preset', 'p4', '-rc', 'vbr', '-profile:v', 'main10'];
|
||||
if (growing) {
|
||||
return [...base, '-bf', '0', '-forced-idr', '1', '-g', '600', '-force_key_frames', 'expr:1'];
|
||||
}
|
||||
|
|
@ -232,7 +248,7 @@ function buildHlsVideoArgs(masterCodec, framerate) {
|
|||
// Low-latency NVENC preset (p1 + ll tune). forced-idr + a keyframe every GOP
|
||||
// frames keeps segment boundaries on IDR frames so hls.js can sync cleanly.
|
||||
return [
|
||||
'-c:v', 'h264_nvenc', '-preset', 'p1', '-tune', 'll',
|
||||
'-c:v', 'h264_nvenc', ...nvencGpuSel(), '-preset', 'p1', '-tune', 'll',
|
||||
'-pix_fmt', 'yuv420p', '-b:v', '2M',
|
||||
'-g', String(gop), '-forced-idr', '1', '-sc_threshold', '0',
|
||||
];
|
||||
|
|
|
|||
|
|
@ -527,6 +527,10 @@ async function handleSidecarStart(body, res) {
|
|||
var startVisibleDevices = pickVisibleDevices(gpuUuid, capturePort);
|
||||
sidecarEnv.push(`NVIDIA_VISIBLE_DEVICES=${startVisibleDevices}`);
|
||||
sidecarEnv.push('NVIDIA_DRIVER_CAPABILITIES=video,compute,utility');
|
||||
// Privileged sidecars see every /dev/nvidiaN regardless of
|
||||
// NVIDIA_VISIBLE_DEVICES, so also tell ffmpeg explicitly which GPU to
|
||||
// encode on via CAPTURE_GPU_INDEX (capture-manager adds `-gpu N`).
|
||||
if (startVisibleDevices !== 'all') sidecarEnv.push(`CAPTURE_GPU_INDEX=${startVisibleDevices}`);
|
||||
console.log(`[gpu] sidecar port ${capturePort} → NVIDIA_VISIBLE_DEVICES=${startVisibleDevices}`);
|
||||
}
|
||||
|
||||
|
|
@ -841,6 +845,7 @@ async function handleSidecarStandby(body, res) {
|
|||
standbyVisibleDevices = pickVisibleDevices(gpuUuid, capturePort);
|
||||
sidecarEnv.push(`NVIDIA_VISIBLE_DEVICES=${standbyVisibleDevices}`);
|
||||
sidecarEnv.push('NVIDIA_DRIVER_CAPABILITIES=video,compute,utility');
|
||||
if (standbyVisibleDevices !== 'all') sidecarEnv.push(`CAPTURE_GPU_INDEX=${standbyVisibleDevices}`);
|
||||
console.log(`[gpu] standby sidecar port ${capturePort} → NVIDIA_VISIBLE_DEVICES=${standbyVisibleDevices}`);
|
||||
}
|
||||
sidecarEnv.push(`FC_URL=${FC_URL}`);
|
||||
|
|
|
|||
Loading…
Reference in a new issue