@luxonis/visualizer-protobuf 2.16.2 → 2.18.0

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 (76) hide show
  1. package/dist/FoxgloveServer-C39Uooyk.js +1172 -0
  2. package/dist/{WorkerImageDecoder.worker-DCoSYoLL.js → WorkerImageDecoder.worker-tkX9-IYo.js} +3 -2
  3. package/dist/_commonjsHelpers-E-ZsRS8r.js +32 -0
  4. package/dist/{comlink-D0blLC4P.js → comlink-DHMAu6X7.js} +1 -1
  5. package/dist/{communicator-CkB-oBVq.js → communicator-D49kmBTQ.js} +1 -1
  6. package/dist/{decodeImage-NYPkamnK.js → decodeImage-C8kB6T3V.js} +1 -1
  7. package/dist/deserialization.worker-DsG76nP8.js +1326 -0
  8. package/dist/{foxglove-protocol-RZlF5fna.js → foxglove-protocol-CYoMweAY.js} +1 -1
  9. package/dist/{i18next-C5Qe4-E1.js → i18next-IYI3-Nuv.js} +1624 -3124
  10. package/dist/{i420ToRgbaToPoitcloud.worker-CQFm7P7B.js → i420ToRgbaToPoitcloud.worker-CzFC0VI1.js} +1 -1
  11. package/dist/{index-_CotNV5x.js → index-4PQpGzhb.js} +10 -8
  12. package/dist/{index-C8kEVNt8.js → index-BFMXTxLw.js} +10 -8
  13. package/dist/{index-D7BaFI3k.js → index-BQecGu9I.js} +10 -8
  14. package/dist/{index-BFmZhB_k.js → index-BT9CBn7l.js} +2663 -2658
  15. package/dist/{index-CGZy-t2h.js → index-BWittpbR.js} +10 -8
  16. package/dist/{index-BRyhvg1u.js → index-BeQ1w8aW.js} +10 -8
  17. package/dist/{index-B-NuHgKz.js → index-BomoqOv5.js} +10 -8
  18. package/dist/{index-qRQvVkdj.js → index-ByIsztCr.js} +10 -8
  19. package/dist/{index-C7bn4vhH.js → index-CJRhjhJ0.js} +10 -8
  20. package/dist/{index-De_-85Dx.js → index-CR6XGTJc.js} +26206 -31958
  21. package/dist/{index-BflsEH7y.js → index-CXIVXFcJ.js} +13 -10
  22. package/dist/{index-DeqZpaJF.js → index-CXThSQcL.js} +10 -8
  23. package/dist/{index-BA7oWwVg.js → index-CcIi7pJR.js} +10 -8
  24. package/dist/{index-BDNOxLbq.js → index-CcP1Qppv.js} +10 -8
  25. package/dist/{index-BsSLQ0Qh.js → index-Ci0X5xT3.js} +10 -8
  26. package/dist/{index-D_n427cy.js → index-CrtBH66u.js} +10 -8
  27. package/dist/{index--q0v8_7h.js → index-DUUnuN10.js} +10 -8
  28. package/dist/{index-C3EAt3Mi.js → index-DchGURxJ.js} +10 -8
  29. package/dist/{index-Cls5O6Ds.js → index-DdKOhCXT.js} +10 -8
  30. package/dist/index.js +10 -8
  31. package/dist/isArrayLikeObject-Bytw9p-q.js +1503 -0
  32. package/dist/lib/src/components/Panel.d.ts +1 -0
  33. package/dist/lib/src/components/Panel.d.ts.map +1 -1
  34. package/dist/lib/src/components/Panel.js +2 -2
  35. package/dist/lib/src/components/Panel.js.map +1 -1
  36. package/dist/lib/src/components/PanelToolbar.d.ts +1 -0
  37. package/dist/lib/src/components/PanelToolbar.d.ts.map +1 -1
  38. package/dist/lib/src/components/PanelToolbar.js +6 -3
  39. package/dist/lib/src/components/PanelToolbar.js.map +1 -1
  40. package/dist/lib/src/components/measure-render-delay.d.ts.map +1 -1
  41. package/dist/lib/src/components/measure-render-delay.js +5 -0
  42. package/dist/lib/src/components/measure-render-delay.js.map +1 -1
  43. package/dist/lib/src/messaging/{deserialization.d.ts → deserialization.worker.d.ts} +6 -2
  44. package/dist/lib/src/messaging/deserialization.worker.d.ts.map +1 -0
  45. package/dist/lib/src/messaging/{deserialization.js → deserialization.worker.js} +28 -3
  46. package/dist/lib/src/messaging/deserialization.worker.js.map +1 -0
  47. package/dist/lib/src/messaging/message-handler.d.ts.map +1 -1
  48. package/dist/lib/src/messaging/message-handler.js +14 -20
  49. package/dist/lib/src/messaging/message-handler.js.map +1 -1
  50. package/dist/lib/src/panels/ImagePanel.d.ts +3 -5
  51. package/dist/lib/src/panels/ImagePanel.d.ts.map +1 -1
  52. package/dist/lib/src/panels/ImagePanel.js +1 -0
  53. package/dist/lib/src/panels/ImagePanel.js.map +1 -1
  54. package/dist/lib/src/panels/PointCloudPanel.d.ts +2 -0
  55. package/dist/lib/src/panels/PointCloudPanel.d.ts.map +1 -1
  56. package/dist/lib/src/panels/PointCloudPanel.js +29 -4
  57. package/dist/lib/src/panels/PointCloudPanel.js.map +1 -1
  58. package/dist/lib/src/utils/poitcloud-sync.d.ts.map +1 -1
  59. package/dist/lib/src/utils/poitcloud-sync.js +5 -2
  60. package/dist/lib/src/utils/poitcloud-sync.js.map +1 -1
  61. package/dist/packages/studio-base/src/panels/ThreeDeeRender/ThreeDeeRender.d.ts.map +1 -1
  62. package/dist/packages/studio-base/src/panels/ThreeDeeRender/ThreeDeeRender.js +3 -0
  63. package/dist/packages/studio-base/src/panels/ThreeDeeRender/ThreeDeeRender.js.map +1 -1
  64. package/dist/packages/studio-base/src/panels/ThreeDeeRender/renderables/CameraStateSettings.js +2 -2
  65. package/dist/packages/studio-base/src/panels/ThreeDeeRender/renderables/CameraStateSettings.js.map +1 -1
  66. package/dist/packages/studio-base/src/panels/ThreeDeeRender/renderables/ImageMode/ImageMode.d.ts.map +1 -1
  67. package/dist/packages/studio-base/src/panels/ThreeDeeRender/renderables/ImageMode/ImageMode.js +0 -1
  68. package/dist/packages/studio-base/src/panels/ThreeDeeRender/renderables/ImageMode/ImageMode.js.map +1 -1
  69. package/dist/{FoxgloveServer-DiLI7KZU.js → protobuf-Cr0sn6Ua.js} +996 -2196
  70. package/dist/tslib.es6-D98N6tjc.js +4116 -0
  71. package/dist/useMessageReducer-Cg30zaG9.js +422 -0
  72. package/dist/{worker-CtuCYYTr.js → worker-B5OJw-Fq.js} +5 -3
  73. package/dist/{worker-Bd7K1fGT.js → worker-aVL4LGa3.js} +5 -3
  74. package/package.json +1 -1
  75. package/dist/lib/src/messaging/deserialization.d.ts.map +0 -1
  76. package/dist/lib/src/messaging/deserialization.js.map +0 -1
