@camstack/addon-pipeline 1.2.326 → 1.2.328

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.
Files changed (39) hide show
  1. package/THIRD_PARTY_MODELS.md +49 -43
  2. package/dist/audio-analyzer/index.js +2 -2
  3. package/dist/audio-analyzer/index.mjs +2 -2
  4. package/dist/{default-detection-model-WnGDQAQh.js → default-detection-model-1SadEKsW.js} +120 -61
  5. package/dist/{default-detection-model-Bu4So71h.mjs → default-detection-model-CMeVTcPZ.mjs} +120 -61
  6. package/dist/detection-pipeline/index.js +49 -9
  7. package/dist/detection-pipeline/index.mjs +49 -9
  8. package/dist/{dist-BuU8Y4o1.mjs → dist-Bpub2VcJ.mjs} +584 -396
  9. package/dist/{dist-BTBbIGSC.js → dist-wJO7mXeO.js} +631 -395
  10. package/dist/motion-wasm/index.js +1 -1
  11. package/dist/motion-wasm/index.mjs +1 -1
  12. package/dist/{node-UK2v2ZSw.js → node-BCrqaejt.js} +1 -1
  13. package/dist/{node-inZFYgkm.mjs → node-BjCSgD4M.mjs} +1 -1
  14. package/dist/pipeline-runner/index.js +253 -87
  15. package/dist/pipeline-runner/index.mjs +253 -88
  16. package/dist/{process-memory-DbSOL63T.mjs → process-memory-BaKQ8u2G.mjs} +1 -1
  17. package/dist/{process-memory-BfDlwJc4.js → process-memory-iUJuTpXs.js} +1 -1
  18. package/dist/recorder/index.js +9 -8
  19. package/dist/recorder/index.mjs +9 -8
  20. package/dist/{segment-demux-js-CMj020zz.mjs → segment-demux-js-C5ez9LYG.mjs} +1 -1
  21. package/dist/{segment-demux-js-C1GXgxZ0.js → segment-demux-js-Opx6Hv9G.js} +1 -1
  22. package/dist/session-decode/decode-worker-main.js +13 -21
  23. package/dist/session-decode/decode-worker-main.mjs +13 -21
  24. package/dist/stream-broker/_stub.js +1 -1
  25. package/dist/stream-broker/{_virtual_mf-localSharedImportMap___mfe_internal__addon_stream_broker_widgets-qHD9Dl1z.mjs → _virtual_mf-localSharedImportMap___mfe_internal__addon_stream_broker_widgets-B94LgsV0.mjs} +3 -3
  26. package/dist/stream-broker/_virtual_mf___mfe_internal__addon_stream_broker_widgets__loadShare___mf_0_camstack_mf_1_types__loadShare__.js-BPWYf4_O.mjs +26 -0
  27. package/dist/stream-broker/demux-worker-child.js +1 -1
  28. package/dist/stream-broker/demux-worker-child.mjs +1 -1
  29. package/dist/stream-broker/{hostInit-BgWrKrQn.mjs → hostInit-xOx7AvgW.mjs} +3 -3
  30. package/dist/stream-broker/index.js +6 -5
  31. package/dist/stream-broker/index.mjs +6 -5
  32. package/dist/stream-broker/remoteEntry.js +1 -1
  33. package/package.json +1 -1
  34. package/python/inference_pool.py +38 -121
  35. package/python/postprocessors/scrfd.py +2 -0
  36. package/python/postprocessors/test_bird_edgetpu.py +124 -0
  37. package/python/postprocessors/testdata/bird_classifier_int8_outputs.json +1 -0
  38. package/python/test_inference_pool_static_batch.py +2 -4
  39. package/dist/stream-broker/_virtual_mf___mfe_internal__addon_stream_broker_widgets__loadShare___mf_0_camstack_mf_1_types__loadShare__.js-NkeMtp-v.mjs +0 -26
@@ -1,6 +1,6 @@
1
- import { D as NativeLeaseAdmissionSchema, En as nodePin, Fn as lazy, In as literal, It as pipelineRunnerCapability, Ln as number, Mn as array, Nn as boolean, Nt as pickDetailCropConvention, O as NativeLeaseSettingsSchema, Pt as pickNativeLeaseOverride, Rn as object, Un as EventCategory, Vn as string, a as BackgroundRunRegistry, bn as defineCustomActions, bt as loadContributionCapability, fn as errMsg, ft as failureContributionCapability, g as DEFAULT_DETAIL_CROP_CONVENTION, jn as _enum, mn as BaseAddon, nt as deriveDetailCropRect, q as cameraOwnsMotionViaSensor, v as DEFAULT_NATIVE_LEASE_SETTINGS, vn as createEvent, w as FailureCounters, yn as customAction } from "../dist-BuU8Y4o1.mjs";
2
- import { i as NO_COST_CLAIM, t as ChildCostRegistry } from "../node-inZFYgkm.mjs";
3
- import { c as macroGateVerdict, d as isSessionDecodeReadGone, f as createSessionDecodeCoordinator, l as rootObjectGate, o as placeDetailStep, p as resolveFrameViewGeometry, r as CustomModelCatalog, s as stepsForElectedPool, u as localFrameRegistry, v as getStepDefinition } from "../default-detection-model-Bu4So71h.mjs";
1
+ import { Bn as array, Bt as pickDetailCropConvention, D as FailureCounters, Dn as customAction, Dt as loadContributionCapability, En as createEvent, Et as linkedStepOf, Gn as number, Kn as object, M as NativeLeaseAdmissionSchema, N as NativeLeaseSettingsSchema, On as defineCustomActions, Pn as nodePin, Q as cameraOwnsMotionViaSensor, Qt as resolveLabelLink, Sn as BaseAddon, Un as lazy, Ut as pipelineRunnerCapability, Vn as boolean, Vt as pickNativeLeaseOverride, Wn as literal, Yn as string, Zn as EventCategory, _t as failureContributionCapability, a as BackgroundRunRegistry, bn as errMsg, g as DEFAULT_DETAIL_CROP_CONVENTION, st as deriveDetailCropRect, y as DEFAULT_NATIVE_LEASE_SETTINGS, zn as _enum } from "../dist-Bpub2VcJ.mjs";
2
+ import { i as NO_COST_CLAIM, t as ChildCostRegistry } from "../node-BjCSgD4M.mjs";
3
+ import { _ as getStep, c as macroGateVerdict, d as isSessionDecodeReadGone, f as createSessionDecodeCoordinator, l as rootObjectGate, o as placeDetailStep, p as resolveFrameViewGeometry, r as CustomModelCatalog, s as stepsForElectedPool, u as localFrameRegistry, v as getStepDefinition } from "../default-detection-model-CMeVTcPZ.mjs";
4
4
  import { t as resolveHubHostname } from "../hub-hostname-cCknRYKj.mjs";
