@camstack/addon-pipeline 1.2.107 → 1.2.115
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/{addon-utils-Vv2dCqA2.js → addon-utils-C0ht2KPO.js} +51 -15
- package/dist/{addon-utils-A2S9D7pu.mjs → addon-utils-CgBCF-mE.mjs} +50 -14
- package/dist/audio-analyzer/index.js +3 -3
- package/dist/audio-analyzer/index.mjs +3 -3
- package/dist/detection-pipeline/index.js +170 -31
- package/dist/detection-pipeline/index.mjs +169 -30
- package/dist/{dist-L-1LMGQs.js → dist-BqIbYW1A.js} +130 -17
- package/dist/{dist-CkXAzTZ2.mjs → dist-DGQkkWc6.mjs} +130 -17
- package/dist/{event-loop-stall-monitor-fHkfgmlw.mjs → event-loop-stall-monitor-D5jK5v4Z.mjs} +223 -2
- package/dist/{event-loop-stall-monitor-DwAho7HD.js → event-loop-stall-monitor-ylMGpz48.js} +234 -1
- package/dist/{lazy-sharp-DfbyQxET.js → lazy-sharp-cOsy7l_P.js} +1 -1
- package/dist/motion-wasm/index.js +2 -2
- package/dist/motion-wasm/index.mjs +1 -1
- package/dist/pipeline-runner/index.js +915 -107
- package/dist/pipeline-runner/index.mjs +914 -106
- package/dist/{process-memory-CgrbLo3l.js → process-memory-45juuHpN.js} +1 -1
- package/dist/{process-memory-DlSOzuHP.mjs → process-memory-BtT7WfbJ.mjs} +1 -1
- package/dist/recorder/index.js +187 -47
- package/dist/recorder/index.mjs +187 -47
- package/dist/session-decode/decode-worker-child.js +30 -10
- package/dist/session-decode/decode-worker-child.mjs +29 -9
- package/dist/stream-broker/_stub.js +2 -2
- package/dist/stream-broker/{_virtual_mf-localSharedImportMap___mfe_internal__addon_stream_broker_widgets-BeL4_jgH.mjs → _virtual_mf-localSharedImportMap___mfe_internal__addon_stream_broker_widgets-C_SFFNGT.mjs} +3 -3
- package/dist/stream-broker/_virtual_mf___mfe_internal__addon_stream_broker_widgets__loadShare___mf_0_camstack_mf_1_types__loadShare__.js-B1LDFHY9.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-CmHtm5CX.mjs → _virtual_mf___mfe_internal__addon_stream_broker_widgets__loadShare___mf_0_camstack_mf_1_ui_mf_2_library__loadShare__.js-BAMyzCWw.mjs} +1 -1
- package/dist/stream-broker/{hostInit-BK9nzKAG.mjs → hostInit-CG28NvlV.mjs} +3 -3
- package/dist/stream-broker/index.js +279 -198
- package/dist/stream-broker/index.mjs +279 -198
- package/dist/stream-broker/remoteEntry.js +1 -1
- package/dist/{worker-protocol-GGnzfWu3.js → worker-protocol-CIrqGbpG.js} +6 -3
- package/dist/{worker-protocol-bEipQT9l.mjs → worker-protocol-DyocTIx_.mjs} +6 -3
- package/package.json +1 -1
- package/python/inference_pool.py +4 -1
- package/python/test_inference_pool_preprocess.py +87 -16
- package/dist/stream-broker/_virtual_mf___mfe_internal__addon_stream_broker_widgets__loadShare___mf_0_camstack_mf_1_types__loadShare__.js-DjndFc5V.mjs +0 -26
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
const require_dist = require("./dist-
|
|
1
|
+
const require_dist = require("./dist-BqIbYW1A.js");
|
|
2
2
|
require("node:crypto");
|
|
3
3
|
let node_path = require("node:path");
|
|
4
4
|
node_path = require_dist.__toESM(node_path, 1);
|
|
@@ -6,7 +6,7 @@ let node_fs = require("node:fs");
|
|
|
6
6
|
node_fs = require_dist.__toESM(node_fs, 1);
|
|
7
7
|
let node_util = require("node:util");
|
|
8
8
|
let node_zlib = require("node:zlib");
|
|
9
|
-
//#region ../system/dist/file-data-plane-
|
|
9
|
+
//#region ../system/dist/file-data-plane-BhKdxJgf.mjs
|
|
10
10
|
function isNonEmptyFile(filePath) {
|
|
11
11
|
return node_fs.existsSync(filePath) && node_fs.statSync(filePath).size > 0;
|
|
12
12
|
}
|
|
@@ -32,21 +32,56 @@ function buildHeaders(url) {
|
|
|
32
32
|
if (hfToken && url.includes("huggingface.co")) headers["Authorization"] = `Bearer ${hfToken}`;
|
|
33
33
|
return headers;
|
|
34
34
|
}
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
35
|
+
var DEFAULT_MAX_REDIRECTS = 5;
|
|
36
|
+
function normalizeDownloadOptions(third) {
|
|
37
|
+
if (typeof third === "function") return { onProgress: third };
|
|
38
|
+
return third ?? {};
|
|
39
|
+
}
|
|
40
|
+
function isRedirectStatus(status) {
|
|
41
|
+
return status === 301 || status === 302 || status === 303 || status === 307 || status === 308;
|
|
42
|
+
}
|
|
43
|
+
function resolveRedirectUrl(current, location) {
|
|
44
|
+
return new URL(location, current);
|
|
45
|
+
}
|
|
46
|
+
async function downloadFile(url, destPath, onProgressOrOptions) {
|
|
42
47
|
if (node_fs.existsSync(destPath)) return destPath;
|
|
48
|
+
const opts = normalizeDownloadOptions(onProgressOrOptions);
|
|
49
|
+
const fetchImpl = opts.fetchImpl ?? fetch;
|
|
50
|
+
const maxRedirects = opts.maxRedirects ?? DEFAULT_MAX_REDIRECTS;
|
|
43
51
|
node_fs.mkdirSync(node_path.dirname(destPath), { recursive: true });
|
|
44
52
|
const tmpPath = destPath + ".downloading";
|
|
45
53
|
try {
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
54
|
+
let current = url;
|
|
55
|
+
const seen = /* @__PURE__ */ new Set();
|
|
56
|
+
let response;
|
|
57
|
+
const manual = opts.redirectPolicy !== void 0;
|
|
58
|
+
for (let hop = 0; hop <= maxRedirects; hop++) {
|
|
59
|
+
const parsed = new URL(current);
|
|
60
|
+
if (opts.redirectPolicy) opts.redirectPolicy(parsed, hop);
|
|
61
|
+
if (seen.has(parsed.href)) throw new Error(`Redirect loop detected at ${parsed.href}`);
|
|
62
|
+
seen.add(parsed.href);
|
|
63
|
+
const controller = opts.timeoutMs !== void 0 ? new AbortController() : void 0;
|
|
64
|
+
const timer = controller && opts.timeoutMs !== void 0 ? setTimeout(() => controller.abort(), opts.timeoutMs) : void 0;
|
|
65
|
+
try {
|
|
66
|
+
response = await fetchImpl(current, {
|
|
67
|
+
redirect: manual ? "manual" : "follow",
|
|
68
|
+
headers: buildHeaders(current),
|
|
69
|
+
...controller ? { signal: controller.signal } : {}
|
|
70
|
+
});
|
|
71
|
+
} finally {
|
|
72
|
+
if (timer) clearTimeout(timer);
|
|
73
|
+
}
|
|
74
|
+
if (manual && isRedirectStatus(response.status)) {
|
|
75
|
+
const location = response.headers.get("location");
|
|
76
|
+
if (!location) throw new Error(`Redirect ${response.status} missing Location header`);
|
|
77
|
+
if (hop >= maxRedirects) throw new Error(`Too many redirects (max ${maxRedirects}) downloading ${url}`);
|
|
78
|
+
current = resolveRedirectUrl(current, location).href;
|
|
79
|
+
continue;
|
|
80
|
+
}
|
|
81
|
+
break;
|
|
82
|
+
}
|
|
83
|
+
if (!response) throw new Error(`No response downloading ${url}`);
|
|
84
|
+
if (manual && isRedirectStatus(response.status)) throw new Error(`Too many redirects (max ${maxRedirects}) downloading ${url}`);
|
|
50
85
|
if (!response.ok) throw new Error(`HTTP ${response.status} downloading ${url}`);
|
|
51
86
|
if (!response.body) throw new Error(`No response body from ${url}`);
|
|
52
87
|
const total = parseInt(response.headers.get("content-length") ?? "0", 10);
|
|
@@ -57,9 +92,10 @@ async function downloadFile(url, destPath, onProgress) {
|
|
|
57
92
|
for (;;) {
|
|
58
93
|
const { done, value } = await reader.read();
|
|
59
94
|
if (done || !value) break;
|
|
60
|
-
fileStream.write(value);
|
|
61
95
|
downloaded += value.length;
|
|
62
|
-
|
|
96
|
+
if (opts.maxBytes !== void 0 && downloaded > opts.maxBytes) throw new Error(`Downloaded ${downloaded} bytes exceeds the ${opts.maxBytes}-byte limit`);
|
|
97
|
+
fileStream.write(value);
|
|
98
|
+
opts.onProgress?.(downloaded, total);
|
|
63
99
|
}
|
|
64
100
|
} finally {
|
|
65
101
|
fileStream.end();
|
|
@@ -5,7 +5,7 @@ import * as fs from "node:fs";
|
|
|
5
5
|
import { createReadStream, promises } from "node:fs";
|
|
6
6
|
import { promisify } from "node:util";
|
|
7
7
|
import { brotliCompress, constants, gzip } from "node:zlib";
|
|
8
|
-
//#region ../system/dist/file-data-plane-
|
|
8
|
+
//#region ../system/dist/file-data-plane-BhKdxJgf.mjs
|
|
9
9
|
function isNonEmptyFile(filePath) {
|
|
10
10
|
return fs.existsSync(filePath) && fs.statSync(filePath).size > 0;
|
|
11
11
|
}
|
|
@@ -31,21 +31,56 @@ function buildHeaders(url) {
|
|
|
31
31
|
if (hfToken && url.includes("huggingface.co")) headers["Authorization"] = `Bearer ${hfToken}`;
|
|
32
32
|
return headers;
|
|
33
33
|
}
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
34
|
+
var DEFAULT_MAX_REDIRECTS = 5;
|
|
35
|
+
function normalizeDownloadOptions(third) {
|
|
36
|
+
if (typeof third === "function") return { onProgress: third };
|
|
37
|
+
return third ?? {};
|
|
38
|
+
}
|
|
39
|
+
function isRedirectStatus(status) {
|
|
40
|
+
return status === 301 || status === 302 || status === 303 || status === 307 || status === 308;
|
|
41
|
+
}
|
|
42
|
+
function resolveRedirectUrl(current, location) {
|
|
43
|
+
return new URL(location, current);
|
|
44
|
+
}
|
|
45
|
+
async function downloadFile(url, destPath, onProgressOrOptions) {
|
|
41
46
|
if (fs.existsSync(destPath)) return destPath;
|
|
47
|
+
const opts = normalizeDownloadOptions(onProgressOrOptions);
|
|
48
|
+
const fetchImpl = opts.fetchImpl ?? fetch;
|
|
49
|
+
const maxRedirects = opts.maxRedirects ?? DEFAULT_MAX_REDIRECTS;
|
|
42
50
|
fs.mkdirSync(path$1.dirname(destPath), { recursive: true });
|
|
43
51
|
const tmpPath = destPath + ".downloading";
|
|
44
52
|
try {
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
53
|
+
let current = url;
|
|
54
|
+
const seen = /* @__PURE__ */ new Set();
|
|
55
|
+
let response;
|
|
56
|
+
const manual = opts.redirectPolicy !== void 0;
|
|
57
|
+
for (let hop = 0; hop <= maxRedirects; hop++) {
|
|
58
|
+
const parsed = new URL(current);
|
|
59
|
+
if (opts.redirectPolicy) opts.redirectPolicy(parsed, hop);
|
|
60
|
+
if (seen.has(parsed.href)) throw new Error(`Redirect loop detected at ${parsed.href}`);
|
|
61
|
+
seen.add(parsed.href);
|
|
62
|
+
const controller = opts.timeoutMs !== void 0 ? new AbortController() : void 0;
|
|
63
|
+
const timer = controller && opts.timeoutMs !== void 0 ? setTimeout(() => controller.abort(), opts.timeoutMs) : void 0;
|
|
64
|
+
try {
|
|
65
|
+
response = await fetchImpl(current, {
|
|
66
|
+
redirect: manual ? "manual" : "follow",
|
|
67
|
+
headers: buildHeaders(current),
|
|
68
|
+
...controller ? { signal: controller.signal } : {}
|
|
69
|
+
});
|
|
70
|
+
} finally {
|
|
71
|
+
if (timer) clearTimeout(timer);
|
|
72
|
+
}
|
|
73
|
+
if (manual && isRedirectStatus(response.status)) {
|
|
74
|
+
const location = response.headers.get("location");
|
|
75
|
+
if (!location) throw new Error(`Redirect ${response.status} missing Location header`);
|
|
76
|
+
if (hop >= maxRedirects) throw new Error(`Too many redirects (max ${maxRedirects}) downloading ${url}`);
|
|
77
|
+
current = resolveRedirectUrl(current, location).href;
|
|
78
|
+
continue;
|
|
79
|
+
}
|
|
80
|
+
break;
|
|
81
|
+
}
|
|
82
|
+
if (!response) throw new Error(`No response downloading ${url}`);
|
|
83
|
+
if (manual && isRedirectStatus(response.status)) throw new Error(`Too many redirects (max ${maxRedirects}) downloading ${url}`);
|
|
49
84
|
if (!response.ok) throw new Error(`HTTP ${response.status} downloading ${url}`);
|
|
50
85
|
if (!response.body) throw new Error(`No response body from ${url}`);
|
|
51
86
|
const total = parseInt(response.headers.get("content-length") ?? "0", 10);
|
|
@@ -56,9 +91,10 @@ async function downloadFile(url, destPath, onProgress) {
|
|
|
56
91
|
for (;;) {
|
|
57
92
|
const { done, value } = await reader.read();
|
|
58
93
|
if (done || !value) break;
|
|
59
|
-
fileStream.write(value);
|
|
60
94
|
downloaded += value.length;
|
|
61
|
-
|
|
95
|
+
if (opts.maxBytes !== void 0 && downloaded > opts.maxBytes) throw new Error(`Downloaded ${downloaded} bytes exceeds the ${opts.maxBytes}-byte limit`);
|
|
96
|
+
fileStream.write(value);
|
|
97
|
+
opts.onProgress?.(downloaded, total);
|
|
62
98
|
}
|
|
63
99
|
} finally {
|
|
64
100
|
fileStream.end();
|
|
@@ -2,9 +2,9 @@ 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_process_memory = require("../process-memory-
|
|
7
|
-
const require_addon_utils = require("../addon-utils-
|
|
5
|
+
const require_dist = require("../dist-BqIbYW1A.js");
|
|
6
|
+
const require_process_memory = require("../process-memory-45juuHpN.js");
|
|
7
|
+
const require_addon_utils = require("../addon-utils-C0ht2KPO.js");
|
|
8
8
|
let node_path = require("node:path");
|
|
9
9
|
node_path = require_dist.__toESM(node_path);
|
|
10
10
|
let node_fs = require("node:fs");
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { n as __require } from "../chunk-DnnnRqeS.mjs";
|
|
2
|
-
import { A as audioAnalyzerCapability, Et as hydrateSchema, _ as HF_BASE_URL, ct as resolvePoolMemoryPolicy, ht as errMsg, k as audioAnalysisCapability, n as AUDIO_BACKEND_CHOICES, q as mapAudioLabelToMacro, s as DEFAULT_AUDIO_ANALYZER_CONFIG, x as PoolMemoryWatchdog, xt as BaseAddon } from "../dist-
|
|
3
|
-
import { n as pickNodePlatformArch, t as readProcessMemory } from "../process-memory-
|
|
4
|
-
import { i as downloadFile } from "../addon-utils-
|
|
2
|
+
import { A as audioAnalyzerCapability, Et as hydrateSchema, _ as HF_BASE_URL, ct as resolvePoolMemoryPolicy, ht as errMsg, k as audioAnalysisCapability, n as AUDIO_BACKEND_CHOICES, q as mapAudioLabelToMacro, s as DEFAULT_AUDIO_ANALYZER_CONFIG, x as PoolMemoryWatchdog, xt as BaseAddon } from "../dist-DGQkkWc6.mjs";
|
|
3
|
+
import { n as pickNodePlatformArch, t as readProcessMemory } from "../process-memory-BtT7WfbJ.mjs";
|
|
4
|
+
import { i as downloadFile } from "../addon-utils-CgBCF-mE.mjs";
|
|
5
5
|
import * as path$1 from "node:path";
|
|
6
6
|
import * as fs from "node:fs";
|
|
7
7
|
//#region src/audio-analyzer/audio-pipeline.ts
|
|
@@ -2,11 +2,11 @@ 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_event_loop_stall_monitor = require("../event-loop-stall-monitor-
|
|
7
|
-
const require_lazy_sharp = require("../lazy-sharp-
|
|
8
|
-
const require_process_memory = require("../process-memory-
|
|
9
|
-
const require_addon_utils = require("../addon-utils-
|
|
5
|
+
const require_dist = require("../dist-BqIbYW1A.js");
|
|
6
|
+
const require_event_loop_stall_monitor = require("../event-loop-stall-monitor-ylMGpz48.js");
|
|
7
|
+
const require_lazy_sharp = require("../lazy-sharp-cOsy7l_P.js");
|
|
8
|
+
const require_process_memory = require("../process-memory-45juuHpN.js");
|
|
9
|
+
const require_addon_utils = require("../addon-utils-C0ht2KPO.js");
|
|
10
10
|
let sharp = require("sharp");
|
|
11
11
|
sharp = require_dist.__toESM(sharp);
|
|
12
12
|
let node_child_process = require("node:child_process");
|
|
@@ -264,7 +264,13 @@ var OBJECT_DETECTION_STEP_ID = "object-detection";
|
|
|
264
264
|
* `null` → the caller substitutes the step's own `defaultModelId` (`yolo26n`).
|
|
265
265
|
* INTEL NPU + iGPU default to OUR YOLOv9 (int8 @320): yolo26 does NOT compile on
|
|
266
266
|
* the Intel NPU (arch incompat → 0 frames), while yolov9 runs on it (~298 fps
|
|
267
|
-
* measured). Apple ANE
|
|
267
|
+
* measured). Apple ANE uses the CoreML yolov9 @320 build.
|
|
268
|
+
*
|
|
269
|
+
* Do **not** promote these ids to `yolov9m-640` / `*-640`. The controlled
|
|
270
|
+
* evaluation recovered 0/3 misses at the current 0.50 threshold and failed the
|
|
271
|
+
* false-positive and capacity gates — see
|
|
272
|
+
* `docs/benchmarks/pipeline-frame-model-eval.md`. 640 remains an explicit
|
|
273
|
+
* operator pick, not a hardware-aware default.
|
|
268
274
|
*/
|
|
269
275
|
var MODEL_BY_CLASS = {
|
|
270
276
|
"apple-ane": "yolov9m-320",
|
|
@@ -1374,7 +1380,7 @@ function macroOfMinConfidenceKey(key) {
|
|
|
1374
1380
|
*/
|
|
1375
1381
|
function reachableMacros(def, entry) {
|
|
1376
1382
|
if (entry.labels.length === 0) return void 0;
|
|
1377
|
-
const map = def.classMap;
|
|
1383
|
+
const map = entry.classMap ?? def.classMap;
|
|
1378
1384
|
if (!map) return new Set(entry.labels.map((l) => l.id));
|
|
1379
1385
|
if (map.preserveOriginal) return void 0;
|
|
1380
1386
|
const macros = /* @__PURE__ */ new Set();
|
|
@@ -1394,7 +1400,7 @@ function reachableMacros(def, entry) {
|
|
|
1394
1400
|
*/
|
|
1395
1401
|
function collectClassMapDropWarning(def, entry) {
|
|
1396
1402
|
if (entry.labels.length === 0) return null;
|
|
1397
|
-
const map = def.classMap;
|
|
1403
|
+
const map = entry.classMap ?? def.classMap;
|
|
1398
1404
|
if (!map || map.preserveOriginal) return null;
|
|
1399
1405
|
const unmapped = entry.labels.filter((l) => map.mapping[l.id] === void 0).map((l) => l.id);
|
|
1400
1406
|
if (unmapped.length === 0) return null;
|
|
@@ -4170,7 +4176,7 @@ function applyChildOutput(parent, childStep, output, stepLatencyMs, ctx) {
|
|
|
4170
4176
|
switch (output.kind) {
|
|
4171
4177
|
case "detections":
|
|
4172
4178
|
if (childStep.definition.slot === "refiner") {
|
|
4173
|
-
const classMap = childStep.
|
|
4179
|
+
const classMap = childStep.effectiveClassMap?.mapping;
|
|
4174
4180
|
const parentMacro = parent.macroClass;
|
|
4175
4181
|
const best = output.detections.filter((d) => {
|
|
4176
4182
|
if (d.mask === void 0) return false;
|
|
@@ -4510,6 +4516,29 @@ function reprojectCropZoneDetections(output, cropOrigin) {
|
|
|
4510
4516
|
}))
|
|
4511
4517
|
};
|
|
4512
4518
|
}
|
|
4519
|
+
function reprojectViewDetections(output, geometry) {
|
|
4520
|
+
const mapPoint = (x, y) => ({
|
|
4521
|
+
x: geometry.sourceCrop.left + x / geometry.scale.x,
|
|
4522
|
+
y: geometry.sourceCrop.top + y / geometry.scale.y
|
|
4523
|
+
});
|
|
4524
|
+
return {
|
|
4525
|
+
kind: "detections",
|
|
4526
|
+
detections: output.detections.map((det) => {
|
|
4527
|
+
const origin = mapPoint(det.bbox[0], det.bbox[1]);
|
|
4528
|
+
const end = mapPoint(det.bbox[2], det.bbox[3]);
|
|
4529
|
+
return {
|
|
4530
|
+
...det,
|
|
4531
|
+
bbox: [
|
|
4532
|
+
origin.x,
|
|
4533
|
+
origin.y,
|
|
4534
|
+
end.x,
|
|
4535
|
+
end.y
|
|
4536
|
+
],
|
|
4537
|
+
...det.landmarks ? { landmarks: det.landmarks.map((landmark) => mapPoint(landmark.x, landmark.y)) } : {}
|
|
4538
|
+
};
|
|
4539
|
+
})
|
|
4540
|
+
};
|
|
4541
|
+
}
|
|
4513
4542
|
var PipelineExecutor = class {
|
|
4514
4543
|
opts;
|
|
4515
4544
|
/** Bounds the full-frame-guard drop log: first example per (device,
|
|
@@ -4571,7 +4600,7 @@ var PipelineExecutor = class {
|
|
|
4571
4600
|
*
|
|
4572
4601
|
* @returns FrameResult + optional trace
|
|
4573
4602
|
*/
|
|
4574
|
-
async run(tree, rootInput, fullFrameJpegProvider, imageWidth, imageHeight, deviceId, runOpts, nativeCropProvider, cropZoneBbox) {
|
|
4603
|
+
async run(tree, rootInput, fullFrameJpegProvider, imageWidth, imageHeight, deviceId, runOpts, nativeCropProvider, cropZoneBbox, rootInputViewProvider) {
|
|
4575
4604
|
const startMs = Date.now();
|
|
4576
4605
|
const verbosity = runOpts?.traceVerbosity ?? "off";
|
|
4577
4606
|
const traceBuilder = new ExecutionTraceBuilder(verbosity, deviceId, imageWidth, imageHeight, this.opts.engineRuntime);
|
|
@@ -4619,18 +4648,20 @@ var PipelineExecutor = class {
|
|
|
4619
4648
|
};
|
|
4620
4649
|
for (const rootStep of tree.roots) {
|
|
4621
4650
|
if (debug) console.log(`[executor] rootStep=${rootStep.stepId} settings=${JSON.stringify(rootStep.settings ?? {})}`);
|
|
4622
|
-
const
|
|
4651
|
+
const rootCrop = rootStep.definition.extractMode === "crop-zone" ? cropZoneBbox : void 0;
|
|
4652
|
+
const rootView = rootInputViewProvider ? await rootInputViewProvider(rootStep, rootCrop) : null;
|
|
4653
|
+
const cropPrep = !rootView && rootCrop !== void 0 ? await this.prepareCropZoneInput(rootCrop, fullFrameJpegProvider, imageWidth, imageHeight, deviceId) : null;
|
|
4623
4654
|
const rootStart = Date.now();
|
|
4624
|
-
const rawRootOutput = await this.executeStep(rootStep, cropPrep?.input ?? withInferenceDeviceId(rootInput, deviceId), cropPrep?.width ?? imageWidth, cropPrep?.height ?? imageHeight, "full-frame", void 0, void 0, traceBuilder, stepTimings, poolAgg, rootShed);
|
|
4655
|
+
const rawRootOutput = await this.executeStep(rootStep, rootView?.input ?? cropPrep?.input ?? withInferenceDeviceId(rootInput, deviceId), rootView?.width ?? cropPrep?.width ?? imageWidth, rootView?.height ?? cropPrep?.height ?? imageHeight, "full-frame", void 0, void 0, traceBuilder, stepTimings, poolAgg, rootShed);
|
|
4625
4656
|
const rootMs = Date.now() - rootStart;
|
|
4626
4657
|
if (rawRootOutput === null) continue;
|
|
4627
|
-
const rootOutput = cropPrep && rawRootOutput.kind === "detections" ? reprojectCropZoneDetections(rawRootOutput, cropPrep.origin) : rawRootOutput;
|
|
4658
|
+
const rootOutput = rootView && rawRootOutput.kind === "detections" ? reprojectViewDetections(rawRootOutput, rootView.geometry) : cropPrep && rawRootOutput.kind === "detections" ? reprojectCropZoneDetections(rawRootOutput, cropPrep.origin) : rawRootOutput;
|
|
4628
4659
|
if (rootOutput.kind !== "detections") {
|
|
4629
4660
|
if (isEnrichmentOutput(rootOutput)) {
|
|
4630
4661
|
const mutable = this.synthesizeRootDetection(rootOutput, rootStep, idGen, rootMs, imageWidth, imageHeight);
|
|
4631
4662
|
applyChildOutput(mutable, rootStep, rootOutput, rootMs, ctx);
|
|
4632
4663
|
try {
|
|
4633
|
-
await this.executeChildren(rootStep.children, mutable, fullFrameJpegProvider, imageWidth, imageHeight, traceBuilder, stepTimings, ctx, poolAgg, runOpts?.plane, deviceId, nativeCropProvider);
|
|
4664
|
+
await this.executeChildren(rootStep.children, mutable, rootView?.jpegProvider ?? fullFrameJpegProvider, imageWidth, imageHeight, traceBuilder, stepTimings, ctx, poolAgg, runOpts?.plane, deviceId, nativeCropProvider);
|
|
4634
4665
|
} catch (err) {
|
|
4635
4666
|
this.opts.logger?.warn("Pipeline child execution failed — keeping parent detection", {
|
|
4636
4667
|
tags: { deviceId },
|
|
@@ -4648,12 +4679,12 @@ var PipelineExecutor = class {
|
|
|
4648
4679
|
}
|
|
4649
4680
|
for (const det of rootOutput.detections) {
|
|
4650
4681
|
const mutable = toMutableRootDetection(det, rootStep, idGen, rootMs);
|
|
4651
|
-
if (rootStep.
|
|
4652
|
-
const mapped = rootStep.
|
|
4682
|
+
if (rootStep.effectiveClassMap) {
|
|
4683
|
+
const mapped = rootStep.effectiveClassMap.mapping[det.class];
|
|
4653
4684
|
if (mapped) {
|
|
4654
4685
|
mutable.originalClass = det.class;
|
|
4655
4686
|
mutable.macroClass = mapped;
|
|
4656
|
-
} else if (!rootStep.
|
|
4687
|
+
} else if (!rootStep.effectiveClassMap.preserveOriginal) {
|
|
4657
4688
|
(discarded ??= []).push({
|
|
4658
4689
|
bbox: [
|
|
4659
4690
|
mutable.bbox[0],
|
|
@@ -4735,7 +4766,7 @@ var PipelineExecutor = class {
|
|
|
4735
4766
|
}
|
|
4736
4767
|
});
|
|
4737
4768
|
try {
|
|
4738
|
-
await this.executeChildren(rootStep.children, mutable, fullFrameJpegProvider, imageWidth, imageHeight, traceBuilder, stepTimings, ctx, poolAgg, runOpts?.plane, deviceId, nativeCropProvider);
|
|
4769
|
+
await this.executeChildren(rootStep.children, mutable, rootView?.jpegProvider ?? fullFrameJpegProvider, imageWidth, imageHeight, traceBuilder, stepTimings, ctx, poolAgg, runOpts?.plane, deviceId, nativeCropProvider);
|
|
4739
4770
|
} catch (err) {
|
|
4740
4771
|
this.opts.logger?.warn("Pipeline child execution failed — keeping parent detection", {
|
|
4741
4772
|
tags: { deviceId },
|
|
@@ -5155,6 +5186,59 @@ function capitalize(s) {
|
|
|
5155
5186
|
return s.charAt(0).toUpperCase() + s.slice(1);
|
|
5156
5187
|
}
|
|
5157
5188
|
//#endregion
|
|
5189
|
+
//#region src/session-decode/frame-view-payload.ts
|
|
5190
|
+
var FRAME_VIEW_PAYLOAD_POLICY = "jpeg";
|
|
5191
|
+
//#endregion
|
|
5192
|
+
//#region src/detection-pipeline/root-frame-view.ts
|
|
5193
|
+
/** Resolve the pre-padding content requested from the decode worker for one root. */
|
|
5194
|
+
function resolveRootFrameViewSpec(model, source, crop, format = FRAME_VIEW_PAYLOAD_POLICY) {
|
|
5195
|
+
const sourceWidth = crop?.width ?? source.width;
|
|
5196
|
+
const sourceHeight = crop?.height ?? source.height;
|
|
5197
|
+
if (model.preprocessMode !== "letterbox") return {
|
|
5198
|
+
...crop ? { crop } : {},
|
|
5199
|
+
content: {
|
|
5200
|
+
width: model.inputSize.width,
|
|
5201
|
+
height: model.inputSize.height
|
|
5202
|
+
},
|
|
5203
|
+
fit: "stretch",
|
|
5204
|
+
format
|
|
5205
|
+
};
|
|
5206
|
+
const scale = Math.min(model.inputSize.width / sourceWidth, model.inputSize.height / sourceHeight);
|
|
5207
|
+
return {
|
|
5208
|
+
...crop ? { crop } : {},
|
|
5209
|
+
content: {
|
|
5210
|
+
width: Math.max(1, Math.round(sourceWidth * scale)),
|
|
5211
|
+
height: Math.max(1, Math.round(sourceHeight * scale))
|
|
5212
|
+
},
|
|
5213
|
+
fit: "contain",
|
|
5214
|
+
format
|
|
5215
|
+
};
|
|
5216
|
+
}
|
|
5217
|
+
//#endregion
|
|
5218
|
+
//#region src/detection-pipeline/frame-ref-view-provider.ts
|
|
5219
|
+
var LocalFrameRefMissError = class extends Error {
|
|
5220
|
+
reason;
|
|
5221
|
+
constructor(reason) {
|
|
5222
|
+
super(`local frameRef miss: ${reason}`);
|
|
5223
|
+
this.reason = reason;
|
|
5224
|
+
this.name = "LocalFrameRefMissError";
|
|
5225
|
+
}
|
|
5226
|
+
};
|
|
5227
|
+
/** Bind one registry lease for all heterogeneous roots of a pipeline invocation. */
|
|
5228
|
+
function createRootFrameViewResolver(registry, ref) {
|
|
5229
|
+
const lease = registry.acquire(ref);
|
|
5230
|
+
if (!lease) throw new LocalFrameRefMissError(ref.registryId === registry.registryId ? "stale-ref" : "foreign-registry");
|
|
5231
|
+
const resolve = async (root, crop) => {
|
|
5232
|
+
const model = root.definition.models.find((candidate) => candidate.id === root.modelId);
|
|
5233
|
+
if (!model) throw new Error(`frame view model not found: ${root.modelId}`);
|
|
5234
|
+
const spec = resolveRootFrameViewSpec(model, ref, crop);
|
|
5235
|
+
const result = await lease.resolve(spec);
|
|
5236
|
+
if (result.kind === "miss") throw new LocalFrameRefMissError(result.reason);
|
|
5237
|
+
return result;
|
|
5238
|
+
};
|
|
5239
|
+
return Object.assign(resolve, { release: (reason) => lease.release(reason) });
|
|
5240
|
+
}
|
|
5241
|
+
//#endregion
|
|
5158
5242
|
//#region src/detection-pipeline/pipeline/native-crop-compose.ts
|
|
5159
5243
|
/** Clamp `v` into `[lo, hi]`. */
|
|
5160
5244
|
function clamp(v, lo, hi) {
|
|
@@ -5194,23 +5278,32 @@ function composeCropRoiToFrameNorm(roi, cropFrameSpace, frameWidth, frameHeight)
|
|
|
5194
5278
|
//#endregion
|
|
5195
5279
|
//#region src/detection-pipeline/pipeline/tree-builder.ts
|
|
5196
5280
|
/**
|
|
5281
|
+
* Effective class map for `(definition, modelId)` without writing back to the
|
|
5282
|
+
* shared StepDefinition. Custom models missing from `definition.models` are
|
|
5283
|
+
* resolved through the optional registry callback.
|
|
5284
|
+
*/
|
|
5285
|
+
function resolveEffectiveClassMap(definition, modelId, resolveModel) {
|
|
5286
|
+
return (definition.models.find((model) => model.id === modelId) ?? resolveModel?.(definition.id, modelId))?.classMap ?? definition.classMap;
|
|
5287
|
+
}
|
|
5288
|
+
/**
|
|
5197
5289
|
* Build an executable tree from user config.
|
|
5198
5290
|
*
|
|
5199
5291
|
* @param steps - User-configured pipeline steps (from PipelineDefaultStep[])
|
|
5200
5292
|
* @param getEngine - Function that returns an IInferenceEngine for a step ID.
|
|
5201
5293
|
* Throws if step not loaded.
|
|
5202
5294
|
*/
|
|
5203
|
-
function buildExecutableTree(steps, getEngine) {
|
|
5204
|
-
return { roots: steps.filter((s) => s.enabled).filter((s) => s.slot !== "audio-classifier").map((s) => buildNode(s, getEngine)) };
|
|
5295
|
+
function buildExecutableTree(steps, getEngine, resolveModel) {
|
|
5296
|
+
return { roots: steps.filter((s) => s.enabled).filter((s) => s.slot !== "audio-classifier").map((s) => buildNode(s, getEngine, resolveModel)) };
|
|
5205
5297
|
}
|
|
5206
|
-
function buildNode(step, getEngine) {
|
|
5298
|
+
function buildNode(step, getEngine, resolveModel) {
|
|
5207
5299
|
const definition = require_event_loop_stall_monitor.getStepDefinition(step.addonId);
|
|
5208
5300
|
const engine = getEngine(step.addonId);
|
|
5209
|
-
const children = (step.children ?? []).filter((c) => c.enabled).map((c) => buildNode(c, getEngine));
|
|
5301
|
+
const children = (step.children ?? []).filter((c) => c.enabled).map((c) => buildNode(c, getEngine, resolveModel));
|
|
5210
5302
|
const mergedSettings = {
|
|
5211
5303
|
...collectSchemaDefaults(step.addonId),
|
|
5212
5304
|
...step.settings
|
|
5213
5305
|
};
|
|
5306
|
+
const effectiveClassMap = resolveEffectiveClassMap(definition, step.modelId, resolveModel);
|
|
5214
5307
|
return {
|
|
5215
5308
|
stepId: step.addonId,
|
|
5216
5309
|
definition,
|
|
@@ -5219,7 +5312,8 @@ function buildNode(step, getEngine) {
|
|
|
5219
5312
|
inputClasses: definition.inputClasses ?? [],
|
|
5220
5313
|
enabled: step.enabled,
|
|
5221
5314
|
children,
|
|
5222
|
-
...Object.keys(mergedSettings).length > 0 ? { settings: mergedSettings } : {}
|
|
5315
|
+
...Object.keys(mergedSettings).length > 0 ? { settings: mergedSettings } : {},
|
|
5316
|
+
...effectiveClassMap !== void 0 ? { effectiveClassMap } : {}
|
|
5223
5317
|
};
|
|
5224
5318
|
}
|
|
5225
5319
|
/**
|
|
@@ -7098,17 +7192,30 @@ var DetectionPipelineProvider = class DetectionPipelineProvider {
|
|
|
7098
7192
|
let jpegProvider;
|
|
7099
7193
|
const sources = [
|
|
7100
7194
|
input.frame ? "frame" : null,
|
|
7195
|
+
input.frameRef ? "frameRef" : null,
|
|
7101
7196
|
input.frameHandle ? "frameHandle" : null,
|
|
7102
7197
|
input.image ? "image" : null,
|
|
7103
7198
|
input.imageBase64 ? "imageBase64" : null,
|
|
7104
7199
|
input.referenceImage ? "referenceImage" : null
|
|
7105
7200
|
].filter((s) => s !== null);
|
|
7106
|
-
if (sources.length === 0) throw new Error("runPipeline requires exactly one of: frame, frameHandle, image, imageBase64, referenceImage");
|
|
7201
|
+
if (sources.length === 0) throw new Error("runPipeline requires exactly one of: frame, frameRef, frameHandle, image, imageBase64, referenceImage");
|
|
7107
7202
|
if (sources.length > 1) throw new Error(`runPipeline received conflicting image sources: ${sources.join(", ")}`);
|
|
7108
7203
|
if (input.frameHandle) return this.emptyFrameHandleResult(input);
|
|
7109
7204
|
const runtimeFrame = input.frame ?? void 0;
|
|
7205
|
+
const runtimeFrameRef = input.frameRef;
|
|
7110
7206
|
const decodeT0 = performance.now();
|
|
7111
|
-
if (
|
|
7207
|
+
if (runtimeFrameRef) {
|
|
7208
|
+
imageWidth = runtimeFrameRef.width;
|
|
7209
|
+
imageHeight = runtimeFrameRef.height;
|
|
7210
|
+
rootInput = {
|
|
7211
|
+
kind: "jpeg",
|
|
7212
|
+
data: Buffer.alloc(0)
|
|
7213
|
+
};
|
|
7214
|
+
jpegProvider = async () => {
|
|
7215
|
+
throw new Error("frameRef root view was requested before model resolution");
|
|
7216
|
+
};
|
|
7217
|
+
emit(`FrameRef: ${imageWidth}×${imageHeight} (${runtimeFrameRef.format})`);
|
|
7218
|
+
} else if (runtimeFrame) {
|
|
7112
7219
|
const frame = runtimeFrame;
|
|
7113
7220
|
imageWidth = frame.width;
|
|
7114
7221
|
imageHeight = frame.height;
|
|
@@ -7308,9 +7415,9 @@ var DetectionPipelineProvider = class DetectionPipelineProvider {
|
|
|
7308
7415
|
emit(`All models loaded`);
|
|
7309
7416
|
}
|
|
7310
7417
|
emit("Running inference...");
|
|
7311
|
-
const tree = buildExecutableTree(benchmarkSteps, (stepId) => dispatchFactory.getEngine(stepId));
|
|
7418
|
+
const tree = buildExecutableTree(benchmarkSteps, (stepId) => dispatchFactory.getEngine(stepId), this.customModelResolver);
|
|
7312
7419
|
setupMs = performance.now() - wallT0 - decodeMs;
|
|
7313
|
-
const isRuntime = Boolean(runtimeFrame);
|
|
7420
|
+
const isRuntime = Boolean(runtimeFrame || runtimeFrameRef);
|
|
7314
7421
|
const effectiveDeviceId = input.deviceId ?? 0;
|
|
7315
7422
|
const deviceOverrides = effectiveDeviceId > 0 ? await this.readDeviceStore(effectiveDeviceId) : {};
|
|
7316
7423
|
const effectiveTree = Object.keys(deviceOverrides).length > 0 ? applyDeviceOverridesToTree(tree, "object-detection", deviceOverrides) : tree;
|
|
@@ -7321,10 +7428,42 @@ var DetectionPipelineProvider = class DetectionPipelineProvider {
|
|
|
7321
7428
|
const proxy = this.deviceProxies.get(effectiveDeviceId);
|
|
7322
7429
|
if (proxy) cropZoneBbox = resolvePackageCropBbox(proxy.state.zones.value?.zones ?? [], proxy.state.zoneRules.value?.package ?? [], imageWidth, imageHeight) ?? void 0;
|
|
7323
7430
|
}
|
|
7324
|
-
|
|
7325
|
-
|
|
7326
|
-
|
|
7327
|
-
|
|
7431
|
+
let frameViewResolver;
|
|
7432
|
+
let rootInputViewProvider;
|
|
7433
|
+
if (runtimeFrameRef) {
|
|
7434
|
+
frameViewResolver = createRootFrameViewResolver(require_event_loop_stall_monitor.localFrameRegistry, runtimeFrameRef);
|
|
7435
|
+
rootInputViewProvider = async (root, crop) => {
|
|
7436
|
+
const view = await frameViewResolver(root, crop ? {
|
|
7437
|
+
left: crop[0],
|
|
7438
|
+
top: crop[1],
|
|
7439
|
+
width: crop[2] - crop[0],
|
|
7440
|
+
height: crop[3] - crop[1]
|
|
7441
|
+
} : void 0);
|
|
7442
|
+
const data = Buffer.from(view.data.buffer, view.data.byteOffset, view.data.byteLength);
|
|
7443
|
+
return {
|
|
7444
|
+
input: {
|
|
7445
|
+
kind: "jpeg",
|
|
7446
|
+
data
|
|
7447
|
+
},
|
|
7448
|
+
jpegProvider: async () => data,
|
|
7449
|
+
width: view.width,
|
|
7450
|
+
height: view.height,
|
|
7451
|
+
geometry: view.geometry
|
|
7452
|
+
};
|
|
7453
|
+
};
|
|
7454
|
+
}
|
|
7455
|
+
let executionSucceeded = false;
|
|
7456
|
+
let execution;
|
|
7457
|
+
try {
|
|
7458
|
+
execution = await executor.run(effectiveTree, rootInput, jpegProvider, imageWidth, imageHeight, effectiveDeviceId, {
|
|
7459
|
+
traceVerbosity: isRuntime ? this.eventBus ? "summary" : "off" : "full",
|
|
7460
|
+
plane: input.plane
|
|
7461
|
+
}, nativeCropProvider, cropZoneBbox, rootInputViewProvider);
|
|
7462
|
+
executionSucceeded = true;
|
|
7463
|
+
} finally {
|
|
7464
|
+
frameViewResolver?.release(executionSucceeded ? "success" : "error");
|
|
7465
|
+
}
|
|
7466
|
+
const { result, trace } = execution;
|
|
7328
7467
|
if (isRuntime) {
|
|
7329
7468
|
if (trace && this.eventBus) this.eventBus.emit(require_dist.createEvent(require_dist.EventCategory.PipelineTrace, {
|
|
7330
7469
|
type: "device",
|