Multicam (c) buffer

This commit is contained in:
chk
2026-06-06 10:49:42 +02:00
parent d0cb0b934c
commit 1811b3281d

View File

@@ -200,11 +200,21 @@ class CameraSwitch extends EventEmitter {
}, 1500);
}
// ── HD-Grab: Live sauber stoppen → 1280 greifen → Live zurück ──────────────
// Garantie: zwischen Stop und 1280-Start liegt das `close`-Event des Live-
// ── HD-Grab: Live sauber stoppen → hires greifen → Live zurück ──────────────
// Garantie: zwischen Stop und hires-Start liegt das `close`-Event des Live-
// FFmpeg → /dev/videoN ist frei. Niemals zwei Encoder gleichzeitig.
//
// minWidth wird automatisch aus hiresSize abgeleitet (90 % der Soll-Breite),
// damit Frames die noch auf der alten Live-Auflösung basieren abgelehnt werden.
// Beispiel: hiresSize="1920x1080" → minWidth=1728 → lehnt 1280er-Frames ab.
async grabHires(opts = {}) {
const { minSize = 15000, minWidth = 1000, settleFrames = 6, maxWaitMs = 6000 } = opts;
const hiresW = parseInt(this.hiresSize.split('x')[0], 10);
const {
minSize = 15000,
minWidth = Math.floor(hiresW * 0.9), // nur Frames bei (fast) der angeforderten Breite
settleFrames = 6,
maxWaitMs = 10000, // mehr Zeit: Kamera braucht nach Format-Wechsel länger
} = opts;
if (this.lock) throw new Error('HD-Grab läuft bereits');
this.lock = true;
const t0 = Date.now();
@@ -213,12 +223,19 @@ class CameraSwitch extends EventEmitter {
try {
// 1. Live-FFmpeg beenden, auf Prozess-Ende warten (= Device-FD frei)
await this._killCurrentAndWait();
this.state = 'grabbing';
console.log(`[cam ${this.id}] HD: Live gestoppt nach ${Date.now() - t0}ms, Gerät frei → 1280-Grab`);
// 2. 1280-FFmpeg starten, warmlaufen lassen, besten Frame greifen
// Kurze Pause: v4l2-Buffer der Kamera können noch Frames der alten Live-
// Auflösung enthalten (z.B. 640×480-Rest wenn hires 1920×1080 fordert).
// 300 ms genügen damit die Kamera den Format-Reset abschliessen kann.
await sleep(300);
this.state = 'grabbing';
console.log(`[cam ${this.id}] HD: Live gestoppt nach ${Date.now() - t0}ms, Gerät frei → ${this.hiresSize}-Grab (minWidth=${minWidth})`);
// 2. hires-FFmpeg starten, warmlaufen lassen, besten Frame greifen
const jpeg = await this._captureHires({ minSize, minWidth, settleFrames, maxWaitMs });
console.log(`[cam ${this.id}] HD OK ${jpeg.length} bytes, Breite=${readJpegWidth(jpeg) ?? '?'} (${Date.now() - t0}ms)`);
const gotW = readJpegWidth(jpeg) ?? '?';
console.log(`[cam ${this.id}] HD OK ${jpeg.length} bytes, Breite=${gotW}px (Soll: ${hiresW}px, ${Date.now() - t0}ms)`);
return jpeg;
} finally {
// 3. Zurück auf Live, sofern noch Verbraucher da sind (On-Demand). Live hat Priorität.