@eventual-ai/mcap-viewer 0.1.0-alpha.0 → 0.1.0-alpha.2

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.
Files changed (51) hide show
  1. package/README.md +15 -14
  2. package/dist/{types/core → core}/index.d.ts +2 -2
  3. package/dist/core/index.js +3 -0
  4. package/dist/core/mcap/codecs/h264.js +22 -0
  5. package/dist/{types/core → core}/mcap/codecs/video.d.ts +2 -1
  6. package/dist/core/mcap/codecs/video.js +64 -0
  7. package/dist/{types/core → core}/mcap/index.d.ts +1 -1
  8. package/dist/core/mcap/index.js +2 -0
  9. package/dist/core/mcap/loading.js +50 -0
  10. package/dist/{types/core → core}/mcap/reader.d.ts +6 -1
  11. package/dist/core/mcap/reader.js +141 -0
  12. package/dist/{types/core → core}/mcap/recording.d.ts +8 -5
  13. package/dist/core/mcap/recording.js +72 -0
  14. package/dist/core/mcap/source.js +67 -0
  15. package/dist/{types/core → core}/mcap/types.d.ts +3 -3
  16. package/dist/core/mcap/types.js +1 -0
  17. package/dist/{types/core → core}/playback/index.d.ts +1 -1
  18. package/dist/core/playback/index.js +1 -0
  19. package/dist/{types/core → core}/playback/player.d.ts +8 -2
  20. package/dist/core/playback/player.js +344 -0
  21. package/dist/{types/core → core}/playback/snapshot.d.ts +2 -2
  22. package/dist/core/playback/snapshot.js +11 -0
  23. package/dist/{types/core → core}/playback/video-sequence.d.ts +7 -7
  24. package/dist/core/playback/video-sequence.js +116 -0
  25. package/dist/{types/core → core}/renderers/image.d.ts +2 -0
  26. package/dist/core/renderers/image.js +165 -0
  27. package/dist/core/renderers/index.js +1 -0
  28. package/dist/{types/core → core}/renderers/video-decoder.d.ts +4 -1
  29. package/dist/core/renderers/video-decoder.js +146 -0
  30. package/dist/core/schemas.d.ts +19 -0
  31. package/dist/core/schemas.js +13 -0
  32. package/dist/data-loader/index.d.ts +2 -0
  33. package/dist/data-loader/index.js +1 -0
  34. package/dist/{types/data-loader → data-loader}/loader.d.ts +4 -4
  35. package/dist/data-loader/loader.js +44 -0
  36. package/dist/{types/data-loader → data-loader}/types.d.ts +3 -3
  37. package/dist/data-loader/types.js +1 -0
  38. package/dist/index.js +2 -0
  39. package/package.json +17 -16
  40. package/dist/THIRD_PARTY_LICENSES.md +0 -415
  41. package/dist/core.js +0 -534
  42. package/dist/data-loader.js +0 -53
  43. package/dist/mcap-viewer.js +0 -11
  44. package/dist/recording-tVYbg6KM.js +0 -9109
  45. package/dist/types/core/schemas.d.ts +0 -15
  46. package/dist/types/data-loader/index.d.ts +0 -2
  47. /package/dist/{types/core → core}/mcap/codecs/h264.d.ts +0 -0
  48. /package/dist/{types/core → core}/mcap/loading.d.ts +0 -0
  49. /package/dist/{types/core → core}/mcap/source.d.ts +0 -0
  50. /package/dist/{types/core → core}/renderers/index.d.ts +0 -0
  51. /package/dist/{types/index.d.ts → index.d.ts} +0 -0
