@luxonis/visualizer-protobuf 3.1.0 → 3.1.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 (57) hide show
  1. package/dist/{depth-BJ1GI-lD.js → depth-DlC6A3Te.js} +65 -1
  2. package/dist/{deserialization.worker-CpadaVUC.js → deserialization.worker-YKcSaSWH.js} +376 -309
  3. package/dist/{index-B0OcF19n.js → index-BMIqHWwd.js} +2 -2
  4. package/dist/{index-M2eVbe_0.js → index-BN2v1iMN.js} +2 -2
  5. package/dist/{index-TElhyLth.js → index-Bq4VaIv3.js} +3 -3
  6. package/dist/{index-lYAUlgOC.js → index-C53DG9uU.js} +2 -2
  7. package/dist/{index-D2XLTZD6.js → index-C77lunov.js} +2 -2
  8. package/dist/{index-DcciMCSs.js → index-C9_ELgH0.js} +2 -2
  9. package/dist/{index-ruqK13K_.js → index-CA-EmEAR.js} +2 -2
  10. package/dist/{index-kX1V6BdV.js → index-D1zXLkli.js} +2 -2
  11. package/dist/{index-DEAiAkuM.js → index-D89yfNy9.js} +2 -2
  12. package/dist/{index-BFuISzq9.js → index-DmP7sjUz.js} +2 -2
  13. package/dist/{index-JtoOqqNH.js → index-DoXJbu-D.js} +2 -2
  14. package/dist/{index-BimzNWm5.js → index-DpUuSNx-.js} +2 -2
  15. package/dist/{index-DnF6OLu4.js → index-Du4IzW8k.js} +2 -2
  16. package/dist/{index-D_329r0B.js → index-Duh8rNuw.js} +2 -2
  17. package/dist/{index-BoW57zty.js → index-Dx4uEaE6.js} +2 -2
  18. package/dist/{index-oMO5wzwz.js → index-Eu-m3JKy.js} +2 -2
  19. package/dist/{index-ByH52TmT.js → index-IGydAG_o.js} +2 -2
  20. package/dist/{index-POkmkil6.js → index-X7vcFOB2.js} +2 -2
  21. package/dist/{index-BQ8ArLBu.js → index-fnrBNnsp.js} +2 -2
  22. package/dist/{index-DQuS45dq.js → index-plyilw_0.js} +61 -28
  23. package/dist/index.js +2 -2
  24. package/dist/lib/src/components/Panel.d.ts.map +1 -1
  25. package/dist/lib/src/components/Panel.js +3 -1
  26. package/dist/lib/src/components/Panel.js.map +1 -1
  27. package/dist/lib/src/connection/connection.d.ts.map +1 -1
  28. package/dist/lib/src/connection/connection.js +7 -1
  29. package/dist/lib/src/connection/connection.js.map +1 -1
  30. package/dist/lib/src/connection/foxglove-connection.d.ts +6 -0
  31. package/dist/lib/src/connection/foxglove-connection.d.ts.map +1 -1
  32. package/dist/lib/src/connection/foxglove-connection.js +24 -3
  33. package/dist/lib/src/connection/foxglove-connection.js.map +1 -1
  34. package/dist/lib/src/context/VisualizerContext.d.ts +2 -0
  35. package/dist/lib/src/context/VisualizerContext.d.ts.map +1 -1
  36. package/dist/lib/src/context/VisualizerContext.js +7 -0
  37. package/dist/lib/src/context/VisualizerContext.js.map +1 -1
  38. package/dist/lib/src/messaging/deserialization/detections/detection.d.ts.map +1 -1
  39. package/dist/lib/src/messaging/deserialization/detections/detection.js +117 -96
  40. package/dist/lib/src/messaging/deserialization/detections/detection.js.map +1 -1
  41. package/dist/lib/src/messaging/deserialization/video/h264.d.ts +2 -1
  42. package/dist/lib/src/messaging/deserialization/video/h264.d.ts.map +1 -1
  43. package/dist/lib/src/messaging/deserialization/video/h264.js +142 -97
  44. package/dist/lib/src/messaging/deserialization/video/h264.js.map +1 -1
  45. package/dist/lib/src/messaging/deserialization/video/h265.d.ts +2 -1
  46. package/dist/lib/src/messaging/deserialization/video/h265.d.ts.map +1 -1
  47. package/dist/lib/src/messaging/deserialization/video/h265.js +57 -16
  48. package/dist/lib/src/messaging/deserialization/video/h265.js.map +1 -1
  49. package/dist/lib/src/messaging/deserialization.worker.d.ts +3 -1
  50. package/dist/lib/src/messaging/deserialization.worker.d.ts.map +1 -1
  51. package/dist/lib/src/messaging/deserialization.worker.js +28 -12
  52. package/dist/lib/src/messaging/deserialization.worker.js.map +1 -1
  53. package/dist/lib/src/utils/error.d.ts +17 -4
  54. package/dist/lib/src/utils/error.d.ts.map +1 -1
  55. package/dist/lib/src/utils/error.js +59 -6
  56. package/dist/lib/src/utils/error.js.map +1 -1
  57. package/package.json +1 -1
@@ -2,7 +2,7 @@
2
2
  import { b as _objectSpread2, P as PointsAnnotationType, p as protobufsBySchema, T as Type, h as Profile } from './protobuf-Be0G3NFz.js';
3
3
  import { e as expose } from './comlink-jf8bdrAf.js';
4
4
  import { t as typescript } from './index-Dqm1x8G2.js';
5
- import { R as parseMessage, e as estimateObjectSize, S as fromMillis, d as dist, U as parsePixelFormat, V as deserializeDepthFrame } from './depth-BJ1GI-lD.js';
5
+ import { U as parseMessage, e as estimateObjectSize, V as fromMillis, W as DecoderRuntimeError, d as dist, X as parsePixelFormat, Y as UnsupportedTopicError, Z as NotInSecureContextError, _ as EncodedStreamNotSupportedError, $ as deserializeDepthFrame } from './depth-DlC6A3Te.js';
6
6
  import { L as Logger } from './logger-Bqy1nuLj.js';
7
7
  import { i as isCapableOfEncodedStream } from './encoding-jXImCIb4.js';
8
8
  import 'react';
@@ -330,6 +330,141 @@ function rotatePoint(point, centerX, centerY, angleDegrees) {
330
330
  y: yRotated + centerY
331
331
  };
332
332
  }