5
5
  import { t as getSharp } from "../lazy-sharp-DXsqwpph.mjs";
6
6
  import { c as withDetectionIntent, o as preRollRequestOf, t as DETECTION_PRE_ROLL_REQUEST_MS } from "../restream-intent-DyGmLAU9.mjs";
@@ -896,10 +896,12 @@ function classifyNativeCropLeaseAge(ageMs, maxAgeMs = NATIVE_CROP_LEASE_MAX_AGE_
896
896
  }
897
897
  //#endregion
898
898
  //#region src/session-decode/native-crop-registry.ts
899
- var DEFAULT_NATIVE_CROP_REGISTRY_CAP = (() => {
900
- const raw = Number(process.env["CAMSTACK_NATIVE_CROP_REGISTRY_CAP"]);
901
- return Number.isFinite(raw) && raw > 0 ? Math.floor(raw) : 4096;
902
- })();
899
+ /**
900
+ * Default max entries retained across all active decode sessions on a node
901
+ * (64 → 256 → 4096; see the class doc for the two windows the cap has been
902
+ * sized to).
903
+ */
904
+ var DEFAULT_NATIVE_CROP_REGISTRY_CAP = 4096;
903
905
  /** Invoke a requester's best-effort `release()`, swallowing any transport error. */
904
906
  function safeRelease(request) {
905
907
  try {
@@ -1166,20 +1168,6 @@ function createRetainedContentFallback(registry, ref) {
1166
1168
  }
1167
1169
  } };
1168
1170
  }
1169
- //#endregion
1170
- //#region src/session-decode/parked-frame-store.ts
1171
- /** Per-camera parcel bound. 24 live tracks × two kinds on one camera is a
1172
- * crowd scene; past that the camera's oldest parcel leaves first. Read ONCE
1173
- * from `CAMSTACK_PARKED_FRAMES_PER_DEVICE`. */
1174
- var PARKED_FRAMES_PER_DEVICE_MAX = (() => {
1175
- const raw = Number(process.env["CAMSTACK_PARKED_FRAMES_PER_DEVICE"]);
1176
- return Number.isFinite(raw) && raw > 0 ? Math.floor(raw) : 48;
1177
- })();
1178
- /** {@link PARKED_FRAME_BUDGET_MB} in bytes. */
1179
- var PARKED_FRAME_BUDGET_BYTES = (() => {
1180
- const raw = Number(process.env["CAMSTACK_PARKED_FRAME_MB"]);
1181
- return Number.isFinite(raw) && raw > 0 ? Math.floor(raw) : 64;
1182
- })() * 1024 * 1024;
1183
1171
  function keyOf$1(deviceId, trackId, kind) {
1184
1172
  return `${deviceId}|${trackId}|${kind}`;
1185
1173
  }
