@camstack/addon-provider-rtsp 1.2.14 → 1.2.15

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.js CHANGED
@@ -25300,13 +25300,24 @@ method(object({
25300
25300
  /** Playback-speed multiplier for the render (1 = realtime). */
25301
25301
  var ExportSpeedSchema = number().min(.25).max(32);
25302
25302
  /**
25303
- * One dense interval, in SECONDS FROM THE EXPORT'S OWN `fromMs`.
25303
+ * One dense interval, in WALL-CLOCK SECONDS FROM THE EXPORT'S OWN `fromMs`.
25304
25304
  *
25305
- * Relative and not absolute epoch on purpose: the renderer's frame-select
25306
- * expression sees ffmpeg's `t`, which starts at 0 for the export's source
25307
- * playlist. Handing it absolute epochs would make every call site responsible
25308
- * for the same subtraction, and the one that forgot would emit a filter that
25309
- * selects nothing silently, as a uniform timelapse.
25305
+ * **Wall clock, not ffmpeg's `t`** and the recorder translates. A caller
25306
+ * derives these bounds from things that happened at a TIME (a track's
25307
+ * `firstSeen`), while `t` runs over the source playlist: the concatenation of
25308
+ * every segment present for the range, with each recording GAP removed. The
25309
+ * two agree only on a window that recorded without one interruption, and only
25310
+ * the render side knows the segments, so the translation lives there
25311
+ * (`export-dense-map.ts`, addon-pipeline).
25312
+ *
25313
+ * It was not always so. These seconds were fed to `between(t,…)` verbatim, and
25314
+ * on a 10 h window holding 29,393 s of footage every range landed late by the
25315
+ * gap accumulated before it — up to 6,607 s, well past EOF. Nothing matched,
25316
+ * the video was a uniform timelapse, and the log line reported the five ranges
25317
+ * that had been ASKED for (2026-08-13, export `57d14363`, camera 615).
25318
+ *
25319
+ * Relative and not absolute epoch, because an absolute epoch would make every
25320
+ * call site responsible for the same subtraction.
25310
25321
  */
25311
25322
  var ExportDenseRangeSchema = object({
25312
25323
  fromSec: number().nonnegative(),
@@ -33999,25 +34010,32 @@ object({
33999
34010
  var NativeLeaseAdmissionSchema = _enum(["all", "inferred"]);
34000
34011
  object({
34001
34012
  /**
34002
- * How long a retained native frame is served before it counts as a miss.
34013
+ * How many delivered frames the worker HOLDS at once, waiting for each one's
34014
+ * detection result.
34003
34015
  *
34004
- * Must cover the FULL late-crop horizon: detection inference + the
34005
- * cross-process inference-result hop to hub post-analysis + tracking + the
34006
- * tRPC crop round-trip back. Below ~500 ms the busiest cameras' subject crops
34007
- * outrun it and fall back to the ≤640 detection frame; above ~3 s the resident
34008
- * RAM per busy camera grows linearly with no measured hit-rate gain.
34016
+ * This replaced a TTL on 2026-08-13, and the replacement is the whole point:
34017
+ * a time window was never related to the event the pixels were waiting for.
34018
+ * A held frame now lives from delivery until the runner has its `FrameResult`
34019
+ * at which moment the runner cuts the subject tiles it actually wanted and
34020
+ * releases the frame. The bound exists only so a runner that stops answering
34021
+ * cannot pin RAM: above it the OLDEST held frame is dropped and counted.
34022
+ *
34023
+ * Sizing: the steady state is `inferenceLatency × deliveredFps`, measured at
34024
+ * 40-160 ms × ≤25 fps = 1-4 frames. The default leaves headroom for a hiccup
34025
+ * without ever approaching the old resident set (43 frames × 24.9 MB at 4K).
34026
+ * Raising it does not buy hit rate — it buys tolerance for a slow runner, and
34027
+ * `holdOverflow` on the metrics line is what says you need it.
34009
34028
  */
34010
- ttlMs: number().int().min(250).max(1e4),
34029
+ holdFrames: number().int().min(1).max(64),
34011
34030
  /**
34012
34031
  * Hard per-decode-worker RAM ceiling for retained native frames, in MB.
34013
34032
  *
34014
- * Intended as a SAFETY ceiling with the TTL as the effective cap — but check
34015
- * which one is actually binding before reasoning from that. At the shipped
34016
- * 1024 MB and a 2 800 ms TTL, a 4K camera hits the CEILING first (~43 frames
34017
- * at ~24 MB each) and the TTL never gets to expire anything; `leaseMb` /
34018
- * `leaseFrames` on the metrics line say which. When the ceiling binds, a
34019
- * change that admits fewer frames buys retention WINDOW at constant RAM
34020
- * rather than giving RAM back — lower this knob if RAM is what you wanted.
34033
+ * Since 2026-08-13 this is a SAFETY ceiling and nothing else: `holdFrames`
34034
+ * is what decides how much is held, and the ceiling is the number above which
34035
+ * something is wrong. Before that it was the effective cap at 1024 MB with
34036
+ * a 2 800 ms TTL a 4K camera sat pinned at `leaseMb:1020, leaseFrames:43`
34037
+ * with the TTL expiring nothing, which is exactly the confusion the hold
34038
+ * removes. `leaseMb` / `leaseFrames` still say what is resident.
34021
34039
  * `0` DISABLES the lease entirely and falls the worker back to the tiny
34022
34040
  * leak-prone GPU surface ring (~85% crop miss; that is what the lease exists
34023
34041
  * to replace).
@@ -34043,22 +34061,45 @@ object({
34043
34061
  * there is the signal that some caller names frames outside the inference set
34044
34062
  * and that this must go back to `all`.
34045
34063
  */
34046
- admission: NativeLeaseAdmissionSchema
34064
+ admission: NativeLeaseAdmissionSchema,
34065
+ /**
34066
+ * RAM ceiling per decode worker, in MB, for the SUBJECT TILES — the
34067
+ * compressed native crops the worker cuts at the moment a frame's detection
34068
+ * result arrives, and keeps long after the frame itself is freed.
34069
+ *
34070
+ * This is the knob that replaced the old retention window, and it buys about
34071
+ * three orders of magnitude more of it: a tile is one subject at native
34072
+ * resolution, JPEG-encoded (~60-120 KB on a 4K person), against ~24.9 MB for
34073
+ * the frame it was cut from. A frame on which nothing was detected costs
34074
+ * nothing at all, which is the real change — the old lease paid per FRAME and
34075
+ * was interrogated per SUBJECT.
34076
+ *
34077
+ * `0` DISABLES tiles, leaving only the hold window and the ≤640 RAM
34078
+ * fallback — i.e. the pre-2026-08-13 miss profile. Set it there only to
34079
+ * reproduce that.
34080
+ */
34081
+ tileBudgetMb: number().int().min(0).max(1024)
34047
34082
  });
34048
34083
  /**
34049
- * The values in force when the operator has set nothing — byte-for-byte the
34050
- * constants the decode worker shipped with as env-var defaults, so making these
34051
- * settings changed no behaviour on the day it landed.
34084
+ * The values in force when the operator has set nothing.
34085
+ *
34086
+ * `budgetMb` stays at 1024 on the day the hold landed, deliberately: it stopped
34087
+ * being the retention window and became the OOM ceiling, and lowering a ceiling
34088
+ * in the same change that redefines it would make a regression and a retune
34089
+ * indistinguishable. Cut it once `tileHits` / `holdOverflow` have been read on
34090
+ * live traffic.
34052
34091
  */
34053
34092
  var DEFAULT_NATIVE_LEASE_SETTINGS = {
34054
- ttlMs: 1200,
34093
+ holdFrames: 8,
34055
34094
  budgetMb: 1024,
34056
34095
  activityMs: 15e3,
34096
+ tileBudgetMb: 64,
34057
34097
  admission: "inferred"
34058
34098
  };
34059
- DEFAULT_NATIVE_LEASE_SETTINGS.ttlMs;
34099
+ DEFAULT_NATIVE_LEASE_SETTINGS.holdFrames;
34060
34100
  DEFAULT_NATIVE_LEASE_SETTINGS.budgetMb;
34061
34101
  DEFAULT_NATIVE_LEASE_SETTINGS.activityMs;
34102
+ DEFAULT_NATIVE_LEASE_SETTINGS.tileBudgetMb;
34062
34103
  DEFAULT_NATIVE_LEASE_SETTINGS.admission;
34063
34104
  /**
34064
34105
  * Names that, when used as URL query parameters, almost certainly carry
package/dist/addon.mjs CHANGED
@@ -25276,13 +25276,24 @@ method(object({
25276
25276
  /** Playback-speed multiplier for the render (1 = realtime). */
25277
25277
  var ExportSpeedSchema = number().min(.25).max(32);
25278
25278
  /**
25279
- * One dense interval, in SECONDS FROM THE EXPORT'S OWN `fromMs`.
25279
+ * One dense interval, in WALL-CLOCK SECONDS FROM THE EXPORT'S OWN `fromMs`.
25280
25280
  *
25281
- * Relative and not absolute epoch on purpose: the renderer's frame-select
25282
- * expression sees ffmpeg's `t`, which starts at 0 for the export's source
25283
- * playlist. Handing it absolute epochs would make every call site responsible
25284
- * for the same subtraction, and the one that forgot would emit a filter that
25285
- * selects nothing silently, as a uniform timelapse.
25281
+ * **Wall clock, not ffmpeg's `t`** and the recorder translates. A caller
25282
+ * derives these bounds from things that happened at a TIME (a track's
25283
+ * `firstSeen`), while `t` runs over the source playlist: the concatenation of
25284
+ * every segment present for the range, with each recording GAP removed. The
25285
+ * two agree only on a window that recorded without one interruption, and only
25286
+ * the render side knows the segments, so the translation lives there
25287
+ * (`export-dense-map.ts`, addon-pipeline).
25288
+ *
25289
+ * It was not always so. These seconds were fed to `between(t,…)` verbatim, and
25290
+ * on a 10 h window holding 29,393 s of footage every range landed late by the
25291
+ * gap accumulated before it — up to 6,607 s, well past EOF. Nothing matched,
25292
+ * the video was a uniform timelapse, and the log line reported the five ranges
25293
+ * that had been ASKED for (2026-08-13, export `57d14363`, camera 615).
25294
+ *
25295
+ * Relative and not absolute epoch, because an absolute epoch would make every
25296
+ * call site responsible for the same subtraction.
25286
25297
  */
25287
25298
  var ExportDenseRangeSchema = object({
25288
25299
  fromSec: number().nonnegative(),
@@ -33975,25 +33986,32 @@ object({
33975
33986
  var NativeLeaseAdmissionSchema = _enum(["all", "inferred"]);
33976
33987
  object({
33977
33988
  /**
33978
- * How long a retained native frame is served before it counts as a miss.
33989
+ * How many delivered frames the worker HOLDS at once, waiting for each one's
33990
+ * detection result.
33979
33991
  *
33980
- * Must cover the FULL late-crop horizon: detection inference + the
33981
- * cross-process inference-result hop to hub post-analysis + tracking + the
33982
- * tRPC crop round-trip back. Below ~500 ms the busiest cameras' subject crops
33983
- * outrun it and fall back to the ≤640 detection frame; above ~3 s the resident
33984
- * RAM per busy camera grows linearly with no measured hit-rate gain.
33992
+ * This replaced a TTL on 2026-08-13, and the replacement is the whole point:
33993
+ * a time window was never related to the event the pixels were waiting for.
33994
+ * A held frame now lives from delivery until the runner has its `FrameResult`
33995
+ * at which moment the runner cuts the subject tiles it actually wanted and
33996
+ * releases the frame. The bound exists only so a runner that stops answering
33997
+ * cannot pin RAM: above it the OLDEST held frame is dropped and counted.
33998
+ *
33999
+ * Sizing: the steady state is `inferenceLatency × deliveredFps`, measured at
34000
+ * 40-160 ms × ≤25 fps = 1-4 frames. The default leaves headroom for a hiccup
34001
+ * without ever approaching the old resident set (43 frames × 24.9 MB at 4K).
34002
+ * Raising it does not buy hit rate — it buys tolerance for a slow runner, and
34003
+ * `holdOverflow` on the metrics line is what says you need it.
33985
34004
  */
33986
- ttlMs: number().int().min(250).max(1e4),
34005
+ holdFrames: number().int().min(1).max(64),
33987
34006
  /**
33988
34007
  * Hard per-decode-worker RAM ceiling for retained native frames, in MB.
33989
34008
  *
33990
- * Intended as a SAFETY ceiling with the TTL as the effective cap — but check
33991
- * which one is actually binding before reasoning from that. At the shipped
33992
- * 1024 MB and a 2 800 ms TTL, a 4K camera hits the CEILING first (~43 frames
33993
- * at ~24 MB each) and the TTL never gets to expire anything; `leaseMb` /
33994
- * `leaseFrames` on the metrics line say which. When the ceiling binds, a
33995
- * change that admits fewer frames buys retention WINDOW at constant RAM
33996
- * rather than giving RAM back — lower this knob if RAM is what you wanted.
34009
+ * Since 2026-08-13 this is a SAFETY ceiling and nothing else: `holdFrames`
34010
+ * is what decides how much is held, and the ceiling is the number above which
34011
+ * something is wrong. Before that it was the effective cap at 1024 MB with
34012
+ * a 2 800 ms TTL a 4K camera sat pinned at `leaseMb:1020, leaseFrames:43`
34013
+ * with the TTL expiring nothing, which is exactly the confusion the hold
34014
+ * removes. `leaseMb` / `leaseFrames` still say what is resident.
33997
34015
  * `0` DISABLES the lease entirely and falls the worker back to the tiny
33998
34016
  * leak-prone GPU surface ring (~85% crop miss; that is what the lease exists
33999
34017
  * to replace).
@@ -34019,22 +34037,45 @@ object({
34019
34037
  * there is the signal that some caller names frames outside the inference set
34020
34038
  * and that this must go back to `all`.
34021
34039
  */
34022
- admission: NativeLeaseAdmissionSchema
34040
+ admission: NativeLeaseAdmissionSchema,
34041
+ /**
34042
+ * RAM ceiling per decode worker, in MB, for the SUBJECT TILES — the
34043
+ * compressed native crops the worker cuts at the moment a frame's detection
34044
+ * result arrives, and keeps long after the frame itself is freed.
34045
+ *
34046
+ * This is the knob that replaced the old retention window, and it buys about
34047
+ * three orders of magnitude more of it: a tile is one subject at native
34048
+ * resolution, JPEG-encoded (~60-120 KB on a 4K person), against ~24.9 MB for
34049
+ * the frame it was cut from. A frame on which nothing was detected costs
34050
+ * nothing at all, which is the real change — the old lease paid per FRAME and
34051
+ * was interrogated per SUBJECT.
34052
+ *
34053
+ * `0` DISABLES tiles, leaving only the hold window and the ≤640 RAM
34054
+ * fallback — i.e. the pre-2026-08-13 miss profile. Set it there only to
34055
+ * reproduce that.
34056
+ */
34057
+ tileBudgetMb: number().int().min(0).max(1024)
34023
34058
  });
34024
34059
  /**
34025
- * The values in force when the operator has set nothing — byte-for-byte the
34026
- * constants the decode worker shipped with as env-var defaults, so making these
34027
- * settings changed no behaviour on the day it landed.
34060
+ * The values in force when the operator has set nothing.
34061
+ *
34062
+ * `budgetMb` stays at 1024 on the day the hold landed, deliberately: it stopped
34063
+ * being the retention window and became the OOM ceiling, and lowering a ceiling
34064
+ * in the same change that redefines it would make a regression and a retune
34065
+ * indistinguishable. Cut it once `tileHits` / `holdOverflow` have been read on
34066
+ * live traffic.
34028
34067
  */
34029
34068
  var DEFAULT_NATIVE_LEASE_SETTINGS = {
34030
- ttlMs: 1200,
34069
+ holdFrames: 8,
34031
34070
  budgetMb: 1024,
34032
34071
  activityMs: 15e3,
34072
+ tileBudgetMb: 64,
34033
34073
  admission: "inferred"
34034
34074
  };
34035
- DEFAULT_NATIVE_LEASE_SETTINGS.ttlMs;
34075
+ DEFAULT_NATIVE_LEASE_SETTINGS.holdFrames;
34036
34076
  DEFAULT_NATIVE_LEASE_SETTINGS.budgetMb;
34037
34077
  DEFAULT_NATIVE_LEASE_SETTINGS.activityMs;
34078
+ DEFAULT_NATIVE_LEASE_SETTINGS.tileBudgetMb;
34038
34079
  DEFAULT_NATIVE_LEASE_SETTINGS.admission;
34039
34080
  /**
34040
34081
  * Names that, when used as URL query parameters, almost certainly carry
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@camstack/addon-provider-rtsp",
3
- "version": "1.2.14",
3
+ "version": "1.2.15",
4
4
  "description": "Generic RTSP camera device provider addon for CamStack",
5
5
  "keywords": [
6
6
  "camstack",