@camstack/addon-pipeline 1.2.212 → 1.2.214
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 +2 -2
- package/dist/audio-analyzer/index.mjs +2 -2
- package/dist/{default-detection-model-6FmFzp0X.mjs → default-detection-model-C2vYSX3O.mjs} +1 -1
- package/dist/{default-detection-model-CXpC8UoM.js → default-detection-model-f0PImZnh.js} +1 -1
- package/dist/detection-pipeline/index.js +5 -5
- package/dist/detection-pipeline/index.mjs +4 -4
- package/dist/{dist-B-MeGV6o.js → dist-DoHcimdu.js} +205 -2
- package/dist/{dist-C-elKxbr.mjs → dist-DttqKvsQ.mjs} +205 -2
- package/dist/{lazy-sharp-xDAJscmd.js → lazy-sharp-BeeQGCUu.js} +1 -1
- package/dist/motion-wasm/index.js +2 -2
- package/dist/motion-wasm/index.mjs +1 -1
- package/dist/{node-DPduceDa.js → node-6uF72wri.js} +1 -1
- package/dist/{node-DIRnjf_L.mjs → node-NtM7__8q.mjs} +1 -1
- package/dist/pipeline-runner/index.js +213 -24
- package/dist/pipeline-runner/index.mjs +212 -23
- package/dist/{process-memory-CUYuwW7H.js → process-memory-BRdyl5fE.js} +1 -1
- package/dist/{process-memory-CJ8yC9r_.mjs → process-memory-CddpCDWL.mjs} +1 -1
- package/dist/recorder/index.js +4 -2
- package/dist/recorder/index.mjs +4 -2
- package/dist/{segment-demux-js-CXXWV0Ph.js → segment-demux-js-CkJPdyDH.js} +1 -1
- package/dist/{segment-demux-js-BhBboAO1.mjs → segment-demux-js-CsFtPVzH.mjs} +1 -1
- package/dist/session-decode/decode-worker-child.js +319 -8
- package/dist/session-decode/decode-worker-child.mjs +318 -7
- package/dist/stream-broker/_stub.js +2 -2
- package/dist/stream-broker/{_virtual_mf-localSharedImportMap___mfe_internal__addon_stream_broker_widgets-NrRAP0ec.mjs → _virtual_mf-localSharedImportMap___mfe_internal__addon_stream_broker_widgets-CbBa4iV-.mjs} +3 -3
- package/dist/stream-broker/_virtual_mf___mfe_internal__addon_stream_broker_widgets__loadShare___mf_0_camstack_mf_1_types__loadShare__.js-0MF-KL1v.mjs +26 -0
- package/dist/stream-broker/{_virtual_mf___mfe_internal__addon_stream_broker_widgets__loadShare___mf_0_camstack_mf_1_ui_mf_2_library__loadShare__.js-LoLVfRky.mjs → _virtual_mf___mfe_internal__addon_stream_broker_widgets__loadShare___mf_0_camstack_mf_1_ui_mf_2_library__loadShare__.js-Uxkwkgy5.mjs} +1 -1
- package/dist/stream-broker/demux-worker-child.js +1 -1
- package/dist/stream-broker/demux-worker-child.mjs +1 -1
- package/dist/stream-broker/{hostInit-BxCqSqXk.mjs → hostInit-CagSUJH7.mjs} +3 -3
- package/dist/stream-broker/index.js +3 -3
- package/dist/stream-broker/index.mjs +3 -3
- package/dist/stream-broker/remoteEntry.js +1 -1
- package/dist/{worker-protocol-C0mDH3xS.mjs → worker-protocol-BKwkLZWT.mjs} +5 -2
- package/dist/{worker-protocol-DMNMfs2E.js → worker-protocol-BWO2WNjw.js} +5 -2
- package/package.json +1 -1
- package/dist/stream-broker/_virtual_mf___mfe_internal__addon_stream_broker_widgets__loadShare___mf_0_camstack_mf_1_types__loadShare__.js-Cw3x0dZG.mjs +0 -26
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { $ as failureContributionCapability, It as errMsg, Qt as nodePin, R as customAction, U as deriveDetailCropRect, Ut as BaseAddon, V as defineCustomActions, _ as FailureCounters, _t as pickDetailCropConvention, an as boolean, bt as pipelineRunnerCapability, cn as literal, hn as EventCategory, in as array, it as loadContributionCapability, ln as number, m as DEVICE_BACKEND_TO_FORMAT, p as DEFAULT_NATIVE_LEASE_SETTINGS, pn as string, qt as createEvent, rn as _enum, sn as lazy, u as DEFAULT_DETAIL_CROP_CONVENTION, un as object, vt as pickNativeLeaseOverride } from "../dist-
|
|
2
|
-
import { i as NO_COST_CLAIM, t as ChildCostRegistry } from "../node-
|
|
3
|
-
import { i as resolveFrameViewGeometry, l as getStepDefinition, r as localFrameRegistry } from "../default-detection-model-
|
|
4
|
-
import { a as nativeLeaseSettingEnv, t as isWorkerReply } from "../worker-protocol-
|
|
1
|
+
import { $ as failureContributionCapability, It as errMsg, Qt as nodePin, R as customAction, U as deriveDetailCropRect, Ut as BaseAddon, V as defineCustomActions, _ as FailureCounters, _t as pickDetailCropConvention, an as boolean, bt as pipelineRunnerCapability, cn as literal, hn as EventCategory, in as array, it as loadContributionCapability, ln as number, m as DEVICE_BACKEND_TO_FORMAT, p as DEFAULT_NATIVE_LEASE_SETTINGS, pn as string, qt as createEvent, rn as _enum, sn as lazy, u as DEFAULT_DETAIL_CROP_CONVENTION, un as object, vt as pickNativeLeaseOverride } from "../dist-DttqKvsQ.mjs";
|
|
2
|
+
import { i as NO_COST_CLAIM, t as ChildCostRegistry } from "../node-NtM7__8q.mjs";
|
|
3
|
+
import { i as resolveFrameViewGeometry, l as getStepDefinition, r as localFrameRegistry } from "../default-detection-model-C2vYSX3O.mjs";
|
|
4
|
+
import { a as nativeLeaseSettingEnv, t as isWorkerReply } from "../worker-protocol-BKwkLZWT.mjs";
|
|
5
5
|
import { t as resolveHubHostname } from "../hub-hostname-cCknRYKj.mjs";
|
|
6
6
|
import { t as getSharp } from "../lazy-sharp-DXsqwpph.mjs";
|
|
7
7
|
import { a as preRollRequestOf, o as withDetectionIntent, t as DETECTION_PRE_ROLL_REQUEST_MS } from "../restream-intent-DWe2kInY.mjs";
|
|
@@ -1004,6 +1004,7 @@ var SessionDecodeSession = class {
|
|
|
1004
1004
|
frameTimeoutMs;
|
|
1005
1005
|
firstFrameMaxWaitMs;
|
|
1006
1006
|
onDialTiming;
|
|
1007
|
+
onPreRollReport;
|
|
1007
1008
|
pendingPull = null;
|
|
1008
1009
|
pendingToBuffers = /* @__PURE__ */ new Map();
|
|
1009
1010
|
/** Outstanding `nativeCrop` requests, keyed by the monotonic `requestId`. */
|
|
@@ -1017,7 +1018,7 @@ var SessionDecodeSession = class {
|
|
|
1017
1018
|
firstFrameReceived = false;
|
|
1018
1019
|
/** `Date.now()` of the FIRST `pull` — the origin of the cold-start ceiling. */
|
|
1019
1020
|
firstPullAt = 0;
|
|
1020
|
-
constructor(child, logger, deviceId, firstFrameTimeoutMs, frameTimeoutMs, firstFrameMaxWaitMs, onDialTiming) {
|
|
1021
|
+
constructor(child, logger, deviceId, firstFrameTimeoutMs, frameTimeoutMs, firstFrameMaxWaitMs, onDialTiming, onPreRollReport) {
|
|
1021
1022
|
this.child = child;
|
|
1022
1023
|
this.logger = logger;
|
|
1023
1024
|
this.deviceId = deviceId;
|
|
@@ -1025,6 +1026,7 @@ var SessionDecodeSession = class {
|
|
|
1025
1026
|
this.frameTimeoutMs = frameTimeoutMs;
|
|
1026
1027
|
this.firstFrameMaxWaitMs = firstFrameMaxWaitMs;
|
|
1027
1028
|
this.onDialTiming = onDialTiming;
|
|
1029
|
+
this.onPreRollReport = onPreRollReport;
|
|
1028
1030
|
this.child.on("message", (m) => this.handleMessage(m));
|
|
1029
1031
|
this.child.on("exit", (m) => this.handleExit(toWorkerExitInfo(m)));
|
|
1030
1032
|
}
|
|
@@ -1215,6 +1217,17 @@ var SessionDecodeSession = class {
|
|
|
1215
1217
|
streamInfoProbed: raw.streamInfoProbed
|
|
1216
1218
|
});
|
|
1217
1219
|
return;
|
|
1220
|
+
case "preRollReport":
|
|
1221
|
+
this.onPreRollReport?.({
|
|
1222
|
+
offered: raw.offered,
|
|
1223
|
+
inferred: raw.inferred,
|
|
1224
|
+
dropped: raw.dropped,
|
|
1225
|
+
droppedByReason: raw.droppedByReason,
|
|
1226
|
+
strideMs: raw.strideMs,
|
|
1227
|
+
subsampled: raw.subsampled,
|
|
1228
|
+
spanMs: raw.spanMs
|
|
1229
|
+
});
|
|
1230
|
+
return;
|
|
1218
1231
|
}
|
|
1219
1232
|
}
|
|
1220
1233
|
handleExit(info) {
|
|
@@ -1439,7 +1452,7 @@ function createSessionDecodeCoordinator(deps) {
|
|
|
1439
1452
|
const frameTimeoutMs = deps.frameTimeoutMs ?? DEFAULT_FRAME_TIMEOUT_MS;
|
|
1440
1453
|
const firstFrameMaxWaitMs = Math.max(deps.firstFrameMaxWaitMs ?? DEFAULT_FIRST_FRAME_MAX_WAIT_MS, firstFrameTimeoutMs);
|
|
1441
1454
|
return { async *generateVideoFrames(source, opts) {
|
|
1442
|
-
const session = new SessionDecodeSession(deps.fork(source), deps.logger, source.deviceId, firstFrameTimeoutMs, frameTimeoutMs, firstFrameMaxWaitMs, deps.onDialTiming);
|
|
1455
|
+
const session = new SessionDecodeSession(deps.fork(source), deps.logger, source.deviceId, firstFrameTimeoutMs, frameTimeoutMs, firstFrameMaxWaitMs, deps.onDialTiming, deps.onPreRollReport);
|
|
1443
1456
|
session.start(source, opts);
|
|
1444
1457
|
try {
|
|
1445
1458
|
while (true) {
|
|
@@ -1448,7 +1461,9 @@ function createSessionDecodeCoordinator(deps) {
|
|
|
1448
1461
|
const { reply } = outcome;
|
|
1449
1462
|
yield {
|
|
1450
1463
|
timestamp: reply.timestamp,
|
|
1451
|
-
image: buildFrameImage(session, reply)
|
|
1464
|
+
image: buildFrameImage(session, reply),
|
|
1465
|
+
...reply.capturedAt !== void 0 ? { capturedAt: reply.capturedAt } : {},
|
|
1466
|
+
...reply.preRoll === true ? { preRoll: true } : {}
|
|
1452
1467
|
};
|
|
1453
1468
|
}
|
|
1454
1469
|
} finally {
|
|
@@ -1462,10 +1477,18 @@ function createSessionDecodeCoordinator(deps) {
|
|
|
1462
1477
|
* Build a {@link DecodedFrame} from one pulled {@link VideoFrame}. Downscales to
|
|
1463
1478
|
* the detection working width (see {@link resolveWorkingResize}) so the ROI
|
|
1464
1479
|
* scaler ships a small frame instead of the full source resolution.
|
|
1465
|
-
* `capturedAt` is
|
|
1466
|
-
*
|
|
1467
|
-
*
|
|
1468
|
-
*
|
|
1480
|
+
* `capturedAt` is the frame's OWN moment: the worker's media clock when it has
|
|
1481
|
+
* one (`media-clock.ts`), else `Date.now()` as before, so downstream frameAge
|
|
1482
|
+
* metrics keep diffing against the wall clock (mirroring the shm-ring source,
|
|
1483
|
+
* which stamps commit time) — this is what lets Step 5 MEASURE session-decode
|
|
1484
|
+
* frameAge vs the shm-ring cameras.
|
|
1485
|
+
*
|
|
1486
|
+
* The fallback is deliberate and must stay: a `Date.now()` here for a frame
|
|
1487
|
+
* replayed out of ~4 s of retained history would date its detections, its
|
|
1488
|
+
* track's `firstSeen`, its media and the notification's instant at SESSION
|
|
1489
|
+
* OPEN. That is a silently wrong timestamp — nothing downstream can tell it
|
|
1490
|
+
* from a right one — and it is a worse failure than the late birth the pre-roll
|
|
1491
|
+
* pass exists to fix.
|
|
1469
1492
|
*/
|
|
1470
1493
|
async function toDecodedFrame(frame, format, viewSpec) {
|
|
1471
1494
|
const geometry = viewSpec ? resolveFrameViewGeometry(frame.image.width, frame.image.height, viewSpec) : void 0;
|
|
@@ -1480,7 +1503,8 @@ async function toDecodedFrame(frame, format, viewSpec) {
|
|
|
1480
1503
|
height: geometry?.output.height ?? frame.image.height,
|
|
1481
1504
|
format: viewSpec?.format ?? format,
|
|
1482
1505
|
timestamp: frame.timestamp,
|
|
1483
|
-
capturedAt: Date.now()
|
|
1506
|
+
capturedAt: frame.capturedAt ?? Date.now(),
|
|
1507
|
+
...frame.preRoll === true ? { preRoll: true } : {}
|
|
1484
1508
|
};
|
|
1485
1509
|
}
|
|
1486
1510
|
/**
|
|
@@ -1501,7 +1525,8 @@ function startSessionDecodePump(deps) {
|
|
|
1501
1525
|
dialTiming = timing;
|
|
1502
1526
|
},
|
|
1503
1527
|
...deps.firstFrameTimeoutMs !== void 0 ? { firstFrameTimeoutMs: deps.firstFrameTimeoutMs } : {},
|
|
1504
|
-
...deps.frameTimeoutMs !== void 0 ? { frameTimeoutMs: deps.frameTimeoutMs } : {}
|
|
1528
|
+
...deps.frameTimeoutMs !== void 0 ? { frameTimeoutMs: deps.frameTimeoutMs } : {},
|
|
1529
|
+
...deps.onPreRollReport ? { onPreRollReport: deps.onPreRollReport } : {}
|
|
1505
1530
|
}).generateVideoFrames(deps.source, deps.opts);
|
|
1506
1531
|
let stopped = false;
|
|
1507
1532
|
let releaseSpawnSlot = null;
|
|
@@ -1543,7 +1568,7 @@ function startSessionDecodePump(deps) {
|
|
|
1543
1568
|
}
|
|
1544
1569
|
let imageOwnershipTransferred = false;
|
|
1545
1570
|
try {
|
|
1546
|
-
if (deps.shouldMaterializeFrame && !deps.shouldMaterializeFrame()) continue;
|
|
1571
|
+
if (deps.shouldMaterializeFrame && !deps.shouldMaterializeFrame(frame.preRoll === true)) continue;
|
|
1547
1572
|
const image = frame.image;
|
|
1548
1573
|
const cropFn = image.nativeCrop;
|
|
1549
1574
|
const nativeCrop = cropFn ? Object.assign((bbox, maxWidth) => cropFn(bbox, maxWidth), {
|
|
@@ -1552,7 +1577,7 @@ function startSessionDecodePump(deps) {
|
|
|
1552
1577
|
markInferred: () => image.markInferred?.()
|
|
1553
1578
|
}) : void 0;
|
|
1554
1579
|
if (deps.frameRegistry && deps.onFrameRef && deps.inlineWhen?.() !== true) {
|
|
1555
|
-
const capturedAt = Date.now();
|
|
1580
|
+
const capturedAt = frame.capturedAt ?? Date.now();
|
|
1556
1581
|
const ref = deps.frameRegistry.register(image, {
|
|
1557
1582
|
timestamp: frame.timestamp,
|
|
1558
1583
|
capturedAt
|
|
@@ -1566,7 +1591,8 @@ function startSessionDecodePump(deps) {
|
|
|
1566
1591
|
format: ref.format,
|
|
1567
1592
|
timestamp: ref.timestamp,
|
|
1568
1593
|
capturedAt,
|
|
1569
|
-
frameRef: ref
|
|
1594
|
+
frameRef: ref,
|
|
1595
|
+
...frame.preRoll === true ? { preRoll: true } : {}
|
|
1570
1596
|
};
|
|
1571
1597
|
try {
|
|
1572
1598
|
if (!await deps.onFrameRef(lazyFrame, nativeCrop)) deps.frameRegistry.release(ref, "drop");
|
|
@@ -4696,6 +4722,44 @@ function ownFrame(frame) {
|
|
|
4696
4722
|
};
|
|
4697
4723
|
}
|
|
4698
4724
|
//#endregion
|
|
4725
|
+
//#region src/pipeline-runner/pre-roll-lane.ts
|
|
4726
|
+
var PreRollLane = class {
|
|
4727
|
+
items = [];
|
|
4728
|
+
capacity;
|
|
4729
|
+
clone;
|
|
4730
|
+
dispose;
|
|
4731
|
+
_refused = 0;
|
|
4732
|
+
constructor(options) {
|
|
4733
|
+
this.capacity = Math.max(0, options.capacity);
|
|
4734
|
+
this.clone = options.clone;
|
|
4735
|
+
this.dispose = options.dispose;
|
|
4736
|
+
}
|
|
4737
|
+
/** Append one entry. `false` ⇒ the lane is full and the caller must log it. */
|
|
4738
|
+
enqueue(item) {
|
|
4739
|
+
if (this.items.length >= this.capacity) {
|
|
4740
|
+
this._refused++;
|
|
4741
|
+
return false;
|
|
4742
|
+
}
|
|
4743
|
+
this.items.push(this.clone(item));
|
|
4744
|
+
return true;
|
|
4745
|
+
}
|
|
4746
|
+
/** Oldest first — the point of the lane. */
|
|
4747
|
+
dequeue() {
|
|
4748
|
+
return this.items.shift();
|
|
4749
|
+
}
|
|
4750
|
+
get size() {
|
|
4751
|
+
return this.items.length;
|
|
4752
|
+
}
|
|
4753
|
+
/** Entries refused because the lane was full, for the session's report line. */
|
|
4754
|
+
get refused() {
|
|
4755
|
+
return this._refused;
|
|
4756
|
+
}
|
|
4757
|
+
clear() {
|
|
4758
|
+
for (const item of this.items) this.dispose?.(item);
|
|
4759
|
+
this.items.length = 0;
|
|
4760
|
+
}
|
|
4761
|
+
};
|
|
4762
|
+
//#endregion
|
|
4699
4763
|
//#region src/pipeline-runner/semaphore.ts
|
|
4700
4764
|
/**
|
|
4701
4765
|
* Counting semaphore with FIFO waiter queue. Used by the runner to bound
|
|
@@ -5014,8 +5078,6 @@ var PipelineTimingSampler = class {
|
|
|
5014
5078
|
this.audioSamples.clear();
|
|
5015
5079
|
}
|
|
5016
5080
|
};
|
|
5017
|
-
//#endregion
|
|
5018
|
-
//#region src/pipeline-runner/runner.ts
|
|
5019
5081
|
/**
|
|
5020
5082
|
* Bound on one `processFrame` call. Chosen well above the slowest legitimate
|
|
5021
5083
|
* inference seen in production (8 617 ms, GPU contention on the hub) so the
|
|
@@ -5190,6 +5252,14 @@ var PipelineRunner = class {
|
|
|
5190
5252
|
registration,
|
|
5191
5253
|
motionQueue,
|
|
5192
5254
|
detectionQueue,
|
|
5255
|
+
preRollQueue: new PreRollLane({
|
|
5256
|
+
capacity: this.config.maxPreRollQueueDepth ?? 12,
|
|
5257
|
+
clone: ownDetectionEntry,
|
|
5258
|
+
dispose: (entry) => {
|
|
5259
|
+
if (entry.handle) this.config.releaseRetention?.(entry.handle, "drop");
|
|
5260
|
+
if (entry.frame.frameRef) this.config.releaseFrameRef?.(entry.frame.frameRef, "drop");
|
|
5261
|
+
}
|
|
5262
|
+
}),
|
|
5193
5263
|
inferenceTimes: [],
|
|
5194
5264
|
shedFrames: 0,
|
|
5195
5265
|
inflight: 0,
|
|
@@ -5236,6 +5306,7 @@ var PipelineRunner = class {
|
|
|
5236
5306
|
if (state.phase === "active") this.detectionStreamHandler?.(deviceId, "unsubscribe");
|
|
5237
5307
|
state.motionQueue.clear();
|
|
5238
5308
|
state.detectionQueue.clear();
|
|
5309
|
+
state.preRollQueue.clear();
|
|
5239
5310
|
this.timingSampler.clearDroppedFramesSource(deviceId);
|
|
5240
5311
|
this.cameras.delete(deviceId);
|
|
5241
5312
|
this.lastAdmittedAt.delete(deviceId);
|
|
@@ -5317,6 +5388,59 @@ var PipelineRunner = class {
|
|
|
5317
5388
|
maxInflightPerCamera: cap
|
|
5318
5389
|
};
|
|
5319
5390
|
}
|
|
5391
|
+
/**
|
|
5392
|
+
* Queue one PRE-ROLL frame — a frame decoded out of the restreamer's retained
|
|
5393
|
+
* history at session open, carrying its own capture moment
|
|
5394
|
+
* (`session-decode/media-clock.ts`), not the moment it was decoded.
|
|
5395
|
+
*
|
|
5396
|
+
* Deliberately NOT routed through {@link reserveDetectionFrame}: that gate
|
|
5397
|
+
* paces on WALL CLOCK, and a catch-up burst delivers seconds of media inside
|
|
5398
|
+
* milliseconds of wall clock, so the governor would reject the whole burst
|
|
5399
|
+
* bar one frame. The burst's own bound is a MEDIA-time stride applied
|
|
5400
|
+
* upstream, under an explicit frame + wall-clock budget
|
|
5401
|
+
* (`session-decode/pre-roll-burst.ts`); by the time a frame reaches here it
|
|
5402
|
+
* has already been chosen.
|
|
5403
|
+
*
|
|
5404
|
+
* `false` means the lane is full or the camera is not taking detection
|
|
5405
|
+
* frames. The caller LOGS that: a burst silently truncated by the lane and a
|
|
5406
|
+
* burst that fit read identically otherwise, and this is a branch that drops
|
|
5407
|
+
* work.
|
|
5408
|
+
*/
|
|
5409
|
+
enqueuePreRollFrame(deviceId, frame, handle) {
|
|
5410
|
+
const state = this.cameras.get(deviceId);
|
|
5411
|
+
if (!state || state.phase !== "active") return false;
|
|
5412
|
+
return state.preRollQueue.enqueue({
|
|
5413
|
+
frame,
|
|
5414
|
+
handle
|
|
5415
|
+
});
|
|
5416
|
+
}
|
|
5417
|
+
/**
|
|
5418
|
+
* Whether one more history frame would be taken. Asked BEFORE pixels are
|
|
5419
|
+
* materialized so a burst that has already filled the lane costs no RGB
|
|
5420
|
+
* conversion, no IPC and no retention work — the same pixel-free discipline
|
|
5421
|
+
* the live path gets from `reserveDetectionFrame`.
|
|
5422
|
+
*/
|
|
5423
|
+
preRollLaneAccepting(deviceId) {
|
|
5424
|
+
const state = this.cameras.get(deviceId);
|
|
5425
|
+
if (!state || state.phase !== "active") return false;
|
|
5426
|
+
return state.preRollQueue.size < (this.config.maxPreRollQueueDepth ?? 12);
|
|
5427
|
+
}
|
|
5428
|
+
/** Frames of history waiting for a spare permit, for the session report line. */
|
|
5429
|
+
preRollQueueDepth(deviceId) {
|
|
5430
|
+
return this.cameras.get(deviceId)?.preRollQueue.size ?? 0;
|
|
5431
|
+
}
|
|
5432
|
+
/** Frames this camera lane REFUSED because it was full. */
|
|
5433
|
+
preRollRefusedCount(deviceId) {
|
|
5434
|
+
return this.cameras.get(deviceId)?.preRollQueue.refused ?? 0;
|
|
5435
|
+
}
|
|
5436
|
+
/**
|
|
5437
|
+
* Whether the node has a permit to spare for history right now — i.e. one
|
|
5438
|
+
* would still be free after the burst took one. See
|
|
5439
|
+
* {@link PRE_ROLL_PERMIT_RESERVE}.
|
|
5440
|
+
*/
|
|
5441
|
+
preRollDispatchable() {
|
|
5442
|
+
return this.semaphore.available > 1;
|
|
5443
|
+
}
|
|
5320
5444
|
enqueueReservedDetectionFrame(deviceId, frame, handle) {
|
|
5321
5445
|
const state = this.cameras.get(deviceId);
|
|
5322
5446
|
if (!state || state.phase !== "active") return false;
|
|
@@ -5747,7 +5871,7 @@ var PipelineRunner = class {
|
|
|
5747
5871
|
entry: state.detectionQueue.dequeue(),
|
|
5748
5872
|
state
|
|
5749
5873
|
};
|
|
5750
|
-
if (this.defaultRoundRobinKeys.length === 0) return
|
|
5874
|
+
if (this.defaultRoundRobinKeys.length === 0) return this.pickNextPreRollFrame();
|
|
5751
5875
|
const startIndex = this.defaultRoundRobinIndex;
|
|
5752
5876
|
for (let i = 0; i < this.defaultRoundRobinKeys.length; i++) {
|
|
5753
5877
|
const idx = (startIndex + i) % this.defaultRoundRobinKeys.length;
|
|
@@ -5766,6 +5890,30 @@ var PipelineRunner = class {
|
|
|
5766
5890
|
};
|
|
5767
5891
|
}
|
|
5768
5892
|
}
|
|
5893
|
+
return this.pickNextPreRollFrame();
|
|
5894
|
+
}
|
|
5895
|
+
/**
|
|
5896
|
+
* The catch-up lane, reached ONLY after every camera's live queue came back
|
|
5897
|
+
* empty. That ordering IS the priority rule: a live frame is always picked
|
|
5898
|
+
* first, so a pre-roll frame can never delay one — and the burst simply
|
|
5899
|
+
* stops progressing while the camera is busy, which is the correct behaviour
|
|
5900
|
+
* for one-shot work whose value does not decay.
|
|
5901
|
+
*/
|
|
5902
|
+
pickNextPreRollFrame() {
|
|
5903
|
+
if (!this.preRollDispatchable()) return null;
|
|
5904
|
+
for (const [deviceId, state] of this.cameras) {
|
|
5905
|
+
if (state.phase !== "active") continue;
|
|
5906
|
+
if (state.preRollQueue.size === 0) continue;
|
|
5907
|
+
if (state.detectionQueue.size > 0) continue;
|
|
5908
|
+
if (state.inflight >= this.maxInflightPerCamera()) continue;
|
|
5909
|
+
const entry = state.preRollQueue.dequeue();
|
|
5910
|
+
if (!entry) continue;
|
|
5911
|
+
return {
|
|
5912
|
+
deviceId,
|
|
5913
|
+
entry,
|
|
5914
|
+
state
|
|
5915
|
+
};
|
|
5916
|
+
}
|
|
5769
5917
|
return null;
|
|
5770
5918
|
}
|
|
5771
5919
|
};
|
|
@@ -8569,10 +8717,23 @@ var PipelineRunnerAddon = class PipelineRunnerAddon extends BaseAddon {
|
|
|
8569
8717
|
/** Attach → first decoded detection frame, one line per attach. See
|
|
8570
8718
|
* {@link FirstDetectionFrameTimer}. */
|
|
8571
8719
|
firstDetectionFrame = new FirstDetectionFrameTimer();
|
|
8720
|
+
/**
|
|
8721
|
+
* Frames this camera's pre-roll catch-up burst may send to inference.
|
|
8722
|
+
*
|
|
8723
|
+
* The switch and the budget are ONE number here on purpose: `false` and
|
|
8724
|
+
* `0` mean the same thing to every layer below (no burst is constructed, the
|
|
8725
|
+
* history is decoded to reach a GOP and then discarded exactly as it was
|
|
8726
|
+
* before D411), and two independent ways to say it is two ways to disagree.
|
|
8727
|
+
*/
|
|
8728
|
+
preRollBudgetFor(config) {
|
|
8729
|
+
if (!config.preRollInferenceEnabled) return 0;
|
|
8730
|
+
const frames = config.preRollInferenceFrames;
|
|
8731
|
+
return Number.isFinite(frames) && frames > 0 ? frames : 0;
|
|
8732
|
+
}
|
|
8572
8733
|
enqueueSharedDetectionFrame(deviceId, frame, handle, reservation) {
|
|
8573
8734
|
const runner = this.runner;
|
|
8574
8735
|
if (!runner) return false;
|
|
8575
|
-
const admitted = reservation ? reservation.detection && runner.enqueueReservedDetectionFrame(deviceId, frame, handle) : runner.enqueueDetectionFrame(deviceId, frame, handle);
|
|
8736
|
+
const admitted = frame.preRoll === true ? runner.enqueuePreRollFrame(deviceId, frame, handle) : reservation ? reservation.detection && runner.enqueueReservedDetectionFrame(deviceId, frame, handle) : runner.enqueueDetectionFrame(deviceId, frame, handle);
|
|
8576
8737
|
if (admitted) {
|
|
8577
8738
|
const latencyMs = this.firstDetectionFrame.takeLatency(deviceId, Date.now());
|
|
8578
8739
|
if (latencyMs !== null) this.ctx?.logger.info("session-decode: first detection frame after attach", {
|
|
@@ -8690,9 +8851,19 @@ var PipelineRunnerAddon = class PipelineRunnerAddon extends BaseAddon {
|
|
|
8690
8851
|
source,
|
|
8691
8852
|
opts: {
|
|
8692
8853
|
fps: config.detectionFps,
|
|
8693
|
-
format: "rgb"
|
|
8854
|
+
format: "rgb",
|
|
8855
|
+
preRollMs: preRollRequestOf(source.restreamUrl),
|
|
8856
|
+
preRollMaxFrames: this.preRollBudgetFor(config)
|
|
8694
8857
|
},
|
|
8695
|
-
shouldMaterializeFrame: () => {
|
|
8858
|
+
shouldMaterializeFrame: (preRoll) => {
|
|
8859
|
+
if (preRoll) {
|
|
8860
|
+
const accepting = runner.preRollLaneAccepting(config.deviceId);
|
|
8861
|
+
reservation = {
|
|
8862
|
+
detection: accepting,
|
|
8863
|
+
motion: false
|
|
8864
|
+
};
|
|
8865
|
+
return accepting;
|
|
8866
|
+
}
|
|
8696
8867
|
reservation = this.reserveSharedDetectionFrame(config.deviceId);
|
|
8697
8868
|
const materialize = reservation.detection || reservation.motion;
|
|
8698
8869
|
this.retention?.noteFrame({
|
|
@@ -8726,7 +8897,7 @@ var PipelineRunnerAddon = class PipelineRunnerAddon extends BaseAddon {
|
|
|
8726
8897
|
materialized: false,
|
|
8727
8898
|
workerToRunnerBytes: 0
|
|
8728
8899
|
});
|
|
8729
|
-
const admitted = current.detection && runner.enqueueReservedDetectionFrame(config.deviceId, frame, handle);
|
|
8900
|
+
const admitted = current.detection && (frame.preRoll === true ? runner.enqueuePreRollFrame(config.deviceId, frame, handle) : runner.enqueueReservedDetectionFrame(config.deviceId, frame, handle));
|
|
8730
8901
|
if (admitted) nativeCrop?.markInferred();
|
|
8731
8902
|
if (current.motion) {
|
|
8732
8903
|
const motion = await resolveMotionFrameView(localFrameRegistry, frame.frameRef);
|
|
@@ -8743,6 +8914,24 @@ var PipelineRunnerAddon = class PipelineRunnerAddon extends BaseAddon {
|
|
|
8743
8914
|
}
|
|
8744
8915
|
} : { inlineViewSpec: SPLIT_DETECTION_VIEW },
|
|
8745
8916
|
acquireSpawnSlot: this.buildDecodeSpawnAcquire(log, "detect"),
|
|
8917
|
+
onPreRollReport: (report) => {
|
|
8918
|
+
log.info("session-decode: pre-roll catch-up burst", {
|
|
8919
|
+
tags: { deviceId: config.deviceId },
|
|
8920
|
+
meta: {
|
|
8921
|
+
streamId: config.detectionStreamId,
|
|
8922
|
+
requestedMs: preRollRequestOf(source.restreamUrl),
|
|
8923
|
+
spanMs: report.spanMs,
|
|
8924
|
+
offered: report.offered,
|
|
8925
|
+
inferred: report.inferred,
|
|
8926
|
+
dropped: report.dropped,
|
|
8927
|
+
droppedByReason: report.droppedByReason,
|
|
8928
|
+
strideMs: report.strideMs,
|
|
8929
|
+
subsampled: report.subsampled,
|
|
8930
|
+
laneRefused: runner.preRollRefusedCount(config.deviceId),
|
|
8931
|
+
budgetFrames: this.preRollBudgetFor(config)
|
|
8932
|
+
}
|
|
8933
|
+
});
|
|
8934
|
+
},
|
|
8746
8935
|
onFirstFrame: (timing) => {
|
|
8747
8936
|
const phaseActiveAt = this.lastMotionAt.get(config.deviceId);
|
|
8748
8937
|
log.info("session-decode: detection first frame", {
|
package/dist/recorder/index.js
CHANGED
|
@@ -2,8 +2,8 @@ Object.defineProperties(exports, {
|
|
|
2
2
|
__esModule: { value: true },
|
|
3
3
|
[Symbol.toStringTag]: { value: "Module" }
|
|
4
4
|
});
|
|
5
|
-
const require_dist = require("../dist-
|
|
6
|
-
const require_node = require("../node-
|
|
5
|
+
const require_dist = require("../dist-DoHcimdu.js");
|
|
6
|
+
const require_node = require("../node-6uF72wri.js");
|
|
7
7
|
const require_hub_hostname = require("../hub-hostname-DAJXlOgV.js");
|
|
8
8
|
const require_restream_intent = require("../restream-intent-B1Difcnq.js");
|
|
9
9
|
const require_event_loop_stall_monitor = require("../event-loop-stall-monitor-DaUBcb13.js");
|
|
@@ -10468,6 +10468,8 @@ Object.freeze({
|
|
|
10468
10468
|
"pipelineEnabled": true,
|
|
10469
10469
|
"zones": [],
|
|
10470
10470
|
"onboardMotionDrivesAnalyzer": true,
|
|
10471
|
+
"preRollInferenceEnabled": true,
|
|
10472
|
+
"preRollInferenceFrames": 12,
|
|
10471
10473
|
"occupancyRecheckEnabled": true,
|
|
10472
10474
|
"occupancyRecheckSec": 300,
|
|
10473
10475
|
"occupancyRecheckFrames": 4,
|
package/dist/recorder/index.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { At as storageEvictableCapability, Ct as recordingSignalCapability, D as RecordingSignalStatusSchema, E as RecordingConfigSchema, Et as resolveLocationMode, Gt as DeviceFeature, H as deriveBatteryPresence, It as errMsg, Jt as hydrateSchema, Kt as DeviceType, Nt as stripRetiredBandPreBufferSec, Ot as resolveRecordingProfiles, P as batteryCapability, Q as evictionPolicyOfLocation, Qt as nodePin, R as customAction, St as recordingExportCapability, T as RECORDING_EXPORT_MAX_READ_BYTES, Ut as BaseAddon, V as defineCustomActions, W as deriveRecordingMode, Y as evaluateSensorEdge, Z as evictionPolicyForMode, an as boolean, ct as mayReadLocation, d as DEFAULT_EVENTS_BAND_BUFFER_SEC, dn as preprocess, dt as modeMayWrite, et as gbToBytes, fn as record, g as ExportRecordSchema, hn as EventCategory, i as BatteryStatusSchema, in as array, it as loadContributionCapability, jt as storageOccupancyCapability, ln as number, lt as mayWriteToLocation, nn as sleep$1, pn as string, rn as _enum, rt as isFirstLevelMacroClass, tn as selectAssignedProfileSlots, un as object, ut as migrateLegacyDeviceSignalConfig, x as OpsLogEntrySchema, xt as recordingCapability } from "../dist-
|
|
2
|
-
import { a as physicalRootOf, i as NO_COST_CLAIM, t as ChildCostRegistry } from "../node-
|
|
1
|
+
import { At as storageEvictableCapability, Ct as recordingSignalCapability, D as RecordingSignalStatusSchema, E as RecordingConfigSchema, Et as resolveLocationMode, Gt as DeviceFeature, H as deriveBatteryPresence, It as errMsg, Jt as hydrateSchema, Kt as DeviceType, Nt as stripRetiredBandPreBufferSec, Ot as resolveRecordingProfiles, P as batteryCapability, Q as evictionPolicyOfLocation, Qt as nodePin, R as customAction, St as recordingExportCapability, T as RECORDING_EXPORT_MAX_READ_BYTES, Ut as BaseAddon, V as defineCustomActions, W as deriveRecordingMode, Y as evaluateSensorEdge, Z as evictionPolicyForMode, an as boolean, ct as mayReadLocation, d as DEFAULT_EVENTS_BAND_BUFFER_SEC, dn as preprocess, dt as modeMayWrite, et as gbToBytes, fn as record, g as ExportRecordSchema, hn as EventCategory, i as BatteryStatusSchema, in as array, it as loadContributionCapability, jt as storageOccupancyCapability, ln as number, lt as mayWriteToLocation, nn as sleep$1, pn as string, rn as _enum, rt as isFirstLevelMacroClass, tn as selectAssignedProfileSlots, un as object, ut as migrateLegacyDeviceSignalConfig, x as OpsLogEntrySchema, xt as recordingCapability } from "../dist-DttqKvsQ.mjs";
|
|
2
|
+
import { a as physicalRootOf, i as NO_COST_CLAIM, t as ChildCostRegistry } from "../node-NtM7__8q.mjs";
|
|
3
3
|
import { t as resolveHubHostname } from "../hub-hostname-cCknRYKj.mjs";
|
|
4
4
|
import { c as PREBUFFER_MAX_MS, r as RECORDING_PRE_ROLL_REQUEST_MS, s as withRecordingIntent } from "../restream-intent-DWe2kInY.mjs";
|
|
5
5
|
import { n as startEventLoopStallMonitor } from "../event-loop-stall-monitor-DXLNBMkY.mjs";
|
|
@@ -10462,6 +10462,8 @@ Object.freeze({
|
|
|
10462
10462
|
"pipelineEnabled": true,
|
|
10463
10463
|
"zones": [],
|
|
10464
10464
|
"onboardMotionDrivesAnalyzer": true,
|
|
10465
|
+
"preRollInferenceEnabled": true,
|
|
10466
|
+
"preRollInferenceFrames": 12,
|
|
10465
10467
|
"occupancyRecheckEnabled": true,
|
|
10466
10468
|
"occupancyRecheckSec": 300,
|
|
10467
10469
|
"occupancyRecheckFrames": 4,
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
const require_dist = require("./dist-
|
|
1
|
+
const require_dist = require("./dist-DoHcimdu.js");
|
|
2
2
|
let node_child_process = require("node:child_process");
|
|
3
3
|
//#region ../../node_modules/mp4box/dist/mp4box.all.js
|
|
4
4
|
var require_mp4box_all = /* @__PURE__ */ require_dist.__commonJSMin(((exports) => {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { r as __toESM, t as __commonJSMin } from "./chunk-DnnnRqeS.mjs";
|
|
2
|
-
import { It as errMsg } from "./dist-
|
|
2
|
+
import { It as errMsg } from "./dist-DttqKvsQ.mjs";
|
|
3
3
|
import { spawn } from "node:child_process";
|
|
4
4
|
//#region ../../node_modules/mp4box/dist/mp4box.all.js
|
|
5
5
|
var require_mp4box_all = /* @__PURE__ */ __commonJSMin(((exports) => {
|