@camstack/types 1.2.222 → 1.2.224

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.
@@ -57,6 +57,7 @@ function buildInputArgs(input, decodeHwAccel) {
57
57
  const args = [];
58
58
  if (!isSoftwareDecode(decodeHwAccel)) args.push("-hwaccel", String(decodeHwAccel));
59
59
  if (input.extraArgs?.length) args.push(...input.extraArgs);
60
+ if (input.decodeThreadCount !== void 0 && input.decodeThreadCount > 0) args.push("-threads", String(input.decodeThreadCount));
60
61
  if (input.analyzeDurationUs !== void 0) args.push("-analyzeduration", String(input.analyzeDurationUs));
61
62
  if (input.probeSizeBytes !== void 0) args.push("-probesize", String(input.probeSizeBytes));
62
63
  if (input.lowDelay === true) args.push("-flags", "low_delay");
@@ -327,7 +328,7 @@ function buildFfmpegArgs(inv) {
327
328
  ...(inv.extraInputs ?? []).flatMap((extra) => buildInputArgs(extra, inv.decodeHwAccel)),
328
329
  ...graph ? ["-filter_complex", graph.graph] : []
329
330
  ];
330
- const threadArgs = inv.threadCount > 0 ? ["-threads", String(inv.threadCount)] : [];
331
+ const threadArgs = [...inv.threadCount > 0 ? ["-threads", String(inv.threadCount)] : [], ...inv.filterThreadCount !== void 0 && inv.filterThreadCount > 0 ? ["-filter_threads", String(inv.filterThreadCount)] : []];
331
332
  const maps = resolveStreamMaps(inv);
332
333
  const videoMapArgs = maps.video ? ["-map", maps.video] : [];
333
334
  const audioMapArgs = maps.audio ? ["-map", maps.audio] : [];
@@ -57,6 +57,7 @@ function buildInputArgs(input, decodeHwAccel) {
57
57
  const args = [];
58
58
  if (!isSoftwareDecode(decodeHwAccel)) args.push("-hwaccel", String(decodeHwAccel));
59
59
  if (input.extraArgs?.length) args.push(...input.extraArgs);
60
+ if (input.decodeThreadCount !== void 0 && input.decodeThreadCount > 0) args.push("-threads", String(input.decodeThreadCount));
60
61
  if (input.analyzeDurationUs !== void 0) args.push("-analyzeduration", String(input.analyzeDurationUs));
61
62
  if (input.probeSizeBytes !== void 0) args.push("-probesize", String(input.probeSizeBytes));
62
63
  if (input.lowDelay === true) args.push("-flags", "low_delay");
@@ -327,7 +328,7 @@ function buildFfmpegArgs(inv) {
327
328
  ...(inv.extraInputs ?? []).flatMap((extra) => buildInputArgs(extra, inv.decodeHwAccel)),
328
329
  ...graph ? ["-filter_complex", graph.graph] : []
329
330
  ];
330
- const threadArgs = inv.threadCount > 0 ? ["-threads", String(inv.threadCount)] : [];
331
+ const threadArgs = [...inv.threadCount > 0 ? ["-threads", String(inv.threadCount)] : [], ...inv.filterThreadCount !== void 0 && inv.filterThreadCount > 0 ? ["-filter_threads", String(inv.filterThreadCount)] : []];
331
332
  const maps = resolveStreamMaps(inv);
332
333
  const videoMapArgs = maps.video ? ["-map", maps.video] : [];
333
334
  const audioMapArgs = maps.audio ? ["-map", maps.audio] : [];
@@ -90,6 +90,7 @@ declare const GridProfileOfferSchema: z.ZodObject<{
90
90
  offered: z.ZodBoolean;
91
91
  missingSources: z.ZodArray<z.ZodNumber>;
92
92
  canvas: z.ZodString;
93
+ published: z.ZodBoolean;
93
94
  }, z.core.$strip>;
94
95
  export declare const GridLayoutViewSchema: z.ZodObject<{
95
96
  instanceId: z.ZodString;
@@ -120,6 +121,7 @@ export declare const GridLayoutViewSchema: z.ZodObject<{
120
121
  offered: z.ZodBoolean;
121
122
  missingSources: z.ZodArray<z.ZodNumber>;
122
123
  canvas: z.ZodString;
124
+ published: z.ZodBoolean;
123
125
  }, z.core.$strip>>;
124
126
  }, z.core.$strip>;
125
127
  export type GridNormalizedRect = z.infer<typeof GridNormalizedRectSchema>;
@@ -130,6 +132,11 @@ export declare const GridLayoutPatchSchema: z.ZodObject<{
130
132
  deviceId: z.ZodNumber;
131
133
  name: z.ZodOptional<z.ZodString>;
132
134
  fps: z.ZodOptional<z.ZodNumber>;
135
+ publishedProfiles: z.ZodOptional<z.ZodArray<z.ZodEnum<{
136
+ high: "high";
137
+ mid: "mid";
138
+ low: "low";
139
+ }>>>;
133
140
  cells: z.ZodArray<z.ZodObject<{
134
141
  deviceId: z.ZodNumber;
135
142
  source: z.ZodObject<{
@@ -210,6 +217,7 @@ export declare const cameraGridLayoutCapability: {
210
217
  offered: z.ZodBoolean;
211
218
  missingSources: z.ZodArray<z.ZodNumber>;
212
219
  canvas: z.ZodString;
220
+ published: z.ZodBoolean;
213
221
  }, z.core.$strip>>;
214
222
  }, z.core.$strip>>, import("./capability-definition.js").CapabilityMethodKind>;
215
223
  /** Write the geometry back. Returns the grid as it now stands, profiles included. */
@@ -217,6 +225,11 @@ export declare const cameraGridLayoutCapability: {
217
225
  deviceId: z.ZodNumber;
218
226
  name: z.ZodOptional<z.ZodString>;
219
227
  fps: z.ZodOptional<z.ZodNumber>;
228
+ publishedProfiles: z.ZodOptional<z.ZodArray<z.ZodEnum<{
229
+ high: "high";
230
+ mid: "mid";
231
+ low: "low";
232
+ }>>>;
220
233
  cells: z.ZodArray<z.ZodObject<{
221
234
  deviceId: z.ZodNumber;
222
235
  source: z.ZodObject<{
@@ -261,6 +274,7 @@ export declare const cameraGridLayoutCapability: {
261
274
  offered: z.ZodBoolean;
262
275
  missingSources: z.ZodArray<z.ZodNumber>;
263
276
  canvas: z.ZodString;
277
+ published: z.ZodBoolean;
264
278
  }, z.core.$strip>>;
265
279
  }, z.core.$strip>, "mutation">;
266
280
  };
@@ -60,6 +60,24 @@ export interface FfmpegInputPlan {
60
60
  */
61
61
  readonly analyzeDurationUs?: number;
62
62
  readonly probeSizeBytes?: number;
63
+ /**
64
+ * `-threads` for the DECODER, emitted before `-i`.
65
+ *
66
+ * Distinct from {@link FfmpegInvocation.threadCount}, which lands after the
67
+ * video args and therefore bounds the ENCODER only. Nothing bounded the
68
+ * decoder at all until 2026-09-18, and that is where the threads were: left
69
+ * at auto, libavcodec creates `min(cores, 16)` frame threads per input, on a
70
+ * 20-core hub, per child.
71
+ *
72
+ * Measured the same day: a grid tile reading a 1080p sub-stream held 72
73
+ * threads; with this set to 1 and `filterThreadCount` to 1 it holds 26. The
74
+ * container's pid cgroup counts every one against a 2048 ceiling it was
75
+ * actively refusing at.
76
+ *
77
+ * A parallel decode is still a real thing — a 4K software decode at 25 fps
78
+ * cannot keep up single-threaded — so this is a number, not a flag.
79
+ */
80
+ readonly decodeThreadCount?: number;
63
81
  /**
64
82
  * A headerless stream of raw frames — `-f rawvideo` and the three facts that
65
83
  * demuxer cannot discover for itself.
@@ -389,6 +407,21 @@ export interface FfmpegInvocation {
389
407
  readonly audio: FfmpegAudioPlan;
390
408
  /** `0` = auto (omit `-threads` and let ffmpeg decide). */
391
409
  readonly threadCount: number;
410
+ /**
411
+ * `-filter_threads` — the size of libavfilter's OWN slice pool, which
412
+ * `-threads` does not touch.
413
+ *
414
+ * A separate number because it is a separate pool: ffmpeg sizes the filter
415
+ * pool to the core count independently of the codec threads, per graph. On
416
+ * this 20-core hub that is ~15 threads per graph doing nothing measurable on
417
+ * a 320x180-class output, and the container's pid cgroup counts every one of
418
+ * them. Measured on the hub 2026-09-18: a recorder passthrough went 20 → 5
419
+ * threads, a snapshot grab 35 → 4, an egress transcode 62 → 18, with
420
+ * `-threads` and this set together.
421
+ *
422
+ * Omitted when absent, so no shipped argv changes by adding the field.
423
+ */
424
+ readonly filterThreadCount?: number;
392
425
  /** Consumer output options, emitted verbatim after the encode block. */
393
426
  readonly outputArgs: readonly string[];
394
427
  readonly sink: FfmpegSink;
@@ -81,6 +81,18 @@ export interface FfmpegProcessOptions {
81
81
  * it is bounded by {@link maxRestarts} regardless of what this returns.
82
82
  */
83
83
  readonly onExit?: (exit: FfmpegExit) => void;
84
+ /**
85
+ * Called ONCE, when the wrapper stops restarting and the child is gone for
86
+ * good.
87
+ *
88
+ * `onExit` cannot answer this: it fires on every exit, including the ones
89
+ * that are about to be respawned, so a caller using it to tear down would
90
+ * tear down on the first hiccup. And the `start()` promise cannot answer it
91
+ * either — its `reject` is spent the moment the child first goes live, so a
92
+ * give-up AFTER that reached nobody at all. A camera-grid tile that died an
93
+ * hour in was indistinguishable, to its owner, from one that never started.
94
+ */
95
+ readonly onGiveUp?: (error: Error) => void;
84
96
  /** Wall-clock budget for the first output byte. `0` disables the deadline. */
85
97
  readonly firstDataTimeoutMs?: number;
86
98
  /** `0` ⇒ never restart (a run-to-completion job). */
package/dist/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
2
  const require_sleep = require("./sleep-VlZxDyXq.js");
3
3
  const require_event_category = require("./event-category-BVfsrBYA.js");
4
- const require_canonical_hash = require("./canonical-hash-BS9dQmcQ.js");
4
+ const require_canonical_hash = require("./canonical-hash-DYsYm8is.js");
5
5
  const require_enums = require("./enums.js");
6
6
  const require_err_msg = require("./err-msg-COpsHMw2.js");
7
7
  let zod = require("zod");
@@ -32559,7 +32559,16 @@ var GridProfileOfferSchema = zod.z.object({
32559
32559
  * grid came out as, and because it is the number an operator would otherwise
32560
32560
  * expect to type.
32561
32561
  */
32562
- canvas: zod.z.string()
32562
+ canvas: zod.z.string(),
32563
+ /**
32564
+ * Whether this profile is PUBLISHED, of the ones the grid could serve.
32565
+ *
32566
+ * A grid's `high` is composed of its sources' `high`, so on a 4K fleet it is
32567
+ * a 4K canvas built from 4K decodes — something to opt into, not something a
32568
+ * viewer's adaptive should be handed by climbing to the top rung it can see.
32569
+ * Default is `mid` + `low`.
32570
+ */
32571
+ published: zod.z.boolean()
32563
32572
  });
32564
32573
  var GridLayoutViewSchema = zod.z.object({
32565
32574
  /** The persisted grid row this camera was declared from. */
@@ -32582,6 +32591,12 @@ var GridLayoutPatchSchema = zod.z.object({
32582
32591
  deviceId: zod.z.number().int().nonnegative(),
32583
32592
  name: zod.z.string().min(1).max(160).optional(),
32584
32593
  fps: zod.z.number().int().min(1).max(60).optional(),
32594
+ /** Which profiles to publish. See `GridProfileOffer.published`. */
32595
+ publishedProfiles: zod.z.array(zod.z.enum([
32596
+ "high",
32597
+ "mid",
32598
+ "low"
32599
+ ])).max(3).optional(),
32585
32600
  /**
32586
32601
  * The whole cell list at once. A per-cell patch would need an ordering the
32587
32602
  * editor does not have, and a half-applied layout is a picture nobody asked
package/dist/index.mjs CHANGED
@@ -1,6 +1,6 @@
1
1
  import { $ as CAM_PROFILE_ORDER, A as DeviceType, At as isEvent, B as systemMethod, Bt as isAudioChunkFormat, C as customAction, Ct as SHARE_VIEW_KINDS, D as ChargingStatus, Dt as createDurableState, E as deviceCustomAction, Et as normalizeAddonInitResult, F as event, Ft as hydrateSchema, G as ReadinessRegistry, H as nodePin, I as expandCapMethods, It as resolveHydratedFieldValue, J as readinessKey, K as ReadinessTimeoutError, L as isDeviceConfigCap, Lt as AUDIO_CHUNK_FORMATS, M as DEFAULT_RUNTIME_STATE_DURABILITY, Mt as WELL_KNOWN_TAB_MAP, N as DEVICE_SETTINGS_CONTRIBUTION_METHODS, Nt as collectHydratedFieldEntries, O as DeviceFeature, Ot as createEvent, P as DEVICE_STATUS_METHOD, Pt as collectHydratedFieldValues, Q as BrokerStatusSchema, R as method, Rt as audioChunkBytesPerSample, S as DEVICE_CHILDREN_BATCH_MAX, St as DATAPLANE_SECRET_HEADER, T as describeCustomActions, Tt as BaseAddon, U as readNodePin, V as CAP_NODE_PIN_CONTEXT_KEY, W as toNodeId, X as AudioChunkFormatSchema, Y as scopeKey, Z as BrokerStatsSchema, _ as createMirrorSource, _t as SubscribeFramesResultSchema, a as asJsonObject, at as DecodedFrameSchema, b as deviceOpsCapability, bt as parseProfileBrokerId, c as parseJsonArray, ct as FrameHandleSchema, d as BOOT_RECOVERY_BACKOFF_MS, dt as ProfileSlotStatusSchema, et as CamProfileSchema, f as DEVICE_SCOPED_CAPS, ft as StreamSourceEntrySchema, g as createLazyTrpcSource, gt as SubscribeFramesInputSchema, h as createEventBusSliceSource, ht as SubscribeAudioChunksResultSchema, i as asJsonArray, it as DecodedAudioChunkSchema, j as adminUiCapability, jt as WELL_KNOWN_TABS, k as DeviceRole, kt as emitReadiness, l as parseJsonObject, lt as ProfileRtspEntrySchema, m as createDeviceProxy, mt as SubscribeAudioChunksInputSchema, n as sleepCancellable, nt as CamStreamResolutionSchema, o as asNumber, ot as EncodedPacketSchema, p as isDeviceScopedCap, pt as StreamSourceSchema, q as emitDownForOwnedCaps, r as asBoolean, rt as CameraStreamSchema, s as asString, st as FrameHandleFormatSchema, t as sleep, tt as CamStreamKindSchema, u as parseJsonUnknown, ut as ProfileSlotSchema, v as createSliceHandle, vt as makeProfileBrokerId, w as defineCustomActions, wt as DisposerChain, x as viewerUiCapability, xt as selectAssignedProfileSlots, y as RawStateResultSchema, yt as makeSourceBrokerId, z as resolveCapMount, zt as expandAudioChunkToF32le } from "./sleep-GU_us3DG.mjs";
2
2
  import { t as EventCategory } from "./event-category-BVDXG4tB.mjs";
3
- import { a as buildAudioArgs, c as buildVideoArgs, d as logBannerArgs, f as pickVideoEncoder, i as audioPlanFromEncodeProfile, l as invocationFromEncodeProfile, n as Fmp4BoxSplitter, o as buildFfmpegArgs, p as resolveStreamMaps, r as AUDIO_PRESETS, s as buildInputArgs, t as canonicalHash, u as isSoftwareDecode } from "./canonical-hash-C5pB-QV1.mjs";
3
+ import { a as buildAudioArgs, c as buildVideoArgs, d as logBannerArgs, f as pickVideoEncoder, i as audioPlanFromEncodeProfile, l as invocationFromEncodeProfile, n as Fmp4BoxSplitter, o as buildFfmpegArgs, p as resolveStreamMaps, r as AUDIO_PRESETS, s as buildInputArgs, t as canonicalHash, u as isSoftwareDecode } from "./canonical-hash-CvL03d3i.mjs";
4
4
  import { EventSourceType } from "./enums.mjs";
5
5
  import { t as errMsg } from "./err-msg-IQTHeDzc.mjs";
6
6
  import { z } from "zod";
@@ -32558,7 +32558,16 @@ var GridProfileOfferSchema = z.object({
32558
32558
  * grid came out as, and because it is the number an operator would otherwise
32559
32559
  * expect to type.
32560
32560
  */
32561
- canvas: z.string()
32561
+ canvas: z.string(),
32562
+ /**
32563
+ * Whether this profile is PUBLISHED, of the ones the grid could serve.
32564
+ *
32565
+ * A grid's `high` is composed of its sources' `high`, so on a 4K fleet it is
32566
+ * a 4K canvas built from 4K decodes — something to opt into, not something a
32567
+ * viewer's adaptive should be handed by climbing to the top rung it can see.
32568
+ * Default is `mid` + `low`.
32569
+ */
32570
+ published: z.boolean()
32562
32571
  });
32563
32572
  var GridLayoutViewSchema = z.object({
32564
32573
  /** The persisted grid row this camera was declared from. */
@@ -32581,6 +32590,12 @@ var GridLayoutPatchSchema = z.object({
32581
32590
  deviceId: z.number().int().nonnegative(),
32582
32591
  name: z.string().min(1).max(160).optional(),
32583
32592
  fps: z.number().int().min(1).max(60).optional(),
32593
+ /** Which profiles to publish. See `GridProfileOffer.published`. */
32594
+ publishedProfiles: z.array(z.enum([
32595
+ "high",
32596
+ "mid",
32597
+ "low"
32598
+ ])).max(3).optional(),
32584
32599
  /**
32585
32600
  * The whole cell list at once. A per-cell patch would need an ordering the
32586
32601
  * editor does not have, and a half-applied layout is a picture nobody asked
package/dist/node.js CHANGED
@@ -21,7 +21,7 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
21
21
  enumerable: true
22
22
  }) : target, mod));
23
23
  //#endregion
24
- const require_canonical_hash = require("./canonical-hash-BS9dQmcQ.js");
24
+ const require_canonical_hash = require("./canonical-hash-DYsYm8is.js");
25
25
  const require_err_msg = require("./err-msg-COpsHMw2.js");
26
26
  let node_crypto = require("node:crypto");
27
27
  let node_fs = require("node:fs");
@@ -1158,7 +1158,9 @@ var FfmpegProcess = class {
1158
1158
  tags: this.logTags,
1159
1159
  meta: { stderrTail: this.stderrTail }
1160
1160
  });
1161
- onDead(new Error(reason));
1161
+ const error = new Error(reason);
1162
+ onDead(error);
1163
+ this.opts.onGiveUp?.(error);
1162
1164
  return;
1163
1165
  }
1164
1166
  this.scheduleRestart(onLive, onDead);
@@ -1166,7 +1168,10 @@ var FfmpegProcess = class {
1166
1168
  scheduleRestart(onLive, onDead) {
1167
1169
  if (this.stopped) return;
1168
1170
  const maxRestarts = this.opts.maxRestarts ?? 0;
1169
- if (maxRestarts === 0) return;
1171
+ if (maxRestarts === 0) {
1172
+ this.opts.onGiveUp?.(/* @__PURE__ */ new Error(`ffmpeg ${this.opts.role} ended and restarts are disabled`));
1173
+ return;
1174
+ }
1170
1175
  if (this.producedOutput && this.now - this.startedAtMs >= (this.opts.stableRunMs ?? DEFAULT_STABLE_RUN_MS)) this.consecutiveFailures = 0;
1171
1176
  if (this.consecutiveFailures > maxRestarts) return;
1172
1177
  (this.opts.setTimeoutFn ?? setTimeout)(() => {
package/dist/node.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import { n as Fmp4BoxSplitter, o as buildFfmpegArgs, t as canonicalHash, u as isSoftwareDecode } from "./canonical-hash-C5pB-QV1.mjs";
1
+ import { n as Fmp4BoxSplitter, o as buildFfmpegArgs, t as canonicalHash, u as isSoftwareDecode } from "./canonical-hash-CvL03d3i.mjs";
2
2
  import { t as errMsg } from "./err-msg-IQTHeDzc.mjs";
3
3
  import { createHash, createHmac, randomUUID, timingSafeEqual } from "node:crypto";
4
4
  import * as fs from "node:fs";
@@ -1135,7 +1135,9 @@ var FfmpegProcess = class {
1135
1135
  tags: this.logTags,
1136
1136
  meta: { stderrTail: this.stderrTail }
1137
1137
  });
1138
- onDead(new Error(reason));
1138
+ const error = new Error(reason);
1139
+ onDead(error);
1140
+ this.opts.onGiveUp?.(error);
1139
1141
  return;
1140
1142
  }
1141
1143
  this.scheduleRestart(onLive, onDead);
@@ -1143,7 +1145,10 @@ var FfmpegProcess = class {
1143
1145
  scheduleRestart(onLive, onDead) {
1144
1146
  if (this.stopped) return;
1145
1147
  const maxRestarts = this.opts.maxRestarts ?? 0;
1146
- if (maxRestarts === 0) return;
1148
+ if (maxRestarts === 0) {
1149
+ this.opts.onGiveUp?.(/* @__PURE__ */ new Error(`ffmpeg ${this.opts.role} ended and restarts are disabled`));
1150
+ return;
1151
+ }
1147
1152
  if (this.producedOutput && this.now - this.startedAtMs >= (this.opts.stableRunMs ?? DEFAULT_STABLE_RUN_MS)) this.consecutiveFailures = 0;
1148
1153
  if (this.consecutiveFailures > maxRestarts) return;
1149
1154
  (this.opts.setTimeoutFn ?? setTimeout)(() => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@camstack/types",
3
- "version": "1.2.222",
3
+ "version": "1.2.224",
4
4
  "description": "Shared types, interfaces, and model catalogs for the CamStack detection ecosystem",
5
5
  "keywords": [
6
6
  "camstack",