@@ -0,0 +1,1326 @@
1
+ import { e as expose } from './comlink-DHMAu6X7.js';
2
+ import { t as typescript } from './useMessageReducer-Cg30zaG9.js';
3
+ import { e as estimateObjectSize, U as uint8ArrayToUint16Array, d as dist } from './tslib.es6-D98N6tjc.js';
4
+ import { T as Type, P as PointsAnnotationType, p as protobufsBySchema, a as Profile } from './protobuf-Cr0sn6Ua.js';
5
+ import 'react';
6
+ import './_commonjsHelpers-E-ZsRS8r.js';
7
+ import 'zustand';
8
+ import 'react-mosaic-component';
9
+ import '@mui/material';
10
+ import './isArrayLikeObject-Bytw9p-q.js';
11
+ import 'protobufjs/minimal';
12
+
13
+ // This Source Code Form is subject to the terms of the Mozilla Public
14
+ // License, v2.0. If a copy of the MPL was not distributed with this
15
+ // file, You can obtain one at http://mozilla.org/MPL/2.0/
16
+
17
+ const glColor = (r, g, b, a) => ({
18
+ r: r / 255,
19
+ g: g / 255,
20
+ b: b / 255,
21
+ a
22
+ });
23
+ const DEFAULT_WIDTH = 1920;
24
+ const DEFAULT_HEIGHT = 1080;
25
+ function interpolate(width, height, base) {
26
+ const widthScale = width / DEFAULT_WIDTH;
27
+ const heightScale = height / DEFAULT_HEIGHT;
28
+ const scale = (widthScale + heightScale) / 2;
29
+ return base * scale;
30
+ }
31
+ const DEFAULT_SIZE = 42;
32
+ const DEFAULT_THICKNESS = 10;
33
+ const getTextSize = (width, height) => interpolate(width, height, DEFAULT_SIZE);
34
+ const getBorderThickness = (width, height) => interpolate(width, height, DEFAULT_THICKNESS);
35
+
36
+ // This Source Code Form is subject to the terms of the Mozilla Public
37
+ // License, v2.0. If a copy of the MPL was not distributed with this
38
+ // file, You can obtain one at http://mozilla.org/MPL/2.0/
39
+
40
+ const GROUP_COLORS = {
41
+ entity: {
42
+ fill: glColor(21, 56, 127, 0.1),
43
+ outline: glColor(21, 56, 127, 1)
44
+ },
45
+ item: {
46
+ fill: glColor(21, 127, 88, 0.1),
47
+ outline: glColor(21, 127, 88, 1)
48
+ },
49
+ bulk: {
50
+ fill: glColor(127, 21, 42, 0.1),
51
+ outline: glColor(127, 21, 42, 1)
52
+ }
53
+ };
54
+ const DETECTION_STYLE = [{
55
+ label: "Person",
56
+ ...GROUP_COLORS.entity
57
+ }, {
58
+ label: "Bicycle",
59
+ ...GROUP_COLORS.bulk
60
+ }, {
61
+ label: "Car",
62
+ ...GROUP_COLORS.bulk
63
+ }, {
64
+ label: "Motorbike",
65
+ ...GROUP_COLORS.bulk
66
+ }, {
67
+ label: "Aeroplane",
68
+ ...GROUP_COLORS.bulk
69
+ }, {
70
+ label: "Bus",
71
+ ...GROUP_COLORS.bulk
72
+ }, {
73
+ label: "Train",
74
+ ...GROUP_COLORS.bulk
75
+ }, {
76
+ label: "Truck",
77
+ ...GROUP_COLORS.bulk
78
+ }, {
79
+ label: "Boat",
80
+ ...GROUP_COLORS.bulk
81
+ }, {
82
+ label: "Traffic Light",
83
+ ...GROUP_COLORS.item
84
+ }, {
85
+ label: "Fire Hydrant",
86
+ ...GROUP_COLORS.item
87
+ }, {
88
+ label: "Stop Sign",
89
+ ...GROUP_COLORS.item
90
+ }, {
91
+ label: "Parking Meter",
92
+ ...GROUP_COLORS.item
93
+ }, {
94
+ label: "Bench",
95
+ ...GROUP_COLORS.bulk
96
+ }, {
97
+ label: "Bird",
98
+ ...GROUP_COLORS.entity
99
+ }, {
100
+ label: "Cat",
101
+ ...GROUP_COLORS.entity
102
+ }, {
103
+ label: "Dog",
104
+ ...GROUP_COLORS.entity
105
+ }, {
106
+ label: "Horse",
107
+ ...GROUP_COLORS.entity
108
+ }, {
109
+ label: "Sheep",
110
+ ...GROUP_COLORS.entity
111
+ }, {
112
+ label: "Cow",
113
+ ...GROUP_COLORS.entity
114
+ }, {
115
+ label: "Elephant",
116
+ ...GROUP_COLORS.entity
117
+ }, {
118
+ label: "Bear",
119
+ ...GROUP_COLORS.entity
120
+ }, {
121
+ label: "Zebra",
122
+ ...GROUP_COLORS.entity
123
+ }, {
124
+ label: "Giraffe",
125
+ ...GROUP_COLORS.entity
126
+ }, {
127
+ label: "Backpack",
128
+ ...GROUP_COLORS.item
129
+ }, {
130
+ label: "Umbrella",
131
+ ...GROUP_COLORS.item
132
+ }, {
133
+ label: "Handbag",
134
+ ...GROUP_COLORS.item
135
+ }, {
136
+ label: "Tie",
137
+ ...GROUP_COLORS.item
138
+ }, {
139
+ label: "Suitcase",
140
+ ...GROUP_COLORS.item
141
+ }, {
142
+ label: "Frisbee",
143
+ ...GROUP_COLORS.item
144
+ }, {
145
+ label: "Skis",
146
+ ...GROUP_COLORS.bulk
147
+ }, {
148
+ label: "Snowboard",
149
+ ...GROUP_COLORS.bulk
150
+ }, {
151
+ label: "Sports Ball",
152
+ ...GROUP_COLORS.item
153
+ }, {
154
+ label: "Lite",
155
+ ...GROUP_COLORS.item
156
+ }, {
157
+ label: "Baseball Bat",
158
+ ...GROUP_COLORS.item
159
+ }, {
160
+ label: "Baseball Glove",
161
+ ...GROUP_COLORS.item
162
+ }, {
163
+ label: "Skateboard",
164
+ ...GROUP_COLORS.item
165
+ }, {
166
+ label: "Surfboard",
167
+ ...GROUP_COLORS.bulk
168
+ }, {
169
+ label: "Tennis Racket",
170
+ ...GROUP_COLORS.item
171
+ }, {
172
+ label: "Bottle",
173
+ ...GROUP_COLORS.item
174
+ }, {
175
+ label: "Wine Glass",
176
+ ...GROUP_COLORS.item
177
+ }, {
178
+ label: "Cup",
179
+ ...GROUP_COLORS.item
180
+ }, {
181
+ label: "Fork",
182
+ ...GROUP_COLORS.item
183
+ }, {
184
+ label: "Knife",
185
+ ...GROUP_COLORS.item
186
+ }, {
187
+ label: "Spoon",
188
+ ...GROUP_COLORS.item
189
+ }, {
190
+ label: "Bowl",
191
+ ...GROUP_COLORS.item
192
+ }, {
193
+ label: "Banana",
194
+ ...GROUP_COLORS.item
195
+ }, {
196
+ label: "Apple",
197
+ ...GROUP_COLORS.item
198
+ }, {
199
+ label: "Sandwich",
200
+ ...GROUP_COLORS.item
201
+ }, {
202
+ label: "Orange",
203
+ ...GROUP_COLORS.item
204
+ }, {
205
+ label: "Broccoli",
206
+ ...GROUP_COLORS.item
207
+ }, {
208
+ label: "Carrot",
209
+ ...GROUP_COLORS.item
210
+ }, {
211
+ label: "Hot Dog",
212
+ ...GROUP_COLORS.item
213
+ }, {
214
+ label: "Pizza",
215
+ ...GROUP_COLORS.item
216
+ }, {
217
+ label: "Donut",
218
+ ...GROUP_COLORS.item
219
+ }, {
220
+ label: "Cake",
221
+ ...GROUP_COLORS.item
222
+ }, {
223
+ label: "Chair",
224
+ ...GROUP_COLORS.bulk
225
+ }, {
226
+ label: "Sofa",
227
+ ...GROUP_COLORS.bulk
228
+ }, {
229
+ label: "Potted Plant",
230
+ ...GROUP_COLORS.item
231
+ }, {
232
+ label: "Bed",
233
+ ...GROUP_COLORS.bulk
234
+ }, {
235
+ label: "Diningtable",
236
+ ...GROUP_COLORS.bulk
237
+ }, {
238
+ label: "Toilet",
239
+ ...GROUP_COLORS.bulk
240
+ }, {
241
+ label: "TV Monitor",
242
+ ...GROUP_COLORS.item
243
+ }, {
244
+ label: "Laptop",
245
+ ...GROUP_COLORS.item
246
+ }, {
247
+ label: "Mouse",
248
+ ...GROUP_COLORS.item
249
+ }, {
250
+ label: "Remote",
251
+ ...GROUP_COLORS.item
252
+ }, {
253
+ label: "Keyboard",
254
+ ...GROUP_COLORS.item
255
+ }, {
256
+ label: "Cell Phone",
257
+ ...GROUP_COLORS.item
258
+ }, {
259
+ label: "Microwave",
260
+ ...GROUP_COLORS.item
261
+ }, {
262
+ label: "Oven",
263
+ ...GROUP_COLORS.item
264
+ }, {
265
+ label: "Toaster",
266
+ ...GROUP_COLORS.item
267
+ }, {
268
+ label: "Sink",
269
+ ...GROUP_COLORS.item
270
+ }, {
271
+ label: "Refrigerator",
272
+ ...GROUP_COLORS.bulk
273
+ }, {
274
+ label: "Book",
275
+ ...GROUP_COLORS.item
276
+ }, {
277
+ label: "Clock",
278
+ ...GROUP_COLORS.item
279
+ }, {
280
+ label: "Vase",
281
+ ...GROUP_COLORS.item
282
+ }, {
283
+ label: "Scissors",
284
+ ...GROUP_COLORS.item
285
+ }, {
286
+ label: "Teddy Bear",
287
+ ...GROUP_COLORS.item
288
+ }, {
289
+ label: "Hair Drier",
290
+ ...GROUP_COLORS.item
291
+ }, {
292
+ label: "Toothbrush",
293
+ ...GROUP_COLORS.item
294
+ }];
295
+ const DEBUG_COLOR = {
296
+ r: 0,
297
+ g: 0.5,
298
+ b: 0,
299
+ a: 1
300
+ };
301
+ const DEFAULT_STYLE = {
302
+ label: null,
303
+ ...GROUP_COLORS.item
304
+ };
305
+ const DEFAULT_TEXT_COLOR = {
306
+ r: 1,
307
+ g: 1,
308
+ b: 1,
309
+ a: 1
310
+ };
311
+ const DEFAULT_BACKGROUND_COLOR = {
312
+ r: 0,
313
+ g: 0,
314
+ b: 0,
315
+ a: 0
316
+ };
317
+
318
+ function fromMillis(value) {
319
+ let sec = Math.trunc(value / 1000);
320
+ let nsec = Math.round((value - sec * 1000) * 1e6);
321
+ sec += Math.trunc(nsec / 1e9);
322
+ nsec %= 1e9;
323
+ return {
324
+ sec,
325
+ nsec
326
+ };
327
+ }
328
+ function parsePixelFormat(format) {
329
+ switch (format) {
330
+ case "BGRA":
331
+ return ["bgra8", 3];
332
+ case "BGRX":
333
+ return ["bgr8", 3];
334
+ // Closest supported
335
+ case "I420":
336
+ case "I420A":
337
+ return ['I420', 2];
338
+ case "I422":
339
+ case "I444":
340
+ return ['yuv422', 2];
341
+ case "RGBA":
342
+ return ["rgba8", 1];
343
+ case "RGBX":
344
+ return ["rgb8", 1];
345
+ // Closest supported
346
+ case "NV12":
347
+ return ["nv12", 1];
348
+ default:
349
+ // Unsupported
350
+ return ["bgra8", 3];
351
+ }
352
+ }
353
+ function parseMessageType(type) {
354
+ switch (type) {
355
+ case Type.YUV422i:
356
+ case Type.YUV422p:
357
+ return ["yuv422", 2];
358
+ case Type.NV12:
359
+ return ["nv12", 1];
360
+ case Type.RGB888i:
361
+ return ["rgb8", 3];
362
+ case Type.RGB888p:
363
+ return ["rgb8p", 1];
364
+ case Type.RGBA8888:
365
+ return ["rgba8", 1];
366
+ case Type.BGR888i:
367
+ return ["bgr8i", 3];
368
+ case Type.BGR888p:
369
+ return ["bgr8p", 3];
370
+ case Type.RAW16:
371
+ return ["mono16", 2];
372
+ case Type.RAW8:
373
+ return ["mono8", 2];
374
+ default:
375
+ throw new Error(`Unsupported encoding ${Type[type]}`);
376
+ }
377
+ }
378
+ function parseMessage(message) {
379
+ const width = Number(message.fb?.width ?? message.sourceFb?.width ?? 1920);
380
+ const height = Number(message.fb?.height ?? message.sourceFb?.height ?? 1200);
381
+ const stride = message.fb?.stride ?? message.sourceFb?.stride ?? null;
382
+ const p2Offset = message.fb?.p2Offset ?? message.sourceFb?.p2Offset ?? null;
383
+ const p1Offset = message.fb?.p1Offset ?? message.sourceFb?.p1Offset ?? null;
384
+ let planeStride = p1Offset != null && p2Offset != null ? p2Offset - p1Offset : 0;
385
+ if (planeStride <= 0) {
386
+ planeStride = null;
387
+ }
388
+ const type = message.fb?.type ?? message.sourceFb?.type ?? Type.RGB888p;
389
+ const [encoding, step] = parseMessageType(type);
390
+ const receiveTime = message.ts ?? message.tsDevice ?? fromMillis(Date.now());
391
+ return {
392
+ encoding,
393
+ step: stride ?? step,
394
+ receiveTime,
395
+ width,
396
+ height,
397
+ stride,
398
+ planeStride,
399
+ type
400
+ };
401
+ }
402
+
403
+ // This Source Code Form is subject to the terms of the Mozilla Public
404
+ // License, v2.0. If a copy of the MPL was not distributed with this
405
+ // file, You can obtain one at http://mozilla.org/MPL/2.0/
406
+
407
+ function deserializeImgDetectionsCustom({
408
+ topic,
409
+ message,
410
+ callback,
411
+ topicSizes
412
+ }) {
413
+ const {
414
+ receiveTime
415
+ } = parseMessage(message);
416
+ const {
417
+ width,
418
+ height
419
+ } = topicSizes.values().next().value ?? {
420
+ width: DEFAULT_WIDTH,
421
+ height: DEFAULT_HEIGHT
422
+ };
423
+ const xMultiplier = width >= height ? 1 : height / width;
424
+ const yMultiplier = height >= width ? 1 : width / height;
425
+ const points = [];
426
+ const texts = [];
427
+ const circles = [];
428
+ for (const annotations of message.annotations) {
429
+ points.push(...annotations.points.map(annotation => ({
430
+ timestamp: receiveTime,
431
+ type: annotation.type === PointsAnnotationType.UNRECOGNIZED ? typescript.PointsAnnotationType.UNKNOWN : Number(annotation.type),
432
+ points: annotation.points,
433
+ outline_color: annotation.outlineColor ?? DEFAULT_STYLE.outline,
434
+ outline_colors: [],
435
+ fill_color: annotation.fillColor ?? DEFAULT_STYLE.fill,
436
+ thickness: annotation.thickness
437
+ })));
438
+ texts.push(...annotations.texts.map(annotation => ({
439
+ timestamp: receiveTime,
440
+ position: annotation.position ?? {
441
+ x: 0,
442
+ y: 0
443
+ },
444
+ text: annotation.text,
445
+ font_size: annotation.fontSize ?? getTextSize(width, height),
446
+ text_color: annotation.textColor ?? DEFAULT_TEXT_COLOR,
447
+ background_color: annotation.backgroundColor ?? DEFAULT_BACKGROUND_COLOR
448
+ })));
449
+ circles.push(...annotations.circles.map(annotation => ({
450
+ timestamp: receiveTime,
451
+ xMultiplier,
452
+ yMultiplier,
453
+ position: annotation.position ?? {
454
+ x: 0,
455
+ y: 0
456
+ },
457
+ diameter: annotation.diameter,
458
+ thickness: annotation.thickness,
459
+ fill_color: annotation.fillColor ?? DEFAULT_STYLE.fill,
460
+ outline_color: annotation.outlineColor ?? DEFAULT_STYLE.outline
461
+ })));
462
+ }
463
+ const foxgloveMessage = {
464
+ points,
465
+ texts,
466
+ circles
467
+ };
468
+ callback({
469
+ topic,
470
+ receiveTime,
471
+ message: foxgloveMessage,
472
+ sizeInBytes: estimateObjectSize(foxgloveMessage),
473
+ schemaName: "foxglove.ImageAnnotations"
474
+ });
475
+ }
476
+
477
+ // This Source Code Form is subject to the terms of the Mozilla Public
478
+ // License, v2.0. If a copy of the MPL was not distributed with this
479
+ // file, You can obtain one at http://mozilla.org/MPL/2.0/
480
+
481
+ function deserializeImgDetections({
482
+ topic,
483
+ message,
484
+ callback,
485
+ topicSizes
486
+ }) {
487
+ const {
488
+ receiveTime
489
+ } = parseMessage(message);
490
+ const foxgloveMessage = {
491
+ points: [],
492
+ texts: [],
493
+ circles: []
494
+ };
495
+ if (message.detections.length > 0) {
496
+ for (const detection of message.detections) {
497
+ const detectionWidth = detection.xmax - detection.xmin;
498
+ const {
499
+ width,
500
+ height
501
+ } = topicSizes.values().next().value ?? {
502
+ width: DEFAULT_WIDTH,
503
+ height: DEFAULT_HEIGHT
504
+ };
505
+ const ratio = width / height;
506
+ const highligtLength = 0.035;
507
+ const highlightSizeX = Math.min(highligtLength, detectionWidth);
508
+ const highlightSizeY = Math.min(highligtLength * ratio, detection.ymax - detection.ymin);
509
+ const style = DETECTION_STYLE[detection.label] ?? DEFAULT_STYLE;
510
+ foxgloveMessage.points.push({
511
+ timestamp: receiveTime,
512
+ points: [{
513
+ x: detection.xmin,
514
+ y: detection.ymin
515
+ }, {
516
+ x: detection.xmin,
517
+ y: detection.ymax
518
+ }, {
519
+ x: detection.xmax,
520
+ y: detection.ymax
521
+ }, {
522
+ x: detection.xmax,
523
+ y: detection.ymin
524
+ }],
525
+ type: typescript.PointsAnnotationType.LINE_LOOP,
526
+ outline_colors: [],
527
+ thickness: 0,
528
+ outline_color: DEBUG_COLOR,
529
+ fill_color: style.fill
530
+ });
531
+ const baseHighlightConfig = {
532
+ timestamp: receiveTime,
533
+ type: typescript.PointsAnnotationType.LINE_LIST,
534
+ outline_colors: [],
535
+ thickness: getBorderThickness(width, height),
536
+ outline_color: style.outline,
537
+ fill_color: DEBUG_COLOR
538
+ };
539
+ foxgloveMessage.points.push({
540
+ ...baseHighlightConfig,
541
+ points: [{
542
+ x: detection.xmin,
543
+ y: detection.ymin
544
+ }, {
545
+ x: detection.xmin + highlightSizeX,
546
+ y: detection.ymin
547
+ }]
548
+ });
549
+ foxgloveMessage.points.push({
550
+ ...baseHighlightConfig,
551
+ points: [{
552
+ x: detection.xmin,
553
+ y: detection.ymin
554
+ }, {
555
+ x: detection.xmin,
556
+ y: detection.ymin + highlightSizeY
557
+ }]
558
+ });
559
+ foxgloveMessage.points.push({
560
+ ...baseHighlightConfig,
561
+ points: [{
562
+ x: detection.xmax,
563
+ y: detection.ymin
564
+ }, {
565
+ x: detection.xmax - highlightSizeX,
566
+ y: detection.ymin
567
+ }]
568
+ });
569
+ foxgloveMessage.points.push({
570
+ ...baseHighlightConfig,
571
+ points: [{
572
+ x: detection.xmax,
573
+ y: detection.ymin
574
+ }, {
575
+ x: detection.xmax,
576
+ y: detection.ymin + highlightSizeY
577
+ }]
578
+ });
579
+ foxgloveMessage.points.push({
580
+ ...baseHighlightConfig,
581
+ points: [{
582
+ x: detection.xmax,
583
+ y: detection.ymax
584
+ }, {
585
+ x: detection.xmax - highlightSizeX,
586
+ y: detection.ymax
587
+ }]
588
+ });
589
+ foxgloveMessage.points.push({
590
+ ...baseHighlightConfig,
591
+ points: [{
592
+ x: detection.xmax,
593
+ y: detection.ymax
594
+ }, {
595
+ x: detection.xmax,
596
+ y: detection.ymax - highlightSizeY
597
+ }]
598
+ });
599
+ foxgloveMessage.points.push({
600
+ ...baseHighlightConfig,
601
+ points: [{
602
+ x: detection.xmin,
603
+ y: detection.ymax
604
+ }, {
605
+ x: detection.xmin + highlightSizeX,
606
+ y: detection.ymax
607
+ }]
608
+ });
609
+ foxgloveMessage.points.push({
610
+ ...baseHighlightConfig,
611
+ points: [{
612
+ x: detection.xmin,
613
+ y: detection.ymax
614
+ }, {
615
+ x: detection.xmin,
616
+ y: detection.ymax - highlightSizeY
617
+ }]
618
+ });
619
+ const label = `${style.label ?? `Unknown #${detection.label}`} ${Math.round(detection.confidence * 100)}%`;
620
+ foxgloveMessage.texts.push({
621
+ timestamp: receiveTime,
622
+ position: {
623
+ x: detection.xmin + highligtLength / 2,
624
+ y: detection.ymin + highlightSizeY
625
+ },
626
+ text: label,
627
+ font_size: getTextSize(width, height),
628
+ text_color: DEFAULT_TEXT_COLOR,
629
+ background_color: DEFAULT_BACKGROUND_COLOR
630
+ });
631
+ }
632
+ }
633
+ callback({
634
+ topic,
635
+ receiveTime,
636
+ message: foxgloveMessage,
637
+ sizeInBytes: estimateObjectSize(foxgloveMessage),
638
+ schemaName: "foxglove.ImageAnnotations"
639
+ });
640
+ }
641
+
642
+ // This Source Code Form is subject to the terms of the Mozilla Public
643
+ // License, v2.0. If a copy of the MPL was not distributed with this
644
+ // file, You can obtain one at http://mozilla.org/MPL/2.0/
645
+
646
+ function deserializePointCloudData({
647
+ topic,
648
+ message,
649
+ callback
650
+ }) {
651
+ const receiveTime = fromMillis(Date.now());
652
+ const foxgloveMessage = {
653
+ timestamp: receiveTime,
654
+ frame_id: `pointcloud-${topic}-frame`,
655
+ point_stride: 12,
656
+ pose: {
657
+ position: {
658
+ x: 0,
659
+ y: 0,
660
+ z: 0
661
+ },
662
+ orientation: {
663
+ x: 0,
664
+ y: 0,
665
+ z: 1,
666
+ w: 0
667
+ }
668
+ },
669
+ fields: [{
670
+ name: "x",
671
+ offset: 0,
672
+ type: typescript.NumericType.FLOAT32
673
+ }, {
674
+ name: "y",
675
+ offset: 4,
676
+ type: typescript.NumericType.FLOAT32
677
+ }, {
678
+ name: "z",
679
+ offset: 8,
680
+ type: typescript.NumericType.FLOAT32
681
+ }],
682
+ data: message.data
683
+ };
684
+ if (message.color) {
685
+ foxgloveMessage.fields.push({
686
+ name: "red",
687
+ offset: 12,
688
+ type: typescript.NumericType.UINT8
689
+ }, {
690
+ name: "green",
691
+ offset: 13,
692
+ type: typescript.NumericType.UINT8
693
+ }, {
694
+ name: "blue",
695
+ offset: 14,
696
+ type: typescript.NumericType.UINT8
697
+ }, {
698
+ name: "alpha",
699
+ offset: 15,
700
+ type: typescript.NumericType.UINT8
701
+ });
702
+ foxgloveMessage.point_stride = 16;
703
+ }
704
+ callback({
705
+ topic,
706
+ receiveTime,
707
+ message: foxgloveMessage,
708
+ sizeInBytes: estimateObjectSize(foxgloveMessage),
709
+ schemaName: "foxglove.PointCloud"
710
+ });
711
+ }
712
+
713
+ // This Source Code Form is subject to the terms of the Mozilla Public
714
+ // License, v2.0. If a copy of the MPL was not distributed with this
715
+ // file, You can obtain one at http://mozilla.org/MPL/2.0/
716
+
717
+ function deserializeColorFrame({
718
+ topic,
719
+ message,
720
+ callback
721
+ }) {
722
+ const {
723
+ receiveTime,
724
+ encoding,
725
+ step,
726
+ width,
727
+ height,
728
+ stride,
729
+ planeStride
730
+ } = parseMessage(message);
731
+ const foxgloveMessage = {
732
+ timestamp: receiveTime,
733
+ frame_id: `color-${topic}-frame`,
734
+ width,
735
+ height,
736
+ encoding,
737
+ step: width * step,
738
+ data: message.data,
739
+ stride,
740
+ planeStride
741
+ };
742
+ callback({
743
+ topic,
744
+ receiveTime,
745
+ message: foxgloveMessage,
746
+ sizeInBytes: estimateObjectSize(foxgloveMessage),
747
+ schemaName: "foxglove.RawImage"
748
+ });
749
+ }
750
+
751
+ // This Source Code Form is subject to the terms of the Mozilla Public
752
+ // License, v2.0. If a copy of the MPL was not distributed with this
753
+ // file, You can obtain one at http://mozilla.org/MPL/2.0/
754
+ /* eslint-disable no-underscore-dangle */
755
+
756
+ const shader = `
757
+ @group(0) @binding(0) var<storage, read> depthBuffer: array<u32>; // Uint16 stored as u32
758
+ @group(0) @binding(1) var<storage, read> intrinsicsBuffer: array<f32>;
759
+ @group(0) @binding(2) var<storage, read_write> xyzColorBuffer: array<u32>; // Stores XYZ + RGBA
760
+
761
+ @compute @workgroup_size(256, 1, 1)
762
+ fn main(@builtin(global_invocation_id) global_id: vec3<u32>) {
763
+ let i = global_id.x;
764
+ let fx = intrinsicsBuffer[0];
765
+ let fy = intrinsicsBuffer[1];
766
+ let cx = intrinsicsBuffer[2];
767
+ let cy = intrinsicsBuffer[3];
768
+ let scale = intrinsicsBuffer[4];
769
+ let width = intrinsicsBuffer[5];
770
+ let height = intrinsicsBuffer[6];
771
+
772
+ if (i >= u32(width * height)) { return; }
773
+
774
+ let u = i % u32(width);
775
+ let v = i / u32(width);
776
+
777
+ // Convert uint16 depth value to float (stored as u32, so we bitwise mask)
778
+ let rawDepth = depthBuffer[i] & 0xFFFFu;
779
+ let z = f32(rawDepth) * scale;
780
+
781
+ let x = (cx - f32(u)) * z / fx;
782
+ let y = (cy - f32(v)) * z / fy;
783
+
784
+ let base = i * 4u; // 4 values per point (X, Y, Z, Color)
785
+
786
+ // Convert floats to u32 representation for storage
787
+ xyzColorBuffer[base] = bitcast<u32>(x);
788
+ xyzColorBuffer[base + 1u] = bitcast<u32>(y);
789
+ xyzColorBuffer[base + 2u] = bitcast<u32>(z);
790
+
791
+ // Example: RGB set based on depth, Alpha is fixed at 255
792
+ let r = u32(clamp(z * 255.0, 0.0, 255.0));
793
+ let g = u32(clamp(y * 255.0, 0.0, 255.0));
794
+ let b = u32(clamp(x * 255.0, 0.0, 255.0));
795
+ xyzColorBuffer[base + 3u] = (r & 0xFFu) | ((g & 0xFFu) << 8) | ((b & 0xFFu) << 16) | (255u << 24);
796
+ }
797
+ `;
798
+ async function depthToPointcloudGPU(depthArray, width, height, fx, fy, cx, cy) {
799
+ // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
800
+ if (!navigator.gpu) {
801
+ console.warn("WebGPU not supported.");
802
+ return depthToPointCloudBuffer(depthArray, width, height, fx, fy, cx, cy);
803
+ }
804
+ const adapter = await navigator.gpu.requestAdapter();
805
+ if (!adapter) {
806
+ console.warn("Couldn't request WebGPU adapter.");
807
+ return depthToPointCloudBuffer(depthArray, width, height, fx, fy, cx, cy);
808
+ }
809
+ const device = await adapter.requestDevice();
810
+ const queue = device.queue;
811
+ const scale = 1.0;
812
+ const numPixels = width * height;
813
+ const outputSize = numPixels * 16;
814
+ const depthData32 = new Uint32Array(depthArray);
815
+ const intrinsics = new Float32Array([fx, fy, cx, cy, scale, width, height]);
816
+ const depthBuffer = device.createBuffer({
817
+ size: depthData32.byteLength,
818
+ usage: GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_DST
819
+ });
820
+ const intrinsicsBuffer = device.createBuffer({
821
+ size: intrinsics.byteLength,
822
+ usage: GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_DST
823
+ });
824
+ const xyzColorBuffer = device.createBuffer({
825
+ size: outputSize,
826
+ usage: GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_SRC
827
+ });
828
+ queue.writeBuffer(depthBuffer, 0, depthData32);
829
+ queue.writeBuffer(intrinsicsBuffer, 0, intrinsics);
830
+ const bindGroupLayout = device.createBindGroupLayout({
831
+ entries: [{
832
+ binding: 0,
833
+ visibility: GPUShaderStage.COMPUTE,
834
+ buffer: {
835
+ type: "read-only-storage"
836
+ }
837
+ }, {
838
+ binding: 1,
839
+ visibility: GPUShaderStage.COMPUTE,
840
+ buffer: {
841
+ type: "read-only-storage"
842
+ }
843
+ }, {
844
+ binding: 2,
845
+ visibility: GPUShaderStage.COMPUTE,
846
+ buffer: {
847
+ type: "storage"
848
+ }
849
+ }]
850
+ });
851
+ const bindGroup = device.createBindGroup({
852
+ layout: bindGroupLayout,
853
+ entries: [{
854
+ binding: 0,
855
+ resource: {
856
+ buffer: depthBuffer
857
+ }
858
+ }, {
859
+ binding: 1,
860
+ resource: {
861
+ buffer: intrinsicsBuffer
862
+ }
863
+ }, {
864
+ binding: 2,
865
+ resource: {
866
+ buffer: xyzColorBuffer
867
+ }
868
+ }]
869
+ });
870
+ const shaderModule = device.createShaderModule({
871
+ code: shader
872
+ });
873
+ const pipeline = device.createComputePipeline({
874
+ layout: device.createPipelineLayout({
875
+ bindGroupLayouts: [bindGroupLayout]
876
+ }),
877
+ compute: {
878
+ module: shaderModule,
879
+ entryPoint: "main"
880
+ }
881
+ });
882
+ const commandEncoder = device.createCommandEncoder();
883
+ const passEncoder = commandEncoder.beginComputePass();
884
+ passEncoder.setPipeline(pipeline);
885
+ passEncoder.setBindGroup(0, bindGroup);
886
+ passEncoder.dispatchWorkgroups(Math.ceil(numPixels / 256));
887
+ passEncoder.end();
888
+ device.queue.submit([commandEncoder.finish()]);
889
+ const outputBuffer = device.createBuffer({
890
+ size: xyzColorBuffer.size,
891
+ usage: GPUBufferUsage.COPY_DST | GPUBufferUsage.MAP_READ
892
+ });
893
+ const copyEncoder = device.createCommandEncoder();
894
+ copyEncoder.copyBufferToBuffer(xyzColorBuffer, 0, outputBuffer, 0, xyzColorBuffer.size);
895
+ device.queue.submit([copyEncoder.finish()]);
896
+
897
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-argument
898
+ await outputBuffer.mapAsync(GPUMapMode.READ);
899
+ const mappedRange = outputBuffer.getMappedRange();
900
+ const result = new Uint8Array(mappedRange.byteLength);
901
+ result.set(new Uint8Array(mappedRange));
902
+ outputBuffer.unmap();
903
+ return result;
904
+ }
905
+ function depthToPointCloudBuffer(uint16Array, width, height, fx, fy, cx, cy) {
906
+ const depthData = Array.from({
907
+ length: height
908
+ }, () => new Array(width));
909
+ for (let v = 0; v < height; v++) {
910
+ depthData[v] = depthData[v] ?? [];
911
+ for (let u = 0; u < width; u++) {
912
+ const d = uint16Array[v * width + u] ?? -1;
913
+ depthData[v][u] = d > 0 ? d : -1;
914
+ }
915
+ }
916
+ const points = [];
917
+ // Accumulate the x, y, z values for each pixel.
918
+ for (let v = 0; v < height; v++) {
919
+ const row = depthData[v];
920
+ if (!row) {
921
+ continue;
922
+ }
923
+ for (let u = 0; u < width; u++) {
924
+ const z = row[u] ?? 0;
925
+ const x = (cx - u) * z / fx;
926
+ const y = (cy - v) * z / fy;
927
+ points.push(x, y, z);
928
+ }
929
+ }
930
+ const pointCount = points.length / 3;
931
+ const buffer = new ArrayBuffer(pointCount * 16);
932
+ const view = new DataView(buffer);
933
+ for (let i = 0; i < pointCount; i++) {
934
+ const offset = i * 16;
935
+ view.setFloat32(offset, points[i * 3] ?? 0, true); //X
936
+ view.setFloat32(offset + 4, points[i * 3 + 1] ?? 0, true); //Y
937
+ view.setFloat32(offset + 8, points[i * 3 + 2] ?? 0, true); //Z
938
+ view.setUint8(offset + 12, 0); // R
939
+ view.setUint8(offset + 13, 0); // G
940
+ view.setUint8(offset + 14, 0); // B
941
+ view.setUint8(offset + 15, 255); // A
942
+ }
943
+ return new Uint8Array(buffer);
944
+ }
945
+ async function deserializeDepthFrame({
946
+ topic,
947
+ message,
948
+ callback
949
+ }) {
950
+ const {
951
+ receiveTime,
952
+ width,
953
+ height
954
+ } = parseMessage(message);
955
+ const neuralCameraIntrinsics = JSON.parse(localStorage.getItem("neuralCameraIntrinsics") ?? "{}");
956
+ const uint16Array = uint8ArrayToUint16Array(message.data);
957
+ const fx = neuralCameraIntrinsics.right.focalLenght.x;
958
+ const fy = neuralCameraIntrinsics.right.focalLenght.y;
959
+ const cx = neuralCameraIntrinsics.right.principalPoint.x;
960
+ const cy = neuralCameraIntrinsics.right.principalPoint.y;
961
+ const pointCloudBufferGPU = depthToPointcloudGPU(uint16Array, width, height, fx, fy, cx, cy);
962
+ const foxgloveMessage = {
963
+ timestamp: receiveTime,
964
+ frame_id: `pointcloud-${topic}-frame`,
965
+ point_stride: 16,
966
+ pose: {
967
+ position: {
968
+ x: 0,
969
+ y: 0,
970
+ z: 0
971
+ },
972
+ orientation: {
973
+ x: 0,
974
+ y: 0,
975
+ z: 1,
976
+ w: 0
977
+ }
978
+ },
979
+ width,
980
+ height,
981
+ fields: [{
982
+ name: "x",
983
+ offset: 0,
984
+ type: typescript.NumericType.FLOAT32
985
+ }, {
986
+ name: "y",
987
+ offset: 4,
988
+ type: typescript.NumericType.FLOAT32
989
+ }, {
990
+ name: "z",
991
+ offset: 8,
992
+ type: typescript.NumericType.FLOAT32
993
+ }, {
994
+ name: "red",
995
+ offset: 12,
996
+ type: typescript.NumericType.UINT8
997
+ }, {
998
+ name: "green",
999
+ offset: 13,
1000
+ type: typescript.NumericType.UINT8
1001
+ }, {
1002
+ name: "blue",
1003
+ offset: 14,
1004
+ type: typescript.NumericType.UINT8
1005
+ }, {
1006
+ name: "alpha",
1007
+ offset: 15,
1008
+ type: typescript.NumericType.UINT8
1009
+ }],
1010
+ data: await pointCloudBufferGPU
1011
+ };
1012
+ callback({
1013
+ topic,
1014
+ receiveTime,
1015
+ message: foxgloveMessage,
1016
+ sizeInBytes: estimateObjectSize(foxgloveMessage),
1017
+ schemaName: "foxglove.PointCloud"
1018
+ });
1019
+ }
1020
+
1021
+ // This Source Code Form is subject to the terms of the Mozilla Public
1022
+ // License, v2.0. If a copy of the MPL was not distributed with this
1023
+ // file, You can obtain one at http://mozilla.org/MPL/2.0/
1024
+
1025
+ function ensureWebCodecsSupported(target) {
1026
+ const supported = typeof target !== "undefined";
1027
+ if (!supported) {
1028
+ const isProtocolSupported = window.location.protocol === "https:" || window.location.protocol === "file:";
1029
+ const isLocalHostname = window.location.hostname === "127.0.0.1" || window.location.hostname === "localhost";
1030
+ const reason = isProtocolSupported || isLocalHostname ? "Unsupported browser" : `${target} only supports \`https\` or \`localhost\` or \`127.0.0.1\``;
1031
+ console.error(`${target} is not available. Reason: ${reason}`);
1032
+ return false;
1033
+ }
1034
+ return true;
1035
+ }
1036
+
1037
+ // This Source Code Form is subject to the terms of the Mozilla Public
1038
+ // License, v2.0. If a copy of the MPL was not distributed with this
1039
+ // file, You can obtain one at http://mozilla.org/MPL/2.0/
1040
+
1041
+ function createVideoDecoder({
1042
+ topic,
1043
+ callback,
1044
+ topicDecoders
1045
+ }) {
1046
+ return new VideoDecoder({
1047
+ output: async frame => {
1048
+ const buffer = new Uint8Array(frame.allocationSize());
1049
+ await frame.copyTo(buffer);
1050
+ const receiveTime = topicDecoders.get(topic)?.timing.get(frame.timestamp) ?? dist.fromMicros(frame.timestamp);
1051
+ const [encoding, step] = parsePixelFormat(frame.format);
1052
+ const foxgloveMessage = {
1053
+ timestamp: receiveTime,
1054
+ frame_id: `h264-${topic}-frame`,
1055
+ width: frame.displayWidth,
1056
+ height: frame.displayHeight,
1057
+ data: buffer,
1058
+ encoding,
1059
+ step: frame.displayWidth * step
1060
+ };
1061
+ callback({
1062
+ topic,
1063
+ receiveTime,
1064
+ message: foxgloveMessage,
1065
+ sizeInBytes: estimateObjectSize(foxgloveMessage),
1066
+ schemaName: "foxglove.RawImage"
1067
+ });
1068
+ frame.close();
1069
+ },
1070
+ error: console.error
1071
+ });
1072
+ }
1073
+ async function deserializeEncodedFrameH264({
1074
+ topic,
1075
+ message,
1076
+ topicDecoders,
1077
+ callback
1078
+ }) {
1079
+ const {
1080
+ receiveTime
1081
+ } = parseMessage(message);
1082
+ const supported = ensureWebCodecsSupported("VideoDecoder");
1083
+ if (!supported) {
1084
+ return;
1085
+ }
1086
+ if (!topicDecoders.has(topic)) {
1087
+ const decoder = createVideoDecoder({
1088
+ topic,
1089
+ callback,
1090
+ topicDecoders
1091
+ });
1092
+ decoder.configure({
1093
+ codec: "avc1.42001E",
1094
+ optimizeForLatency: true
1095
+ });
1096
+ topicDecoders.set(topic, {
1097
+ decoder,
1098
+ timing: new Map()
1099
+ });
1100
+ }
1101
+ const decoderInfo = topicDecoders.get(topic);
1102
+ if (!decoderInfo) {
1103
+ return;
1104
+ }
1105
+ if (decoderInfo.decoder.decodeQueueSize > 60) {
1106
+ decoderInfo.decoder.reset();
1107
+ return;
1108
+ }
1109
+ const microTimestamp = receiveTime.sec * 1_000_000 + Math.floor(receiveTime.nsec / 1_000);
1110
+ decoderInfo.timing.set(microTimestamp, receiveTime);
1111
+ const frame = {
1112
+ type: 'key',
1113
+ data: message.data,
1114
+ timestamp: microTimestamp
1115
+ };
1116
+ try {
1117
+ const chunk = new EncodedVideoChunk(frame);
1118
+ decoderInfo.decoder.decode(chunk);
1119
+ } catch {
1120
+ topicDecoders.delete(topic);
1121
+ }
1122
+ }
1123
+
1124
+ // This Source Code Form is subject to the terms of the Mozilla Public
1125
+ // License, v2.0. If a copy of the MPL was not distributed with this
1126
+ // file, You can obtain one at http://mozilla.org/MPL/2.0/
1127
+
1128
+ async function deserializeMJPEGFrame({
1129
+ topic,
1130
+ message,
1131
+ callback
1132
+ }) {
1133
+ const {
1134
+ receiveTime
1135
+ } = parseMessage(message);
1136
+ const supported = ensureWebCodecsSupported("ImageDecoder");
1137
+ if (!supported) {
1138
+ return;
1139
+ }
1140
+ const decoder = new ImageDecoder({
1141
+ type: "image/jpeg",
1142
+ data: message.data
1143
+ });
1144
+ const {
1145
+ image: frame
1146
+ } = await decoder.decode();
1147
+ const buffer = new Uint8Array(frame.allocationSize());
1148
+ await frame.copyTo(buffer);
1149
+ const [encoding, step] = parsePixelFormat(frame.format);
1150
+ const foxgloveMessage = {
1151
+ timestamp: receiveTime,
1152
+ frame_id: "camera",
1153
+ width: frame.displayWidth,
1154
+ height: frame.displayHeight,
1155
+ data: buffer,
1156
+ encoding,
1157
+ step: frame.displayWidth * step
1158
+ };
1159
+ frame.close();
1160
+ callback({
1161
+ topic,
1162
+ receiveTime,
1163
+ message: foxgloveMessage,
1164
+ sizeInBytes: estimateObjectSize(foxgloveMessage),
1165
+ schemaName: "foxglove.RawImage"
1166
+ });
1167
+ }
1168
+
1169
+ // This Source Code Form is subject to the terms of the Mozilla Public
1170
+ // License, v2.0. If a copy of the MPL was not distributed with this
1171
+ // file, You can obtain one at http://mozilla.org/MPL/2.0/
1172
+ const topicDecoders = new Map();
1173
+ const topicSizes = new Map();
1174
+ let callback;
1175
+ function initCallback(cb) {
1176
+ callback = cb;
1177
+ }
1178
+ function handleMessageToDecode({
1179
+ schema,
1180
+ buffer,
1181
+ topic
1182
+ }) {
1183
+ const protobufSchema = protobufsBySchema[schema];
1184
+ if (!protobufSchema) {
1185
+ console.warn(`Unsupported message schema "${schema}"`);
1186
+ return;
1187
+ }
1188
+ const bufferArray = new Uint8Array(buffer.buffer, buffer.byteOffset, buffer.byteLength);
1189
+ const message = protobufSchema.decoder.decode(bufferArray);
1190
+ void deserializeDepthAiMessage({
1191
+ topic,
1192
+ topicSizes,
1193
+ topicDecoders,
1194
+ message,
1195
+ callback,
1196
+ type: protobufSchema.type
1197
+ });
1198
+ }
1199
+ async function deserializeDepthAiMessage(args) {
1200
+ const {
1201
+ topicDecoders,
1202
+ topicSizes,
1203
+ type,
1204
+ message,
1205
+ callback,
1206
+ topic
1207
+ } = args;
1208
+ switch (type) {
1209
+ case "encodedFrame":
1210
+ {
1211
+ topicSizes.set(topic, {
1212
+ width: message.width,
1213
+ height: message.height
1214
+ });
1215
+ if (message.profile === Profile.AVC) {
1216
+ await deserializeEncodedFrameH264({
1217
+ topic,
1218
+ message,
1219
+ topicDecoders,
1220
+ callback
1221
+ });
1222
+ } else if (message.profile === Profile.JPEG) {
1223
+ await deserializeMJPEGFrame({
1224
+ topic,
1225
+ message,
1226
+ callback
1227
+ });
1228
+ } else ;
1229
+ break;
1230
+ }
1231
+ case "imageFrame":
1232
+ {
1233
+ const {
1234
+ width,
1235
+ height,
1236
+ type: messageType
1237
+ } = parseMessage(message);
1238
+ topicSizes.set(topic, {
1239
+ width,
1240
+ height
1241
+ });
1242
+ switch (messageType) {
1243
+ case Type.BITSTREAM:
1244
+ {
1245
+ await deserializeEncodedFrameH264({
1246
+ topic,
1247
+ message,
1248
+ topicDecoders,
1249
+ callback
1250
+ });
1251
+ break;
1252
+ }
1253
+ case Type.RAW16:
1254
+ {
1255
+ await deserializeDepthFrame({
1256
+ topic,
1257
+ message,
1258
+ callback
1259
+ });
1260
+ break;
1261
+ }
1262
+ default:
1263
+ {
1264
+ deserializeColorFrame({
1265
+ topic,
1266
+ message,
1267
+ callback
1268
+ });
1269
+ }
1270
+ }
1271
+ break;
1272
+ }
1273
+ case "imageDetections":
1274
+ {
1275
+ deserializeImgDetections({
1276
+ topic,
1277
+ message,
1278
+ callback,
1279
+ topicSizes
1280
+ });
1281
+ break;
1282
+ }
1283
+ case "imageDetectionsCustom":
1284
+ {
1285
+ deserializeImgDetectionsCustom({
1286
+ topic,
1287
+ message,
1288
+ callback,
1289
+ topicSizes
1290
+ });
1291
+ break;
1292
+ }
1293
+ case "imageDetectionsSpatial":
1294
+ {
1295
+ // TODO: Use separate 3D detection deserializer
1296
+ deserializeImgDetections({
1297
+ topic,
1298
+ topicSizes,
1299
+ message: {
1300
+ ...message,
1301
+ detections: message.detections.map(detections => detections.detection)
1302
+ },
1303
+ callback
1304
+ });
1305
+ break;
1306
+ }
1307
+ case "pointCloud":
1308
+ {
1309
+ deserializePointCloudData({
1310
+ topic,
1311
+ message,
1312
+ callback
1313
+ });
1314
+ break;
1315
+ }
1316
+ default:
1317
+ {
1318
+ console.warn(`Message decoding failed: unsupported type "${type}"`);
1319
+ break;
1320
+ }
1321
+ }
1322
+ }
1323
+ expose({
1324
+ initCallback,
1325
+ handleMessageToDecode
1326
+ });