@camstack/system 1.1.24 → 1.1.26
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-runner.js +1 -1
- package/dist/addon-runner.mjs +1 -1
- package/dist/builtins/platform-probe/index.d.ts +20 -9
- package/dist/builtins/platform-probe/index.js +81 -305
- package/dist/builtins/platform-probe/index.mjs +83 -305
- package/dist/builtins/system-config/system-config.addon.js +51 -118
- package/dist/builtins/system-config/system-config.addon.mjs +51 -118
- package/dist/index.js +1 -2
- package/dist/index.mjs +2 -2
- package/dist/kernel/hwaccel/hwaccel-resolver.d.ts +9 -0
- package/dist/kernel/index.d.ts +0 -2
- package/dist/kernel/inference/inference-resolver.d.ts +16 -0
- package/dist/kernel/transport/parent-unowned-call.d.ts +20 -0
- package/dist/{manifest-python-deps-XWJwKYDx.js → manifest-python-deps-CCmnJmNf.js} +27 -37
- package/dist/{manifest-python-deps-CPJXzrZt.mjs → manifest-python-deps-DPA7N9UP.mjs} +31 -35
- package/package.json +1 -1
- package/dist/builtins/platform-probe/hardware-decode-accel-probe.d.ts +0 -37
- package/dist/builtins/platform-probe/hardware-encoder-probe.d.ts +0 -13
- package/dist/kernel/hwaccel/hwaccel-service.d.ts +0 -4
package/dist/addon-runner.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
const require_chunk = require("./chunk-Cek0wNdY.js");
|
|
2
|
-
const require_manifest_python_deps = require("./manifest-python-deps-
|
|
2
|
+
const require_manifest_python_deps = require("./manifest-python-deps-CCmnJmNf.js");
|
|
3
3
|
const require_custom_action_registry = require("./custom-action-registry-vLYEFTtv.js");
|
|
4
4
|
let node_fs = require("node:fs");
|
|
5
5
|
node_fs = require_chunk.__toESM(node_fs);
|
package/dist/addon-runner.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { F as createUdsLoggerWithControl, I as LocalChildClient, i as createUdsAddonContext, it as setWorkerNativeCapsChangeListener, nt as getWorkerNativeCapSnapshot, ot as validateProviderRegistrations, t as installManifestPythonDeps, tt as getWorkerNativeCapProvider, vt as installManifestNativeDeps, yt as resolveAddonClass } from "./manifest-python-deps-DPA7N9UP.mjs";
|
|
2
2
|
import { t as CustomActionRegistry } from "./custom-action-registry-BEXwC-oo.mjs";
|
|
3
3
|
import { register } from "node:module";
|
|
4
4
|
import * as fs from "node:fs";
|
|
@@ -1,21 +1,32 @@
|
|
|
1
1
|
import { ProviderRegistration, BaseAddon } from '@camstack/types';
|
|
2
2
|
export { PlatformScorer } from './platform-scorer.js';
|
|
3
3
|
export { InferenceConfigResolver } from './inference-config-resolver.js';
|
|
4
|
-
export { HardwareEncoderProber } from './hardware-encoder-probe.js';
|
|
5
|
-
export { HardwareDecodeAccelProber } from './hardware-decode-accel-probe.js';
|
|
6
4
|
export declare class PlatformProbeNativeAddon extends BaseAddon {
|
|
7
5
|
private scorer;
|
|
8
|
-
private encoderProber;
|
|
9
|
-
private decodeAccelProber;
|
|
10
6
|
private cachedCaps;
|
|
7
|
+
/**
|
|
8
|
+
* Per-boot generation stamp for the manual readiness emissions below.
|
|
9
|
+
* Constant for the lifetime of this addon instance (== one process boot);
|
|
10
|
+
* consumer-side registries derive a monotonic epoch from generation
|
|
11
|
+
* transitions. Mirrors `BaseAddon._readinessGeneration` (private there).
|
|
12
|
+
*/
|
|
13
|
+
private readonly readinessGeneration;
|
|
11
14
|
constructor();
|
|
12
15
|
/**
|
|
13
|
-
*
|
|
14
|
-
* `
|
|
15
|
-
*
|
|
16
|
-
*
|
|
16
|
+
* Manual readiness protocol. The provider registers synchronously from
|
|
17
|
+
* `onInitialize`, but the REAL hardware + EP scoring is the async
|
|
18
|
+
* `probePromise` (embedded-Python install included). The BaseAddon
|
|
19
|
+
* auto-emit would flip `ready` at registration time — BEFORE any
|
|
20
|
+
* accelerator is visible — so probe-gated consumers (detection-pipeline
|
|
21
|
+
* engine auto-pick) would read accelerator-blind results and stick on
|
|
22
|
+
* onnx-CPU. Instead: `starting` at init, the single authoritative
|
|
23
|
+
* `ready` once the probe resolves, `down` on shutdown.
|
|
17
24
|
*/
|
|
18
|
-
|
|
25
|
+
protected get autoEmitReadiness(): boolean;
|
|
26
|
+
/** Bare cluster node id — readiness is scoped `{type:'node', nodeId}`. */
|
|
27
|
+
private bareLocalNodeId;
|
|
28
|
+
/** Emit a `system.ready-state` transition for the platform-probe cap. */
|
|
29
|
+
private emitProbeReadiness;
|
|
19
30
|
protected onInitialize(): Promise<ProviderRegistration[]>;
|
|
20
31
|
protected onShutdown(): Promise<void>;
|
|
21
32
|
}
|
|
@@ -18,7 +18,7 @@ node_os = require_chunk.__toESM(node_os);
|
|
|
18
18
|
* entire Node process (WS handshakes, tRPC subscriptions, metrics — all
|
|
19
19
|
* stalled). Keeping it async turns the probe into a true background task.
|
|
20
20
|
*/
|
|
21
|
-
var execFileAsync
|
|
21
|
+
var execFileAsync = (0, node_util.promisify)(node_child_process.execFile);
|
|
22
22
|
/** Minimal no-op logger for default parameter */
|
|
23
23
|
var noopLogger = {
|
|
24
24
|
debug() {},
|
|
@@ -46,7 +46,7 @@ async function getAvailableRAM_MB() {
|
|
|
46
46
|
const platform = node_os.platform();
|
|
47
47
|
try {
|
|
48
48
|
if (platform === "darwin") {
|
|
49
|
-
const { stdout: output } = await execFileAsync
|
|
49
|
+
const { stdout: output } = await execFileAsync("vm_stat", [], {
|
|
50
50
|
encoding: "utf8",
|
|
51
51
|
timeout: 3e3
|
|
52
52
|
});
|
|
@@ -171,7 +171,7 @@ var PlatformScorer = class {
|
|
|
171
171
|
}
|
|
172
172
|
if (platform === "linux") {
|
|
173
173
|
try {
|
|
174
|
-
const { stdout } = await execFileAsync
|
|
174
|
+
const { stdout } = await execFileAsync("nvidia-smi", ["--query-gpu=name,memory.total", "--format=csv,noheader"], {
|
|
175
175
|
encoding: "utf8",
|
|
176
176
|
timeout: 5e3
|
|
177
177
|
});
|
|
@@ -237,7 +237,7 @@ var PlatformScorer = class {
|
|
|
237
237
|
"python"
|
|
238
238
|
];
|
|
239
239
|
for (const cmd of candidates) try {
|
|
240
|
-
await execFileAsync
|
|
240
|
+
await execFileAsync(cmd, ["--version"], { timeout: 5e3 });
|
|
241
241
|
return cmd;
|
|
242
242
|
} catch (err) {
|
|
243
243
|
this.logger.debug(`Python command "${cmd}" not found`, { meta: { error: (0, _camstack_types.errMsg)(err) } });
|
|
@@ -335,296 +335,91 @@ var InferenceConfigResolver = class {
|
|
|
335
335
|
}
|
|
336
336
|
};
|
|
337
337
|
//#endregion
|
|
338
|
-
//#region src/builtins/platform-probe/
|
|
339
|
-
var execFileAsync$1 = (0, node_util.promisify)(node_child_process.execFile);
|
|
340
|
-
function buildCandidates(hardware) {
|
|
341
|
-
const out = [];
|
|
342
|
-
if (hardware.platform === "darwin") {
|
|
343
|
-
out.push({
|
|
344
|
-
encoder: "h264_videotoolbox",
|
|
345
|
-
codec: "H264",
|
|
346
|
-
family: "videotoolbox"
|
|
347
|
-
});
|
|
348
|
-
out.push({
|
|
349
|
-
encoder: "hevc_videotoolbox",
|
|
350
|
-
codec: "H265",
|
|
351
|
-
family: "videotoolbox"
|
|
352
|
-
});
|
|
353
|
-
}
|
|
354
|
-
if (hardware.platform === "linux") {
|
|
355
|
-
if (hardware.gpu?.type === "nvidia") {
|
|
356
|
-
out.push({
|
|
357
|
-
encoder: "h264_nvenc",
|
|
358
|
-
codec: "H264",
|
|
359
|
-
family: "nvenc"
|
|
360
|
-
});
|
|
361
|
-
out.push({
|
|
362
|
-
encoder: "hevc_nvenc",
|
|
363
|
-
codec: "H265",
|
|
364
|
-
family: "nvenc"
|
|
365
|
-
});
|
|
366
|
-
}
|
|
367
|
-
if (hardware.gpu?.type === "intel" || hardware.gpu?.type === "amd" || !hardware.gpu) {
|
|
368
|
-
out.push({
|
|
369
|
-
encoder: "h264_vaapi",
|
|
370
|
-
codec: "H264",
|
|
371
|
-
family: "vaapi"
|
|
372
|
-
});
|
|
373
|
-
out.push({
|
|
374
|
-
encoder: "hevc_vaapi",
|
|
375
|
-
codec: "H265",
|
|
376
|
-
family: "vaapi"
|
|
377
|
-
});
|
|
378
|
-
}
|
|
379
|
-
}
|
|
380
|
-
return out;
|
|
381
|
-
}
|
|
382
|
-
async function runTestEncode(candidate, opts) {
|
|
383
|
-
const ffmpeg = opts.ffmpegPath ?? "ffmpeg";
|
|
384
|
-
const timeout = opts.timeoutMs ?? 8e3;
|
|
385
|
-
const nullSink = node_os.platform() === "win32" ? "NUL" : "/dev/null";
|
|
386
|
-
const baseArgs = [
|
|
387
|
-
"-hide_banner",
|
|
388
|
-
"-loglevel",
|
|
389
|
-
"error"
|
|
390
|
-
];
|
|
391
|
-
const inArgs = [
|
|
392
|
-
"-f",
|
|
393
|
-
"lavfi",
|
|
394
|
-
"-i",
|
|
395
|
-
"testsrc=duration=0.04:size=16x16:rate=25"
|
|
396
|
-
];
|
|
397
|
-
let outArgs;
|
|
398
|
-
if (candidate.family === "vaapi") outArgs = [
|
|
399
|
-
"-vaapi_device",
|
|
400
|
-
"/dev/dri/renderD128",
|
|
401
|
-
"-vf",
|
|
402
|
-
"format=nv12,hwupload",
|
|
403
|
-
"-c:v",
|
|
404
|
-
candidate.encoder,
|
|
405
|
-
"-frames:v",
|
|
406
|
-
"1",
|
|
407
|
-
"-f",
|
|
408
|
-
"null",
|
|
409
|
-
nullSink
|
|
410
|
-
];
|
|
411
|
-
else outArgs = [
|
|
412
|
-
"-c:v",
|
|
413
|
-
candidate.encoder,
|
|
414
|
-
"-frames:v",
|
|
415
|
-
"1",
|
|
416
|
-
"-f",
|
|
417
|
-
"null",
|
|
418
|
-
nullSink
|
|
419
|
-
];
|
|
420
|
-
try {
|
|
421
|
-
await execFileAsync$1(ffmpeg, [
|
|
422
|
-
...baseArgs,
|
|
423
|
-
...inArgs,
|
|
424
|
-
...outArgs
|
|
425
|
-
], {
|
|
426
|
-
timeout,
|
|
427
|
-
encoding: "utf8"
|
|
428
|
-
});
|
|
429
|
-
return {
|
|
430
|
-
encoder: candidate.encoder,
|
|
431
|
-
codec: candidate.codec,
|
|
432
|
-
family: candidate.family,
|
|
433
|
-
available: true
|
|
434
|
-
};
|
|
435
|
-
} catch (err) {
|
|
436
|
-
return {
|
|
437
|
-
encoder: candidate.encoder,
|
|
438
|
-
codec: candidate.codec,
|
|
439
|
-
family: candidate.family,
|
|
440
|
-
available: false,
|
|
441
|
-
reason: (0, _camstack_types.errMsg)(err)
|
|
442
|
-
};
|
|
443
|
-
}
|
|
444
|
-
}
|
|
445
|
-
var HardwareEncoderProber = class {
|
|
446
|
-
cached = null;
|
|
447
|
-
inflight = null;
|
|
448
|
-
logger;
|
|
449
|
-
ffmpegPath;
|
|
450
|
-
constructor(logger, ffmpegPath = "ffmpeg") {
|
|
451
|
-
this.logger = logger;
|
|
452
|
-
this.ffmpegPath = ffmpegPath;
|
|
453
|
-
}
|
|
454
|
-
getCached() {
|
|
455
|
-
return this.cached;
|
|
456
|
-
}
|
|
457
|
-
async probe(hardware, options = {}) {
|
|
458
|
-
if (!options.force && this.cached) return this.cached;
|
|
459
|
-
if (this.inflight) return this.inflight;
|
|
460
|
-
this.inflight = this.runProbe(hardware).then((res) => {
|
|
461
|
-
this.cached = res;
|
|
462
|
-
this.inflight = null;
|
|
463
|
-
return res;
|
|
464
|
-
}).catch((err) => {
|
|
465
|
-
this.inflight = null;
|
|
466
|
-
throw err;
|
|
467
|
-
});
|
|
468
|
-
return this.inflight;
|
|
469
|
-
}
|
|
470
|
-
async runProbe(hardware) {
|
|
471
|
-
const candidates = buildCandidates(hardware);
|
|
472
|
-
const start = Date.now();
|
|
473
|
-
this.logger.info("Probing hardware encoders", { meta: {
|
|
474
|
-
platform: hardware.platform,
|
|
475
|
-
arch: hardware.arch,
|
|
476
|
-
candidates: candidates.length
|
|
477
|
-
} });
|
|
478
|
-
const probes = await Promise.all(candidates.map((c) => runTestEncode(c, { ffmpegPath: this.ffmpegPath })));
|
|
479
|
-
probes.push({
|
|
480
|
-
encoder: "libx264",
|
|
481
|
-
codec: "H264",
|
|
482
|
-
family: "software",
|
|
483
|
-
available: true
|
|
484
|
-
});
|
|
485
|
-
probes.push({
|
|
486
|
-
encoder: "libx265",
|
|
487
|
-
codec: "H265",
|
|
488
|
-
family: "software",
|
|
489
|
-
available: true
|
|
490
|
-
});
|
|
491
|
-
const pickDefault = (codec) => {
|
|
492
|
-
const hw = probes.find((p) => p.codec === codec && p.available && p.family !== "software");
|
|
493
|
-
if (hw) return hw.encoder;
|
|
494
|
-
return codec === "H264" ? "libx264" : "libx265";
|
|
495
|
-
};
|
|
496
|
-
const result = {
|
|
497
|
-
encoders: probes,
|
|
498
|
-
defaultH264: pickDefault("H264"),
|
|
499
|
-
defaultH265: pickDefault("H265"),
|
|
500
|
-
probedAt: Date.now()
|
|
501
|
-
};
|
|
502
|
-
const elapsed = Date.now() - start;
|
|
503
|
-
this.logger.info("Hardware encoder probe complete", { meta: {
|
|
504
|
-
elapsedMs: elapsed,
|
|
505
|
-
defaultH264: result.defaultH264,
|
|
506
|
-
defaultH265: result.defaultH265,
|
|
507
|
-
availableHw: probes.filter((p) => p.available && p.family !== "software").map((p) => p.encoder)
|
|
508
|
-
} });
|
|
509
|
-
return result;
|
|
510
|
-
}
|
|
511
|
-
};
|
|
512
|
-
//#endregion
|
|
513
|
-
//#region src/builtins/platform-probe/hardware-decode-accel-probe.ts
|
|
514
|
-
var execFileAsync = (0, node_util.promisify)(node_child_process.execFile);
|
|
515
|
-
var defaultExecFn = async (ffmpegPath, args) => {
|
|
516
|
-
const { stdout } = await execFileAsync(ffmpegPath, [...args], {
|
|
517
|
-
timeout: 8e3,
|
|
518
|
-
encoding: "utf8"
|
|
519
|
-
});
|
|
520
|
-
return { stdout };
|
|
521
|
-
};
|
|
338
|
+
//#region src/builtins/platform-probe/index.ts
|
|
522
339
|
/**
|
|
523
|
-
*
|
|
524
|
-
*
|
|
525
|
-
*
|
|
526
|
-
*
|
|
527
|
-
*
|
|
528
|
-
*
|
|
529
|
-
* method names, lowercased and de-duplicated (order preserved).
|
|
340
|
+
* The decode-hwaccel backends `ctx.kernel.hwaccel.resolve` accepts. The cap
|
|
341
|
+
* input enum is WIDER (it also carries EP-only names — coreml/openvino/… —
|
|
342
|
+
* shared with other probe surfaces), so the provider param must stay
|
|
343
|
+
* `string`-typed to satisfy the `InferProvider` contract. We narrow it here
|
|
344
|
+
* with a type guard instead of a cast: any value that is not a known decode
|
|
345
|
+
* backend (or the `'none'` sentinel) resolves to `null` → auto-probe.
|
|
530
346
|
*/
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
347
|
+
var HWACCEL_DECODE_BACKENDS = [
|
|
348
|
+
"videotoolbox",
|
|
349
|
+
"cuda",
|
|
350
|
+
"nvdec",
|
|
351
|
+
"vaapi",
|
|
352
|
+
"qsv",
|
|
353
|
+
"d3d11va",
|
|
354
|
+
"dxva2",
|
|
355
|
+
"amf",
|
|
356
|
+
"vdpau",
|
|
357
|
+
"drm"
|
|
358
|
+
];
|
|
359
|
+
function isHwAccelBackend(value) {
|
|
360
|
+
return HWACCEL_DECODE_BACKENDS.includes(value);
|
|
361
|
+
}
|
|
362
|
+
function narrowHwAccelPrefer(value) {
|
|
363
|
+
if (value === "none") return "none";
|
|
364
|
+
if (typeof value === "string" && isHwAccelBackend(value)) return value;
|
|
365
|
+
return null;
|
|
543
366
|
}
|
|
544
|
-
/**
|
|
545
|
-
* Probes which `-hwaccel` decode backends the configured ffmpeg binary
|
|
546
|
-
* supports. Mirrors {@link HardwareEncoderProber} (configured binary, cached,
|
|
547
|
-
* single-flight, forceable). Never throws: a probe failure yields an empty
|
|
548
|
-
* method list so callers fall back to software decode.
|
|
549
|
-
*/
|
|
550
|
-
var HardwareDecodeAccelProber = class {
|
|
551
|
-
cached = null;
|
|
552
|
-
inflight = null;
|
|
553
|
-
logger;
|
|
554
|
-
ffmpegPath;
|
|
555
|
-
execFn;
|
|
556
|
-
constructor(logger, ffmpegPath = "ffmpeg", execFn = defaultExecFn) {
|
|
557
|
-
this.logger = logger;
|
|
558
|
-
this.ffmpegPath = ffmpegPath;
|
|
559
|
-
this.execFn = execFn;
|
|
560
|
-
}
|
|
561
|
-
getCached() {
|
|
562
|
-
return this.cached;
|
|
563
|
-
}
|
|
564
|
-
async probe(options = {}) {
|
|
565
|
-
if (!options.force && this.cached) return this.cached;
|
|
566
|
-
if (this.inflight) return this.inflight;
|
|
567
|
-
this.inflight = this.runProbe().then((res) => {
|
|
568
|
-
this.cached = res;
|
|
569
|
-
this.inflight = null;
|
|
570
|
-
return res;
|
|
571
|
-
}).catch((err) => {
|
|
572
|
-
this.inflight = null;
|
|
573
|
-
throw err;
|
|
574
|
-
});
|
|
575
|
-
return this.inflight;
|
|
576
|
-
}
|
|
577
|
-
async runProbe() {
|
|
578
|
-
try {
|
|
579
|
-
const { stdout } = await this.execFn(this.ffmpegPath, ["-hide_banner", "-hwaccels"]);
|
|
580
|
-
const methods = parseHwAccelsOutput(stdout);
|
|
581
|
-
this.logger.info("Hardware decode-accel probe complete", { meta: { methods } });
|
|
582
|
-
return {
|
|
583
|
-
methods,
|
|
584
|
-
probedAt: Date.now()
|
|
585
|
-
};
|
|
586
|
-
} catch (err) {
|
|
587
|
-
this.logger.warn("Hardware decode-accel probe failed — assuming none available", { meta: { error: (0, _camstack_types.errMsg)(err) } });
|
|
588
|
-
return {
|
|
589
|
-
methods: [],
|
|
590
|
-
probedAt: Date.now()
|
|
591
|
-
};
|
|
592
|
-
}
|
|
593
|
-
}
|
|
594
|
-
};
|
|
595
|
-
//#endregion
|
|
596
|
-
//#region src/builtins/platform-probe/index.ts
|
|
597
367
|
var PlatformProbeNativeAddon = class extends _camstack_types.BaseAddon {
|
|
598
368
|
scorer = null;
|
|
599
|
-
encoderProber = null;
|
|
600
|
-
decodeAccelProber = null;
|
|
601
369
|
cachedCaps = null;
|
|
370
|
+
/**
|
|
371
|
+
* Per-boot generation stamp for the manual readiness emissions below.
|
|
372
|
+
* Constant for the lifetime of this addon instance (== one process boot);
|
|
373
|
+
* consumer-side registries derive a monotonic epoch from generation
|
|
374
|
+
* transitions. Mirrors `BaseAddon._readinessGeneration` (private there).
|
|
375
|
+
*/
|
|
376
|
+
readinessGeneration = typeof crypto !== "undefined" && crypto.randomUUID ? crypto.randomUUID() : Math.random().toString(36).slice(2, 14);
|
|
602
377
|
constructor() {
|
|
603
378
|
super({});
|
|
604
379
|
}
|
|
605
380
|
/**
|
|
606
|
-
*
|
|
607
|
-
* `
|
|
608
|
-
*
|
|
609
|
-
*
|
|
381
|
+
* Manual readiness protocol. The provider registers synchronously from
|
|
382
|
+
* `onInitialize`, but the REAL hardware + EP scoring is the async
|
|
383
|
+
* `probePromise` (embedded-Python install included). The BaseAddon
|
|
384
|
+
* auto-emit would flip `ready` at registration time — BEFORE any
|
|
385
|
+
* accelerator is visible — so probe-gated consumers (detection-pipeline
|
|
386
|
+
* engine auto-pick) would read accelerator-blind results and stick on
|
|
387
|
+
* onnx-CPU. Instead: `starting` at init, the single authoritative
|
|
388
|
+
* `ready` once the probe resolves, `down` on shutdown.
|
|
610
389
|
*/
|
|
611
|
-
|
|
390
|
+
get autoEmitReadiness() {
|
|
391
|
+
return false;
|
|
392
|
+
}
|
|
393
|
+
/** Bare cluster node id — readiness is scoped `{type:'node', nodeId}`. */
|
|
394
|
+
bareLocalNodeId() {
|
|
395
|
+
const raw = this.ctx.kernel?.localNodeId ?? "hub";
|
|
396
|
+
return raw.includes("/") ? raw.split("/")[0] : raw;
|
|
397
|
+
}
|
|
398
|
+
/** Emit a `system.ready-state` transition for the platform-probe cap. */
|
|
399
|
+
emitProbeReadiness(state) {
|
|
400
|
+
const ctx = this.ctxIfReady;
|
|
401
|
+
if (!ctx) return;
|
|
402
|
+
const nodeId = this.bareLocalNodeId();
|
|
612
403
|
try {
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
404
|
+
(0, _camstack_types.emitReadiness)(ctx.eventBus, {
|
|
405
|
+
capName: _camstack_types.platformProbeCapability.name,
|
|
406
|
+
scope: {
|
|
407
|
+
type: "node",
|
|
408
|
+
nodeId
|
|
409
|
+
},
|
|
410
|
+
state,
|
|
411
|
+
generation: this.readinessGeneration,
|
|
412
|
+
sourceNodeId: nodeId
|
|
413
|
+
});
|
|
414
|
+
} catch {}
|
|
618
415
|
}
|
|
619
416
|
async onInitialize() {
|
|
417
|
+
this.emitProbeReadiness("starting");
|
|
620
418
|
const embeddedPython = await this.ctx.deps.ensurePython().catch((err) => {
|
|
621
419
|
this.ctx.logger.debug("ensurePython unavailable for platform probe", { meta: { error: (0, _camstack_types.errMsg)(err) } });
|
|
622
420
|
return null;
|
|
623
421
|
});
|
|
624
422
|
this.scorer = new PlatformScorer(this.ctx.logger, embeddedPython);
|
|
625
|
-
const ffmpegPath = await this.resolveFfmpegBinaryPath();
|
|
626
|
-
this.encoderProber = new HardwareEncoderProber(this.ctx.logger, ffmpegPath);
|
|
627
|
-
this.decodeAccelProber = new HardwareDecodeAccelProber(this.ctx.logger, ffmpegPath);
|
|
628
423
|
const emitPhase = (phase, payload) => {
|
|
629
424
|
this.ctx.eventBus?.emit({
|
|
630
425
|
id: `platform-probe-${phase}-${Date.now()}`,
|
|
@@ -651,6 +446,7 @@ var PlatformProbeNativeAddon = class extends _camstack_types.BaseAddon {
|
|
|
651
446
|
bestReason: caps.bestScore.reason,
|
|
652
447
|
bestScore: caps.bestScore.score
|
|
653
448
|
} });
|
|
449
|
+
this.emitProbeReadiness("ready");
|
|
654
450
|
return caps;
|
|
655
451
|
}).catch((err) => {
|
|
656
452
|
const msg = (0, _camstack_types.errMsg)(err);
|
|
@@ -676,46 +472,26 @@ var PlatformProbeNativeAddon = class extends _camstack_types.BaseAddon {
|
|
|
676
472
|
},
|
|
677
473
|
resolveHwAccel: async (input) => {
|
|
678
474
|
const hwaccel = this.ctx.kernel.hwaccel;
|
|
679
|
-
if (!hwaccel) return {
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
const
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
return prober.probe(caps.hardware);
|
|
689
|
-
},
|
|
690
|
-
refreshHardwareEncoders: async () => {
|
|
691
|
-
const prober = this.encoderProber;
|
|
692
|
-
if (!prober) throw new Error("Hardware encoder prober not initialized");
|
|
693
|
-
const caps = await getCaps();
|
|
694
|
-
return prober.probe(caps.hardware, { force: true });
|
|
695
|
-
},
|
|
696
|
-
getHardwareDecodeAccels: async () => {
|
|
697
|
-
const prober = this.decodeAccelProber;
|
|
698
|
-
if (!prober) throw new Error("Hardware decode-accel prober not initialized");
|
|
699
|
-
return prober.probe();
|
|
700
|
-
},
|
|
701
|
-
refreshHardwareDecodeAccels: async () => {
|
|
702
|
-
const prober = this.decodeAccelProber;
|
|
703
|
-
if (!prober) throw new Error("Hardware decode-accel prober not initialized");
|
|
704
|
-
return prober.probe({ force: true });
|
|
475
|
+
if (!hwaccel) return {
|
|
476
|
+
preferred: [],
|
|
477
|
+
rationale: "kernel hwaccel unavailable"
|
|
478
|
+
};
|
|
479
|
+
const res = await hwaccel.resolve(narrowHwAccelPrefer(input.prefer));
|
|
480
|
+
return {
|
|
481
|
+
preferred: res.preferred,
|
|
482
|
+
rationale: res.rationale
|
|
483
|
+
};
|
|
705
484
|
}
|
|
706
485
|
}
|
|
707
486
|
}];
|
|
708
487
|
}
|
|
709
488
|
async onShutdown() {
|
|
489
|
+
this.emitProbeReadiness("down");
|
|
710
490
|
this.scorer = null;
|
|
711
|
-
this.encoderProber = null;
|
|
712
|
-
this.decodeAccelProber = null;
|
|
713
491
|
this.cachedCaps = null;
|
|
714
492
|
}
|
|
715
493
|
};
|
|
716
494
|
//#endregion
|
|
717
|
-
exports.HardwareDecodeAccelProber = HardwareDecodeAccelProber;
|
|
718
|
-
exports.HardwareEncoderProber = HardwareEncoderProber;
|
|
719
495
|
exports.InferenceConfigResolver = InferenceConfigResolver;
|
|
720
496
|
exports.PlatformProbeNativeAddon = PlatformProbeNativeAddon;
|
|
721
497
|
exports.default = PlatformProbeNativeAddon;
|