@@ -1196,8 +1184,8 @@ var ParkedFrameStore = class {
1196
1184
  perDeviceKeys = /* @__PURE__ */ new Map();
1197
1185
  totalBytes = 0;
1198
1186
  constructor(options = {}) {
1199
- this.budgetBytes = options.budgetBytes ?? PARKED_FRAME_BUDGET_BYTES;
1200
- this.perDeviceMax = options.perDeviceMax ?? PARKED_FRAMES_PER_DEVICE_MAX;
1187
+ this.budgetBytes = options.budgetBytes ?? 67108864;
1188
+ this.perDeviceMax = options.perDeviceMax ?? 48;
1201
1189
  this.maxAgeMs = options.maxAgeMs ?? 6e5;
1202
1190
  this.now = options.now ?? Date.now;
1203
1191
  this.onEvict = options.onEvict;
@@ -1382,47 +1370,6 @@ var PartitionedParkedFrameStore = class {
1382
1370
  this.faceSource.clear();
1383
1371
  }
1384
1372
  };
1385
- /** {@link RETAINED_FRAME_BUDGET_MB} in bytes. */
1386
- var RETAINED_FRAME_BUDGET_BYTES = (() => {
1387
- const raw = Number(process.env["CAMSTACK_SESSION_RETAIN_MB"]);
1388
- return Number.isFinite(raw) && raw > 0 ? Math.floor(raw) : 160;
1389
- })() * 1024 * 1024;
1390
- /**
1391
- * How many of each device's MOST RECENT frames are protected from a busy
1392
- * neighbour's budget eviction. Sized to cover the late two-plane / cross-process
1393
- * enrichment horizon (~150-500 ms) at the REAL delivered rate: the store writes
1394
- * every DELIVERED rgb frame, and a high-fps camera delivers ~25 fps (observed on
1395
- * the 4K outdoor cams), so the old floor of 6 protected only ~240 ms there and
1396
- * its late captures hit "frame recycled before resolve" (2026-07-22 triage —
1397
- * missing thumbnails/firstFrames concentrated on exactly those cameras).
1398
- * 16 frames ≈ 0.64 s @25 fps (1.6 s @10 fps). Only ACTIVE cameras hold frames,
1399
- * so the worst-case protected footprint stays well inside the byte budget for
1400
- * realistic concurrency (4 active cams ≈ 44 MB of 160); the hard ceiling always
1401
- * overrides the floor regardless. Read ONCE from `CAMSTACK_SESSION_RETAIN_FLOOR`;
1402
- * `0` disables the floor (pure global FIFO — the pre-2026-07-19 behaviour).
1403
- */
1404
- var RETAINED_FRAME_PER_DEVICE_FLOOR = (() => {
1405
- const raw = Number(process.env["CAMSTACK_SESSION_RETAIN_FLOOR"]);
1406
- return Number.isFinite(raw) && raw >= 0 ? Math.floor(raw) : 16;
1407
- })();
1408
- /**
1409
- * TIME-based per-device protection (2026-07-23 cold-window fix): a frame
1410
- * YOUNGER than this survives budget eviction regardless of how many frames
1411
- * its device holds. The COUNT floor above protects a fixed number of frames —
1412
- * but the wall-clock window that buys depends on the delivered fps (16 frames
1413
- * = 1.6 s @10 fps but only 0.64 s @25 fps, and the 4K street cams deliver
1414
- * ~25). The late-capture horizon is TIME (session attach + enrichment +
1415
- * round-trip ≈ 0.5–1.5 s, worst on cold on-motion dials), so the guarantee
1416
- * must be time-denominated: 12/13 of the zero-media/missing-firstFrame tracks
1417
- * in the 2026-07-23 audit were ≤6 s cold-session subjects whose handles were
1418
- * recycled before their first captures ran. Bounded by the hard byte ceiling
1419
- * (pass 2) exactly like the count floor — worst case ~26 MB per ACTIVE camera
1420
- * @25 fps. `CAMSTACK_SESSION_RETAIN_FLOOR_MS`; `0` disables (count floor only).
1421
- */
1422
- var RETAINED_FRAME_TIME_FLOOR_MS = (() => {
1423
- const raw = Number(process.env["CAMSTACK_SESSION_RETAIN_FLOOR_MS"]);
1424
- return Number.isFinite(raw) && raw >= 0 ? Math.floor(raw) : 3e3;
1425
- })();
1426
1373
  /** Opaque RAM-key prefix stamped into a retained frame's `FrameHandle.shmId`. */
1427
1374
  var RETAINED_FRAME_KEY_PREFIX = "ram:";
1428
1375
  /** A retention frame is uniquely identified by its key + slot + committed seq. */
@@ -1461,9 +1408,9 @@ var RetainedFrameStore = class RetainedFrameStore {
1461
1408
  static SLOT_SPREAD = 1024;
1462
1409
  constructor(options) {
1463
1410
  this.nodeId = options.nodeId;
1464
- this.budgetBytes = options.budgetBytes ?? RETAINED_FRAME_BUDGET_BYTES;
1465
- this.perDeviceFloor = options.perDeviceFloor ?? RETAINED_FRAME_PER_DEVICE_FLOOR;
1466
- this.timeFloorMs = options.timeFloorMs ?? RETAINED_FRAME_TIME_FLOOR_MS;
1411
+ this.budgetBytes = options.budgetBytes ?? 167772160;
1412
+ this.perDeviceFloor = options.perDeviceFloor ?? 16;
1413
+ this.timeFloorMs = options.timeFloorMs ?? 3e3;
1467
1414
  this.now = options.now ?? Date.now;
1468
1415
  this.onEvict = options.onEvict;
1469
1416
  }
@@ -2022,6 +1969,154 @@ function onboardRootDetections(slot, frame, gate) {
2022
1969
  };
2023
1970
  }
2024
1971
  //#endregion
1972
+ //#region src/pipeline-runner/label-link.ts
1973
+ /**
1974
+ * The runner's half of the detector ↔ step label link (D715).
1975
+ *
1976
+ * The runner holds the camera's WHOLE step tree (the attach config), so it is
1977
+ * the one place that can answer "who writes this effect?" for a camera: the
1978
+ * root model's declaration (`fillsClassifierEffects`) against the filled
1979
+ * step's own `labelLink` policy and class list (`resolveLabelLink`). Three
1980
+ * consumers read that one answer:
1981
+ *
1982
+ * - the frame result — a linked label the executor wrote at score 0 is raised
1983
+ * to the detection's score when the detector is authoritative;
1984
+ * - the `detailSteps` announce — a skipped classifier is announced with
1985
+ * `filledBy`, so post-analysis does not dispatch it for a subject the
1986
+ * detector already named;
1987
+ * - `package-detection` — when the root fills it, the package root is not
1988
+ * dispatched at all and the root's own `package` boxes ARE the package
1989
+ * result (the operator's package threshold moves onto the root's gate, and
1990
+ * the frame says it looked).
1991
+ *
1992
+ * Pure: the caller passes the model resolver; no I/O, no clock.
1993
+ */
1994
+ /** The root step the fills are read from — the always-on camera root. */
1995
+ var LABEL_LINK_ROOT_STEP_ID = "object-detection";
1996
+ var PACKAGE_STEP_ID = "package-detection";
1997
+ var PACKAGE_THRESHOLD_KEY = "minConfidencePackage";
1998
+ var EMPTY_LABEL_LINK_PLAN = { decisions: /* @__PURE__ */ new Map() };
1999
+ function findStep(steps, addonId) {
2000
+ for (const step of steps) {
2001
+ if (step.addonId === addonId) return step;
2002
+ const nested = step.children !== void 0 ? findStep(step.children, addonId) : void 0;
2003
+ if (nested !== void 0) return nested;
2004
+ }
2005
+ }
2006
+ /**
2007
+ * Plan a camera's label links from its configured tree. A root with no pinned
2008
+ * model runs the static default — a COCO model, which fills nothing.
2009
+ */
2010
+ function planLabelLinks(steps, resolveModel) {
2011
+ if (steps === void 0) return EMPTY_LABEL_LINK_PLAN;
2012
+ const root = steps.find((s) => s.addonId === "object-detection" && s.enabled !== false);
2013
+ if (root?.modelId === void 0) return EMPTY_LABEL_LINK_PLAN;
2014
+ const fills = resolveModel("object-detection", root.modelId)?.fillsClassifierEffects ?? [];
2015
+ if (fills.length === 0) return {
2016
+ rootModelId: root.modelId,
2017
+ decisions: /* @__PURE__ */ new Map()
2018
+ };
2019
+ const decisions = /* @__PURE__ */ new Map();
2020
+ for (const fill of fills) {
2021
+ const step = findStep(steps, fill.stepId);
2022
+ decisions.set(fill.stepId, resolveLabelLink(fill, step === void 0 ? void 0 : {
2023
+ enabled: step.enabled !== false,
2024
+ ...step.settings !== void 0 ? { settings: step.settings } : {}
2025
+ }));
2026
+ }
2027
+ return {
2028
+ rootModelId: root.modelId,
2029
+ decisions
2030
+ };
2031
+ }
2032
+ /** Steps this plan says must not be dispatched, with the model that fills them. */
2033
+ function filledStepIds(plan) {
2034
+ const out = /* @__PURE__ */ new Map();
2035
+ if (plan.rootModelId === void 0) return out;
2036
+ for (const [stepId, decision] of plan.decisions) if (decision.skip) out.set(stepId, plan.rootModelId);
2037
+ return out;
2038
+ }
2039
+ function raiseLinkedLabels(detection, plan) {
2040
+ let changed = false;
2041
+ const labels = detection.labels.map((label) => {
2042
+ const stepId = linkedStepOf(label.stepId);
2043
+ if (stepId === void 0 || plan.decisions.get(stepId)?.authoritative !== true) return label;
2044
+ if (label.score === detection.score) return label;
2045
+ changed = true;
2046
+ return {
2047
+ ...label,
2048
+ score: detection.score
2049
+ };
2050
+ });
2051
+ return changed ? labels : void 0;
2052
+ }
2053
+ /**
2054
+ * Raise each linked label to its detection's score where the detector is the
2055
+ * authoritative writer of that effect. Every other linked label stays the
2056
+ * score-0 fallback the executor wrote. Never mutates; returns the input when
2057
+ * nothing changes.
2058
+ */
2059
+ function applyLabelLinkAuthority(result, plan) {
2060
+ if (plan.decisions.size === 0) return result;
2061
+ let changed = false;
2062
+ const detections = result.detections.map((d) => {
2063
+ const labels = raiseLinkedLabels(d, plan);
2064
+ if (labels === void 0) return d;
2065
+ changed = true;
2066
+ return {
2067
+ ...d,
2068
+ labels
2069
+ };
2070
+ });
2071
+ return changed ? {
2072
+ ...result,
2073
+ detections
2074
+ } : result;
2075
+ }
2076
+ /** The root step's schema default for its class allow-list. */
2077
+ function rootDefaultMacroClasses() {
2078
+ const field = getStep(LABEL_LINK_ROOT_STEP_ID).getConfigSchema().find((f) => "key" in f && f.key === "enabledMacroClasses");
2079
+ const value = field !== void 0 && "default" in field ? field.default : void 0;
2080
+ return Array.isArray(value) ? value : [];
2081
+ }
2082
+ function withPackageAdmitted(root, packageStep) {
2083
+ const settings = root.settings ?? {};
2084
+ const stored = settings["enabledMacroClasses"];
2085
+ const enabled = Array.isArray(stored) ? stored : rootDefaultMacroClasses();
2086
+ const admitted = enabled.length > 0 && !enabled.includes("package") ? { enabledMacroClasses: [...enabled, "package"] } : {};
2087
+ const threshold = packageStep.settings?.[PACKAGE_THRESHOLD_KEY];
2088
+ const gate = typeof threshold === "number" ? { [PACKAGE_THRESHOLD_KEY]: threshold } : {};
2089
+ return {
2090
+ ...root,
2091
+ settings: {
2092
+ ...settings,
2093
+ ...admitted,
2094
+ ...gate
2095
+ }
2096
+ };
2097
+ }
2098
+ /**
2099
+ * When the root fills `package-detection` and that step's policy lets it be
2100
+ * skipped, drop the package root from the dispatch and let the camera root
2101
+ * report packages: its gate admits `package` at the package step's threshold.
2102
+ * Otherwise the tree is returned untouched.
2103
+ */
2104
+ function applyPackageFill(steps, plan) {
2105
+ if (plan.decisions.get(PACKAGE_STEP_ID)?.skip !== true) return {
2106
+ steps,
2107
+ filledByRoot: false
2108
+ };
2109
+ const packageStep = steps.find((s) => s.addonId === PACKAGE_STEP_ID);
2110
+ if (packageStep === void 0) return {
2111
+ steps,
2112
+ filledByRoot: false
2113
+ };
2114
+ return {
2115
+ steps: steps.filter((s) => s.addonId !== PACKAGE_STEP_ID).map((s) => s.addonId === "object-detection" && s.enabled !== false ? withPackageAdmitted(s, packageStep) : s),
2116
+ filledByRoot: true
2117
+ };
2118
+ }
2119
+ //#endregion
2025
2120
  //#region src/pipeline-runner/bench-step-schema.ts
2026
2121
  /**
2027
2122
  * Shared bench-facing schemas: the minimal recursive step tree. Extracted from
@@ -4537,9 +4632,9 @@ var PACKAGE_DETECTION_STEP_ID = "package-detection";
4537
4632
  * through) and the frame was not shed. Post-analysis reads it as "an empty
4538
4633
  * doormat on this frame is an ABSENCE, not silence" (D687). Never mutates.
4539
4634
  */
4540
- function withPackageLook(result, dispatched) {
4635
+ function withPackageLook(result, dispatched, filledByRoot = false) {
4541
4636
  if (result.shed === true) return result;
4542
- return dispatched.some((s) => s.addonId === "package-detection" && s.enabled !== false) ? {
4637
+ return filledByRoot || dispatched.some((s) => s.addonId === "package-detection" && s.enabled !== false) ? {
4543
4638
  ...result,
4544
4639
  packageLooked: true
4545
4640
  } : result;
@@ -5925,12 +6020,10 @@ var PipelineRunner = class {
5925
6020
  }, (registration.occupancyRecheckSec ?? 0) * 1e3);
5926
6021
  if (initialPhase === "active") {
5927
6022
  this.detectionStreamHandler?.(deviceId, "subscribe");
5928
- const cooldownMs = registration.motionCooldownMs ?? DEFAULT_MOTION_COOLDOWN_MS;
5929
6023
  this.config.onPhaseChanged?.(deviceId, "active", {
5930
- source: "analyzer",
5931
- regions: void 0,
6024
+ cause: "attach",
5932
6025
  timestamp: Date.now(),
5933
- cooldownMs
6026
+ ...registration.sessionTrigger !== void 0 ? { trigger: registration.sessionTrigger } : {}
5934
6027
  });
5935
6028
  }
5936
6029
  }
@@ -5945,7 +6038,13 @@ var PipelineRunner = class {
5945
6038
  clearInterval(state.occupancyTimer);
5946
6039
  state.occupancyTimer = null;
5947
6040
  }
5948
- if (state.phase === "active") this.detectionStreamHandler?.(deviceId, "unsubscribe");
6041
+ if (state.phase === "active") {
6042
+ this.detectionStreamHandler?.(deviceId, "unsubscribe");
6043
+ this.config.onPhaseChanged?.(deviceId, "watching", {
6044
+ cause: "detach",
6045
+ timestamp: Date.now()
6046
+ });
6047
+ }
5949
6048
  state.motionQueue.clear();
5950
6049
  this.discardQueuedDetectionFrames(deviceId, state, "detach");
5951
6050
  this.timingSampler.clearDroppedFramesSource(deviceId);
@@ -6316,6 +6415,7 @@ var PipelineRunner = class {
6316
6415
  });
6317
6416
  this.detectionStreamHandler?.(deviceId, "subscribe");
6318
6417
  this.config.onPhaseChanged?.(deviceId, "active", {
6418
+ cause: "motion",
6319
6419
  source,
6320
6420
  regions,
6321
6421
  timestamp: Date.now(),
@@ -6337,6 +6437,7 @@ var PipelineRunner = class {
6337
6437
  this.detectionStreamHandler?.(deviceId, "unsubscribe");
6338
6438
  const source = state.lastArmedSource ?? "analyzer";
6339
6439
  this.config.onPhaseChanged?.(deviceId, "watching", {
6440
+ cause: "motion",
6340
6441
  source,
6341
6442
  regions: void 0,
6342
6443
  timestamp: Date.now(),
@@ -7151,6 +7252,25 @@ var DETECTION_REDIAL_GIVEUP_WINDOW_MS = 6e4;
7151
7252
  * NOTHING — see D453 for what that costs and why it was not taken either.
7152
7253
  */
7153
7254
  /**
7255
+ * The source fields a `DetectionPhaseTransition` carries, per cause. A motion
7256
+ * transition: its source and cooldown. A session attach: the motion that opened
7257
+ * it, as the orchestrator dispatched it — absent when it sent none. A detach:
7258
+ * nothing.
7259
+ */
7260
+ function phaseTransitionSourceFields(meta) {
7261
+ if (meta.cause === "motion") return {
7262
+ source: meta.source,
7263
+ cooldownMs: meta.cooldownMs
7264
+ };
7265
+ if (meta.cause === "detach" || meta.trigger === void 0) return {};
7266
+ const { source, triggeredBy, sensorName } = meta.trigger;
7267
+ return {
7268
+ source,
7269
+ triggeredBy,
7270
+ ...sensorName !== void 0 ? { sensorName } : {}
7271
+ };
7272
+ }
7273
+ /**
7154
7274
  * Pure decision helper: returns `true` when a dynamic frame-diff analyzer
7155
7275
  * subscription should be opened for an onboard-motion camera.
7156
7276
  *
@@ -7214,20 +7334,23 @@ function isDetailPlaneStepId(stepId) {
7214
7334
  * Extracted as a pure function so the unit suite can exercise the
7215
7335
  * derivation without instantiating the full addon.
7216
7336
  */
7217
- function deriveDetailSteps(steps) {
7337
+ function deriveDetailSteps(steps, plan = EMPTY_LABEL_LINK_PLAN) {
7218
7338
  const stepIds = /* @__PURE__ */ new Set();
7219
7339
  collectEnabledStepIds(steps, stepIds);
7340
+ const filled = filledStepIds(plan);
7220
7341
  const announces = [];
7221
7342
  for (const stepId of stepIds) {
7222
7343
  const def = tryGetStepDefinition(stepId);
7223
7344
  if (!def || def.inputClasses === null) continue;
7345
+ const filledBy = filled.get(def.id);
7224
7346
  announces.push({
7225
7347
  stepId: def.id,
7226
7348
  inputClasses: def.inputClasses,
7227
7349
  cadence: def.cadence ?? {
7228
7350
  trigger: "once",
7229
7351
  maxPerTrack: 3
7230
- }
7352
+ },
7353
+ ...filledBy !== void 0 ? { filledBy } : {}
7231
7354
  });
7232
7355
  }
7233
7356
  return announces;
@@ -8706,6 +8829,7 @@ var PipelineRunnerAddon = class PipelineRunnerAddon extends BaseAddon {
8706
8829
  runner.registerCamera(config.deviceId, {
8707
8830
  detectionMode: config.detectionMode,
8708
8831
  ...config.detectionSources !== void 0 ? { detectionSources: config.detectionSources } : {},
8832
+ ...config.sessionTrigger !== void 0 ? { sessionTrigger: config.sessionTrigger } : {},
8709
8833
  ...rootObjectGate(config.steps) !== void 0 ? { objectGate: rootObjectGate(config.steps) } : {},
8710
8834
  fps: config.detectionFps,
8711
8835
  motionCooldownMs: config.motionCooldownMs,
@@ -9542,6 +9666,42 @@ var PipelineRunnerAddon = class PipelineRunnerAddon extends BaseAddon {
9542
9666
  * read synchronously by the placement.
9543
9667
  */
9544
9668
  customModels = new CustomModelCatalog({ warn: (message, extras) => this.ctxIfReady?.logger.warn(message, extras) });
9669
+ /**
9670
+ * Per camera, the label-link plan (D715) and the announce derived from it,
9671
+ * keyed on the two inputs it reads: the attach tree and the custom-model
9672
+ * snapshot (a Frigate+ root is a custom model). Recomputed when either
9673
+ * changes identity — at most once per catalog refresh.
9674
+ */
9675
+ labelLinkCache = /* @__PURE__ */ new Map();
9676
+ /** The camera's label-link plan; logs once per change of what is filled. */
9677
+ labelLinkPlanFor(deviceId, steps) {
9678
+ const byStep = this.customModels.current();
9679
+ const cached = this.labelLinkCache.get(deviceId);
9680
+ if (cached !== void 0 && cached.steps === steps && cached.byStep === byStep) return cached.plan;
9681
+ const plan = planLabelLinks(steps, (stepId, modelId) => this.customModels.stepDefinition(stepId)?.models.find((m) => m.id === modelId));
9682
+ const announces = deriveDetailSteps(steps, plan);
9683
+ this.labelLinkCache.set(deviceId, {
9684
+ steps,
9685
+ byStep,
9686
+ plan,
9687
+ announces
9688
+ });
9689
+ const describe = (p) => p === void 0 ? "" : [...p.decisions].map(([id, d]) => `${id}:${d.skip ? "skip" : d.authoritative ? "sole" : "fallback"}`).join(",");
9690
+ if (describe(cached?.plan) !== describe(plan) && plan.decisions.size > 0) this.ctxIfReady?.logger.info("label link: the root model fills pipeline steps", {
9691
+ tags: { deviceId },
9692
+ meta: {
9693
+ rootModelId: plan.rootModelId ?? null,
9694
+ steps: [...plan.decisions].map(([stepId, d]) => ({
9695
+ stepId,
9696
+ policy: d.policy,
9697
+ authoritative: d.authoritative,
9698
+ skip: d.skip,
9699
+ openGaps: d.openGaps
9700
+ }))
9701
+ }
9702
+ });
9703
+ return plan;
9704
+ }
9545
9705
  cropConvention = new CropConventionSource({ logger: {
9546
9706
  info: (message, extras) => this.ctxIfReady?.logger.info(message, extras),
9547
9707
  warn: (message, extras) => this.ctxIfReady?.logger.warn(message, extras)
@@ -9937,6 +10097,7 @@ var PipelineRunnerAddon = class PipelineRunnerAddon extends BaseAddon {
9937
10097
  this.lastDecodeUnexpectedEndAt.delete(deviceId);
9938
10098
  this.packageGovernor.forget(deviceId);
9939
10099
  this.packageGateSkips.delete(deviceId);
10100
+ this.labelLinkCache.delete(deviceId);
9940
10101
  this.packageZoneUnionByDevice.delete(deviceId);
9941
10102
  this.packageZoneUnionAt.delete(deviceId);
9942
10103
  this.lastMotionNearPackageZone.delete(deviceId);
@@ -10333,7 +10494,7 @@ var PipelineRunnerAddon = class PipelineRunnerAddon extends BaseAddon {
10333
10494
  acquire: () => this.acquireSessionDecodeRestream(api, config.deviceId, config.detectionStreamId, `session-decode:detect:${config.deviceId}`, resolveSessionDecodeHostname(config, process.env["CAMSTACK_HUB_URL"]), resolveSessionDecodeOwnerNodeId(config), true),
10334
10495
  startPump: (source, hooks) => {
10335
10496
  const dialMs = Date.now() - requestedAt;
10336
- const useLocalFrameRef = this.executorCoLocated() && process.env["CAMSTACK_DISABLE_LOCAL_FRAME_REF"] !== "1";
10497
+ const useLocalFrameRef = this.executorCoLocated();
10337
10498
  log.info("session-decode: detection routed through per-session decode worker (rgb)", { meta: {
10338
10499
  streamId: config.detectionStreamId,
10339
10500
  codec: source.codec,
@@ -10593,9 +10754,11 @@ var PipelineRunnerAddon = class PipelineRunnerAddon extends BaseAddon {
10593
10754
  * The phase is NOT the camera's motion and writes no `motion` runtime slice
10594
10755
  * (D696). Every on-motion detection session attaches `always-on`, so the
10595
10756
  * phase reads `active` for a whole session, and an always-on camera is
10596
- * `active` for as long as it is attached; a detach writes nothing at all.
10757
+ * `active` for as long as it is attached (`cause: 'attach'`), and returns to
10758
+ * `watching` on detach (`cause: 'detach'`) — neither names a motion source.
10597
10759
  * The slice it used to write was therefore "a session is attached", and was
10598
- * left `detected: true` after every session. The orchestrator is the only
10760
+ * left `detected: true` after every session (the detach close of the EVENT
10761
+ * did not exist either until 2026-10-06). The orchestrator is the only
10599
10762
  * writer of that slice, with the EFFECTIVE motion, and this runner says so
10600
10763
  * on `getLocalLoad().motionSliceWriter` so that it never writes the slice
10601
10764
  * while a runner older than D696 still does.
@@ -10609,8 +10772,8 @@ var PipelineRunnerAddon = class PipelineRunnerAddon extends BaseAddon {
10609
10772
  from: detected ? "watching" : "active",
10610
10773
  to: detected ? "active" : "watching",
10611
10774
  reason: detected ? "motion_detected" : "cooldown_expired",
10612
- source: meta.source,
10613
- cooldownMs: meta.cooldownMs,
10775
+ cause: meta.cause,
10776
+ ...phaseTransitionSourceFields(meta),
10614
10777
  timestamp: meta.timestamp
10615
10778
  };
10616
10779
  this.ctx.eventBus.emit(createEvent(EventCategory.DetectionPhaseTransition, {
@@ -10650,8 +10813,10 @@ var PipelineRunnerAddon = class PipelineRunnerAddon extends BaseAddon {
10650
10813
  return null;
10651
10814
  }
10652
10815
  if (steps.length === 0) return null;
10653
- let dispatchSteps = steps;
10654
- if (steps.some((s) => s.addonId === "package-detection" && s.enabled !== false)) {
10816
+ const labelLinkPlan = this.labelLinkPlanFor(deviceId, steps);
10817
+ const packageFill = applyPackageFill(steps, labelLinkPlan);
10818
+ let dispatchSteps = packageFill.steps;
10819
+ if (dispatchSteps.some((s) => s.addonId === "package-detection" && s.enabled !== false)) {
10655
10820
  this.refreshPackageZoneUnion(deviceId);
10656
10821
  const motionInZone = this.lastMotionNearPackageZone.get(deviceId) ?? this.lastAnalyzerDetected.get(deviceId) ?? false;
10657
10822
  const decision = this.packageGovernor.evaluate({
@@ -10661,7 +10826,7 @@ var PipelineRunnerAddon = class PipelineRunnerAddon extends BaseAddon {
10661
10826
  });
10662
10827
  const skipped = this.packageGateSkips.get(deviceId) ?? 0;
10663
10828
  if (!decision.run) {
10664
- dispatchSteps = steps.filter((s) => s.addonId !== PACKAGE_DETECTION_STEP_ID);
10829
+ dispatchSteps = dispatchSteps.filter((s) => s.addonId !== PACKAGE_DETECTION_STEP_ID);
10665
10830
  if (skipped === 0) log.info("package-detection gated off by the motion-settle governor", {
10666
10831
  tags: { deviceId },
10667
10832
  meta: { motionInZone: this.lastAnalyzerDetected.get(deviceId) ?? false }
@@ -10738,7 +10903,7 @@ var PipelineRunnerAddon = class PipelineRunnerAddon extends BaseAddon {
10738
10903
  return null;
10739
10904
  }
10740
10905
  if (result === null) return null;
10741
- const looked = withPackageLook(result, dispatchSteps);
10906
+ const looked = withPackageLook(applyLabelLinkAuthority(result, labelLinkPlan), dispatchSteps, packageFill.filledByRoot);
10742
10907
  return this.recoverSmallSubjects(deviceId, frame, looked, dispatchSteps, camConfig?.deviceKey);
10743
10908
  }
10744
10909
  /**
@@ -11385,7 +11550,7 @@ var PipelineRunnerAddon = class PipelineRunnerAddon extends BaseAddon {
11385
11550
  ...this.liveWorkerSlotWaiter(deviceId),
11386
11551
  acquire: () => this.acquireSessionDecodeRestream(api, config.deviceId, config.detectionStreamId, `session-decode:occupancy:${config.deviceId}`, resolveSessionDecodeHostname(config, process.env["CAMSTACK_HUB_URL"]), resolveSessionDecodeOwnerNodeId(config)),
11387
11552
  startPump: (source, hooks) => {
11388
- const useLocalFrameRef = this.executorCoLocated() && process.env["CAMSTACK_DISABLE_LOCAL_FRAME_REF"] !== "1";
11553
+ const useLocalFrameRef = this.executorCoLocated();
11389
11554
  return startSessionDecodePump({
11390
11555
  fork: this.forkDecodeWorkerWithLease,
11391
11556
  lease: this.resolveSessionLeaseKnobs,
@@ -11435,7 +11600,7 @@ var PipelineRunnerAddon = class PipelineRunnerAddon extends BaseAddon {
11435
11600
  emitInferenceResult(deviceId, frame, result, handle, source, occasion) {
11436
11601
  if (!this.ctx?.eventBus) return;
11437
11602
  const capturedAt = frame.capturedAt;
11438
- const detailSteps = this.attached.get(deviceId)?.detailSteps;
11603
+ const detailSteps = this.labelLinkCache.get(deviceId)?.announces ?? this.attached.get(deviceId)?.detailSteps;
11439
11604
  const payload = {
11440
11605
  deviceId,
11441
11606
  frame: result,
@@ -11620,4 +11785,4 @@ var PipelineRunnerAddon = class PipelineRunnerAddon extends BaseAddon {
11620
11785
  }
11621
11786
  };
11622
11787
  //#endregion
11623
- export { DEFAULT_CONFIG, FrameQueue, PipelineRunner, PipelineTimingSampler, Semaphore, acquireSessionDecodeRestreamFrom, cameraOwnsMotionViaSensor, pipelineRunnerBenchActions as customActions, PipelineRunnerAddon as default, deriveDetailSteps, resolveMotionFrameSource, resolveSessionDecodeHostname, resolveSessionDecodeOwnerNodeId, rgbFrameToGrayFrame, shouldStartOnboardAnalyzer };
11788
+ export { DEFAULT_CONFIG, FrameQueue, PipelineRunner, PipelineTimingSampler, Semaphore, acquireSessionDecodeRestreamFrom, cameraOwnsMotionViaSensor, pipelineRunnerBenchActions as customActions, PipelineRunnerAddon as default, deriveDetailSteps, phaseTransitionSourceFields, resolveMotionFrameSource, resolveSessionDecodeHostname, resolveSessionDecodeOwnerNodeId, rgbFrameToGrayFrame, shouldStartOnboardAnalyzer };
@@ -1,4 +1,4 @@
1
- import { jt as parseProcStatus } from "./dist-BuU8Y4o1.mjs";
1
+ import { Rt as parseProcStatus } from "./dist-Bpub2VcJ.mjs";
2
2
  import * as fs from "node:fs";
3
3
  import { execFile } from "node:child_process";
4
4
  //#region src/shared/node-topology-platform.ts
@@ -1,5 +1,5 @@
1
1
  const require_chunk = require("./chunk-emK7D4bc.js");
2
- const require_dist = require("./dist-BTBbIGSC.js");
2
+ const require_dist = require("./dist-wJO7mXeO.js");
3
3
  let node_fs = require("node:fs");
4
4
  node_fs = require_chunk.__toESM(node_fs);
5
5
  let node_child_process = require("node:child_process");
@@ -3,8 +3,8 @@ Object.defineProperties(exports, {
3
3
  [Symbol.toStringTag]: { value: "Module" }
4
4
  });
5
5
  const require_chunk = require("../chunk-emK7D4bc.js");
6
- const require_dist = require("../dist-BTBbIGSC.js");
7
- const require_node = require("../node-UK2v2ZSw.js");
6
+ const require_dist = require("../dist-wJO7mXeO.js");
7
+ const require_node = require("../node-BCrqaejt.js");
8
8
  const require_hub_hostname = require("../hub-hostname-DAJXlOgV.js");
9
9
  const require_restream_intent = require("../restream-intent-7uDNqMKs.js");
10
10
  const require_retire_root_keys = require("../retire-root-keys-Csb8z2f3.js");
@@ -8066,15 +8066,16 @@ function runShrinkFfmpeg(spawn, ffmpegPath, args) {
8066
8066
  return new Promise((resolve, reject) => {
8067
8067
  const proc = spawn(ffmpegPath, args);
8068
8068
  let stderr = "";
8069
- proc.stderr?.on("data", (chunk) => {
8070
- stderr += chunk.toString("utf8");
8069
+ proc.stderr?.on("data", (...emitted) => {
8070
+ const chunk = emitted[0];
8071
+ stderr += Buffer.isBuffer(chunk) ? chunk.toString("utf8") : String(chunk);
8071
8072
  });
8072
- proc.on("error", (...args) => {
8073
- const err = args[0];
8073
+ proc.on("error", (...emitted) => {
8074
+ const err = emitted[0];
8074
8075
  reject(err instanceof Error ? err : new Error(String(err)));
8075
8076
  });
8076
- proc.on("close", (...args) => {
8077
- const code = args[0];
8077
+ proc.on("close", (...emitted) => {
8078
+ const code = emitted[0];
8078
8079
  if (code === 0) {
8079
8080
  resolve();
8080
8081
  return;
@@ -1,5 +1,5 @@
1
- import { $t as stripRetiredBandPreBufferSec, An as sleep$1, B as VISIT_MERGE_GAP_MS, Bn as record, Bt as recordingExportCapability, C as ExportRecordSchema, Dt as migrateLegacyDeviceSignalConfig, En as nodePin, Et as memoizePinnedFfmpeg, F as RECORDING_SOURCE_CAMSTACK_ADDON, Gt as resolveLocationMode, I as RecordingConfigSchema, K as batteryCapability, L as RecordingSignalStatusSchema, Ln as number, Mn as array, N as RECORDING_EXPORT_MAX_READ_BYTES, Nn as boolean, Ot as modeMayWrite, P as RECORDING_SOURCE_CAMSTACK, Rn as object, Rt as recordingArchiveCapability, Sn as hydrateSchema, Tt as mayWriteToLocation, Un as EventCategory, Ut as resolveCreateExportSubject, Vn as string, Vt as recordingSignalCapability, X as clipExportFailureOf, Xt as storageEvictableCapability, Y as clipExportFailure, Zt as storageOccupancyCapability, _ as DEFAULT_EVENTS_BAND_BUFFER_SEC, b as EVENT_OWNER_TYPES, bn as defineCustomActions, bt as loadContributionCapability, dn as DeviceType, dt as exportSubjectOf, fn as errMsg$1, jn as _enum, k as OpsLogEntrySchema, kn as selectAssignedProfileSlots, lt as evictionPolicyForMode, mn as BaseAddon, mt as gbToBytes, o as BatteryStatusSchema, qt as resolveRecordingProfiles, rt as deriveRecordingMode, s as CLIP_BROKER_PACED_RATES, sn as evaluateSensorEdge, tn as videoclipsCapability, tt as deriveBatteryPresence, un as DeviceFeature, ut as evictionPolicyOfLocation, wt as mayReadLocation, x as EVENT_PAD_MS, yn as customAction, yt as isFirstLevelMacroClass, z as VIDEOCLIPS_MAX_OFFER_BYTES, zn as preprocess, zt as recordingCapability } from "../dist-BuU8Y4o1.mjs";
2
- import { a as physicalRootOf, i as NO_COST_CLAIM, t as ChildCostRegistry } from "../node-inZFYgkm.mjs";
1
+ import { $t as resolveLocationMode, An as hydrateSchema, B as RECORDING_SOURCE_CAMSTACK_ADDON, Bn as array, Dn as customAction, Dt as loadContributionCapability, Ft as modeMayWrite, G as VISIT_MERGE_GAP_MS, Gn as number, Gt as recordingArchiveCapability, H as RecordingSignalStatusSchema, Jn as record, Jt as recordingSignalCapability, Kn as object, Kt as recordingCapability, Ln as selectAssignedProfileSlots, Mt as mayWriteToLocation, Nt as memoizePinnedFfmpeg, On as defineCustomActions, P as OpsLogEntrySchema, Pn as nodePin, Pt as migrateLegacyDeviceSignalConfig, R as RECORDING_EXPORT_MAX_READ_BYTES, Rn as sleep$1, S as EVENT_PAD_MS, Sn as BaseAddon, V as RecordingConfigSchema, Vn as boolean, W as VIDEOCLIPS_MAX_OFFER_BYTES, Xt as resolveCreateExportSubject, Yn as string, Z as batteryCapability, Zn as EventCategory, _ as DEFAULT_EVENTS_BAND_BUFFER_SEC, an as storageOccupancyCapability, bn as errMsg$1, ct as deriveRecordingMode, et as clipExportFailure, gt as exportSubjectOf, hn as evaluateSensorEdge, ht as evictionPolicyOfLocation, in as storageEvictableCapability, jt as mayReadLocation, ln as videoclipsCapability, mt as evictionPolicyForMode, o as BatteryStatusSchema, ot as deriveBatteryPresence, qn as preprocess, qt as recordingExportCapability, s as CLIP_BROKER_PACED_RATES, sn as stripRetiredBandPreBufferSec, tn as resolveRecordingProfiles, tt as clipExportFailureOf, vn as DeviceFeature, w as ExportRecordSchema, wt as isFirstLevelMacroClass, x as EVENT_OWNER_TYPES, yn as DeviceType, yt as gbToBytes, z as RECORDING_SOURCE_CAMSTACK, zn as _enum } from "../dist-Bpub2VcJ.mjs";
2
+ import { a as physicalRootOf, i as NO_COST_CLAIM, t as ChildCostRegistry } from "../node-BjCSgD4M.mjs";
3
3
  import { t as resolveHubHostname } from "../hub-hostname-cCknRYKj.mjs";
4
4
  import { d as PREBUFFER_MAX_MS, l as withRecordingIntent, r as RECORDING_PRE_ROLL_REQUEST_MS } from "../restream-intent-DyGmLAU9.mjs";
5
5
  import { n as RowMapStore, t as retireRootKeys } from "../retire-root-keys-DZvlso2l.mjs";
@@ -8058,15 +8058,16 @@ function runShrinkFfmpeg(spawn, ffmpegPath, args) {
8058
8058
  return new Promise((resolve, reject) => {
8059
8059
  const proc = spawn(ffmpegPath, args);
8060
8060
  let stderr = "";
8061
- proc.stderr?.on("data", (chunk) => {
8062
- stderr += chunk.toString("utf8");
8061
+ proc.stderr?.on("data", (...emitted) => {
8062
+ const chunk = emitted[0];
8063
+ stderr += Buffer.isBuffer(chunk) ? chunk.toString("utf8") : String(chunk);
8063
8064
  });
8064
- proc.on("error", (...args) => {
8065
- const err = args[0];
8065
+ proc.on("error", (...emitted) => {
8066
+ const err = emitted[0];
8066
8067
  reject(err instanceof Error ? err : new Error(String(err)));
8067
8068
  });
8068
- proc.on("close", (...args) => {
8069
- const code = args[0];
8069
+ proc.on("close", (...emitted) => {
8070
+ const code = emitted[0];
8070
8071
  if (code === 0) {
8071
8072
  resolve();
8072
8073
  return;
@@ -1,5 +1,5 @@
1
1
  import { r as __toESM, t as __commonJSMin } from "./chunk-DnnnRqeS.mjs";
2
- import { fn as errMsg } from "./dist-BuU8Y4o1.mjs";
2
+ import { bn as errMsg } from "./dist-Bpub2VcJ.mjs";
3
3
  import { spawn } from "node:child_process";
4
4
  //#region src/stream-broker/recorded/avcc-annexb.ts
5
5
  /**
@@ -1,5 +1,5 @@
1
1
  const require_chunk = require("./chunk-emK7D4bc.js");
2
- const require_dist = require("./dist-BTBbIGSC.js");
2
+ const require_dist = require("./dist-wJO7mXeO.js");
3
3
  let node_child_process = require("node:child_process");
4
4
  //#region src/stream-broker/recorded/avcc-annexb.ts
5
5
  /**