@camstack/addon-pipeline 1.2.194 → 1.2.195
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/stream-broker/{_virtual_mf-localSharedImportMap___mfe_internal__addon_stream_broker_widgets-C6K2j4VN.mjs → _virtual_mf-localSharedImportMap___mfe_internal__addon_stream_broker_widgets-B17jLw_E.mjs} +3 -3
- package/dist/stream-broker/{hostInit-cpmZf09I.mjs → hostInit-C6ku1nL0.mjs} +3 -3
- package/dist/stream-broker/index.js +130 -7
- package/dist/stream-broker/index.mjs +130 -7
- package/dist/stream-broker/remoteEntry.js +1 -1
- package/package.json +1 -1
|
@@ -3,7 +3,7 @@ import "./dist-CYZr2fwk.mjs";
|
|
|
3
3
|
var e = {
|
|
4
4
|
"@camstack/sdk": {
|
|
5
5
|
name: "@camstack/sdk",
|
|
6
|
-
version: "1.2.
|
|
6
|
+
version: "1.2.77",
|
|
7
7
|
scope: ["default"],
|
|
8
8
|
loaded: !1,
|
|
9
9
|
from: "addon_stream_broker_widgets",
|
|
@@ -18,7 +18,7 @@ var e = {
|
|
|
18
18
|
},
|
|
19
19
|
"@camstack/types": {
|
|
20
20
|
name: "@camstack/types",
|
|
21
|
-
version: "1.2.
|
|
21
|
+
version: "1.2.157",
|
|
22
22
|
scope: ["default"],
|
|
23
23
|
loaded: !1,
|
|
24
24
|
from: "addon_stream_broker_widgets",
|
|
@@ -33,7 +33,7 @@ var e = {
|
|
|
33
33
|
},
|
|
34
34
|
"@camstack/ui-library": {
|
|
35
35
|
name: "@camstack/ui-library",
|
|
36
|
-
version: "1.2.
|
|
36
|
+
version: "1.2.125",
|
|
37
37
|
scope: ["default"],
|
|
38
38
|
loaded: !1,
|
|
39
39
|
from: "addon_stream_broker_widgets",
|
|
@@ -36,7 +36,7 @@ async function r() {
|
|
|
36
36
|
}
|
|
37
37
|
},
|
|
38
38
|
"@camstack/types": {
|
|
39
|
-
version: "1.2.
|
|
39
|
+
version: "1.2.157",
|
|
40
40
|
scope: "default",
|
|
41
41
|
shareConfig: {
|
|
42
42
|
singleton: !0,
|
|
@@ -45,7 +45,7 @@ async function r() {
|
|
|
45
45
|
}
|
|
46
46
|
},
|
|
47
47
|
"@camstack/sdk": {
|
|
48
|
-
version: "1.2.
|
|
48
|
+
version: "1.2.77",
|
|
49
49
|
scope: "default",
|
|
50
50
|
shareConfig: {
|
|
51
51
|
singleton: !0,
|
|
@@ -81,7 +81,7 @@ async function r() {
|
|
|
81
81
|
}
|
|
82
82
|
},
|
|
83
83
|
"@camstack/ui-library": {
|
|
84
|
-
version: "1.2.
|
|
84
|
+
version: "1.2.125",
|
|
85
85
|
scope: "default",
|
|
86
86
|
shareConfig: {
|
|
87
87
|
singleton: !0,
|
|
@@ -24079,6 +24079,79 @@ var ScrubFragmentCache = class {
|
|
|
24079
24079
|
return this.map.size;
|
|
24080
24080
|
}
|
|
24081
24081
|
};
|
|
24082
|
+
//#endregion
|
|
24083
|
+
//#region src/stream-broker/recorded/segment-pts-repair.ts
|
|
24084
|
+
function median(values) {
|
|
24085
|
+
const sorted = values.toSorted((a, b) => a - b);
|
|
24086
|
+
const mid = sorted.length >> 1;
|
|
24087
|
+
if (sorted.length % 2 === 1) return sorted[mid] ?? 0;
|
|
24088
|
+
return ((sorted[mid - 1] ?? 0) + (sorted[mid] ?? 0)) / 2;
|
|
24089
|
+
}
|
|
24090
|
+
function untouched(aus, read) {
|
|
24091
|
+
const first = aus[0];
|
|
24092
|
+
const last = aus[aus.length - 1];
|
|
24093
|
+
const span = first !== void 0 && last !== void 0 ? read(last) - read(first) : 0;
|
|
24094
|
+
return {
|
|
24095
|
+
aus,
|
|
24096
|
+
repaired: false,
|
|
24097
|
+
discontinuities: 0,
|
|
24098
|
+
collapsedMs: 0,
|
|
24099
|
+
spanBeforeMs: span,
|
|
24100
|
+
spanAfterMs: span
|
|
24101
|
+
};
|
|
24102
|
+
}
|
|
24103
|
+
/**
|
|
24104
|
+
* Rewrite the stamps of `aus` so no inter-AU gap exceeds `durMs`, the window
|
|
24105
|
+
* the recorder measured for this segment.
|
|
24106
|
+
*
|
|
24107
|
+
* Returns the INPUT array unchanged (same identity, so a healthy segment costs
|
|
24108
|
+
* nothing) when there is nothing to repair, when there are fewer than two units
|
|
24109
|
+
* to compare, or when `durMs` is not a usable window — with no declared window
|
|
24110
|
+
* there is no authority to judge a gap against, and inventing one would be
|
|
24111
|
+
* worse than pacing what the file says.
|
|
24112
|
+
*/
|
|
24113
|
+
function repairSegmentPts(aus, durMs, read, write) {
|
|
24114
|
+
if (aus.length < 2 || !Number.isFinite(durMs) || durMs <= 0) return untouched(aus, read);
|
|
24115
|
+
const gaps = [];
|
|
24116
|
+
let faults = 0;
|
|
24117
|
+
for (let i = 1; i < aus.length; i++) {
|
|
24118
|
+
const prev = aus[i - 1];
|
|
24119
|
+
const cur = aus[i];
|
|
24120
|
+
if (prev === void 0 || cur === void 0) return untouched(aus, read);
|
|
24121
|
+
const gap = read(cur) - read(prev);
|
|
24122
|
+
gaps.push(gap);
|
|
24123
|
+
if (gap > durMs) faults++;
|
|
24124
|
+
}
|
|
24125
|
+
if (faults === 0) return untouched(aus, read);
|
|
24126
|
+
const healthy = gaps.filter((g) => g <= durMs);
|
|
24127
|
+
const cadenceMs = healthy.length > 0 ? median(healthy) : durMs / gaps.length;
|
|
24128
|
+
const first = aus[0];
|
|
24129
|
+
if (first === void 0) return untouched(aus, read);
|
|
24130
|
+
const repaired = [first];
|
|
24131
|
+
let shiftMs = 0;
|
|
24132
|
+
let collapsedMs = 0;
|
|
24133
|
+
for (let i = 1; i < aus.length; i++) {
|
|
24134
|
+
const au = aus[i];
|
|
24135
|
+
if (au === void 0) return untouched(aus, read);
|
|
24136
|
+
const gap = gaps[i - 1] ?? 0;
|
|
24137
|
+
if (gap > durMs) {
|
|
24138
|
+
const removed = gap - cadenceMs;
|
|
24139
|
+
shiftMs += removed;
|
|
24140
|
+
collapsedMs += removed;
|
|
24141
|
+
}
|
|
24142
|
+
repaired.push(write(au, read(au) - shiftMs));
|
|
24143
|
+
}
|
|
24144
|
+
const lastIn = aus[aus.length - 1];
|
|
24145
|
+
const lastOut = repaired[repaired.length - 1];
|
|
24146
|
+
return {
|
|
24147
|
+
aus: repaired,
|
|
24148
|
+
repaired: true,
|
|
24149
|
+
discontinuities: faults,
|
|
24150
|
+
collapsedMs,
|
|
24151
|
+
spanBeforeMs: lastIn === void 0 ? 0 : read(lastIn) - read(first),
|
|
24152
|
+
spanAfterMs: lastOut === void 0 ? 0 : read(lastOut) - read(first)
|
|
24153
|
+
};
|
|
24154
|
+
}
|
|
24082
24155
|
/**
|
|
24083
24156
|
* `velocity` is ms of timeline per ms of wall clock, signed. `readMs` is what a
|
|
24084
24157
|
* read costs on this disk right now. Either being null means "not enough is
|
|
@@ -24161,6 +24234,13 @@ var PLAY_CENSUS_INTERVAL_TICKS = 5;
|
|
|
24161
24234
|
*/
|
|
24162
24235
|
var PLAY_STALL_MS = 50;
|
|
24163
24236
|
/**
|
|
24237
|
+
* How many distinct segment starts a feeder remembers having reported as
|
|
24238
|
+
* PTS-repaired, so a camera writing broken stamps names each damaged segment
|
|
24239
|
+
* once instead of once per scrub warm. Cleared wholesale when full — the set is
|
|
24240
|
+
* a log de-duplicator, not state anything reads.
|
|
24241
|
+
*/
|
|
24242
|
+
var PTS_REPAIR_LOG_MEMORY = 64;
|
|
24243
|
+
/**
|
|
24164
24244
|
* Upper bound on a single inter-frame sleep. Frame gaps at 10–30 fps are
|
|
24165
24245
|
* 33–100 ms, so this rarely splits a real wait; it exists so an unusually long
|
|
24166
24246
|
* PTS gap (or an empty/tail wait) still re-checks the abort guards promptly,
|
|
@@ -24612,6 +24692,8 @@ var RecordedFeeder = class {
|
|
|
24612
24692
|
* that is the bottleneck and the census would look calm.
|
|
24613
24693
|
*/
|
|
24614
24694
|
scrubPrefetched = /* @__PURE__ */ new Set();
|
|
24695
|
+
/** Segment starts already reported by {@link repairPts} — see the docblock. */
|
|
24696
|
+
ptsRepairLogged = /* @__PURE__ */ new Set();
|
|
24615
24697
|
/** Recent read durations — the evidence speculation is suspended on. */
|
|
24616
24698
|
scrubReadMsWindow = [];
|
|
24617
24699
|
/** Warm-up runs once per drag, from the playhead the finger went down on. */
|
|
@@ -24916,7 +24998,7 @@ var RecordedFeeder = class {
|
|
|
24916
24998
|
bytes: reusedWhole.bytes.byteLength
|
|
24917
24999
|
};
|
|
24918
25000
|
} else {
|
|
24919
|
-
const fullLoad = this.loadAus(loc.startMs, this.rate !== 0, this.deps.readGop ? void 0 : (video) => {
|
|
25001
|
+
const fullLoad = this.loadAus(loc.startMs, loc.durMs, this.rate !== 0, this.deps.readGop ? void 0 : (video) => {
|
|
24920
25002
|
if (this.disposed || token !== this.seekToken) return;
|
|
24921
25003
|
this.feedPrefix(loc, video, landMs);
|
|
24922
25004
|
prefixFed = true;
|
|
@@ -25872,8 +25954,9 @@ var RecordedFeeder = class {
|
|
|
25872
25954
|
}));
|
|
25873
25955
|
const readEndMs = performance.now();
|
|
25874
25956
|
if (this.disposed || token !== this.seekToken) return null;
|
|
25875
|
-
const
|
|
25957
|
+
const demuxed = await this.withTimeout(this.deps.demux(gop.bytes));
|
|
25876
25958
|
if (this.disposed || token !== this.seekToken) return null;
|
|
25959
|
+
const aus = this.repairPts(demuxed, gop.gopStartMs, gop.gopDurMs);
|
|
25877
25960
|
this.noteScrubReadMs(readEndMs - readStartMs);
|
|
25878
25961
|
return {
|
|
25879
25962
|
seg: {
|
|
@@ -25896,8 +25979,9 @@ var RecordedFeeder = class {
|
|
|
25896
25979
|
}));
|
|
25897
25980
|
const readEndMs = performance.now();
|
|
25898
25981
|
if (this.disposed || token !== this.seekToken) return null;
|
|
25899
|
-
const
|
|
25982
|
+
const demuxedWhole = await this.withTimeout(this.deps.demux(bytes));
|
|
25900
25983
|
if (this.disposed || token !== this.seekToken) return null;
|
|
25984
|
+
const aus = this.repairPts(demuxedWhole, loc.startMs, loc.durMs);
|
|
25901
25985
|
this.noteScrubReadMs(readEndMs - readStartMs);
|
|
25902
25986
|
return {
|
|
25903
25987
|
seg: {
|
|
@@ -26280,7 +26364,7 @@ var RecordedFeeder = class {
|
|
|
26280
26364
|
if (this.disposed || token !== this.seekToken || this.rate !== 0) return;
|
|
26281
26365
|
}
|
|
26282
26366
|
if (loc.kind !== "segment" || loc.startMs >= seg.startMs) return;
|
|
26283
|
-
const loaded = await this.loadAus(loc.startMs, false);
|
|
26367
|
+
const loaded = await this.loadAus(loc.startMs, loc.durMs, false);
|
|
26284
26368
|
if (loaded === null || loaded.video.length === 0) return;
|
|
26285
26369
|
if (this.disposed || this.rate !== 0) return;
|
|
26286
26370
|
this.currentSegment = {
|
|
@@ -26544,7 +26628,7 @@ var RecordedFeeder = class {
|
|
|
26544
26628
|
probe = loc.startMs + loc.durMs + 1;
|
|
26545
26629
|
continue;
|
|
26546
26630
|
}
|
|
26547
|
-
const loaded = await this.loadAus(loc.startMs);
|
|
26631
|
+
const loaded = await this.loadAus(loc.startMs, loc.durMs);
|
|
26548
26632
|
if (loaded === null) return null;
|
|
26549
26633
|
return {
|
|
26550
26634
|
startMs: loc.startMs,
|
|
@@ -26563,7 +26647,7 @@ var RecordedFeeder = class {
|
|
|
26563
26647
|
* (latest-wins). Returns null on abort. Audio demux failures yield [] (audio
|
|
26564
26648
|
* never blocks video). `wantAudio: false` skips the audio transcode entirely
|
|
26565
26649
|
* (paused scrubs would throw it away). */
|
|
26566
|
-
async loadAus(startMs, wantAudio = true, onVideoReady) {
|
|
26650
|
+
async loadAus(startMs, durMs, wantAudio = true, onVideoReady) {
|
|
26567
26651
|
const token = this.seekToken;
|
|
26568
26652
|
const readStartedAt = performance.now();
|
|
26569
26653
|
const bytes = await this.withTimeout(this.deps.readBytes({
|
|
@@ -26575,7 +26659,8 @@ var RecordedFeeder = class {
|
|
|
26575
26659
|
if (this.disposed || token !== this.seekToken) return null;
|
|
26576
26660
|
const demuxStartedAt = performance.now();
|
|
26577
26661
|
const audioPromise = wantAudio && this.deps.demuxAudio && this.resolveAudioPush() !== void 0 ? this.withTimeout(this.deps.demuxAudio(bytes)).catch(() => []) : Promise.resolve([]);
|
|
26578
|
-
const videoPromise = this.withTimeout(this.deps.demux(bytes)).then((
|
|
26662
|
+
const videoPromise = this.withTimeout(this.deps.demux(bytes)).then((demuxed) => {
|
|
26663
|
+
const video = this.repairPts(demuxed, startMs, durMs);
|
|
26579
26664
|
if (!this.disposed && token === this.seekToken) onVideoReady?.(video);
|
|
26580
26665
|
return video;
|
|
26581
26666
|
});
|
|
@@ -26590,6 +26675,44 @@ var RecordedFeeder = class {
|
|
|
26590
26675
|
bytes: bytes.byteLength
|
|
26591
26676
|
};
|
|
26592
26677
|
}
|
|
26678
|
+
/**
|
|
26679
|
+
* Make one demuxed series fit the window the recorder measured for it, and
|
|
26680
|
+
* SAY SO when it did not — see `segment-pts-repair.ts` for why a gap wider
|
|
26681
|
+
* than `durMs` cannot be footage.
|
|
26682
|
+
*
|
|
26683
|
+
* This is the only guard between the file's stamps and `paceSegment`, which
|
|
26684
|
+
* sleeps every inter-AU delta out with no bound. Device 4374's segments put
|
|
26685
|
+
* their key frame 73 s before the frame after it inside a 9 955 ms window;
|
|
26686
|
+
* the loop slept, the cursor never moved off the seek target, and the only
|
|
26687
|
+
* evidence was a `recorded:play-census` line with `pacedAus=150 segments=1`.
|
|
26688
|
+
* A branch that silently drops work logs (repo rule) — and the log carries
|
|
26689
|
+
* `deviceId` through `onLog`'s tags, because "why is 4374 worse than 615" is
|
|
26690
|
+
* the only way this question is ever asked.
|
|
26691
|
+
*
|
|
26692
|
+
* Logged once per segment start per feeder: a broken camera should name every
|
|
26693
|
+
* distinct segment it damages, not repeat one on every scrub warm.
|
|
26694
|
+
*/
|
|
26695
|
+
repairPts(aus, startMs, durMs) {
|
|
26696
|
+
const result = repairSegmentPts(aus, durMs, (au) => au.ptsMs, (au, ptsMs) => ({
|
|
26697
|
+
...au,
|
|
26698
|
+
ptsMs
|
|
26699
|
+
}));
|
|
26700
|
+
if (!result.repaired) return aus;
|
|
26701
|
+
if (!this.ptsRepairLogged.has(startMs)) {
|
|
26702
|
+
if (this.ptsRepairLogged.size >= PTS_REPAIR_LOG_MEMORY) this.ptsRepairLogged.clear();
|
|
26703
|
+
this.ptsRepairLogged.add(startMs);
|
|
26704
|
+
this.deps.onLog?.("recorded:segment-pts-repaired", {
|
|
26705
|
+
startMs,
|
|
26706
|
+
durMs,
|
|
26707
|
+
aus: aus.length,
|
|
26708
|
+
discontinuities: result.discontinuities,
|
|
26709
|
+
collapsedMs: Math.round(result.collapsedMs),
|
|
26710
|
+
spanBeforeMs: Math.round(result.spanBeforeMs),
|
|
26711
|
+
spanAfterMs: Math.round(result.spanAfterMs)
|
|
26712
|
+
});
|
|
26713
|
+
}
|
|
26714
|
+
return [...result.aus];
|
|
26715
|
+
}
|
|
26593
26716
|
startPositionReports() {
|
|
26594
26717
|
if (this.positionTimer) return;
|
|
26595
26718
|
this.positionTicks = 0;
|
|
@@ -24076,6 +24076,79 @@ var ScrubFragmentCache = class {
|
|
|
24076
24076
|
return this.map.size;
|
|
24077
24077
|
}
|
|
24078
24078
|
};
|
|
24079
|
+
//#endregion
|
|
24080
|
+
//#region src/stream-broker/recorded/segment-pts-repair.ts
|
|
24081
|
+
function median(values) {
|
|
24082
|
+
const sorted = values.toSorted((a, b) => a - b);
|
|
24083
|
+
const mid = sorted.length >> 1;
|
|
24084
|
+
if (sorted.length % 2 === 1) return sorted[mid] ?? 0;
|
|
24085
|
+
return ((sorted[mid - 1] ?? 0) + (sorted[mid] ?? 0)) / 2;
|
|
24086
|
+
}
|
|
24087
|
+
function untouched(aus, read) {
|
|
24088
|
+
const first = aus[0];
|
|
24089
|
+
const last = aus[aus.length - 1];
|
|
24090
|
+
const span = first !== void 0 && last !== void 0 ? read(last) - read(first) : 0;
|
|
24091
|
+
return {
|
|
24092
|
+
aus,
|
|
24093
|
+
repaired: false,
|
|
24094
|
+
discontinuities: 0,
|
|
24095
|
+
collapsedMs: 0,
|
|
24096
|
+
spanBeforeMs: span,
|
|
24097
|
+
spanAfterMs: span
|
|
24098
|
+
};
|
|
24099
|
+
}
|
|
24100
|
+
/**
|
|
24101
|
+
* Rewrite the stamps of `aus` so no inter-AU gap exceeds `durMs`, the window
|
|
24102
|
+
* the recorder measured for this segment.
|
|
24103
|
+
*
|
|
24104
|
+
* Returns the INPUT array unchanged (same identity, so a healthy segment costs
|
|
24105
|
+
* nothing) when there is nothing to repair, when there are fewer than two units
|
|
24106
|
+
* to compare, or when `durMs` is not a usable window — with no declared window
|
|
24107
|
+
* there is no authority to judge a gap against, and inventing one would be
|
|
24108
|
+
* worse than pacing what the file says.
|
|
24109
|
+
*/
|
|
24110
|
+
function repairSegmentPts(aus, durMs, read, write) {
|
|
24111
|
+
if (aus.length < 2 || !Number.isFinite(durMs) || durMs <= 0) return untouched(aus, read);
|
|
24112
|
+
const gaps = [];
|
|
24113
|
+
let faults = 0;
|
|
24114
|
+
for (let i = 1; i < aus.length; i++) {
|
|
24115
|
+
const prev = aus[i - 1];
|
|
24116
|
+
const cur = aus[i];
|
|
24117
|
+
if (prev === void 0 || cur === void 0) return untouched(aus, read);
|
|
24118
|
+
const gap = read(cur) - read(prev);
|
|
24119
|
+
gaps.push(gap);
|
|
24120
|
+
if (gap > durMs) faults++;
|
|
24121
|
+
}
|
|
24122
|
+
if (faults === 0) return untouched(aus, read);
|
|
24123
|
+
const healthy = gaps.filter((g) => g <= durMs);
|
|
24124
|
+
const cadenceMs = healthy.length > 0 ? median(healthy) : durMs / gaps.length;
|
|
24125
|
+
const first = aus[0];
|
|
24126
|
+
if (first === void 0) return untouched(aus, read);
|
|
24127
|
+
const repaired = [first];
|
|
24128
|
+
let shiftMs = 0;
|
|
24129
|
+
let collapsedMs = 0;
|
|
24130
|
+
for (let i = 1; i < aus.length; i++) {
|
|
24131
|
+
const au = aus[i];
|
|
24132
|
+
if (au === void 0) return untouched(aus, read);
|
|
24133
|
+
const gap = gaps[i - 1] ?? 0;
|
|
24134
|
+
if (gap > durMs) {
|
|
24135
|
+
const removed = gap - cadenceMs;
|
|
24136
|
+
shiftMs += removed;
|
|
24137
|
+
collapsedMs += removed;
|
|
24138
|
+
}
|
|
24139
|
+
repaired.push(write(au, read(au) - shiftMs));
|
|
24140
|
+
}
|
|
24141
|
+
const lastIn = aus[aus.length - 1];
|
|
24142
|
+
const lastOut = repaired[repaired.length - 1];
|
|
24143
|
+
return {
|
|
24144
|
+
aus: repaired,
|
|
24145
|
+
repaired: true,
|
|
24146
|
+
discontinuities: faults,
|
|
24147
|
+
collapsedMs,
|
|
24148
|
+
spanBeforeMs: lastIn === void 0 ? 0 : read(lastIn) - read(first),
|
|
24149
|
+
spanAfterMs: lastOut === void 0 ? 0 : read(lastOut) - read(first)
|
|
24150
|
+
};
|
|
24151
|
+
}
|
|
24079
24152
|
/**
|
|
24080
24153
|
* `velocity` is ms of timeline per ms of wall clock, signed. `readMs` is what a
|
|
24081
24154
|
* read costs on this disk right now. Either being null means "not enough is
|
|
@@ -24158,6 +24231,13 @@ var PLAY_CENSUS_INTERVAL_TICKS = 5;
|
|
|
24158
24231
|
*/
|
|
24159
24232
|
var PLAY_STALL_MS = 50;
|
|
24160
24233
|
/**
|
|
24234
|
+
* How many distinct segment starts a feeder remembers having reported as
|
|
24235
|
+
* PTS-repaired, so a camera writing broken stamps names each damaged segment
|
|
24236
|
+
* once instead of once per scrub warm. Cleared wholesale when full — the set is
|
|
24237
|
+
* a log de-duplicator, not state anything reads.
|
|
24238
|
+
*/
|
|
24239
|
+
var PTS_REPAIR_LOG_MEMORY = 64;
|
|
24240
|
+
/**
|
|
24161
24241
|
* Upper bound on a single inter-frame sleep. Frame gaps at 10–30 fps are
|
|
24162
24242
|
* 33–100 ms, so this rarely splits a real wait; it exists so an unusually long
|
|
24163
24243
|
* PTS gap (or an empty/tail wait) still re-checks the abort guards promptly,
|
|
@@ -24609,6 +24689,8 @@ var RecordedFeeder = class {
|
|
|
24609
24689
|
* that is the bottleneck and the census would look calm.
|
|
24610
24690
|
*/
|
|
24611
24691
|
scrubPrefetched = /* @__PURE__ */ new Set();
|
|
24692
|
+
/** Segment starts already reported by {@link repairPts} — see the docblock. */
|
|
24693
|
+
ptsRepairLogged = /* @__PURE__ */ new Set();
|
|
24612
24694
|
/** Recent read durations — the evidence speculation is suspended on. */
|
|
24613
24695
|
scrubReadMsWindow = [];
|
|
24614
24696
|
/** Warm-up runs once per drag, from the playhead the finger went down on. */
|
|
@@ -24913,7 +24995,7 @@ var RecordedFeeder = class {
|
|
|
24913
24995
|
bytes: reusedWhole.bytes.byteLength
|
|
24914
24996
|
};
|
|
24915
24997
|
} else {
|
|
24916
|
-
const fullLoad = this.loadAus(loc.startMs, this.rate !== 0, this.deps.readGop ? void 0 : (video) => {
|
|
24998
|
+
const fullLoad = this.loadAus(loc.startMs, loc.durMs, this.rate !== 0, this.deps.readGop ? void 0 : (video) => {
|
|
24917
24999
|
if (this.disposed || token !== this.seekToken) return;
|
|
24918
25000
|
this.feedPrefix(loc, video, landMs);
|
|
24919
25001
|
prefixFed = true;
|
|
@@ -25869,8 +25951,9 @@ var RecordedFeeder = class {
|
|
|
25869
25951
|
}));
|
|
25870
25952
|
const readEndMs = performance.now();
|
|
25871
25953
|
if (this.disposed || token !== this.seekToken) return null;
|
|
25872
|
-
const
|
|
25954
|
+
const demuxed = await this.withTimeout(this.deps.demux(gop.bytes));
|
|
25873
25955
|
if (this.disposed || token !== this.seekToken) return null;
|
|
25956
|
+
const aus = this.repairPts(demuxed, gop.gopStartMs, gop.gopDurMs);
|
|
25874
25957
|
this.noteScrubReadMs(readEndMs - readStartMs);
|
|
25875
25958
|
return {
|
|
25876
25959
|
seg: {
|
|
@@ -25893,8 +25976,9 @@ var RecordedFeeder = class {
|
|
|
25893
25976
|
}));
|
|
25894
25977
|
const readEndMs = performance.now();
|
|
25895
25978
|
if (this.disposed || token !== this.seekToken) return null;
|
|
25896
|
-
const
|
|
25979
|
+
const demuxedWhole = await this.withTimeout(this.deps.demux(bytes));
|
|
25897
25980
|
if (this.disposed || token !== this.seekToken) return null;
|
|
25981
|
+
const aus = this.repairPts(demuxedWhole, loc.startMs, loc.durMs);
|
|
25898
25982
|
this.noteScrubReadMs(readEndMs - readStartMs);
|
|
25899
25983
|
return {
|
|
25900
25984
|
seg: {
|
|
@@ -26277,7 +26361,7 @@ var RecordedFeeder = class {
|
|
|
26277
26361
|
if (this.disposed || token !== this.seekToken || this.rate !== 0) return;
|
|
26278
26362
|
}
|
|
26279
26363
|
if (loc.kind !== "segment" || loc.startMs >= seg.startMs) return;
|
|
26280
|
-
const loaded = await this.loadAus(loc.startMs, false);
|
|
26364
|
+
const loaded = await this.loadAus(loc.startMs, loc.durMs, false);
|
|
26281
26365
|
if (loaded === null || loaded.video.length === 0) return;
|
|
26282
26366
|
if (this.disposed || this.rate !== 0) return;
|
|
26283
26367
|
this.currentSegment = {
|
|
@@ -26541,7 +26625,7 @@ var RecordedFeeder = class {
|
|
|
26541
26625
|
probe = loc.startMs + loc.durMs + 1;
|
|
26542
26626
|
continue;
|
|
26543
26627
|
}
|
|
26544
|
-
const loaded = await this.loadAus(loc.startMs);
|
|
26628
|
+
const loaded = await this.loadAus(loc.startMs, loc.durMs);
|
|
26545
26629
|
if (loaded === null) return null;
|
|
26546
26630
|
return {
|
|
26547
26631
|
startMs: loc.startMs,
|
|
@@ -26560,7 +26644,7 @@ var RecordedFeeder = class {
|
|
|
26560
26644
|
* (latest-wins). Returns null on abort. Audio demux failures yield [] (audio
|
|
26561
26645
|
* never blocks video). `wantAudio: false` skips the audio transcode entirely
|
|
26562
26646
|
* (paused scrubs would throw it away). */
|
|
26563
|
-
async loadAus(startMs, wantAudio = true, onVideoReady) {
|
|
26647
|
+
async loadAus(startMs, durMs, wantAudio = true, onVideoReady) {
|
|
26564
26648
|
const token = this.seekToken;
|
|
26565
26649
|
const readStartedAt = performance.now();
|
|
26566
26650
|
const bytes = await this.withTimeout(this.deps.readBytes({
|
|
@@ -26572,7 +26656,8 @@ var RecordedFeeder = class {
|
|
|
26572
26656
|
if (this.disposed || token !== this.seekToken) return null;
|
|
26573
26657
|
const demuxStartedAt = performance.now();
|
|
26574
26658
|
const audioPromise = wantAudio && this.deps.demuxAudio && this.resolveAudioPush() !== void 0 ? this.withTimeout(this.deps.demuxAudio(bytes)).catch(() => []) : Promise.resolve([]);
|
|
26575
|
-
const videoPromise = this.withTimeout(this.deps.demux(bytes)).then((
|
|
26659
|
+
const videoPromise = this.withTimeout(this.deps.demux(bytes)).then((demuxed) => {
|
|
26660
|
+
const video = this.repairPts(demuxed, startMs, durMs);
|
|
26576
26661
|
if (!this.disposed && token === this.seekToken) onVideoReady?.(video);
|
|
26577
26662
|
return video;
|
|
26578
26663
|
});
|
|
@@ -26587,6 +26672,44 @@ var RecordedFeeder = class {
|
|
|
26587
26672
|
bytes: bytes.byteLength
|
|
26588
26673
|
};
|
|
26589
26674
|
}
|
|
26675
|
+
/**
|
|
26676
|
+
* Make one demuxed series fit the window the recorder measured for it, and
|
|
26677
|
+
* SAY SO when it did not — see `segment-pts-repair.ts` for why a gap wider
|
|
26678
|
+
* than `durMs` cannot be footage.
|
|
26679
|
+
*
|
|
26680
|
+
* This is the only guard between the file's stamps and `paceSegment`, which
|
|
26681
|
+
* sleeps every inter-AU delta out with no bound. Device 4374's segments put
|
|
26682
|
+
* their key frame 73 s before the frame after it inside a 9 955 ms window;
|
|
26683
|
+
* the loop slept, the cursor never moved off the seek target, and the only
|
|
26684
|
+
* evidence was a `recorded:play-census` line with `pacedAus=150 segments=1`.
|
|
26685
|
+
* A branch that silently drops work logs (repo rule) — and the log carries
|
|
26686
|
+
* `deviceId` through `onLog`'s tags, because "why is 4374 worse than 615" is
|
|
26687
|
+
* the only way this question is ever asked.
|
|
26688
|
+
*
|
|
26689
|
+
* Logged once per segment start per feeder: a broken camera should name every
|
|
26690
|
+
* distinct segment it damages, not repeat one on every scrub warm.
|
|
26691
|
+
*/
|
|
26692
|
+
repairPts(aus, startMs, durMs) {
|
|
26693
|
+
const result = repairSegmentPts(aus, durMs, (au) => au.ptsMs, (au, ptsMs) => ({
|
|
26694
|
+
...au,
|
|
26695
|
+
ptsMs
|
|
26696
|
+
}));
|
|
26697
|
+
if (!result.repaired) return aus;
|
|
26698
|
+
if (!this.ptsRepairLogged.has(startMs)) {
|
|
26699
|
+
if (this.ptsRepairLogged.size >= PTS_REPAIR_LOG_MEMORY) this.ptsRepairLogged.clear();
|
|
26700
|
+
this.ptsRepairLogged.add(startMs);
|
|
26701
|
+
this.deps.onLog?.("recorded:segment-pts-repaired", {
|
|
26702
|
+
startMs,
|
|
26703
|
+
durMs,
|
|
26704
|
+
aus: aus.length,
|
|
26705
|
+
discontinuities: result.discontinuities,
|
|
26706
|
+
collapsedMs: Math.round(result.collapsedMs),
|
|
26707
|
+
spanBeforeMs: Math.round(result.spanBeforeMs),
|
|
26708
|
+
spanAfterMs: Math.round(result.spanAfterMs)
|
|
26709
|
+
});
|
|
26710
|
+
}
|
|
26711
|
+
return [...result.aus];
|
|
26712
|
+
}
|
|
26590
26713
|
startPositionReports() {
|
|
26591
26714
|
if (this.positionTimer) return;
|
|
26592
26715
|
this.positionTicks = 0;
|
|
@@ -30,7 +30,7 @@ async function d(e) {
|
|
|
30
30
|
}
|
|
31
31
|
}
|
|
32
32
|
async function f() {
|
|
33
|
-
return l ||= d(() => import("./_virtual_mf-localSharedImportMap___mfe_internal__addon_stream_broker_widgets-
|
|
33
|
+
return l ||= d(() => import("./_virtual_mf-localSharedImportMap___mfe_internal__addon_stream_broker_widgets-B17jLw_E.mjs")).catch((e) => {
|
|
34
34
|
throw l = void 0, e;
|
|
35
35
|
}), l;
|
|
36
36
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@camstack/addon-pipeline",
|
|
3
|
-
"version": "1.2.
|
|
3
|
+
"version": "1.2.195",
|
|
4
4
|
"description": "Pipeline bundle — runner, detection, motion, audio + stream broker. Multi-entry npm package shipping pipeline addons under a single bundle.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"camstack",
|