333
+ function getDetectionGeometry(detection, highlightSizeX, highlightSizeY) {
334
+ const rotatedBoundingBox = detection.boundingBox;
335
+ if (rotatedBoundingBox !== null && rotatedBoundingBox !== void 0 && rotatedBoundingBox.center && rotatedBoundingBox.size) {
336
+ const {
337
+ center,
338
+ size,
339
+ angle
340
+ } = rotatedBoundingBox;
341
+ const halfWidth = size.width / 2;
342
+ const halfHeight = size.height / 2;
343
+ const topLeft = rotatePoint({
344
+ x: center.x - halfWidth,
345
+ y: center.y - halfHeight
346
+ }, center.x, center.y, angle);
347
+ const bottomLeft = rotatePoint({
348
+ x: center.x - halfWidth,
349
+ y: center.y + halfHeight
350
+ }, center.x, center.y, angle);
351
+ const bottomRight = rotatePoint({
352
+ x: center.x + halfWidth,
353
+ y: center.y + halfHeight
354
+ }, center.x, center.y, angle);
355
+ const topRight = rotatePoint({
356
+ x: center.x + halfWidth,
357
+ y: center.y - halfHeight
358
+ }, center.x, center.y, angle);
359
+ const _outline = [topLeft, bottomLeft, bottomRight, topRight];
360
+ const highlightTopWidth = Math.min(highlightSizeX, size.width);
361
+ const highlightSideHeight = Math.min(highlightSizeY, size.height);
362
+ const highlightSegments = [[topLeft, rotatePoint({
363
+ x: center.x - halfWidth + highlightTopWidth,
364
+ y: center.y - halfHeight
365
+ }, center.x, center.y, angle)], [topLeft, rotatePoint({
366
+ x: center.x - halfWidth,
367
+ y: center.y - halfHeight + highlightSideHeight
368
+ }, center.x, center.y, angle)], [topRight, rotatePoint({
369
+ x: center.x + halfWidth - highlightTopWidth,
370
+ y: center.y - halfHeight
371
+ }, center.x, center.y, angle)], [topRight, rotatePoint({
372
+ x: center.x + halfWidth,
373
+ y: center.y - halfHeight + highlightSideHeight
374
+ }, center.x, center.y, angle)], [bottomRight, rotatePoint({
375
+ x: center.x + halfWidth - highlightTopWidth,
376
+ y: center.y + halfHeight
377
+ }, center.x, center.y, angle)], [bottomRight, rotatePoint({
378
+ x: center.x + halfWidth,
379
+ y: center.y + halfHeight - highlightSideHeight
380
+ }, center.x, center.y, angle)], [bottomLeft, rotatePoint({
381
+ x: center.x - halfWidth + highlightTopWidth,
382
+ y: center.y + halfHeight
383
+ }, center.x, center.y, angle)], [bottomLeft, rotatePoint({
384
+ x: center.x - halfWidth,
385
+ y: center.y + halfHeight - highlightSideHeight
386
+ }, center.x, center.y, angle)]];
387
+ const minX = Math.min(..._outline.map(point => point.x));
388
+ const minY = Math.min(..._outline.map(point => point.y));
389
+ return {
390
+ outline: _outline,
391
+ highlightSegments,
392
+ labelPosition: {
393
+ x: minX + highlightSizeX / 2,
394
+ y: minY + highlightSizeY
395
+ }
396
+ };
397
+ }
398
+ const outline = [{
399
+ x: detection.xmin,
400
+ y: detection.ymin
401
+ }, {
402
+ x: detection.xmin,
403
+ y: detection.ymax
404
+ }, {
405
+ x: detection.xmax,
406
+ y: detection.ymax
407
+ }, {
408
+ x: detection.xmax,
409
+ y: detection.ymin
410
+ }];
411
+ return {
412
+ outline,
413
+ highlightSegments: [[{
414
+ x: detection.xmin,
415
+ y: detection.ymin
416
+ }, {
417
+ x: detection.xmin + highlightSizeX,
418
+ y: detection.ymin
419
+ }], [{
420
+ x: detection.xmin,
421
+ y: detection.ymin
422
+ }, {
423
+ x: detection.xmin,
424
+ y: detection.ymin + highlightSizeY
425
+ }], [{
426
+ x: detection.xmax,
427
+ y: detection.ymin
428
+ }, {
429
+ x: detection.xmax - highlightSizeX,
430
+ y: detection.ymin
431
+ }], [{
432
+ x: detection.xmax,
433
+ y: detection.ymin
434
+ }, {
435
+ x: detection.xmax,
436
+ y: detection.ymin + highlightSizeY
437
+ }], [{
438
+ x: detection.xmax,
439
+ y: detection.ymax
440
+ }, {
441
+ x: detection.xmax - highlightSizeX,
442
+ y: detection.ymax
443
+ }], [{
444
+ x: detection.xmax,
445
+ y: detection.ymax
446
+ }, {
447
+ x: detection.xmax,
448
+ y: detection.ymax - highlightSizeY
449
+ }], [{
450
+ x: detection.xmin,
451
+ y: detection.ymax
452
+ }, {
453
+ x: detection.xmin + highlightSizeX,
454
+ y: detection.ymax
455
+ }], [{
456
+ x: detection.xmin,
457
+ y: detection.ymax
458
+ }, {
459
+ x: detection.xmin,
460
+ y: detection.ymax - highlightSizeY
461
+ }]],
462
+ labelPosition: {
463
+ x: detection.xmin + highlightSizeX / 2,
464
+ y: detection.ymin + highlightSizeY
465
+ }
466
+ };
467
+ }
333
468
  function deserializeImgDetections({
334
469
  topic,
335
470
  message,
@@ -346,8 +481,9 @@ function deserializeImgDetections({
346
481
  };
347
482
  if (message.detections.length > 0) {
348
483
  for (const detection of message.detections) {
349
- var _message$transformati, _topicSizes$values$ne, _DETECTION_STYLE$dete, _detection$boundingBo, _detection$boundingBo2, _detection$boundingBo3, _detection$boundingBo4, _detection$boundingBo5, _detection$boundingBo6, _detection$boundingBo7, _detection$boundingBo8, _detection$boundingBo9, _detection$boundingBo0, _detection$boundingBo1, _detection$boundingBo10, _detection$boundingBo11, _detection$boundingBo12, _detection$boundingBo13, _detection$boundingBo14, _detection$boundingBo15, _detection$boundingBo16, _style$label;
350
- const detectionWidth = detection.xmax - detection.xmin;
484
+ var _detection$boundingBo, _detection$boundingBo2, _detection$boundingBo3, _detection$boundingBo4, _message$transformati, _topicSizes$values$ne, _DETECTION_STYLE$dete, _style$label;
485
+ const detectionWidth = (_detection$boundingBo = (_detection$boundingBo2 = detection.boundingBox) === null || _detection$boundingBo2 === void 0 || (_detection$boundingBo2 = _detection$boundingBo2.size) === null || _detection$boundingBo2 === void 0 ? void 0 : _detection$boundingBo2.width) !== null && _detection$boundingBo !== void 0 ? _detection$boundingBo : detection.xmax - detection.xmin;
486
+ const detectionHeight = (_detection$boundingBo3 = (_detection$boundingBo4 = detection.boundingBox) === null || _detection$boundingBo4 === void 0 || (_detection$boundingBo4 = _detection$boundingBo4.size) === null || _detection$boundingBo4 === void 0 ? void 0 : _detection$boundingBo4.height) !== null && _detection$boundingBo3 !== void 0 ? _detection$boundingBo3 : detection.ymax - detection.ymin;
351
487
  const {
352
488
  width,
353
489
  height
@@ -361,38 +497,15 @@ function deserializeImgDetections({
361
497
  const ratio = width / height;
362
498
  const highligtLength = 0.035;
363
499
  const highlightSizeX = Math.min(highligtLength, detectionWidth);
364
- const highlightSizeY = Math.min(highligtLength * ratio, detection.ymax - detection.ymin);
500
+ const highlightSizeY = Math.min(highligtLength * ratio, detectionHeight);
501
+ const geometry = getDetectionGeometry(detection, highlightSizeX, highlightSizeY);
365
502
  const style = (_DETECTION_STYLE$dete = DETECTION_STYLE[detection.label]) !== null && _DETECTION_STYLE$dete !== void 0 ? _DETECTION_STYLE$dete : DEFAULT_STYLE;
366
503
  if (detection.labelName) {
367
504
  style.label = detection.labelName;
368
505
  }
369
506
  foxgloveMessage.points.push({
370
507
  timestamp: receiveTime,
371
- points: (_detection$boundingBo = detection.boundingBox) !== null && _detection$boundingBo !== void 0 && _detection$boundingBo.angle && (_detection$boundingBo2 = detection.boundingBox) !== null && _detection$boundingBo2 !== void 0 && _detection$boundingBo2.center ? [rotatePoint({
372
- x: detection.xmin,
373
- y: detection.ymin
374
- }, detection.boundingBox.center.x, detection.boundingBox.center.y, detection.boundingBox.angle), rotatePoint({
375
- x: detection.xmin,
376
- y: detection.ymax
377
- }, detection.boundingBox.center.x, detection.boundingBox.center.y, detection.boundingBox.angle), rotatePoint({
378
- x: detection.xmax,
379
- y: detection.ymax
380
- }, detection.boundingBox.center.x, detection.boundingBox.center.y, detection.boundingBox.angle), rotatePoint({
381
- x: detection.xmax,
382
- y: detection.ymin
383
- }, detection.boundingBox.center.x, detection.boundingBox.center.y, detection.boundingBox.angle)] : [{
384
- x: detection.xmin,
385
- y: detection.ymin
386
- }, {
387
- x: detection.xmin,
388
- y: detection.ymax
389
- }, {
390
- x: detection.xmax,
391
- y: detection.ymax
392
- }, {
393
- x: detection.xmax,
394
- y: detection.ymin
395
- }],
508
+ points: geometry.outline,
396
509
  type: typescript.PointsAnnotationType.LINE_LOOP,
397
510
  outline_colors: [],
398
511
  thickness: 0,
@@ -453,133 +566,15 @@ function deserializeImgDetections({
453
566
  outline_color: style.outline,
454
567
  fill_color: DEBUG_COLOR
455
568
  };
456
- foxgloveMessage.points.push(_objectSpread2(_objectSpread2({}, baseHighlightConfig), {}, {
457
- points: (_detection$boundingBo3 = detection.boundingBox) !== null && _detection$boundingBo3 !== void 0 && _detection$boundingBo3.angle && (_detection$boundingBo4 = detection.boundingBox) !== null && _detection$boundingBo4 !== void 0 && _detection$boundingBo4.center ? [rotatePoint({
458
- x: detection.xmin,
459
- y: detection.ymin
460
- }, detection.boundingBox.center.x, detection.boundingBox.center.y, detection.boundingBox.angle), rotatePoint({
461
- x: detection.xmin + highlightSizeX,
462
- y: detection.ymin
463
- }, detection.boundingBox.center.x, detection.boundingBox.center.y, detection.boundingBox.angle)] : [{
464
- x: detection.xmin,
465
- y: detection.ymin
466
- }, {
467
- x: detection.xmin + highlightSizeX,
468
- y: detection.ymin
469
- }]
470
- }));
471
- foxgloveMessage.points.push(_objectSpread2(_objectSpread2({}, baseHighlightConfig), {}, {
472
- points: (_detection$boundingBo5 = detection.boundingBox) !== null && _detection$boundingBo5 !== void 0 && _detection$boundingBo5.angle && (_detection$boundingBo6 = detection.boundingBox) !== null && _detection$boundingBo6 !== void 0 && _detection$boundingBo6.center ? [rotatePoint({
473
- x: detection.xmin,
474
- y: detection.ymin
475
- }, detection.boundingBox.center.x, detection.boundingBox.center.y, detection.boundingBox.angle), rotatePoint({
476
- x: detection.xmin,
477
- y: detection.ymin + highlightSizeY
478
- }, detection.boundingBox.center.x, detection.boundingBox.center.y, detection.boundingBox.angle)] : [{
479
- x: detection.xmin,
480
- y: detection.ymin
481
- }, {
482
- x: detection.xmin,
483
- y: detection.ymin + highlightSizeY
484
- }]
485
- }));
486
- foxgloveMessage.points.push(_objectSpread2(_objectSpread2({}, baseHighlightConfig), {}, {
487
- points: (_detection$boundingBo7 = detection.boundingBox) !== null && _detection$boundingBo7 !== void 0 && _detection$boundingBo7.angle && (_detection$boundingBo8 = detection.boundingBox) !== null && _detection$boundingBo8 !== void 0 && _detection$boundingBo8.center ? [rotatePoint({
488
- x: detection.xmax,
489
- y: detection.ymin
490
- }, detection.boundingBox.center.x, detection.boundingBox.center.y, detection.boundingBox.angle), rotatePoint({
491
- x: detection.xmax - highlightSizeX,
492
- y: detection.ymin
493
- }, detection.boundingBox.center.x, detection.boundingBox.center.y, detection.boundingBox.angle)] : [{
494
- x: detection.xmax,
495
- y: detection.ymin
496
- }, {
497
- x: detection.xmax - highlightSizeX,
498
- y: detection.ymin
499
- }]
500
- }));
501
- foxgloveMessage.points.push(_objectSpread2(_objectSpread2({}, baseHighlightConfig), {}, {
502
- points: (_detection$boundingBo9 = detection.boundingBox) !== null && _detection$boundingBo9 !== void 0 && _detection$boundingBo9.angle && (_detection$boundingBo0 = detection.boundingBox) !== null && _detection$boundingBo0 !== void 0 && _detection$boundingBo0.center ? [rotatePoint({
503
- x: detection.xmax,
504
- y: detection.ymin
505
- }, detection.boundingBox.center.x, detection.boundingBox.center.y, detection.boundingBox.angle), rotatePoint({
506
- x: detection.xmax,
507
- y: detection.ymin + highlightSizeY
508
- }, detection.boundingBox.center.x, detection.boundingBox.center.y, detection.boundingBox.angle)] : [{
509
- x: detection.xmax,
510
- y: detection.ymin
511
- }, {
512
- x: detection.xmax,
513
- y: detection.ymin + highlightSizeY
514
- }]
515
- }));
516
- foxgloveMessage.points.push(_objectSpread2(_objectSpread2({}, baseHighlightConfig), {}, {
517
- points: (_detection$boundingBo1 = detection.boundingBox) !== null && _detection$boundingBo1 !== void 0 && _detection$boundingBo1.angle && (_detection$boundingBo10 = detection.boundingBox) !== null && _detection$boundingBo10 !== void 0 && _detection$boundingBo10.center ? [rotatePoint({
518
- x: detection.xmax,
519
- y: detection.ymax
520
- }, detection.boundingBox.center.x, detection.boundingBox.center.y, detection.boundingBox.angle), rotatePoint({
521
- x: detection.xmax - highlightSizeX,
522
- y: detection.ymax
523
- }, detection.boundingBox.center.x, detection.boundingBox.center.y, detection.boundingBox.angle)] : [{
524
- x: detection.xmax,
525
- y: detection.ymax
526
- }, {
527
- x: detection.xmax - highlightSizeX,
528
- y: detection.ymax
529
- }]
530
- }));
531
- foxgloveMessage.points.push(_objectSpread2(_objectSpread2({}, baseHighlightConfig), {}, {
532
- points: (_detection$boundingBo11 = detection.boundingBox) !== null && _detection$boundingBo11 !== void 0 && _detection$boundingBo11.angle && (_detection$boundingBo12 = detection.boundingBox) !== null && _detection$boundingBo12 !== void 0 && _detection$boundingBo12.center ? [rotatePoint({
533
- x: detection.xmax,
534
- y: detection.ymax
535
- }, detection.boundingBox.center.x, detection.boundingBox.center.y, detection.boundingBox.angle), rotatePoint({
536
- x: detection.xmax,
537
- y: detection.ymax - highlightSizeY
538
- }, detection.boundingBox.center.x, detection.boundingBox.center.y, detection.boundingBox.angle)] : [{
539
- x: detection.xmax,
540
- y: detection.ymax
541
- }, {
542
- x: detection.xmax,
543
- y: detection.ymax - highlightSizeY
544
- }]
545
- }));
546
- foxgloveMessage.points.push(_objectSpread2(_objectSpread2({}, baseHighlightConfig), {}, {
547
- points: (_detection$boundingBo13 = detection.boundingBox) !== null && _detection$boundingBo13 !== void 0 && _detection$boundingBo13.angle && (_detection$boundingBo14 = detection.boundingBox) !== null && _detection$boundingBo14 !== void 0 && _detection$boundingBo14.center ? [rotatePoint({
548
- x: detection.xmin,
549
- y: detection.ymax
550
- }, detection.boundingBox.center.x, detection.boundingBox.center.y, detection.boundingBox.angle), rotatePoint({
551
- x: detection.xmin + highlightSizeX,
552
- y: detection.ymax
553
- }, detection.boundingBox.center.x, detection.boundingBox.center.y, detection.boundingBox.angle)] : [{
554
- x: detection.xmin,
555
- y: detection.ymax
556
- }, {
557
- x: detection.xmin + highlightSizeX,
558
- y: detection.ymax
559
- }]
560
- }));
561
- foxgloveMessage.points.push(_objectSpread2(_objectSpread2({}, baseHighlightConfig), {}, {
562
- points: (_detection$boundingBo15 = detection.boundingBox) !== null && _detection$boundingBo15 !== void 0 && _detection$boundingBo15.angle && (_detection$boundingBo16 = detection.boundingBox) !== null && _detection$boundingBo16 !== void 0 && _detection$boundingBo16.center ? [rotatePoint({
563
- x: detection.xmin,
564
- y: detection.ymax
565
- }, detection.boundingBox.center.x, detection.boundingBox.center.y, detection.boundingBox.angle), rotatePoint({
566
- x: detection.xmin,
567
- y: detection.ymax - highlightSizeY
568
- }, detection.boundingBox.center.x, detection.boundingBox.center.y, detection.boundingBox.angle)] : [{
569
- x: detection.xmin,
570
- y: detection.ymax
571
- }, {
572
- x: detection.xmin,
573
- y: detection.ymax - highlightSizeY
574
- }]
575
- }));
569
+ for (const segment of geometry.highlightSegments) {
570
+ foxgloveMessage.points.push(_objectSpread2(_objectSpread2({}, baseHighlightConfig), {}, {
571
+ points: segment
572
+ }));
573
+ }
576
574
  const label = `${(_style$label = style.label) !== null && _style$label !== void 0 ? _style$label : `Unknown #${detection.label}`} ${Math.round(detection.confidence * 100)}%`;
577
575
  foxgloveMessage.texts.push({
578
576
  timestamp: receiveTime,
579
- position: {
580
- x: detection.xmin + highligtLength / 2,
581
- y: detection.ymin + highlightSizeY
582
- },
577
+ position: geometry.labelPosition,
583
578
  text: label,
584
579
  font_size: getTextSize(width, height),
585
580
  text_color: DEFAULT_TEXT_COLOR,
@@ -802,64 +797,30 @@ function ensureWebCodecsSupported(target) {
802
797
  // file, You can obtain one at http://mozilla.org/MPL/2.0/
803
798
 
804
799
  const logger$2 = Logger.getLogger();
805
- function bgrxToI420(bgrx, width, height) {
806
- if ((width & 1) !== 0 || (height & 1) !== 0) {
807
- throw new Error("I420 requires even width and height.");
800
+ function closeDecoder$1(decoder) {
801
+ if (!decoder) {
802
+ return;
808
803
  }
809
- const ySize = width * height;
810
- const uvSize = width * height >> 2;
811
- const out = new Uint8Array(ySize + uvSize + uvSize);
812
- const Y = out.subarray(0, ySize);
813
- const U = out.subarray(ySize, ySize + uvSize);
814
- const V = out.subarray(ySize + uvSize);
815
- const stride = width * 4;
816
- const clamp8 = x => x < 0 ? 0 : x > 255 ? 255 : x | 0;
817
- for (let y = 0; y < height; y += 2) {
818
- const row0 = y * stride;
819
- const row1 = (y + 1) * stride;
820
- for (let x = 0; x < width; x += 2) {
821
- const p00 = row0 + x * 4;
822
- const p01 = row0 + (x + 1) * 4;
823
- const p10 = row1 + x * 4;
824
- const p11 = row1 + (x + 1) * 4;
825
- const B00 = bgrx[p00 + 0],
826
- G00 = bgrx[p00 + 1],
827
- R00 = bgrx[p00 + 2];
828
- const B01 = bgrx[p01 + 0],
829
- G01 = bgrx[p01 + 1],
830
- R01 = bgrx[p01 + 2];
831
- const B10 = bgrx[p10 + 0],
832
- G10 = bgrx[p10 + 1],
833
- R10 = bgrx[p10 + 2];
834
- const B11 = bgrx[p11 + 0],
835
- G11 = bgrx[p11 + 1],
836
- R11 = bgrx[p11 + 2];
837
- const Y00 = 77 * R00 + 150 * G00 + 29 * B00 + 128 >> 8;
838
- const Y01 = 77 * R01 + 150 * G01 + 29 * B01 + 128 >> 8;
839
- const Y10 = 77 * R10 + 150 * G10 + 29 * B10 + 128 >> 8;
840
- const Y11 = 77 * R11 + 150 * G11 + 29 * B11 + 128 >> 8;
841
- const yRow0 = y * width + x;
842
- const yRow1 = (y + 1) * width + x;
843
- Y[yRow0 + 0] = Y00;
844
- Y[yRow0 + 1] = Y01;
845
- Y[yRow1 + 0] = Y10;
846
- Y[yRow1 + 1] = Y11;
847
- const Ravg = R00 + R01 + R10 + R11 >> 2;
848
- const Gavg = G00 + G01 + G10 + G11 >> 2;
849
- const Bavg = B00 + B01 + B10 + B11 >> 2;
850
- const Uval = clamp8((-43 * Ravg - 85 * Gavg + 128 * Bavg >> 8) + 128);
851
- const Vval = clamp8((128 * Ravg - 107 * Gavg - 21 * Bavg >> 8) + 128);
852
- const uvCol = x >> 1;
853
- const uvRow = y >> 1;
854
- const uvW = width >> 1;
855
- const uvPos = uvRow * uvW + uvCol;
856
- U[uvPos] = Uval;
857
- V[uvPos] = Vval;
858
- }
804
+ if (decoder.state === "closed") {
805
+ return;
806
+ }
807
+ try {
808
+ decoder.close();
809
+ } catch (error) {
810
+ logger$2.warn("Failed to close H264 decoder cleanly.", error);
859
811
  }
860
- return out;
861
812
  }
862
- function bgraToI420(bgra, width, height) {
813
+ function closeTopicDecoder$1(topic, topicDecoders) {
814
+ const decoderInfo = topicDecoders.get(topic);
815
+ closeDecoder$1(decoderInfo === null || decoderInfo === void 0 ? void 0 : decoderInfo.decoder);
816
+ decoderInfo === null || decoderInfo === void 0 || decoderInfo.timing.clear();
817
+ decoderInfo === null || decoderInfo === void 0 || decoderInfo.transformations.clear();
818
+ }
819
+ function isIgnorableInitialDecodeError(error) {
820
+ const message = error instanceof Error ? error.message : String(error);
821
+ return message.includes("A key frame is required after configure() or flush()");
822
+ }
823
+ function packedToI420(packed, width, height, stride, format, cropLeft = 0, cropTop = 0) {
863
824
  if ((width & 1) !== 0 || (height & 1) !== 0) {
864
825
  throw new Error("I420 requires even width and height.");
865
826
  }
@@ -869,28 +830,29 @@ function bgraToI420(bgra, width, height) {
869
830
  const Y = out.subarray(0, ySize);
870
831
  const U = out.subarray(ySize, ySize + uvSize);
871
832
  const V = out.subarray(ySize + uvSize);
872
- const stride = width * 4;
833
+ const isRgbLayout = format === "RGBX" || format === "RGBA";
873
834
  const clamp8 = x => x < 0 ? 0 : x > 255 ? 255 : x | 0;
874
835
  for (let y = 0; y < height; y += 2) {
875
- const row0 = y * stride;
876
- const row1 = (y + 1) * stride;
836
+ const row0 = (y + cropTop) * stride;
837
+ const row1 = (y + cropTop + 1) * stride;
877
838
  for (let x = 0; x < width; x += 2) {
878
- const p00 = row0 + x * 4;
879
- const p01 = row0 + (x + 1) * 4;
880
- const p10 = row1 + x * 4;
881
- const p11 = row1 + (x + 1) * 4;
882
- const B00 = bgra[p00 + 0],
883
- G00 = bgra[p00 + 1],
884
- R00 = bgra[p00 + 2];
885
- const B01 = bgra[p01 + 0],
886
- G01 = bgra[p01 + 1],
887
- R01 = bgra[p01 + 2];
888
- const B10 = bgra[p10 + 0],
889
- G10 = bgra[p10 + 1],
890
- R10 = bgra[p10 + 2];
891
- const B11 = bgra[p11 + 0],
892
- G11 = bgra[p11 + 1],
893
- R11 = bgra[p11 + 2];
839
+ const srcX = x + cropLeft;
840
+ const p00 = row0 + srcX * 4;
841
+ const p01 = row0 + (srcX + 1) * 4;
842
+ const p10 = row1 + srcX * 4;
843
+ const p11 = row1 + (srcX + 1) * 4;
844
+ const R00 = packed[p00 + (isRgbLayout ? 0 : 2)];
845
+ const G00 = packed[p00 + 1];
846
+ const B00 = packed[p00 + (isRgbLayout ? 2 : 0)];
847
+ const R01 = packed[p01 + (isRgbLayout ? 0 : 2)];
848
+ const G01 = packed[p01 + 1];
849
+ const B01 = packed[p01 + (isRgbLayout ? 2 : 0)];
850
+ const R10 = packed[p10 + (isRgbLayout ? 0 : 2)];
851
+ const G10 = packed[p10 + 1];
852
+ const B10 = packed[p10 + (isRgbLayout ? 2 : 0)];
853
+ const R11 = packed[p11 + (isRgbLayout ? 0 : 2)];
854
+ const G11 = packed[p11 + 1];
855
+ const B11 = packed[p11 + (isRgbLayout ? 2 : 0)];
894
856
  const Y00 = 77 * R00 + 150 * G00 + 29 * B00 + 128 >> 8;
895
857
  const Y01 = 77 * R01 + 150 * G01 + 29 * B01 + 128 >> 8;
896
858
  const Y10 = 77 * R10 + 150 * G10 + 29 * B10 + 128 >> 8;
@@ -916,15 +878,12 @@ function bgraToI420(bgra, width, height) {
916
878
  }
917
879
  return out;
918
880
  }
919
- function convertNv12ToI420(nv12Buffer, width, height, stride) {
920
- const actualStride = stride !== null && stride !== void 0 ? stride : width;
881
+ function convertNv12ToI420(nv12Buffer, width, height, yStride, uvStride, yOffset = 0, uvOffset = yStride * height, cropLeft = 0, cropTop = 0) {
921
882
  const ySize = width * height;
922
883
  const uvSize = ySize / 4;
923
884
  const i420Buffer = new Uint8Array(ySize + 2 * uvSize);
924
-
925
- // Copy Y plane row by row (accounting for stride)
926
885
  for (let row = 0; row < height; row++) {
927
- const srcOffset = row * actualStride;
886
+ const srcOffset = yOffset + (row + cropTop) * yStride + cropLeft;
928
887
  const dstOffset = row * width;
929
888
  i420Buffer.set(nv12Buffer.subarray(srcOffset, srcOffset + width), dstOffset);
930
889
  }
@@ -932,12 +891,12 @@ function convertNv12ToI420(nv12Buffer, width, height, stride) {
932
891
  const vPlaneOffset = ySize + uvSize;
933
892
  const uvHeight = height / 2;
934
893
  const uvWidth = width / 2;
935
-
936
- // De-interleave UV plane row by row (accounting for stride)
894
+ const uvCropLeft = cropLeft >> 1;
895
+ const uvCropTop = cropTop >> 1;
937
896
  for (let row = 0; row < uvHeight; row++) {
938
897
  for (let col = 0; col < uvWidth; col++) {
939
898
  var _nv12Buffer$srcIndex, _nv12Buffer;
940
- const srcIndex = height * actualStride + row * actualStride + col * 2;
899
+ const srcIndex = uvOffset + (row + uvCropTop) * uvStride + (col + uvCropLeft) * 2;
941
900
  const dstIndex = row * uvWidth + col;
942
901
  i420Buffer[uPlaneOffset + dstIndex] = (_nv12Buffer$srcIndex = nv12Buffer[srcIndex]) !== null && _nv12Buffer$srcIndex !== void 0 ? _nv12Buffer$srcIndex : 0; // U
943
902
  i420Buffer[vPlaneOffset + dstIndex] = (_nv12Buffer = nv12Buffer[srcIndex + 1]) !== null && _nv12Buffer !== void 0 ? _nv12Buffer : 0; // V
@@ -945,47 +904,77 @@ function convertNv12ToI420(nv12Buffer, width, height, stride) {
945
904
  }
946
905
  return i420Buffer;
947
906
  }
907
+ function repackI420(source, width, height, yLayout, uLayout, vLayout, cropLeft = 0, cropTop = 0) {
908
+ const ySize = width * height;
909
+ const uvWidth = width >> 1;
910
+ const uvHeight = height >> 1;
911
+ const uvSize = uvWidth * uvHeight;
912
+ const out = new Uint8Array(ySize + uvSize * 2);
913
+ const uvCropLeft = cropLeft >> 1;
914
+ const uvCropTop = cropTop >> 1;
915
+ for (let row = 0; row < height; row++) {
916
+ const srcOffset = yLayout.offset + (row + cropTop) * yLayout.stride + cropLeft;
917
+ out.set(source.subarray(srcOffset, srcOffset + width), row * width);
918
+ }
919
+ for (let row = 0; row < uvHeight; row++) {
920
+ const uSrcOffset = uLayout.offset + (row + uvCropTop) * uLayout.stride + uvCropLeft;
921
+ const vSrcOffset = vLayout.offset + (row + uvCropTop) * vLayout.stride + uvCropLeft;
922
+ const dstOffset = row * uvWidth;
923
+ out.set(source.subarray(uSrcOffset, uSrcOffset + uvWidth), ySize + dstOffset);
924
+ out.set(source.subarray(vSrcOffset, vSrcOffset + uvWidth), ySize + uvSize + dstOffset);
925
+ }
926
+ return out;
927
+ }
948
928
  function createVideoDecoder$1({
949
929
  topic,
950
930
  callback,
951
- topicDecoders
931
+ topicDecoders,
932
+ onError
952
933
  }) {
934
+ let hasProducedFrame = false;
953
935
  return new VideoDecoder({
954
936
  output: async frame => {
955
- var _topicDecoders$get$ti, _topicDecoders$get, _topicDecoders$get2, _topicDecoders$get3;
937
+ var _visibleRect$width, _visibleRect$height, _visibleRect$x, _visibleRect$y, _topicDecoders$get$ti, _topicDecoders$get, _topicDecoders$get2, _topicDecoders$get3;
938
+ hasProducedFrame = true;
939
+ const visibleRect = frame.visibleRect;
940
+ const frameWidth = (_visibleRect$width = visibleRect === null || visibleRect === void 0 ? void 0 : visibleRect.width) !== null && _visibleRect$width !== void 0 ? _visibleRect$width : frame.codedWidth;
941
+ const frameHeight = (_visibleRect$height = visibleRect === null || visibleRect === void 0 ? void 0 : visibleRect.height) !== null && _visibleRect$height !== void 0 ? _visibleRect$height : frame.codedHeight;
942
+ const cropLeft = (_visibleRect$x = visibleRect === null || visibleRect === void 0 ? void 0 : visibleRect.x) !== null && _visibleRect$x !== void 0 ? _visibleRect$x : 0;
943
+ const cropTop = (_visibleRect$y = visibleRect === null || visibleRect === void 0 ? void 0 : visibleRect.y) !== null && _visibleRect$y !== void 0 ? _visibleRect$y : 0;
956
944
  let finalBuffer = new Uint8Array(frame.allocationSize());
945
+ logger$2.warn(`H264 decoder output format: ${frame.format}, coded=${frame.codedWidth}x${frame.codedHeight}, display=${frame.displayWidth}x${frame.displayHeight}, visible=${frameWidth}x${frameHeight}@${cropLeft},${cropTop}`);
957
946
  switch (frame.format) {
958
947
  case "I420":
959
948
  {
960
- finalBuffer = new Uint8Array(frame.allocationSize());
961
- await frame.copyTo(finalBuffer);
949
+ const i420Buffer = new Uint8Array(frame.allocationSize());
950
+ const layouts = await frame.copyTo(i420Buffer);
951
+ const [yLayout, uLayout, vLayout] = layouts;
952
+ finalBuffer = yLayout != undefined && uLayout != undefined && vLayout != undefined ? repackI420(i420Buffer, frameWidth, frameHeight, yLayout, uLayout, vLayout, cropLeft, cropTop) : i420Buffer;
962
953
  break;
963
954
  }
964
955
  case "NV12":
965
956
  {
957
+ var _yLayout$stride, _uvLayout$stride, _yLayout$offset, _uvLayout$offset, _yLayout$stride2;
966
958
  const nv12Buffer = new Uint8Array(frame.allocationSize());
967
- await frame.copyTo(nv12Buffer);
968
- finalBuffer = convertNv12ToI420(nv12Buffer, frame.displayWidth, frame.displayHeight, frame.codedWidth);
959
+ const layouts = await frame.copyTo(nv12Buffer);
960
+ const [yLayout, uvLayout] = layouts;
961
+ finalBuffer = convertNv12ToI420(nv12Buffer, frameWidth, frameHeight, (_yLayout$stride = yLayout === null || yLayout === void 0 ? void 0 : yLayout.stride) !== null && _yLayout$stride !== void 0 ? _yLayout$stride : frame.codedWidth, (_uvLayout$stride = uvLayout === null || uvLayout === void 0 ? void 0 : uvLayout.stride) !== null && _uvLayout$stride !== void 0 ? _uvLayout$stride : frame.codedWidth, (_yLayout$offset = yLayout === null || yLayout === void 0 ? void 0 : yLayout.offset) !== null && _yLayout$offset !== void 0 ? _yLayout$offset : 0, (_uvLayout$offset = uvLayout === null || uvLayout === void 0 ? void 0 : uvLayout.offset) !== null && _uvLayout$offset !== void 0 ? _uvLayout$offset : ((_yLayout$stride2 = yLayout === null || yLayout === void 0 ? void 0 : yLayout.stride) !== null && _yLayout$stride2 !== void 0 ? _yLayout$stride2 : frame.codedWidth) * frame.codedHeight, cropLeft, cropTop);
969
962
  break;
970
963
  }
971
964
  case "RGBX":
965
+ case "RGBA":
972
966
  case "BGRX":
973
- {
974
- const bgrxBuffer = new Uint8Array(frame.allocationSize());
975
- await frame.copyTo(bgrxBuffer);
976
- logger$2.warn("PointCloud decoder received RGBX frame.");
977
- finalBuffer = bgrxToI420(bgrxBuffer, frame.codedWidth, frame.codedHeight);
978
- break;
979
- }
980
967
  case "BGRA":
981
968
  {
982
- const bgraBuffer = new Uint8Array(frame.allocationSize());
983
- await frame.copyTo(bgraBuffer);
984
- finalBuffer = bgraToI420(bgraBuffer, frame.codedWidth, frame.codedHeight);
969
+ var _layout$stride;
970
+ const packedBuffer = new Uint8Array(frame.allocationSize());
971
+ const [layout] = await frame.copyTo(packedBuffer);
972
+ logger$2.warn(`H264 decoder received ${frame.format} frame.`);
973
+ finalBuffer = packedToI420(packedBuffer, frameWidth, frameHeight, (_layout$stride = layout === null || layout === void 0 ? void 0 : layout.stride) !== null && _layout$stride !== void 0 ? _layout$stride : frame.codedWidth * 4, frame.format, cropLeft, cropTop);
985
974
  break;
986
975
  }
987
976
  }
988
- if (frame.format !== "I420" && frame.format !== "NV12" && frame.format !== "RGBX" && frame.format !== "BGRX" && frame.format !== "BGRA") {
977
+ if (frame.format !== "I420" && frame.format !== "NV12" && frame.format !== "RGBX" && frame.format !== "RGBA" && frame.format !== "BGRX" && frame.format !== "BGRA") {
989
978
  logger$2.warn("H264 decoder received unexpected frame format:", frame.format);
990
979
  }
991
980
  const receiveTime = (_topicDecoders$get$ti = (_topicDecoders$get = topicDecoders.get(topic)) === null || _topicDecoders$get === void 0 ? void 0 : _topicDecoders$get.timing.get(frame.timestamp)) !== null && _topicDecoders$get$ti !== void 0 ? _topicDecoders$get$ti : dist.fromMicros(frame.timestamp);
@@ -994,11 +983,11 @@ function createVideoDecoder$1({
994
983
  const foxgloveMessage = {
995
984
  timestamp: receiveTime,
996
985
  frame_id: `h264-${topic}-frame`,
997
- width: frame.displayWidth,
998
- height: frame.displayHeight,
986
+ width: frameWidth,
987
+ height: frameHeight,
999
988
  data: finalBuffer,
1000
989
  encoding: "yuv420p",
1001
- step: frame.displayWidth
990
+ step: frameWidth
1002
991
  };
1003
992
  callback({
1004
993
  topic,
@@ -1010,14 +999,24 @@ function createVideoDecoder$1({
1010
999
  });
1011
1000
  frame.close();
1012
1001
  },
1013
- error: logger$2.error
1002
+ error: error => {
1003
+ if (!hasProducedFrame && isIgnorableInitialDecodeError(error)) {
1004
+ logger$2.warn(`Ignoring initial H264 decoder error for topic ${topic}: ${error.message}`);
1005
+ closeTopicDecoder$1(topic, topicDecoders);
1006
+ return;
1007
+ }
1008
+ logger$2.error(error);
1009
+ closeTopicDecoder$1(topic, topicDecoders);
1010
+ onError(new DecoderRuntimeError(topic, error.message));
1011
+ }
1014
1012
  });
1015
1013
  }
1016
1014
  async function deserializeEncodedFrameH264({
1017
1015
  topic,
1018
1016
  message,
1019
1017
  topicDecoders,
1020
- callback
1018
+ callback,
1019
+ onError
1021
1020
  }) {
1022
1021
  const {
1023
1022
  receiveTime
@@ -1026,21 +1025,35 @@ async function deserializeEncodedFrameH264({
1026
1025
  if (!supported) {
1027
1026
  return;
1028
1027
  }
1029
- if (!topicDecoders.has(topic)) {
1028
+ const existingDecoderInfo = topicDecoders.get(topic);
1029
+ if (!existingDecoderInfo || existingDecoderInfo.decoder.state === "closed") {
1030
1030
  const decoder = createVideoDecoder$1({
1031
1031
  topic,
1032
1032
  callback,
1033
- topicDecoders
1034
- });
1035
- decoder.configure({
1036
- codec: "avc1.42001E",
1037
- optimizeForLatency: true
1038
- });
1039
- topicDecoders.set(topic, {
1040
- decoder,
1041
- timing: new Map(),
1042
- transformations: new Map()
1033
+ topicDecoders,
1034
+ onError
1043
1035
  });
1036
+ try {
1037
+ decoder.configure({
1038
+ codec: "avc1.42001E",
1039
+ optimizeForLatency: true
1040
+ });
1041
+ } catch (error) {
1042
+ closeDecoder$1(decoder);
1043
+ onError(new DecoderRuntimeError(topic, error instanceof Error ? error.message : "Failed to configure H.264 decoder."));
1044
+ return;
1045
+ }
1046
+ if (existingDecoderInfo) {
1047
+ existingDecoderInfo.decoder = decoder;
1048
+ existingDecoderInfo.timing.clear();
1049
+ existingDecoderInfo.transformations.clear();
1050
+ } else {
1051
+ topicDecoders.set(topic, {
1052
+ decoder,
1053
+ timing: new Map(),
1054
+ transformations: new Map()
1055
+ });
1056
+ }
1044
1057
  }
1045
1058
  const decoderInfo = topicDecoders.get(topic);
1046
1059
  if (!decoderInfo) {
@@ -1061,8 +1074,13 @@ async function deserializeEncodedFrameH264({
1061
1074
  try {
1062
1075
  const chunk = new EncodedVideoChunk(frame);
1063
1076
  decoderInfo.decoder.decode(chunk);
1064
- } catch (_unused) {
1065
- topicDecoders.delete(topic);
1077
+ } catch (error) {
1078
+ if (isIgnorableInitialDecodeError(error)) {
1079
+ closeTopicDecoder$1(topic, topicDecoders);
1080
+ return;
1081
+ }
1082
+ closeTopicDecoder$1(topic, topicDecoders);
1083
+ onError(new DecoderRuntimeError(topic, error instanceof Error ? error.message : "Failed to decode H.264 frame."));
1066
1084
  }
1067
1085
  }
1068
1086
 
@@ -1071,10 +1089,30 @@ async function deserializeEncodedFrameH264({
1071
1089
  // file, You can obtain one at http://mozilla.org/MPL/2.0/
1072
1090
 
1073
1091
  const logger$1 = Logger.getLogger();
1092
+ function closeDecoder(decoder) {
1093
+ if (!decoder) {
1094
+ return;
1095
+ }
1096
+ if (decoder.state === "closed") {
1097
+ return;
1098
+ }
1099
+ try {
1100
+ decoder.close();
1101
+ } catch (error) {
1102
+ logger$1.warn("Failed to close H265 decoder cleanly.", error);
1103
+ }
1104
+ }
1105
+ function closeTopicDecoder(topic, topicDecoders) {
1106
+ const decoderInfo = topicDecoders.get(topic);
1107
+ closeDecoder(decoderInfo === null || decoderInfo === void 0 ? void 0 : decoderInfo.decoder);
1108
+ decoderInfo === null || decoderInfo === void 0 || decoderInfo.timing.clear();
1109
+ decoderInfo === null || decoderInfo === void 0 || decoderInfo.transformations.clear();
1110
+ }
1074
1111
  function createVideoDecoder({
1075
1112
  topic,
1076
1113
  callback,
1077
- topicDecoders
1114
+ topicDecoders,
1115
+ onError
1078
1116
  }) {
1079
1117
  return new VideoDecoder({
1080
1118
  output: async frame => {
@@ -1104,14 +1142,19 @@ function createVideoDecoder({
1104
1142
  });
1105
1143
  frame.close();
1106
1144
  },
1107
- error: logger$1.error
1145
+ error: error => {
1146
+ logger$1.error(error);
1147
+ closeTopicDecoder(topic, topicDecoders);
1148
+ onError(new DecoderRuntimeError(topic, error.message));
1149
+ }
1108
1150
  });
1109
1151
  }
1110
1152
  async function deserializeEncodedFrameH265({
1111
1153
  topic,
1112
1154
  message,
1113
1155
  topicDecoders,
1114
- callback
1156
+ callback,
1157
+ onError
1115
1158
  }) {
1116
1159
  const {
1117
1160
  receiveTime
@@ -1120,21 +1163,35 @@ async function deserializeEncodedFrameH265({
1120
1163
  if (!supported) {
1121
1164
  return;
1122
1165
  }
1123
- if (!topicDecoders.has(topic)) {
1166
+ const existingDecoderInfo = topicDecoders.get(topic);
1167
+ if (!existingDecoderInfo || existingDecoderInfo.decoder.state === "closed") {
1124
1168
  const decoder = createVideoDecoder({
1125
1169
  topic,
1126
1170
  callback,
1127
- topicDecoders
1128
- });
1129
- decoder.configure({
1130
- codec: "hev1.1.6.L93.B0",
1131
- optimizeForLatency: true
1132
- });
1133
- topicDecoders.set(topic, {
1134
- decoder,
1135
- timing: new Map(),
1136
- transformations: new Map()
1171
+ topicDecoders,
1172
+ onError
1137
1173
  });
1174
+ try {
1175
+ decoder.configure({
1176
+ codec: "hev1.1.6.L93.B0",
1177
+ optimizeForLatency: true
1178
+ });
1179
+ } catch (error) {
1180
+ closeDecoder(decoder);
1181
+ onError(new DecoderRuntimeError(topic, error instanceof Error ? error.message : "Failed to configure H.265 decoder."));
1182
+ return;
1183
+ }
1184
+ if (existingDecoderInfo) {
1185
+ existingDecoderInfo.decoder = decoder;
1186
+ existingDecoderInfo.timing.clear();
1187
+ existingDecoderInfo.transformations.clear();
1188
+ } else {
1189
+ topicDecoders.set(topic, {
1190
+ decoder,
1191
+ timing: new Map(),
1192
+ transformations: new Map()
1193
+ });
1194
+ }
1138
1195
  }
1139
1196
  const decoderInfo = topicDecoders.get(topic);
1140
1197
  if (!decoderInfo) {
@@ -1155,8 +1212,9 @@ async function deserializeEncodedFrameH265({
1155
1212
  try {
1156
1213
  const chunk = new EncodedVideoChunk(frame);
1157
1214
  decoderInfo.decoder.decode(chunk);
1158
- } catch (_unused) {
1159
- topicDecoders.delete(topic);
1215
+ } catch (error) {
1216
+ closeTopicDecoder(topic, topicDecoders);
1217
+ onError(new DecoderRuntimeError(topic, error instanceof Error ? error.message : "Failed to decode H.265 frame."));
1160
1218
  }
1161
1219
  }
1162
1220
 
@@ -1206,23 +1264,18 @@ async function deserializeMJPEGFrame({
1206
1264
  });
1207
1265
  }
1208
1266
 
1209
- class EncodedStreamNotSupportedError extends Error {
1210
- constructor(topicName) {
1211
- super("Encoded stream not supported on this platform");
1212
- this.topicName = void 0;
1213
- this.name = "EncodedStreamNotSupportedError";
1214
- this.errorType = "EncodedStreamNotSupportedError";
1215
- this.topicName = topicName;
1216
- Object.setPrototypeOf(this, EncodedStreamNotSupportedError.prototype);
1217
- }
1218
- }
1219
-
1220
1267
  const logger = Logger.getLogger();
1221
1268
  function errorInstanceToErrorCode(error) {
1269
+ if (error instanceof UnsupportedTopicError) {
1270
+ return "UnsupportedTopic";
1271
+ }
1272
+ if (error instanceof NotInSecureContextError) {
1273
+ return "NotInSecureContext";
1274
+ }
1222
1275
  if (error instanceof EncodedStreamNotSupportedError) {
1223
1276
  return "EncodedStreamNotSupported";
1224
1277
  }
1225
- return "Error";
1278
+ return "DecoderError";
1226
1279
  }
1227
1280
  const topicDecoders = new Map();
1228
1281
  const topicSizes = new Map();
@@ -1230,6 +1283,14 @@ let callback;
1230
1283
  function initCallback(cb) {
1231
1284
  callback = cb;
1232
1285
  }
1286
+ function ensureEncodedStreamSupport(topic) {
1287
+ if (!globalThis.isSecureContext) {
1288
+ throw new NotInSecureContextError(topic);
1289
+ }
1290
+ if (!isCapableOfEncodedStream()) {
1291
+ throw new EncodedStreamNotSupportedError(topic);
1292
+ }
1293
+ }
1233
1294
  function handleMessageToDecode({
1234
1295
  schema,
1235
1296
  buffer,
@@ -1243,12 +1304,14 @@ function handleMessageToDecode({
1243
1304
  // Type information about an error gets lost during transfer from worker to main thread
1244
1305
  // This means that we have to remap the errors based on type here to an 'error enum'
1245
1306
  // Which can then be parsed on the main thread
1246
- errorCallback === null || errorCallback === void 0 || errorCallback(errorInstanceToErrorCode(error), topic, {});
1307
+ errorCallback === null || errorCallback === void 0 || errorCallback(errorInstanceToErrorCode(error), topic, {
1308
+ message: error.message
1309
+ });
1247
1310
  };
1248
1311
  const protobufSchema = protobufsBySchema[schema];
1249
1312
  if (!protobufSchema) {
1250
1313
  logger.warn(`Unsupported message schema "${schema}"`);
1251
- handleDecodingError(new Error(`Unsupported message schema "${schema}"`));
1314
+ handleDecodingError(new UnsupportedTopicError(topic, `Unsupported message schema "${schema}"`));
1252
1315
  return;
1253
1316
  }
1254
1317
  const bufferArray = new Uint8Array(buffer.buffer, buffer.byteOffset, buffer.byteLength);
@@ -1268,7 +1331,8 @@ function handleMessageToDecode({
1268
1331
  message,
1269
1332
  callback,
1270
1333
  type: protobufSchema.type,
1271
- maxSteroDepth: stereoDepthMaxValue
1334
+ maxSteroDepth: stereoDepthMaxValue,
1335
+ onError: handleDecodingError
1272
1336
  }).catch(handleDecodingError);
1273
1337
  } catch (error) {
1274
1338
  handleDecodingError(error);
@@ -1283,14 +1347,13 @@ async function deserializeDepthAiMessage(args) {
1283
1347
  message,
1284
1348
  callback,
1285
1349
  topic,
1286
- maxSteroDepth
1350
+ maxSteroDepth,
1351
+ onError
1287
1352
  } = args;
1288
1353
  switch (type) {
1289
1354
  case "encodedFrame":
1290
1355
  {
1291
- if (!isCapableOfEncodedStream()) {
1292
- throw new EncodedStreamNotSupportedError(topic);
1293
- }
1356
+ ensureEncodedStreamSupport(topic);
1294
1357
  topicSizes.set(topic, {
1295
1358
  width: message.width,
1296
1359
  height: message.height
@@ -1300,7 +1363,8 @@ async function deserializeDepthAiMessage(args) {
1300
1363
  topic,
1301
1364
  message,
1302
1365
  topicDecoders,
1303
- callback
1366
+ callback,
1367
+ onError
1304
1368
  });
1305
1369
  } else if (message.profile === Profile.JPEG) {
1306
1370
  await deserializeMJPEGFrame({
@@ -1313,7 +1377,8 @@ async function deserializeDepthAiMessage(args) {
1313
1377
  topic,
1314
1378
  message,
1315
1379
  topicDecoders,
1316
- callback
1380
+ callback,
1381
+ onError
1317
1382
  });
1318
1383
  } else ;
1319
1384
  break;
@@ -1332,11 +1397,13 @@ async function deserializeDepthAiMessage(args) {
1332
1397
  switch (messageType) {
1333
1398
  case Type.BITSTREAM:
1334
1399
  {
1400
+ ensureEncodedStreamSupport(topic);
1335
1401
  await deserializeEncodedFrameH264({
1336
1402
  topic,
1337
1403
  message,
1338
1404
  topicDecoders,
1339
- callback
1405
+ callback,
1406
+ onError
1340
1407
  });
1341
1408
  break;
1342
1409
  }
@@ -1428,7 +1495,7 @@ async function deserializeDepthAiMessage(args) {
1428
1495
  default:
1429
1496
  {
1430
1497
  logger.warn(`Message decoding failed: unsupported type "${type}"`);
1431
- break;
1498
+ throw new UnsupportedTopicError(topic, `Unsupported message type "${type}"`);
1432
1499
  }
1433
1500
  }
1434
1501
  }