@camstack/addon-pipeline 1.1.57 → 1.1.58
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/audio-analyzer/index.js +1 -1
- package/dist/audio-analyzer/index.mjs +1 -1
- package/dist/detection-pipeline/index.js +2 -2
- package/dist/detection-pipeline/index.mjs +2 -2
- package/dist/{dist-CK8Ur-OS.js → dist-Bn6Uq4vq.js} +4647 -4639
- package/dist/{dist-CL531uVA.mjs → dist-CnwwDzX3.mjs} +4648 -4640
- package/dist/motion-wasm/index.js +1 -1
- package/dist/motion-wasm/index.mjs +1 -1
- package/dist/pipeline-runner/index.js +26 -10
- package/dist/pipeline-runner/index.mjs +26 -10
- package/dist/recorder/index.js +1 -1
- package/dist/recorder/index.mjs +1 -1
- package/dist/session-decode/decode-worker-child.js +97 -2
- package/dist/session-decode/decode-worker-child.mjs +97 -2
- package/dist/{step-definitions-DHAxruAQ.js → step-definitions-D7NOrnzz.js} +1 -1
- package/dist/{step-definitions-1d3_vQ6S.mjs → step-definitions-DhEe57Wn.mjs} +1 -1
- package/dist/stream-broker/{_virtual_mf-localSharedImportMap___mfe_internal__addon_stream_broker_widgets-Cm_B-hQT.mjs → _virtual_mf-localSharedImportMap___mfe_internal__addon_stream_broker_widgets-B8FQ1e0a.mjs} +3 -3
- package/dist/stream-broker/{hostInit-DEaqJpGA.mjs → hostInit-D1Vdyu-4.mjs} +3 -3
- package/dist/stream-broker/index.js +5 -4
- package/dist/stream-broker/index.mjs +5 -4
- package/dist/stream-broker/remoteEntry.js +1 -1
- package/embed-dist/assets/{MaskShapeCanvas-DI4BY7W2-CZUzu3MF.js → MaskShapeCanvas-DI4BY7W2-CG5EE0W4.js} +1 -1
- package/embed-dist/assets/{MotionZonesSettings-NcxxQN8r-CmZbzLQi.js → MotionZonesSettings-NcxxQN8r-BFeLUNOl.js} +1 -1
- package/embed-dist/assets/{PrivacyMaskSettings-APgPLF7p-BOKDrH0N.js → PrivacyMaskSettings-APgPLF7p-pQQunq1F.js} +1 -1
- package/embed-dist/assets/index-BxqQ931j.js +81 -0
- package/embed-dist/index.html +1 -1
- package/package.json +1 -1
- package/embed-dist/assets/index-DOsK8CZb.js +0 -81
|
@@ -2,7 +2,7 @@ Object.defineProperties(exports, {
|
|
|
2
2
|
__esModule: { value: true },
|
|
3
3
|
[Symbol.toStringTag]: { value: "Module" }
|
|
4
4
|
});
|
|
5
|
-
const require_dist = require("../dist-
|
|
5
|
+
const require_dist = require("../dist-Bn6Uq4vq.js");
|
|
6
6
|
let node_fs = require("node:fs");
|
|
7
7
|
let node_path = require("node:path");
|
|
8
8
|
//#region src/motion-wasm/wasm-motion-detector.ts
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { B as DeviceType, E as motionDetectionCapability,
|
|
1
|
+
import { B as DeviceType, E as motionDetectionCapability, H as hydrateSchema, L as BaseAddon, x as evaluateZoneRules } from "../dist-CnwwDzX3.mjs";
|
|
2
2
|
import { readFileSync } from "node:fs";
|
|
3
3
|
import { join } from "node:path";
|
|
4
4
|
//#region src/motion-wasm/wasm-motion-detector.ts
|
|
@@ -3,11 +3,11 @@ Object.defineProperties(exports, {
|
|
|
3
3
|
[Symbol.toStringTag]: { value: "Module" }
|
|
4
4
|
});
|
|
5
5
|
const require_chunk = require("../chunk-D6vf50IK.js");
|
|
6
|
-
const require_dist = require("../dist-
|
|
6
|
+
const require_dist = require("../dist-Bn6Uq4vq.js");
|
|
7
7
|
const require_remote_restream = require("../remote-restream-CO36Sr30.js");
|
|
8
8
|
const require_hub_hostname = require("../hub-hostname-DAJXlOgV.js");
|
|
9
9
|
const require_worker_protocol = require("../worker-protocol-PP4jKHHJ.js");
|
|
10
|
-
const require_step_definitions = require("../step-definitions-
|
|
10
|
+
const require_step_definitions = require("../step-definitions-D7NOrnzz.js");
|
|
11
11
|
let node_child_process = require("node:child_process");
|
|
12
12
|
let node_url = require("node:url");
|
|
13
13
|
let sharp = require("sharp");
|
|
@@ -3516,14 +3516,16 @@ var PipelineRunnerAddon = class extends require_dist.BaseAddon {
|
|
|
3516
3516
|
}
|
|
3517
3517
|
if (steps.length === 0) return null;
|
|
3518
3518
|
let image;
|
|
3519
|
-
if (
|
|
3520
|
-
|
|
3521
|
-
|
|
3522
|
-
|
|
3523
|
-
|
|
3524
|
-
|
|
3525
|
-
|
|
3526
|
-
|
|
3519
|
+
if (!this.executorCoLocated()) {
|
|
3520
|
+
if (frame.format === "rgb") try {
|
|
3521
|
+
image = await (0, sharp.default)(frame.data, { raw: {
|
|
3522
|
+
width: frame.width,
|
|
3523
|
+
height: frame.height,
|
|
3524
|
+
channels: 3
|
|
3525
|
+
} }).jpeg({ quality: DETECTION_HOP_JPEG_QUALITY }).toBuffer();
|
|
3526
|
+
} catch (err) {
|
|
3527
|
+
log.debug("runInference: frame JPEG encode failed — falling back to raw pixels", { meta: { error: require_dist.errMsg(err) } });
|
|
3528
|
+
}
|
|
3527
3529
|
}
|
|
3528
3530
|
try {
|
|
3529
3531
|
return await api.pipelineExecutor.runPipeline.mutate({
|
|
@@ -3538,6 +3540,20 @@ var PipelineRunnerAddon = class extends require_dist.BaseAddon {
|
|
|
3538
3540
|
return null;
|
|
3539
3541
|
}
|
|
3540
3542
|
}
|
|
3543
|
+
/** Sticky true once the executor's provider shows up in THIS process' local
|
|
3544
|
+
* registry (the `detection` execution.group) — from then on the per-frame
|
|
3545
|
+
* call is in-process and raw pixels are zero-copy. Re-checks while false
|
|
3546
|
+
* (a co-located sibling may register after the runner's first frames). */
|
|
3547
|
+
executorCoLocatedSticky = false;
|
|
3548
|
+
executorCoLocated() {
|
|
3549
|
+
if (this.executorCoLocatedSticky) return true;
|
|
3550
|
+
if (this.ctx?.capabilities?.get("pipeline-executor") !== void 0) {
|
|
3551
|
+
this.executorCoLocatedSticky = true;
|
|
3552
|
+
this.ctx?.logger.info("executor co-located in this runner — raw in-process frame transport");
|
|
3553
|
+
return true;
|
|
3554
|
+
}
|
|
3555
|
+
return false;
|
|
3556
|
+
}
|
|
3541
3557
|
async runMotionAnalysis(deviceId, frame, handle) {
|
|
3542
3558
|
const ctx = this.ctx;
|
|
3543
3559
|
const runner = this.runner;
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { D as nodePin, I as errMsg, L as BaseAddon, Q as boolean, V as createEvent, X as _enum, Z as array, _ as customAction, at as string, et as lazy, k as pipelineRunnerCapability, nt as number, rt as object, st as EventCategory, y as defineCustomActions } from "../dist-CnwwDzX3.mjs";
|
|
2
2
|
import { n as profileForStreamId, t as isRemoteRestream } from "../remote-restream-BeHi78PZ.mjs";
|
|
3
3
|
import { t as resolveHubHostname } from "../hub-hostname-cCknRYKj.mjs";
|
|
4
4
|
import { t as isWorkerReply } from "../worker-protocol-CyVJTZEO.mjs";
|
|
5
|
-
import { a as getStepDefinition } from "../step-definitions-
|
|
5
|
+
import { a as getStepDefinition } from "../step-definitions-DhEe57Wn.mjs";
|
|
6
6
|
import { fork } from "node:child_process";
|
|
7
7
|
import { fileURLToPath } from "node:url";
|
|
8
8
|
import sharp from "sharp";
|
|
@@ -3510,14 +3510,16 @@ var PipelineRunnerAddon = class extends BaseAddon {
|
|
|
3510
3510
|
}
|
|
3511
3511
|
if (steps.length === 0) return null;
|
|
3512
3512
|
let image;
|
|
3513
|
-
if (
|
|
3514
|
-
|
|
3515
|
-
|
|
3516
|
-
|
|
3517
|
-
|
|
3518
|
-
|
|
3519
|
-
|
|
3520
|
-
|
|
3513
|
+
if (!this.executorCoLocated()) {
|
|
3514
|
+
if (frame.format === "rgb") try {
|
|
3515
|
+
image = await sharp(frame.data, { raw: {
|
|
3516
|
+
width: frame.width,
|
|
3517
|
+
height: frame.height,
|
|
3518
|
+
channels: 3
|
|
3519
|
+
} }).jpeg({ quality: DETECTION_HOP_JPEG_QUALITY }).toBuffer();
|
|
3520
|
+
} catch (err) {
|
|
3521
|
+
log.debug("runInference: frame JPEG encode failed — falling back to raw pixels", { meta: { error: errMsg(err) } });
|
|
3522
|
+
}
|
|
3521
3523
|
}
|
|
3522
3524
|
try {
|
|
3523
3525
|
return await api.pipelineExecutor.runPipeline.mutate({
|
|
@@ -3532,6 +3534,20 @@ var PipelineRunnerAddon = class extends BaseAddon {
|
|
|
3532
3534
|
return null;
|
|
3533
3535
|
}
|
|
3534
3536
|
}
|
|
3537
|
+
/** Sticky true once the executor's provider shows up in THIS process' local
|
|
3538
|
+
* registry (the `detection` execution.group) — from then on the per-frame
|
|
3539
|
+
* call is in-process and raw pixels are zero-copy. Re-checks while false
|
|
3540
|
+
* (a co-located sibling may register after the runner's first frames). */
|
|
3541
|
+
executorCoLocatedSticky = false;
|
|
3542
|
+
executorCoLocated() {
|
|
3543
|
+
if (this.executorCoLocatedSticky) return true;
|
|
3544
|
+
if (this.ctx?.capabilities?.get("pipeline-executor") !== void 0) {
|
|
3545
|
+
this.executorCoLocatedSticky = true;
|
|
3546
|
+
this.ctx?.logger.info("executor co-located in this runner — raw in-process frame transport");
|
|
3547
|
+
return true;
|
|
3548
|
+
}
|
|
3549
|
+
return false;
|
|
3550
|
+
}
|
|
3535
3551
|
async runMotionAnalysis(deviceId, frame, handle) {
|
|
3536
3552
|
const ctx = this.ctx;
|
|
3537
3553
|
const runner = this.runner;
|
package/dist/recorder/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
const require_chunk = require("../chunk-D6vf50IK.js");
|
|
2
|
-
const require_dist = require("../dist-
|
|
2
|
+
const require_dist = require("../dist-Bn6Uq4vq.js");
|
|
3
3
|
const require_hub_hostname = require("../hub-hostname-DAJXlOgV.js");
|
|
4
4
|
const require_model_download_service_C_IHWnXx = require("../model-download-service-C-IHWnXx-D326YNnt.js");
|
|
5
5
|
let node_child_process = require("node:child_process");
|
package/dist/recorder/index.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { A as recordingCapability, B as DeviceType, D as nodePin,
|
|
1
|
+
import { A as recordingCapability, B as DeviceType, D as nodePin, H as hydrateSchema, I as errMsg, J as selectAssignedProfileSlots, L as BaseAddon, M as storageEvictableCapability, T as migrateConfigToBands, at as string, it as record, s as EVENT_PAD_MS, st as EventCategory, u as RecordingConfigSchema } from "../dist-CnwwDzX3.mjs";
|
|
2
2
|
import { t as resolveHubHostname } from "../hub-hostname-cCknRYKj.mjs";
|
|
3
3
|
import { t as createFileDataPlaneHandler } from "../model-download-service-C-IHWnXx-3Mmeob3l.mjs";
|
|
4
4
|
import { spawn } from "node:child_process";
|
|
@@ -189,6 +189,66 @@ var FrameSlot = class {
|
|
|
189
189
|
}
|
|
190
190
|
};
|
|
191
191
|
//#endregion
|
|
192
|
+
//#region src/session-decode/lease-activity-gate.ts
|
|
193
|
+
/**
|
|
194
|
+
* Demand-driven gate for the native-frame lease capture (see
|
|
195
|
+
* `decode-worker-child.ts` `captureNativeFrame`).
|
|
196
|
+
*
|
|
197
|
+
* Eagerly downloading EVERY delivered frame from the GPU at native resolution
|
|
198
|
+
* is sustained memory-bandwidth burn a small host (N100) cannot afford when
|
|
199
|
+
* nothing consumes the leases — live 2026-07-16: dev 584 ran 24 native-4K
|
|
200
|
+
* downloads/s with `nativeCropHits:0` for hours, and two such sessions
|
|
201
|
+
* saturated the box (load ~9 on 4 cores) until delivered fps collapsed to 0.
|
|
202
|
+
*
|
|
203
|
+
* The gate keeps capture ON only while there is plausible demand:
|
|
204
|
+
* - `arm()` at dial start — the FIRST track of a fresh on-motion session gets
|
|
205
|
+
* native-quality media before any crop request has been seen;
|
|
206
|
+
* - `arm()` on every native-crop request — post-analysis snapshot crops and
|
|
207
|
+
* the detail plane re-arm it continuously while tracks are active;
|
|
208
|
+
* - after `windowMs` without demand it closes and per-frame downloads stop
|
|
209
|
+
* (a later crop request simply misses once — the caller's designed
|
|
210
|
+
* detection-frame-crop fallback — and re-arms the gate for the retry).
|
|
211
|
+
*
|
|
212
|
+
* `windowMs: 0` disables gating entirely (always active — the legacy eager
|
|
213
|
+
* behaviour).
|
|
214
|
+
*/
|
|
215
|
+
var LeaseActivityGate = class {
|
|
216
|
+
windowMs;
|
|
217
|
+
now;
|
|
218
|
+
armedUntil = 0;
|
|
219
|
+
disabled = false;
|
|
220
|
+
constructor(windowMs, now = Date.now) {
|
|
221
|
+
this.windowMs = windowMs;
|
|
222
|
+
this.now = now;
|
|
223
|
+
}
|
|
224
|
+
/** Open (or slide) the demand window from now. A no-op while disabled. */
|
|
225
|
+
arm() {
|
|
226
|
+
if (this.windowMs === 0) return;
|
|
227
|
+
this.armedUntil = this.now() + this.windowMs;
|
|
228
|
+
}
|
|
229
|
+
/**
|
|
230
|
+
* Force the gate closed regardless of demand — for a download path that has
|
|
231
|
+
* PROVEN broken this dial (an add/receive failure). Rebuilding the vaapi
|
|
232
|
+
* filtergraph per failing frame both leaks (node-av reclaims hw pools only
|
|
233
|
+
* by process exit) and burns GPU churn, so a broken path stays off until
|
|
234
|
+
* {@link reset} (the next dial). Overrides `windowMs: 0` too.
|
|
235
|
+
*/
|
|
236
|
+
disable() {
|
|
237
|
+
this.disabled = true;
|
|
238
|
+
}
|
|
239
|
+
/** New dial: clear the broken flag AND any stale demand (caller re-arms explicitly). */
|
|
240
|
+
reset() {
|
|
241
|
+
this.disabled = false;
|
|
242
|
+
this.armedUntil = 0;
|
|
243
|
+
}
|
|
244
|
+
/** Whether lease capture should run for the current frame. */
|
|
245
|
+
get active() {
|
|
246
|
+
if (this.disabled) return false;
|
|
247
|
+
if (this.windowMs === 0) return true;
|
|
248
|
+
return this.now() < this.armedUntil;
|
|
249
|
+
}
|
|
250
|
+
};
|
|
251
|
+
//#endregion
|
|
192
252
|
//#region src/session-decode/native-frame-ring.ts
|
|
193
253
|
/**
|
|
194
254
|
* A hard-capped, insertion-ordered map from worker frameId → retained frame.
|
|
@@ -408,6 +468,16 @@ var NATIVE_LEASE_TTL_MS = (() => {
|
|
|
408
468
|
return Number.isFinite(raw) && raw > 0 ? Math.floor(raw) : 500;
|
|
409
469
|
})();
|
|
410
470
|
/**
|
|
471
|
+
* Demand window (ms) for the lease-capture {@link LeaseActivityGate}: eager
|
|
472
|
+
* per-frame native downloads run only within this window of the last
|
|
473
|
+
* native-crop request (or dial start). `0` disables gating (legacy always-on
|
|
474
|
+
* eager capture). `CAMSTACK_SESSION_NATIVE_LEASE_ACTIVITY_MS` (default 15000).
|
|
475
|
+
*/
|
|
476
|
+
var NATIVE_LEASE_ACTIVITY_WINDOW_MS = (() => {
|
|
477
|
+
const raw = Number(process.env["CAMSTACK_SESSION_NATIVE_LEASE_ACTIVITY_MS"]);
|
|
478
|
+
return Number.isFinite(raw) && raw >= 0 ? Math.floor(raw) : 15e3;
|
|
479
|
+
})();
|
|
480
|
+
/**
|
|
411
481
|
* The libav GPU scale filter for a hwaccel backend, or `null` when none is
|
|
412
482
|
* known here — those backends fall back to the software crop+scale path.
|
|
413
483
|
* Mirrors `addon-decoder-ffmpeg/src/ffmpeg-args.ts` `gpuScaleFilterForBackend`.
|
|
@@ -660,6 +730,13 @@ var DecodeWorkerChild = class {
|
|
|
660
730
|
ttlMs: NATIVE_LEASE_TTL_MS
|
|
661
731
|
});
|
|
662
732
|
/**
|
|
733
|
+
* Demand gate for lease capture — armed at dial start + on every native-crop
|
|
734
|
+
* request; while cold, {@link captureNativeFrame} declines retention so the
|
|
735
|
+
* per-frame native-res GPU→RAM download (the N100 saturation source) stops
|
|
736
|
+
* on cameras nothing is cropping. See `lease-activity-gate.ts`.
|
|
737
|
+
*/
|
|
738
|
+
leaseGate = new LeaseActivityGate(NATIVE_LEASE_ACTIVITY_WINDOW_MS);
|
|
739
|
+
/**
|
|
663
740
|
* DEDICATED full-frame GPU→system download filtergraph
|
|
664
741
|
* (`scale_<be>=iw:ih,hwdownload,format=nv12,format=yuv420p`) used ONLY to
|
|
665
742
|
* materialize a HW surface into a leasable software frame at NATIVE
|
|
@@ -670,6 +747,10 @@ var DecodeWorkerChild = class {
|
|
|
670
747
|
*/
|
|
671
748
|
nativeLeaseDownloadFilter = null;
|
|
672
749
|
nativeLeaseDownloadFilterKey = "";
|
|
750
|
+
/** Root-cause instrumentation for the sporadic EIO/EINVAL add-frame failures (task: lease-filter EIO). */
|
|
751
|
+
leaseDownloadFilterUses = 0;
|
|
752
|
+
leaseDownloadFilterBuiltAt = 0;
|
|
753
|
+
dialStartedAt = 0;
|
|
673
754
|
/** Throttled native-crop hit/miss counters, emitted with the throughput line. */
|
|
674
755
|
nativeCropHits = 0;
|
|
675
756
|
nativeCropMisses = 0;
|
|
@@ -838,6 +919,7 @@ var DecodeWorkerChild = class {
|
|
|
838
919
|
* session to software on a GPU-filter error).
|
|
839
920
|
*/
|
|
840
921
|
handleNativeCrop(requestId, frameId, bbox, maxWidth) {
|
|
922
|
+
this.leaseGate.arm();
|
|
841
923
|
const frame = this.leaseStore.get(frameId)?.frame ?? this.resolveRetainedFrame(frameId);
|
|
842
924
|
if (!frame) {
|
|
843
925
|
this.nativeCropMisses++;
|
|
@@ -885,6 +967,7 @@ var DecodeWorkerChild = class {
|
|
|
885
967
|
*/
|
|
886
968
|
captureNativeFrame(frameId, frame) {
|
|
887
969
|
if (!this.leaseStore.enabled) return this.nativeRing.retain(frameId, frame);
|
|
970
|
+
if (!this.leaseGate.active) return false;
|
|
888
971
|
if (frame.isHwFrame()) {
|
|
889
972
|
const software = this.downloadToSoftware(frame);
|
|
890
973
|
frame.free();
|
|
@@ -911,7 +994,11 @@ var DecodeWorkerChild = class {
|
|
|
911
994
|
for (let i = 1; i < outputs.length; i++) outputs[i]?.free();
|
|
912
995
|
return first;
|
|
913
996
|
} catch (err) {
|
|
914
|
-
this.emitStderr(`decode-worker-child: native lease download failed — ${errMessage(err)}\n`);
|
|
997
|
+
this.emitStderr(`decode-worker-child: native lease download failed — ${errMessage(err)} [forensics: frame=${frame.width}x${frame.height} fmt=${frame.format} hw=${frame.isHwFrame()} filterUses=${this.leaseDownloadFilterUses} filterAgeMs=${Date.now() - this.leaseDownloadFilterBuiltAt} dialAgeMs=${Date.now() - this.dialStartedAt} decoded=${this.framesDecoded}]\n`);
|
|
998
|
+
this.nativeLeaseDownloadFilter?.close();
|
|
999
|
+
this.nativeLeaseDownloadFilter = null;
|
|
1000
|
+
this.nativeLeaseDownloadFilterKey = "";
|
|
1001
|
+
this.leaseGate.disable();
|
|
915
1002
|
return null;
|
|
916
1003
|
}
|
|
917
1004
|
}
|
|
@@ -919,7 +1006,10 @@ var DecodeWorkerChild = class {
|
|
|
919
1006
|
ensureLeaseDownloadFilter(nav, scaleFilter, srcW, srcH) {
|
|
920
1007
|
const key = `${srcW}x${srcH}`;
|
|
921
1008
|
const cached = this.nativeLeaseDownloadFilter;
|
|
922
|
-
if (cached && key === this.nativeLeaseDownloadFilterKey)
|
|
1009
|
+
if (cached && key === this.nativeLeaseDownloadFilterKey) {
|
|
1010
|
+
this.leaseDownloadFilterUses++;
|
|
1011
|
+
return cached;
|
|
1012
|
+
}
|
|
923
1013
|
this.nativeLeaseDownloadFilter?.close();
|
|
924
1014
|
this.nativeLeaseDownloadFilter = null;
|
|
925
1015
|
this.nativeLeaseDownloadFilterKey = "";
|
|
@@ -927,6 +1017,8 @@ var DecodeWorkerChild = class {
|
|
|
927
1017
|
const filter = nav.FilterAPI.create(description, { hardware: this.hwContext });
|
|
928
1018
|
this.nativeLeaseDownloadFilter = filter;
|
|
929
1019
|
this.nativeLeaseDownloadFilterKey = key;
|
|
1020
|
+
this.leaseDownloadFilterUses = 1;
|
|
1021
|
+
this.leaseDownloadFilterBuiltAt = Date.now();
|
|
930
1022
|
return filter;
|
|
931
1023
|
}
|
|
932
1024
|
/** Map a normalized bbox to an even-aligned pixel crop + (optionally capped) target. */
|
|
@@ -1078,6 +1170,9 @@ var DecodeWorkerChild = class {
|
|
|
1078
1170
|
* Same demuxer options + `exitOnError: false` bad-frame tolerance throughout.
|
|
1079
1171
|
*/
|
|
1080
1172
|
async dialAndDecode(nav, C, url) {
|
|
1173
|
+
this.leaseGate.reset();
|
|
1174
|
+
this.leaseGate.arm();
|
|
1175
|
+
this.dialStartedAt = Date.now();
|
|
1081
1176
|
this.abortController = new AbortController();
|
|
1082
1177
|
const demuxer = await nav.Demuxer.open(url, {
|
|
1083
1178
|
options: buildDemuxerOptions(),
|
|
@@ -185,6 +185,66 @@ var FrameSlot = class {
|
|
|
185
185
|
}
|
|
186
186
|
};
|
|
187
187
|
//#endregion
|
|
188
|
+
//#region src/session-decode/lease-activity-gate.ts
|
|
189
|
+
/**
|
|
190
|
+
* Demand-driven gate for the native-frame lease capture (see
|
|
191
|
+
* `decode-worker-child.ts` `captureNativeFrame`).
|
|
192
|
+
*
|
|
193
|
+
* Eagerly downloading EVERY delivered frame from the GPU at native resolution
|
|
194
|
+
* is sustained memory-bandwidth burn a small host (N100) cannot afford when
|
|
195
|
+
* nothing consumes the leases — live 2026-07-16: dev 584 ran 24 native-4K
|
|
196
|
+
* downloads/s with `nativeCropHits:0` for hours, and two such sessions
|
|
197
|
+
* saturated the box (load ~9 on 4 cores) until delivered fps collapsed to 0.
|
|
198
|
+
*
|
|
199
|
+
* The gate keeps capture ON only while there is plausible demand:
|
|
200
|
+
* - `arm()` at dial start — the FIRST track of a fresh on-motion session gets
|
|
201
|
+
* native-quality media before any crop request has been seen;
|
|
202
|
+
* - `arm()` on every native-crop request — post-analysis snapshot crops and
|
|
203
|
+
* the detail plane re-arm it continuously while tracks are active;
|
|
204
|
+
* - after `windowMs` without demand it closes and per-frame downloads stop
|
|
205
|
+
* (a later crop request simply misses once — the caller's designed
|
|
206
|
+
* detection-frame-crop fallback — and re-arms the gate for the retry).
|
|
207
|
+
*
|
|
208
|
+
* `windowMs: 0` disables gating entirely (always active — the legacy eager
|
|
209
|
+
* behaviour).
|
|
210
|
+
*/
|
|
211
|
+
var LeaseActivityGate = class {
|
|
212
|
+
windowMs;
|
|
213
|
+
now;
|
|
214
|
+
armedUntil = 0;
|
|
215
|
+
disabled = false;
|
|
216
|
+
constructor(windowMs, now = Date.now) {
|
|
217
|
+
this.windowMs = windowMs;
|
|
218
|
+
this.now = now;
|
|
219
|
+
}
|
|
220
|
+
/** Open (or slide) the demand window from now. A no-op while disabled. */
|
|
221
|
+
arm() {
|
|
222
|
+
if (this.windowMs === 0) return;
|
|
223
|
+
this.armedUntil = this.now() + this.windowMs;
|
|
224
|
+
}
|
|
225
|
+
/**
|
|
226
|
+
* Force the gate closed regardless of demand — for a download path that has
|
|
227
|
+
* PROVEN broken this dial (an add/receive failure). Rebuilding the vaapi
|
|
228
|
+
* filtergraph per failing frame both leaks (node-av reclaims hw pools only
|
|
229
|
+
* by process exit) and burns GPU churn, so a broken path stays off until
|
|
230
|
+
* {@link reset} (the next dial). Overrides `windowMs: 0` too.
|
|
231
|
+
*/
|
|
232
|
+
disable() {
|
|
233
|
+
this.disabled = true;
|
|
234
|
+
}
|
|
235
|
+
/** New dial: clear the broken flag AND any stale demand (caller re-arms explicitly). */
|
|
236
|
+
reset() {
|
|
237
|
+
this.disabled = false;
|
|
238
|
+
this.armedUntil = 0;
|
|
239
|
+
}
|
|
240
|
+
/** Whether lease capture should run for the current frame. */
|
|
241
|
+
get active() {
|
|
242
|
+
if (this.disabled) return false;
|
|
243
|
+
if (this.windowMs === 0) return true;
|
|
244
|
+
return this.now() < this.armedUntil;
|
|
245
|
+
}
|
|
246
|
+
};
|
|
247
|
+
//#endregion
|
|
188
248
|
//#region src/session-decode/native-frame-ring.ts
|
|
189
249
|
/**
|
|
190
250
|
* A hard-capped, insertion-ordered map from worker frameId → retained frame.
|
|
@@ -404,6 +464,16 @@ var NATIVE_LEASE_TTL_MS = (() => {
|
|
|
404
464
|
return Number.isFinite(raw) && raw > 0 ? Math.floor(raw) : 500;
|
|
405
465
|
})();
|
|
406
466
|
/**
|
|
467
|
+
* Demand window (ms) for the lease-capture {@link LeaseActivityGate}: eager
|
|
468
|
+
* per-frame native downloads run only within this window of the last
|
|
469
|
+
* native-crop request (or dial start). `0` disables gating (legacy always-on
|
|
470
|
+
* eager capture). `CAMSTACK_SESSION_NATIVE_LEASE_ACTIVITY_MS` (default 15000).
|
|
471
|
+
*/
|
|
472
|
+
var NATIVE_LEASE_ACTIVITY_WINDOW_MS = (() => {
|
|
473
|
+
const raw = Number(process.env["CAMSTACK_SESSION_NATIVE_LEASE_ACTIVITY_MS"]);
|
|
474
|
+
return Number.isFinite(raw) && raw >= 0 ? Math.floor(raw) : 15e3;
|
|
475
|
+
})();
|
|
476
|
+
/**
|
|
407
477
|
* The libav GPU scale filter for a hwaccel backend, or `null` when none is
|
|
408
478
|
* known here — those backends fall back to the software crop+scale path.
|
|
409
479
|
* Mirrors `addon-decoder-ffmpeg/src/ffmpeg-args.ts` `gpuScaleFilterForBackend`.
|
|
@@ -656,6 +726,13 @@ var DecodeWorkerChild = class {
|
|
|
656
726
|
ttlMs: NATIVE_LEASE_TTL_MS
|
|
657
727
|
});
|
|
658
728
|
/**
|
|
729
|
+
* Demand gate for lease capture — armed at dial start + on every native-crop
|
|
730
|
+
* request; while cold, {@link captureNativeFrame} declines retention so the
|
|
731
|
+
* per-frame native-res GPU→RAM download (the N100 saturation source) stops
|
|
732
|
+
* on cameras nothing is cropping. See `lease-activity-gate.ts`.
|
|
733
|
+
*/
|
|
734
|
+
leaseGate = new LeaseActivityGate(NATIVE_LEASE_ACTIVITY_WINDOW_MS);
|
|
735
|
+
/**
|
|
659
736
|
* DEDICATED full-frame GPU→system download filtergraph
|
|
660
737
|
* (`scale_<be>=iw:ih,hwdownload,format=nv12,format=yuv420p`) used ONLY to
|
|
661
738
|
* materialize a HW surface into a leasable software frame at NATIVE
|
|
@@ -666,6 +743,10 @@ var DecodeWorkerChild = class {
|
|
|
666
743
|
*/
|
|
667
744
|
nativeLeaseDownloadFilter = null;
|
|
668
745
|
nativeLeaseDownloadFilterKey = "";
|
|
746
|
+
/** Root-cause instrumentation for the sporadic EIO/EINVAL add-frame failures (task: lease-filter EIO). */
|
|
747
|
+
leaseDownloadFilterUses = 0;
|
|
748
|
+
leaseDownloadFilterBuiltAt = 0;
|
|
749
|
+
dialStartedAt = 0;
|
|
669
750
|
/** Throttled native-crop hit/miss counters, emitted with the throughput line. */
|
|
670
751
|
nativeCropHits = 0;
|
|
671
752
|
nativeCropMisses = 0;
|
|
@@ -834,6 +915,7 @@ var DecodeWorkerChild = class {
|
|
|
834
915
|
* session to software on a GPU-filter error).
|
|
835
916
|
*/
|
|
836
917
|
handleNativeCrop(requestId, frameId, bbox, maxWidth) {
|
|
918
|
+
this.leaseGate.arm();
|
|
837
919
|
const frame = this.leaseStore.get(frameId)?.frame ?? this.resolveRetainedFrame(frameId);
|
|
838
920
|
if (!frame) {
|
|
839
921
|
this.nativeCropMisses++;
|
|
@@ -881,6 +963,7 @@ var DecodeWorkerChild = class {
|
|
|
881
963
|
*/
|
|
882
964
|
captureNativeFrame(frameId, frame) {
|
|
883
965
|
if (!this.leaseStore.enabled) return this.nativeRing.retain(frameId, frame);
|
|
966
|
+
if (!this.leaseGate.active) return false;
|
|
884
967
|
if (frame.isHwFrame()) {
|
|
885
968
|
const software = this.downloadToSoftware(frame);
|
|
886
969
|
frame.free();
|
|
@@ -907,7 +990,11 @@ var DecodeWorkerChild = class {
|
|
|
907
990
|
for (let i = 1; i < outputs.length; i++) outputs[i]?.free();
|
|
908
991
|
return first;
|
|
909
992
|
} catch (err) {
|
|
910
|
-
this.emitStderr(`decode-worker-child: native lease download failed — ${errMessage(err)}\n`);
|
|
993
|
+
this.emitStderr(`decode-worker-child: native lease download failed — ${errMessage(err)} [forensics: frame=${frame.width}x${frame.height} fmt=${frame.format} hw=${frame.isHwFrame()} filterUses=${this.leaseDownloadFilterUses} filterAgeMs=${Date.now() - this.leaseDownloadFilterBuiltAt} dialAgeMs=${Date.now() - this.dialStartedAt} decoded=${this.framesDecoded}]\n`);
|
|
994
|
+
this.nativeLeaseDownloadFilter?.close();
|
|
995
|
+
this.nativeLeaseDownloadFilter = null;
|
|
996
|
+
this.nativeLeaseDownloadFilterKey = "";
|
|
997
|
+
this.leaseGate.disable();
|
|
911
998
|
return null;
|
|
912
999
|
}
|
|
913
1000
|
}
|
|
@@ -915,7 +1002,10 @@ var DecodeWorkerChild = class {
|
|
|
915
1002
|
ensureLeaseDownloadFilter(nav, scaleFilter, srcW, srcH) {
|
|
916
1003
|
const key = `${srcW}x${srcH}`;
|
|
917
1004
|
const cached = this.nativeLeaseDownloadFilter;
|
|
918
|
-
if (cached && key === this.nativeLeaseDownloadFilterKey)
|
|
1005
|
+
if (cached && key === this.nativeLeaseDownloadFilterKey) {
|
|
1006
|
+
this.leaseDownloadFilterUses++;
|
|
1007
|
+
return cached;
|
|
1008
|
+
}
|
|
919
1009
|
this.nativeLeaseDownloadFilter?.close();
|
|
920
1010
|
this.nativeLeaseDownloadFilter = null;
|
|
921
1011
|
this.nativeLeaseDownloadFilterKey = "";
|
|
@@ -923,6 +1013,8 @@ var DecodeWorkerChild = class {
|
|
|
923
1013
|
const filter = nav.FilterAPI.create(description, { hardware: this.hwContext });
|
|
924
1014
|
this.nativeLeaseDownloadFilter = filter;
|
|
925
1015
|
this.nativeLeaseDownloadFilterKey = key;
|
|
1016
|
+
this.leaseDownloadFilterUses = 1;
|
|
1017
|
+
this.leaseDownloadFilterBuiltAt = Date.now();
|
|
926
1018
|
return filter;
|
|
927
1019
|
}
|
|
928
1020
|
/** Map a normalized bbox to an even-aligned pixel crop + (optionally capped) target. */
|
|
@@ -1074,6 +1166,9 @@ var DecodeWorkerChild = class {
|
|
|
1074
1166
|
* Same demuxer options + `exitOnError: false` bad-frame tolerance throughout.
|
|
1075
1167
|
*/
|
|
1076
1168
|
async dialAndDecode(nav, C, url) {
|
|
1169
|
+
this.leaseGate.reset();
|
|
1170
|
+
this.leaseGate.arm();
|
|
1171
|
+
this.dialStartedAt = Date.now();
|
|
1077
1172
|
this.abortController = new AbortController();
|
|
1078
1173
|
const demuxer = await nav.Demuxer.open(url, {
|
|
1079
1174
|
options: buildDemuxerOptions(),
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { S as hfModelUrl, a as COCO_TO_MACRO, i as COCO_80_LABELS, r as AUDIO_MACRO_LABELS } from "./dist-
|
|
1
|
+
import { S as hfModelUrl, a as COCO_TO_MACRO, i as COCO_80_LABELS, r as AUDIO_MACRO_LABELS } from "./dist-CnwwDzX3.mjs";
|
|
2
2
|
//#region src/detection-pipeline/registry/model-catalogs.ts
|
|
3
3
|
var HF_REPO = "camstack/camstack-models";
|
|
4
4
|
var HF_SCRYPTED = "scrypted/plugin-models";
|
|
@@ -3,7 +3,7 @@ import "./dist-CYZr2fwk.mjs";
|
|
|
3
3
|
var e = {
|
|
4
4
|
"@camstack/sdk": {
|
|
5
5
|
name: "@camstack/sdk",
|
|
6
|
-
version: "1.1.
|
|
6
|
+
version: "1.1.25",
|
|
7
7
|
scope: ["default"],
|
|
8
8
|
loaded: !1,
|
|
9
9
|
from: "addon_stream_broker_widgets",
|
|
@@ -18,7 +18,7 @@ var e = {
|
|
|
18
18
|
},
|
|
19
19
|
"@camstack/types": {
|
|
20
20
|
name: "@camstack/types",
|
|
21
|
-
version: "1.1.
|
|
21
|
+
version: "1.1.46",
|
|
22
22
|
scope: ["default"],
|
|
23
23
|
loaded: !1,
|
|
24
24
|
from: "addon_stream_broker_widgets",
|
|
@@ -33,7 +33,7 @@ var e = {
|
|
|
33
33
|
},
|
|
34
34
|
"@camstack/ui-library": {
|
|
35
35
|
name: "@camstack/ui-library",
|
|
36
|
-
version: "1.1.
|
|
36
|
+
version: "1.1.37",
|
|
37
37
|
scope: ["default"],
|
|
38
38
|
loaded: !1,
|
|
39
39
|
from: "addon_stream_broker_widgets",
|
|
@@ -36,7 +36,7 @@ async function r() {
|
|
|
36
36
|
}
|
|
37
37
|
},
|
|
38
38
|
"@camstack/types": {
|
|
39
|
-
version: "1.1.
|
|
39
|
+
version: "1.1.46",
|
|
40
40
|
scope: "default",
|
|
41
41
|
shareConfig: {
|
|
42
42
|
singleton: !0,
|
|
@@ -45,7 +45,7 @@ async function r() {
|
|
|
45
45
|
}
|
|
46
46
|
},
|
|
47
47
|
"@camstack/sdk": {
|
|
48
|
-
version: "1.1.
|
|
48
|
+
version: "1.1.25",
|
|
49
49
|
scope: "default",
|
|
50
50
|
shareConfig: {
|
|
51
51
|
singleton: !0,
|
|
@@ -81,7 +81,7 @@ async function r() {
|
|
|
81
81
|
}
|
|
82
82
|
},
|
|
83
83
|
"@camstack/ui-library": {
|
|
84
|
-
version: "1.1.
|
|
84
|
+
version: "1.1.37",
|
|
85
85
|
scope: "default",
|
|
86
86
|
shareConfig: {
|
|
87
87
|
singleton: !0,
|
|
@@ -3,7 +3,7 @@ Object.defineProperties(exports, {
|
|
|
3
3
|
[Symbol.toStringTag]: { value: "Module" }
|
|
4
4
|
});
|
|
5
5
|
const require_chunk = require("../chunk-D6vf50IK.js");
|
|
6
|
-
const require_dist = require("../dist-
|
|
6
|
+
const require_dist = require("../dist-Bn6Uq4vq.js");
|
|
7
7
|
const require_remote_restream = require("../remote-restream-CO36Sr30.js");
|
|
8
8
|
const require_model_download_service_C_IHWnXx = require("../model-download-service-C-IHWnXx-D326YNnt.js");
|
|
9
9
|
let node_child_process = require("node:child_process");
|
|
@@ -14379,8 +14379,9 @@ var StreamBrokerManager = class StreamBrokerManager {
|
|
|
14379
14379
|
const keep = new Set(descriptors.map((d) => d.camStreamId));
|
|
14380
14380
|
await this.publishCatalog(deviceId, descriptors);
|
|
14381
14381
|
const existing = this.cameraStreams.get(deviceId);
|
|
14382
|
-
if (existing) {
|
|
14383
|
-
|
|
14382
|
+
if (existing) for (const [camStreamId, cam] of Array.from(existing.entries())) {
|
|
14383
|
+
if (cam.kind === "derived") continue;
|
|
14384
|
+
if (!keep.has(camStreamId)) await this.retractCameraStream({
|
|
14384
14385
|
deviceId,
|
|
14385
14386
|
camStreamId
|
|
14386
14387
|
});
|
|
@@ -19123,7 +19124,7 @@ var WebrtcSessionProvider = class WebrtcSessionProvider {
|
|
|
19123
19124
|
const streamingDebug = this.resolveSessionDebug(input.deviceId);
|
|
19124
19125
|
const transcodeProfile = this.resolveTranscodeProfile(input.deviceId, camStreamId);
|
|
19125
19126
|
try {
|
|
19126
|
-
return await this.webrtcServer.handleOffer(streamId, input.sdpOffer,
|
|
19127
|
+
return await this.webrtcServer.handleOffer(streamId, input.sdpOffer, input.hints, {
|
|
19127
19128
|
streamingDebug,
|
|
19128
19129
|
sessionId: input.sessionId,
|
|
19129
19130
|
relayOnly: input.relayOnly === true,
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { t as __require } from "../chunk-BdkLduGY.mjs";
|
|
2
|
-
import { $ as
|
|
2
|
+
import { $ as discriminatedUnion, B as DeviceType, D as nodePin, F as webrtcSessionCapability, G as makeSourceBrokerId, I as errMsg, L as BaseAddon, N as streamBrokerCapability, Q as boolean, R as CAM_PROFILE_ORDER, U as isEvent, V as createEvent, W as makeProfileBrokerId, X as _enum, Z as array, at as string, c as EncodeProfileSchema, d as RingBuffer, g as cameraStreamsCapability, it as record, nt as number, ot as union, p as addonWidgetsSourceCapability, q as parseProfileBrokerId, rt as object, st as EventCategory, tt as literal, w as maskUrlCredentials, z as DeviceFeature } from "../dist-CnwwDzX3.mjs";
|
|
3
3
|
import { n as profileForStreamId } from "../remote-restream-BeHi78PZ.mjs";
|
|
4
4
|
import { t as createFileDataPlaneHandler } from "../model-download-service-C-IHWnXx-3Mmeob3l.mjs";
|
|
5
5
|
import { createRequire } from "node:module";
|
|
@@ -14374,8 +14374,9 @@ var StreamBrokerManager = class StreamBrokerManager {
|
|
|
14374
14374
|
const keep = new Set(descriptors.map((d) => d.camStreamId));
|
|
14375
14375
|
await this.publishCatalog(deviceId, descriptors);
|
|
14376
14376
|
const existing = this.cameraStreams.get(deviceId);
|
|
14377
|
-
if (existing) {
|
|
14378
|
-
|
|
14377
|
+
if (existing) for (const [camStreamId, cam] of Array.from(existing.entries())) {
|
|
14378
|
+
if (cam.kind === "derived") continue;
|
|
14379
|
+
if (!keep.has(camStreamId)) await this.retractCameraStream({
|
|
14379
14380
|
deviceId,
|
|
14380
14381
|
camStreamId
|
|
14381
14382
|
});
|
|
@@ -19118,7 +19119,7 @@ var WebrtcSessionProvider = class WebrtcSessionProvider {
|
|
|
19118
19119
|
const streamingDebug = this.resolveSessionDebug(input.deviceId);
|
|
19119
19120
|
const transcodeProfile = this.resolveTranscodeProfile(input.deviceId, camStreamId);
|
|
19120
19121
|
try {
|
|
19121
|
-
return await this.webrtcServer.handleOffer(streamId, input.sdpOffer,
|
|
19122
|
+
return await this.webrtcServer.handleOffer(streamId, input.sdpOffer, input.hints, {
|
|
19122
19123
|
streamingDebug,
|
|
19123
19124
|
sessionId: input.sessionId,
|
|
19124
19125
|
relayOnly: input.relayOnly === true,
|
|
@@ -30,7 +30,7 @@ async function d(e) {
|
|
|
30
30
|
}
|
|
31
31
|
}
|
|
32
32
|
async function f() {
|
|
33
|
-
return l ||= d(() => import("./_virtual_mf-localSharedImportMap___mfe_internal__addon_stream_broker_widgets-
|
|
33
|
+
return l ||= d(() => import("./_virtual_mf-localSharedImportMap___mfe_internal__addon_stream_broker_widgets-B8FQ1e0a.mjs")).catch((e) => {
|
|
34
34
|
throw l = void 0, e;
|
|
35
35
|
}), l;
|
|
36
36
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{d as e,f as t,g as n,h as r,m as i,p as a}from"./index-
|
|
1
|
+
import{d as e,f as t,g as n,h as r,m as i,p as a}from"./index-BxqQ931j.js";var o=n(t()),s=n(e(),1),c=Math.PI/180;function l(){return typeof window<`u`&&({}.toString.call(window)===`[object Window]`||{}.toString.call(window)===`[object global]`)}var u=typeof global<`u`?global:typeof window<`u`?window:typeof WorkerGlobalScope<`u`?self:{},d={_global:u,version:`10.3.0`,isBrowser:l(),isUnminified:/param/.test(function(e){}.toString()),dblClickWindow:400,getAngle(e){return d.angleDeg?e*c:e},enableTrace:!1,pointerEventsEnabled:!0,autoDrawEnabled:!0,hitOnDragEnabled:!1,capturePointerEventsEnabled:!1,_mouseListenClick:!1,_touchListenClick:!1,_pointerListenClick:!1,_mouseInDblClickWindow:!1,_touchInDblClickWindow:!1,_pointerInDblClickWindow:!1,_mouseDblClickPointerId:null,_touchDblClickPointerId:null,_pointerDblClickPointerId:null,_renderBackend:`web`,legacyTextRendering:!1,pixelRatio:typeof window<`u`&&window.devicePixelRatio||1,dragDistance:3,angleDeg:!0,showWarnings:!0,dragButtons:[0,1],isDragging(){return d.DD.isDragging},isTransforming(){return d.Transformer?.isTransforming()??!1},isDragReady(){return!!d.DD.node},releaseCanvasOnDestroy:!0,document:u.document,_injectGlobal(e){u.Konva!==void 0&&console.error(`Several Konva instances detected. It is not recommended to use multiple Konva instances in the same environment.`),u.Konva=e}},f=e=>{d[e.prototype.getClassName()]=e};d._injectGlobal(d);var p=`Konva.js unsupported environment.
|
|
2
2
|
|
|
3
3
|
Looks like you are trying to use Konva.js in Node.js environment. because "document" object is undefined.
|
|
4
4
|
|