package/dist/core.js DELETED
@@ -1,534 +0,0 @@
1
- import { B as M, H as D, M as x } from "./recording-tVYbg6KM.js";
2
- const w = "eventual.replay.v1.CompressedVideo";
3
- function m(r) {
4
- if (!r || typeof r != "object" || !("data" in r) || !(r.data instanceof Uint8Array) || !("format" in r) || typeof r.format != "string" || !("keyframe" in r) || typeof r.keyframe != "boolean")
5
- throw new Error("Invalid CompressedVideo message");
6
- return r;
7
- }
8
- function b(r) {
9
- return r.schemaName === w;
10
- }
11
- function g(r) {
12
- const e = m(r.value).decode_order;
13
- if (typeof e != "string" || !/^\d+$/.test(e))
14
- throw new Error("Video packet is missing a valid decode_order");
15
- return BigInt(e);
16
- }
17
- const v = /* @__PURE__ */ new WeakMap();
18
- function y(r, e) {
19
- let t = v.get(e);
20
- return t || (t = new E(r, e), v.set(e, t)), t;
21
- }
22
- class E {
23
- constructor(e, t) {
24
- this.channel = e, this.records = t;
25
- const i = (s) => {
26
- const o = e.metadata.get(s);
27
- if (o === void 0 || !/^\d+$/.test(o))
28
- throw new Error(`Missing or invalid ${s} video metadata`);
29
- return BigInt(o);
30
- };
31
- if (this.start = i("video.decode_start"), this.end = i("video.decode_end"), this.lookahead = i("video.max_reorder_frames"), this.start > this.end) throw new Error("Invalid video decode interval");
32
- this.contiguous = this.start - 1n;
33
- }
34
- channel;
35
- records;
36
- start;
37
- end;
38
- lookahead;
39
- packets = /* @__PURE__ */ new Map();
40
- keyframes = /* @__PURE__ */ new Map();
41
- count = 0;
42
- safeCount = 0;
43
- contiguous;
44
- update() {
45
- for (; this.count < this.records.length; this.count++) {
46
- const e = this.records[this.count], t = g(e);
47
- if (t < this.start || t > this.end || this.packets.has(t))
48
- throw new Error(
49
- "Video decode_order is duplicated or outside the declared interval"
50
- );
51
- this.packets.set(t, e), m(e.value).keyframe && this.keyframes.set(t, e);
52
- }
53
- for (; this.packets.has(this.contiguous + 1n); ) this.contiguous++;
54
- }
55
- required(e) {
56
- const t = g(e) + this.lookahead;
57
- return t > this.end ? this.end : t;
58
- }
59
- target(e) {
60
- let t = 0, i = this.records.length;
61
- for (; t < i; ) {
62
- const s = t + i >>> 1;
63
- this.records[s].time <= e ? t = s + 1 : i = s;
64
- }
65
- return this.records[t - 1];
66
- }
67
- bufferedEnd(e, t) {
68
- if (this.update(), t && this.contiguous !== this.end)
69
- throw new Error("Incomplete video decode interval");
70
- if (t) return e;
71
- for (; this.safeCount < this.records.length && this.required(this.records[this.safeCount]) <= this.contiguous; )
72
- this.safeCount++;
73
- const i = this.records[this.safeCount];
74
- return i && i.time <= e ? i.time - 1n : e;
75
- }
76
- snapshot(e) {
77
- this.update();
78
- const t = this.target(e);
79
- if (!t) return [];
80
- const i = g(t);
81
- let s;
82
- for (const [o, c] of this.keyframes)
83
- o <= i && c.time <= e && (s === void 0 || o > s) && (s = o);
84
- if (s === void 0)
85
- throw new Error("MCAP is missing the preceding video keyframe");
86
- return this.range(s, this.required(t));
87
- }
88
- after(e, t) {
89
- this.update();
90
- const i = this.target(e);
91
- return i ? this.range(t + 1n, this.required(i)) : [];
92
- }
93
- range(e, t) {
94
- if (t > this.contiguous)
95
- throw new Error("Video decode dependencies are not buffered");
96
- const i = [];
97
- for (let s = e; s <= t; s++)
98
- i.push(this.packets.get(s));
99
- return i;
100
- }
101
- }
102
- function k(r, e) {
103
- const t = [];
104
- for (const i of r.byTopic.values()) {
105
- const s = i[0]?.channel;
106
- s && b(s) && t.push(...y(s, i).snapshot(e));
107
- }
108
- return t;
109
- }
110
- const T = {
111
- now: () => performance.now(),
112
- request: (r) => requestAnimationFrame(r),
113
- cancel: (r) => cancelAnimationFrame(r)
114
- };
115
- class q {
116
- constructor(e, t = {}, i = T) {
117
- this.recording = e, this.scheduler = i, this.time = e.start, this.subscribe(t), this.unsubscribeRecording = e.subscribe?.(() => this.onLoad());
118
- }
119
- recording;
120
- scheduler;
121
- time;
122
- speed = 1;
123
- playing = !1;
124
- status = "paused";
125
- closed = !1;
126
- generation = 0;
127
- frame;
128
- anchorTime = 0n;
129
- anchorWall = 0;
130
- waitingForData = !1;
131
- seekController;
132
- video = /* @__PURE__ */ new Map();
133
- submitted = /* @__PURE__ */ new Map();
134
- unsubscribeRecording;
135
- listeners = /* @__PURE__ */ new Set();
136
- /** Subscribe a view or renderer to the shared playback clock and selected topics. */
137
- subscribe(e, { topics: t } = {}) {
138
- if (this.closed) throw new Error("Player is closed");
139
- const i = {
140
- listener: e,
141
- topics: t ? new Set(t) : void 0
142
- };
143
- return this.listeners.add(i), () => {
144
- this.listeners.delete(i);
145
- };
146
- }
147
- emit() {
148
- const e = {
149
- time: this.time,
150
- status: this.status,
151
- playing: this.playing,
152
- speed: this.speed
153
- };
154
- for (const { listener: t } of this.listeners) t.onState?.(e);
155
- }
156
- publish(e) {
157
- this.submitted.set(e.channel.topic, g(e));
158
- for (const { listener: t, topics: i } of this.listeners) {
159
- if (this.closed) return;
160
- (!i || i.has(e.channel.topic)) && t.onMessage?.(e.channel, e.time, e.value);
161
- }
162
- }
163
- cancelFrame() {
164
- this.frame !== void 0 && this.scheduler.cancel(this.frame), this.frame = void 0;
165
- }
166
- fail(e) {
167
- this.generation++, this.seekController?.abort(), this.waitingForData = !1, this.playing = !1, this.status = "error", this.cancelFrame();
168
- for (const { listener: t } of this.listeners)
169
- t.onError?.(
170
- e instanceof Error ? e : new Error(String(e))
171
- );
172
- this.emit();
173
- }
174
- availableEnd() {
175
- for (const t of this.recording.byTopic.values()) {
176
- const i = t[0]?.channel;
177
- i && b(i) && !this.video.has(i.topic) && this.video.set(i.topic, y(i, t));
178
- }
179
- let e = this.recording.complete === !1 ? this.recording.bufferedEnd ?? this.recording.start - 1n : this.recording.end;
180
- for (const t of this.video.values())
181
- e = t.bufferedEnd(e, this.recording.complete !== !1);
182
- return e;
183
- }
184
- endBuffered() {
185
- return this.recording.complete !== !1 || this.recording.bounds !== void 0 && this.availableEnd() >= this.recording.end;
186
- }
187
- onLoad() {
188
- if (this.closed) return;
189
- if (this.recording.error) {
190
- this.fail(this.recording.error);
191
- return;
192
- }
193
- let e;
194
- try {
195
- e = this.availableEnd();
196
- } catch (t) {
197
- this.fail(t);
198
- return;
199
- }
200
- this.waitingForData && this.playing && (this.recording.complete !== !1 || e !== void 0 && e > this.time) && (this.waitingForData = !1, this.anchorTime = this.time, this.anchorWall = this.scheduler.now(), this.status = "playing", this.frame = this.scheduler.request(() => {
201
- this.tick();
202
- })), this.emit();
203
- }
204
- waitForTime(e, t) {
205
- return this.recording.error ? Promise.reject(this.recording.error) : this.availableEnd() >= e || this.recording.complete !== !1 ? Promise.resolve() : new Promise((i, s) => {
206
- const o = () => {
207
- a?.(), t.removeEventListener("abort", n);
208
- }, c = () => {
209
- if (this.recording.error)
210
- o(), s(this.recording.error);
211
- else
212
- try {
213
- (this.availableEnd() >= e || this.recording.complete !== !1) && (o(), i());
214
- } catch (l) {
215
- o(), s(l);
216
- }
217
- }, n = () => {
218
- o(), s(t.reason);
219
- }, a = this.recording.subscribe?.(c);
220
- t.addEventListener("abort", n, { once: !0 }), t.aborted ? n() : c();
221
- });
222
- }
223
- async endSnapshot(e) {
224
- await Promise.all(
225
- [...this.listeners].map(
226
- ({ listener: t }) => t.onSnapshotEnd?.(e)
227
- )
228
- );
229
- }
230
- async seek(e) {
231
- if (this.closed) return;
232
- const t = ++this.generation;
233
- this.seekController?.abort();
234
- const i = new AbortController();
235
- this.seekController = i, this.waitingForData = !1, this.cancelFrame(), this.time = e < this.recording.start ? this.recording.start : e > this.recording.end && (this.recording.complete !== !1 || this.recording.bounds !== void 0) ? this.recording.end : e, this.status = "buffering", this.emit();
236
- try {
237
- if (this.recording.error) throw this.recording.error;
238
- if (this.recording.complete === !1 && this.availableEnd() < this.time && await this.waitForTime(this.time, i.signal), t !== this.generation || this.closed) return;
239
- this.time > this.recording.end && (this.time = this.recording.end), this.submitted.clear();
240
- for (const { listener: s } of this.listeners) s.onSnapshotStart?.();
241
- for (const s of k(this.recording, this.time)) {
242
- if (t !== this.generation || this.closed) return;
243
- this.publish(s);
244
- }
245
- if (await this.endSnapshot(!this.playing), t !== this.generation || this.closed) return;
246
- this.anchorTime = this.time, this.anchorWall = this.scheduler.now(), this.status = this.playing ? "playing" : "paused", this.emit(), this.playing && (this.frame = this.scheduler.request(() => {
247
- this.tick();
248
- }));
249
- } catch (s) {
250
- t === this.generation && !this.closed && this.fail(s);
251
- }
252
- }
253
- play() {
254
- if (!this.closed)
255
- return this.playing = !0, this.seek(
256
- this.endBuffered() && this.time >= this.recording.end ? this.recording.start : this.time
257
- );
258
- }
259
- pause() {
260
- if (!this.closed)
261
- return this.playing = !1, this.seek(this.time);
262
- }
263
- setSpeed(e) {
264
- if (!this.closed) {
265
- if (!Number.isFinite(e) || e <= 0)
266
- throw new Error("Playback speed must be positive");
267
- this.speed = e, this.anchorTime = this.time, this.anchorWall = this.scheduler.now(), this.emit();
268
- }
269
- }
270
- async tick() {
271
- if (this.frame = void 0, this.closed || !this.playing) return;
272
- const e = this.generation, t = this.anchorTime + BigInt(
273
- Math.round((this.scheduler.now() - this.anchorWall) * 1e6 * this.speed)
274
- );
275
- try {
276
- const i = this.availableEnd(), s = i < this.recording.end ? i : this.recording.end;
277
- this.time = t > s ? s : t;
278
- for (const [o, c] of this.video) {
279
- const n = this.submitted.get(o), a = n === void 0 ? c.snapshot(this.time) : c.after(this.time, n);
280
- for (const l of a)
281
- if (this.publish(l), e !== this.generation || this.closed) return;
282
- }
283
- if (this.emit(), this.time === this.recording.end && this.endBuffered()) {
284
- if (this.playing = !1, await this.endSnapshot(!0), e !== this.generation || this.closed) return;
285
- this.status = "ended";
286
- } else this.recording.complete === !1 && t >= s && (this.status = "buffering", this.waitingForData = !0);
287
- this.emit(), this.playing && !this.waitingForData && (this.frame = this.scheduler.request(() => {
288
- this.tick();
289
- }));
290
- } catch (i) {
291
- e === this.generation && !this.closed && this.fail(i);
292
- }
293
- }
294
- close() {
295
- this.closed = !0, this.playing = !1, this.generation++, this.seekController?.abort(), this.unsubscribeRecording?.(), this.waitingForData = !1, this.cancelFrame(), this.listeners.clear();
296
- }
297
- }
298
- function S(r) {
299
- let e = !1, t;
300
- for (let i = 0; i + 3 < r.length; i++) {
301
- if (r[i] !== 0 || r[i + 1] !== 0) continue;
302
- let s = -1;
303
- if (r[i + 2] === 1 ? s = i + 3 : r[i + 2] === 0 && r[i + 3] === 1 && (s = i + 4), s < 0 || s >= r.length) continue;
304
- const o = r[s] & 31;
305
- o === 5 && (e = !0), o === 7 && s + 3 < r.length && (t = `avc1.${Array.from(r.slice(s + 1, s + 4), (c) => c.toString(16).padStart(2, "0")).join("")}`), i = s;
306
- }
307
- return { keyframe: e, codec: t };
308
- }
309
- function F(r, e) {
310
- if (e === "h264") return S(r);
311
- if (e !== "h265") throw new Error(`Unsupported video format: ${e}`);
312
- let t = !1, i;
313
- const s = [];
314
- let o = -1;
315
- for (let n = 0; n + 3 < r.length; n++) {
316
- if (r[n] !== 0 || r[n + 1] !== 0) continue;
317
- const a = r[n + 2] === 1 ? 3 : r[n + 2] === 0 && r[n + 3] === 1 ? 4 : 0;
318
- a && (o >= 0 && s.push(r.subarray(o, n)), o = n + a, n = o - 1);
319
- }
320
- o >= 0 && s.push(r.subarray(o));
321
- const c = /* @__PURE__ */ new Set();
322
- for (const n of s) {
323
- const a = n[0] >> 1 & 63;
324
- if (a >= 16 && a <= 21 && (t = !0), a >= 32 && a <= 34 && c.add(a), a !== 33) continue;
325
- const l = [];
326
- for (let d = 2; d < n.length; d++)
327
- d >= 4 && n[d] === 3 && n[d - 1] === 0 && n[d - 2] === 0 || l.push(n[d]);
328
- if (l.length < 13) continue;
329
- const h = l[1];
330
- let f = 0;
331
- for (let d = 0; d < 32; d++)
332
- f += (l[2 + (d >> 3)] >> 7 - (d & 7) & 1) * 2 ** d;
333
- const u = l.slice(6, 12);
334
- for (; u.length && u.at(-1) === 0; ) u.pop();
335
- const p = u.map((d) => d.toString(16).toUpperCase().padStart(2, "0")).join(".");
336
- i = `hvc1.${["", "A", "B", "C"][h >> 6]}${h & 31}.${f.toString(16).toUpperCase()}.${h & 32 ? "H" : "L"}${l[12]}${p ? `.${p}` : ""}`;
337
- }
338
- return c.size !== 3 && (i = void 0), { keyframe: t, codec: i };
339
- }
340
- class C {
341
- constructor(e, t) {
342
- this.output = e, this.error = t;
343
- }
344
- output;
345
- error;
346
- decoder;
347
- origin = 0n;
348
- times = /* @__PURE__ */ new Map();
349
- generation = 0;
350
- initializing;
351
- flushing;
352
- pending = [];
353
- failed = !1;
354
- decode(e, t, i = "h264") {
355
- if (!this.failed)
356
- try {
357
- const s = F(t, i);
358
- if (!this.decoder && !this.initializing) {
359
- if (!s.keyframe || !s.codec)
360
- throw new Error(
361
- `${i === "h265" ? "HEVC" : "H.264"} playback must begin at a keyframe with codec headers`
362
- );
363
- if (typeof VideoDecoder > "u")
364
- throw new Error(
365
- "This browser does not support WebCodecs video decoding"
366
- );
367
- this.origin = e;
368
- const n = this.generation, a = { codec: s.codec, optimizeForLatency: !0 }, l = () => {
369
- if (n === this.generation) {
370
- this.decoder = new VideoDecoder({
371
- output: (h) => {
372
- if (n !== this.generation) {
373
- h.close();
374
- return;
375
- }
376
- const f = this.times.get(h.timestamp);
377
- if (this.times.delete(h.timestamp), f === void 0) {
378
- h.close();
379
- return;
380
- }
381
- this.output(h, f);
382
- },
383
- error: (h) => {
384
- n === this.generation && this.reject(h, a.codec);
385
- }
386
- }), this.decoder.configure(a);
387
- for (const h of this.pending.splice(0))
388
- this.decoder.decode(h);
389
- }
390
- };
391
- typeof VideoDecoder.isConfigSupported == "function" ? this.initializing = VideoDecoder.isConfigSupported(a).then((h) => {
392
- if (n === this.generation) {
393
- if (!h.supported)
394
- throw new Error(
395
- `This browser or device does not support ${i === "h265" ? "HEVC" : "H.264"} video decoding (${a.codec})`
396
- );
397
- l();
398
- }
399
- }).catch((h) => {
400
- n === this.generation && this.reject(h, a.codec);
401
- }) : l();
402
- }
403
- const o = Number((e - this.origin) / 1000n);
404
- this.times.set(o, e);
405
- const c = new EncodedVideoChunk({
406
- type: s.keyframe ? "key" : "delta",
407
- timestamp: o,
408
- data: Uint8Array.from(t)
409
- });
410
- this.decoder ? this.decoder.decode(c) : this.pending.push(c);
411
- } catch (s) {
412
- this.error(
413
- s instanceof Error ? s : new Error("Video decode failed")
414
- );
415
- }
416
- }
417
- reject(e, t) {
418
- this.failed = !0, this.pending = [], this.times.clear(), this.error(
419
- new Error(
420
- `Video decoding failed (${t}): ${e instanceof Error ? e.message : String(e)}`
421
- )
422
- );
423
- }
424
- flush() {
425
- if (this.flushing) return this.flushing;
426
- const e = this.generation;
427
- return this.flushing = (async () => {
428
- this.initializing && await this.initializing;
429
- const t = this.decoder;
430
- if (!(e !== this.generation || !t || t.state !== "configured"))
431
- try {
432
- await t.flush();
433
- } catch (i) {
434
- e === this.generation && this.error(
435
- i instanceof Error ? i : new Error("Video decode failed")
436
- );
437
- }
438
- })(), this.flushing;
439
- }
440
- reset() {
441
- this.generation++, this.decoder && this.decoder.state !== "closed" && this.decoder.close(), this.decoder = void 0, this.initializing = void 0, this.flushing = void 0, this.pending = [], this.failed = !1, this.times.clear();
442
- }
443
- }
444
- class V {
445
- constructor(e, t = {}) {
446
- this.canvas = e, this.options = t, this.imageTopic = t.imageTopic, this.video = new C(
447
- (i, s) => this.present(i, s),
448
- (i) => this.onError?.(i)
449
- );
450
- }
451
- canvas;
452
- options;
453
- onFrame;
454
- onError;
455
- image;
456
- frameTime = 0n;
457
- presentationTime;
458
- frames = /* @__PURE__ */ new Map();
459
- latestInputTime;
460
- presentationFloor = 0n;
461
- requested;
462
- generation = 0;
463
- snapshot = !1;
464
- imageTopic;
465
- video;
466
- onMessage(e, t, i) {
467
- try {
468
- if (e.schemaName !== w || (this.imageTopic ??= e.topic, this.imageTopic !== e.topic)) return;
469
- const s = m(i);
470
- (this.presentationTime === void 0 || t <= this.presentationTime) && (this.latestInputTime === void 0 || t > this.latestInputTime) && (this.latestInputTime = t), this.video.decode(t, s.data, s.format), s.decode_order === e.metadata.get("video.decode_end") && this.video.flush();
471
- } catch (s) {
472
- this.onError?.(s instanceof Error ? s : new Error(String(s)));
473
- }
474
- }
475
- onState(e) {
476
- this.presentationTime = e.time, e.status !== "buffering" && this.selectFrame();
477
- }
478
- onSnapshotStart() {
479
- this.resetSnapshot(), this.snapshot = !0;
480
- }
481
- async onSnapshotEnd(e) {
482
- const t = this.generation;
483
- this.presentationFloor = this.latestInputTime ?? 0n, e && await this.video.flush(), t === this.generation && (this.snapshot = !1, (this.latestInputTime === void 0 || e && (!this.image || this.frameTime < this.presentationFloor)) && this.clearCanvas(), this.image && this.frameTime >= this.presentationFloor && (this.render(), this.onFrame?.(this.frameTime)));
484
- }
485
- present(e, t) {
486
- if (this.image && t < this.frameTime) {
487
- e.close();
488
- return;
489
- }
490
- this.frames.get(t)?.close(), this.frames.set(t, e), this.selectFrame();
491
- }
492
- selectFrame() {
493
- let e;
494
- for (const i of this.frames.keys())
495
- (this.presentationTime === void 0 || i <= this.presentationTime) && (e === void 0 || i > e) && (e = i);
496
- if (e === void 0) return;
497
- const t = this.frames.get(e);
498
- this.frames.delete(e);
499
- for (const [i, s] of this.frames)
500
- i < e && (s.close(), this.frames.delete(i));
501
- this.image?.close(), this.image = t, this.frameTime = e, !this.snapshot && e >= this.presentationFloor && (this.render(), this.onFrame?.(e));
502
- }
503
- render() {
504
- this.requested === void 0 && (this.requested = requestAnimationFrame(() => {
505
- this.requested = void 0;
506
- const e = this.canvas.getContext("2d");
507
- if (!this.image || !e || this.snapshot || this.frameTime < this.presentationFloor)
508
- return;
509
- const t = this.image.displayWidth, i = this.image.displayHeight;
510
- (this.canvas.width !== t || this.canvas.height !== i) && (this.canvas.width = t, this.canvas.height = i, this.canvas.style.aspectRatio = `${t} / ${i}`), e.drawImage(this.image, 0, 0);
511
- }));
512
- }
513
- resetSnapshot() {
514
- this.generation++, this.video.reset();
515
- for (const e of this.frames.values()) e.close();
516
- this.frames.clear(), this.snapshot = !1, this.frameTime = 0n, this.latestInputTime = void 0, this.presentationFloor = 0n, this.imageTopic = this.options.imageTopic, this.image?.close(), this.image = void 0;
517
- }
518
- clearCanvas() {
519
- this.canvas.getContext("2d")?.clearRect(0, 0, this.canvas.width, this.canvas.height);
520
- }
521
- reset() {
522
- this.resetSnapshot(), this.presentationTime = void 0, this.clearCanvas();
523
- }
524
- destroy() {
525
- this.reset(), this.requested !== void 0 && cancelAnimationFrame(this.requested), this.requested = void 0;
526
- }
527
- }
528
- export {
529
- M as BlobSource,
530
- D as HttpSource,
531
- V as ImageRenderer,
532
- x as McapRecording,
533
- q as ReplayPlayer
534
- };
@@ -1,53 +0,0 @@
1
- import { M as o } from "./recording-tVYbg6KM.js";
2
- class h {
3
- baseUrl;
4
- headers;
5
- constructor({ baseUrl: e, headers: r }) {
6
- this.baseUrl = new URL(`${String(e).replace(/\/+$/, "")}/`), this.headers = new Headers(r);
7
- }
8
- async request(e, r, t) {
9
- const a = new Headers(this.headers);
10
- new Headers(r.headers).forEach(
11
- (n, i) => a.set(i, n)
12
- ), t !== void 0 && a.set("Content-Type", "application/json");
13
- const s = await fetch(new URL(`v1/${e}`, this.baseUrl), {
14
- method: t === void 0 ? "GET" : "POST",
15
- headers: a,
16
- signal: r.signal,
17
- body: t === void 0 ? void 0 : JSON.stringify(t),
18
- cache: "no-store"
19
- });
20
- if (!s.ok)
21
- throw new Error(
22
- `Replay request failed (${s.status}): ${await s.text()}`
23
- );
24
- return s.json();
25
- }
26
- /** List the service's supported canonical data types. */
27
- capabilities(e = {}) {
28
- return this.request("capabilities", e);
29
- }
30
- /** Discover a datasource's canonical schemas and actual wire encodings. */
31
- discover(e, r = {}) {
32
- return this.request(
33
- `discover?${new URLSearchParams({ datasource: e })}`,
34
- r
35
- );
36
- }
37
- /** Resolve topic URLs for ordered spans; each span can succeed or fail independently. */
38
- manifest(e, r = {}) {
39
- return this.request("manifest", r, e);
40
- }
41
- /** Open the single MCAP shared by all topics in one successful manifest result. */
42
- async openSpan(e, r = {}) {
43
- if ("error" in e)
44
- throw new Error(`${e.error.code}: ${e.error.message}`);
45
- const t = await o.open(e.manifest.url, r);
46
- if (r.bounds) return t;
47
- const a = t.metadata.get("replay"), s = a?.get("start_ns"), n = a?.get("end_ns");
48
- return s !== void 0 && n !== void 0 ? t.withBounds({ start: BigInt(s), end: BigInt(n) - 1n }) : t;
49
- }
50
- }
51
- export {
52
- h as ReplayDataLoader
53
- };
@@ -1,11 +0,0 @@
1
- import { B as a, H as o, M as p } from "./recording-tVYbg6KM.js";
2
- import { ImageRenderer as c, ReplayPlayer as l } from "./core.js";
3
- import { ReplayDataLoader as R } from "./data-loader.js";
4
- export {
5
- a as BlobSource,
6
- o as HttpSource,
7
- c as ImageRenderer,
8
- p as McapRecording,
9
- R as ReplayDataLoader,
10
- l as ReplayPlayer
11
- };