@luxonis/visualizer-protobuf 3.1.12 → 3.1.14

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 (68) hide show
  1. package/dist/{FoxgloveServer-Da9kV1cr.js → FoxgloveServer-CpnCBMeV.js} +1 -1
  2. package/dist/{communicator-Dh2aL-rj.js → communicator-DO6hmBxI.js} +1 -1
  3. package/dist/{depth-DiD1V2Sg.js → depth-Me_0Xnx6.js} +89 -2
  4. package/dist/{deserialization.worker-CxHfbNSI.js → deserialization.worker-CUrCdjHf.js} +435 -154
  5. package/dist/{foxglove-protocol-BtLMVx24.js → foxglove-protocol-SrBOBs-8.js} +1 -1
  6. package/dist/{index-B5oN0fQm.js → index-5ZSfZI8d.js} +1 -1
  7. package/dist/{index-yO9F9DL5.js → index-B8aafdRQ.js} +5 -5
  8. package/dist/{index-gafqmUmi.js → index-BMew9qiQ.js} +57 -126
  9. package/dist/{index-BydKxany.js → index-BsIRFSYD.js} +36 -9
  10. package/dist/{index-B8JZ9tAh.js → index-CIhAU5Cs.js} +5 -5
  11. package/dist/{index-DuP_Wg3E.js → index-CN6tI-uI.js} +5 -5
  12. package/dist/{index-BFAcwVLJ.js → index-CQtXiN8I.js} +5 -5
  13. package/dist/{index-C-n27_wk.js → index-CZGEFE1k.js} +5 -5
  14. package/dist/{index-O1aT66OM.js → index-CeRrHeG_.js} +5 -5
  15. package/dist/{index-BtMMMbp8.js → index-CqH6rdRP.js} +5 -5
  16. package/dist/{index-CVrY6MoS.js → index-CrPun-aU.js} +5 -5
  17. package/dist/{index-9Qz76jnn.js → index-Dc3rS1Cf.js} +7 -7
  18. package/dist/{index-RxEWv1Fn.js → index-DgNYLOM9.js} +5 -5
  19. package/dist/{index-8bTMarZg.js → index-DjRF0u25.js} +5 -5
  20. package/dist/{index-CwAmHvi3.js → index-Dmc1065I.js} +5 -5
  21. package/dist/{index-BvC_JYBX.js → index-Dn6pTTdu.js} +5 -5
  22. package/dist/{index-DXdd6C_Q.js → index-N2I7Bhtx.js} +5 -5
  23. package/dist/{index-CQhsew4_.js → index-_Z7btKy-.js} +5 -5
  24. package/dist/{index-D_TjqfY9.js → index-_ggcs841.js} +5 -5
  25. package/dist/{index-oyn_LQK1.js → index-svPKcEP3.js} +5 -5
  26. package/dist/{index-DnaaNoIT.js → index-u1cGSF5c.js} +5 -5
  27. package/dist/index.js +5 -5
  28. package/dist/lib/src/components/PanelToolbar.d.ts.map +1 -1
  29. package/dist/lib/src/components/PanelToolbar.js +2 -2
  30. package/dist/lib/src/components/PanelToolbar.js.map +1 -1
  31. package/dist/lib/src/connection/foxglove-connection.d.ts.map +1 -1
  32. package/dist/lib/src/connection/foxglove-connection.js +12 -2
  33. package/dist/lib/src/connection/foxglove-connection.js.map +1 -1
  34. package/dist/lib/src/messaging/deserialization/pointcloud/pointcloudFromDepth.worker.js +59 -20
  35. package/dist/lib/src/messaging/deserialization/pointcloud/pointcloudFromDepth.worker.js.map +1 -1
  36. package/dist/lib/src/messaging/deserialization/pointcloud/utils.d.ts.map +1 -1
  37. package/dist/lib/src/messaging/deserialization/pointcloud/utils.js.map +1 -1
  38. package/dist/lib/src/messaging/deserialization/video/h264.d.ts +4 -1
  39. package/dist/lib/src/messaging/deserialization/video/h264.d.ts.map +1 -1
  40. package/dist/lib/src/messaging/deserialization/video/h264.js +25 -13
  41. package/dist/lib/src/messaging/deserialization/video/h264.js.map +1 -1
  42. package/dist/lib/src/messaging/deserialization/video/h265.d.ts +3 -0
  43. package/dist/lib/src/messaging/deserialization/video/h265.d.ts.map +1 -1
  44. package/dist/lib/src/messaging/deserialization/video/h265.js +21 -9
  45. package/dist/lib/src/messaging/deserialization/video/h265.js.map +1 -1
  46. package/dist/lib/src/messaging/deserialization/video/rgbd-to-pointcloud.d.ts +5 -5
  47. package/dist/lib/src/messaging/deserialization/video/rgbd-to-pointcloud.d.ts.map +1 -1
  48. package/dist/lib/src/messaging/deserialization/video/rgbd-to-pointcloud.js +362 -91
  49. package/dist/lib/src/messaging/deserialization/video/rgbd-to-pointcloud.js.map +1 -1
  50. package/dist/lib/src/messaging/protobuf.d.ts +2 -2
  51. package/dist/lib/src/messaging/protobuf.d.ts.map +1 -1
  52. package/dist/lib/src/messaging/protobuf.js +3 -3
  53. package/dist/lib/src/messaging/protobuf.js.map +1 -1
  54. package/dist/lib/src/utils/poitcloud-sync.d.ts +7 -2
  55. package/dist/lib/src/utils/poitcloud-sync.d.ts.map +1 -1
  56. package/dist/lib/src/utils/poitcloud-sync.js +10 -6
  57. package/dist/lib/src/utils/poitcloud-sync.js.map +1 -1
  58. package/dist/packages/studio-base/src/panels/ThreeDeeRender/Renderer.d.ts.map +1 -1
  59. package/dist/packages/studio-base/src/panels/ThreeDeeRender/Renderer.js +7 -2
  60. package/dist/packages/studio-base/src/panels/ThreeDeeRender/Renderer.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 +33 -1
  63. package/dist/packages/studio-base/src/panels/ThreeDeeRender/ThreeDeeRender.js.map +1 -1
  64. package/dist/{pointcloudFromDepth.worker-60RA4Ief.js → pointcloudFromDepth.worker-wzSOsJVb.js} +86 -47
  65. package/dist/{protobuf-OcbVtxg1.js → protobuf-CKMA2Rn8.js} +214 -214
  66. package/dist/{worker-C2MHIq3t.js → worker-Bhe7uYcO.js} +4 -4
  67. package/dist/{worker-Be-hru8f.js → worker-VIU0v1ZW.js} +3 -3
  68. package/package.json +1 -1
@@ -1,8 +1,8 @@
1
1
  'use client';
2
- import { b as _objectSpread2, P as PointsAnnotationType, T as Type, h as Profile, p as protobufsBySchema } from './protobuf-OcbVtxg1.js';
3
- import { w as wrap, e as expose } from './comlink-jf8bdrAf.js';
4
- import { t as typescript } from './index-B5oN0fQm.js';
5
- import { U as parseMessage, e as estimateObjectSize, V as fromMillis, W as DecoderRuntimeError, d as dist, X as deserializeDepthFrame, Y as UnsupportedTopicError, Z as NotInSecureContextError, _ as EncodedStreamNotSupportedError } from './depth-DiD1V2Sg.js';
2
+ import { b as _objectSpread2, P as PointsAnnotationType, T as Type, h as Profile, p as protobufsBySchema } from './protobuf-CKMA2Rn8.js';
3
+ import { w as wrap, r as releaseProxy, e as expose } from './comlink-jf8bdrAf.js';
4
+ import { t as typescript } from './index-5ZSfZI8d.js';
5
+ import { Z as parseMessage, e as estimateObjectSize, _ as fromMillis, $ as DecoderRuntimeError, d as dist, a0 as deserializeDepthFrame, f as globalRenderMetricsManager, c as constructKeyForTopicRenderMetrics, g as globalInputEventMetricsManager, a as globalDecodeMetricsManager, a1 as UnsupportedTopicError, a2 as NotInSecureContextError, a3 as EncodedStreamNotSupportedError } from './depth-Me_0Xnx6.js';
6
6
  import { L as Logger } from './logger-Bqy1nuLj.js';
7
7
  import { i as isCapableOfEncodedStream } from './encoding-jXImCIb4.js';
8
8
  import { u as uint8ArrayToUint16Array } from './utils-DmlHZWuo.js';
@@ -822,6 +822,7 @@ function closeTopicDecoder$1(topic, topicDecoders) {
822
822
  closeDecoder$1(decoderInfo === null || decoderInfo === void 0 ? void 0 : decoderInfo.decoder);
823
823
  decoderInfo === null || decoderInfo === void 0 || decoderInfo.timing.clear();
824
824
  decoderInfo === null || decoderInfo === void 0 || decoderInfo.transformations.clear();
825
+ decoderInfo === null || decoderInfo === void 0 || decoderInfo.pendingCallbacks.clear();
825
826
  }
826
827
  function isIgnorableInitialDecodeError(error) {
827
828
  const message = error instanceof Error ? error.message : String(error);
@@ -932,7 +933,7 @@ function repackI420(source, width, height, yLayout, uLayout, vLayout, cropLeft =
932
933
  }
933
934
  return out;
934
935
  }
935
- async function copyVideoFrameToI420(frame, logPrefix) {
936
+ async function copyVideoFrameToI420(frame, _logPrefix) {
936
937
  var _visibleRect$width, _visibleRect$height, _visibleRect$x, _visibleRect$y;
937
938
  const visibleRect = frame.visibleRect;
938
939
  const frameWidth = (_visibleRect$width = visibleRect === null || visibleRect === void 0 ? void 0 : visibleRect.width) !== null && _visibleRect$width !== void 0 ? _visibleRect$width : frame.codedWidth;
@@ -940,7 +941,6 @@ async function copyVideoFrameToI420(frame, logPrefix) {
940
941
  const cropLeft = (_visibleRect$x = visibleRect === null || visibleRect === void 0 ? void 0 : visibleRect.x) !== null && _visibleRect$x !== void 0 ? _visibleRect$x : 0;
941
942
  const cropTop = (_visibleRect$y = visibleRect === null || visibleRect === void 0 ? void 0 : visibleRect.y) !== null && _visibleRect$y !== void 0 ? _visibleRect$y : 0;
942
943
  let finalBuffer = new Uint8Array(frame.allocationSize());
943
- logger$2.warn(`${logPrefix} decoder output format: ${frame.format}, coded=${frame.codedWidth}x${frame.codedHeight}, display=${frame.displayWidth}x${frame.displayHeight}, visible=${frameWidth}x${frameHeight}@${cropLeft},${cropTop}`);
944
944
  switch (frame.format) {
945
945
  case "I420":
946
946
  {
@@ -967,13 +967,9 @@ async function copyVideoFrameToI420(frame, logPrefix) {
967
967
  var _layout$stride;
968
968
  const packedBuffer = new Uint8Array(frame.allocationSize());
969
969
  const [layout] = await frame.copyTo(packedBuffer);
970
- logger$2.warn(`${logPrefix} decoder received ${frame.format} frame.`);
971
970
  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);
972
971
  break;
973
972
  }
974
- default:
975
- logger$2.warn(`${logPrefix} decoder received unexpected frame format:`, frame.format);
976
- break;
977
973
  }
978
974
  return {
979
975
  data: finalBuffer,
@@ -983,23 +979,25 @@ async function copyVideoFrameToI420(frame, logPrefix) {
983
979
  }
984
980
  function createVideoDecoder$1({
985
981
  topic,
986
- callback,
987
- topicDecoders,
988
- onError
982
+ topicDecoders
989
983
  }) {
990
984
  let hasProducedFrame = false;
991
985
  return new VideoDecoder({
992
986
  output: async frame => {
993
- var _topicDecoders$get$ti, _topicDecoders$get, _topicDecoders$get2, _topicDecoders$get3;
987
+ var _decoderInfo$timing$g, _decoderInfo$pendingC;
994
988
  hasProducedFrame = true;
995
989
  const {
996
990
  data: finalBuffer,
997
991
  width: frameWidth,
998
992
  height: frameHeight
999
- } = await copyVideoFrameToI420(frame, "H264");
1000
- 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);
1001
- const transformation = (_topicDecoders$get2 = topicDecoders.get(topic)) === null || _topicDecoders$get2 === void 0 ? void 0 : _topicDecoders$get2.transformations.get(frame.timestamp);
1002
- (_topicDecoders$get3 = topicDecoders.get(topic)) === null || _topicDecoders$get3 === void 0 || _topicDecoders$get3.transformations.delete(frame.timestamp);
993
+ } = await copyVideoFrameToI420(frame);
994
+ const decoderInfo = topicDecoders.get(topic);
995
+ const receiveTime = (_decoderInfo$timing$g = decoderInfo === null || decoderInfo === void 0 ? void 0 : decoderInfo.timing.get(frame.timestamp)) !== null && _decoderInfo$timing$g !== void 0 ? _decoderInfo$timing$g : dist.fromMicros(frame.timestamp);
996
+ const transformation = decoderInfo === null || decoderInfo === void 0 ? void 0 : decoderInfo.transformations.get(frame.timestamp);
997
+ const callback = (_decoderInfo$pendingC = decoderInfo === null || decoderInfo === void 0 ? void 0 : decoderInfo.pendingCallbacks.get(frame.timestamp)) !== null && _decoderInfo$pendingC !== void 0 ? _decoderInfo$pendingC : decoderInfo === null || decoderInfo === void 0 ? void 0 : decoderInfo.callback;
998
+ decoderInfo === null || decoderInfo === void 0 || decoderInfo.timing.delete(frame.timestamp);
999
+ decoderInfo === null || decoderInfo === void 0 || decoderInfo.transformations.delete(frame.timestamp);
1000
+ decoderInfo === null || decoderInfo === void 0 || decoderInfo.pendingCallbacks.delete(frame.timestamp);
1003
1001
  const foxgloveMessage = {
1004
1002
  timestamp: receiveTime,
1005
1003
  frame_id: `h264-${topic}-frame`,
@@ -1009,7 +1007,7 @@ function createVideoDecoder$1({
1009
1007
  encoding: "yuv420p",
1010
1008
  step: frameWidth
1011
1009
  };
1012
- callback({
1010
+ callback === null || callback === void 0 || callback({
1013
1011
  topic,
1014
1012
  receiveTime,
1015
1013
  message: foxgloveMessage,
@@ -1020,6 +1018,7 @@ function createVideoDecoder$1({
1020
1018
  frame.close();
1021
1019
  },
1022
1020
  error: error => {
1021
+ var _topicDecoders$get;
1023
1022
  if (!hasProducedFrame && isIgnorableInitialDecodeError(error)) {
1024
1023
  logger$2.warn(`Ignoring initial H264 decoder error for topic ${topic}: ${error.message}`);
1025
1024
  closeTopicDecoder$1(topic, topicDecoders);
@@ -1027,7 +1026,7 @@ function createVideoDecoder$1({
1027
1026
  }
1028
1027
  logger$2.error(error);
1029
1028
  closeTopicDecoder$1(topic, topicDecoders);
1030
- onError(new DecoderRuntimeError(topic, error.message));
1029
+ (_topicDecoders$get = topicDecoders.get(topic)) === null || _topicDecoders$get === void 0 || _topicDecoders$get.onError(new DecoderRuntimeError(topic, error.message));
1031
1030
  }
1032
1031
  });
1033
1032
  }
@@ -1049,9 +1048,7 @@ async function deserializeEncodedFrameH264({
1049
1048
  if (!existingDecoderInfo || existingDecoderInfo.decoder.state === "closed") {
1050
1049
  const decoder = createVideoDecoder$1({
1051
1050
  topic,
1052
- callback,
1053
- topicDecoders,
1054
- onError
1051
+ topicDecoders
1055
1052
  });
1056
1053
  try {
1057
1054
  configureDecoder(decoder);
@@ -1064,11 +1061,17 @@ async function deserializeEncodedFrameH264({
1064
1061
  existingDecoderInfo.decoder = decoder;
1065
1062
  existingDecoderInfo.timing.clear();
1066
1063
  existingDecoderInfo.transformations.clear();
1064
+ existingDecoderInfo.pendingCallbacks.clear();
1065
+ existingDecoderInfo.callback = callback;
1066
+ existingDecoderInfo.onError = onError;
1067
1067
  } else {
1068
1068
  topicDecoders.set(topic, {
1069
1069
  decoder,
1070
1070
  timing: new Map(),
1071
- transformations: new Map()
1071
+ transformations: new Map(),
1072
+ pendingCallbacks: new Map(),
1073
+ callback,
1074
+ onError
1072
1075
  });
1073
1076
  }
1074
1077
  } else if (existingDecoderInfo.decoder.state === "unconfigured") {
@@ -1076,6 +1079,9 @@ async function deserializeEncodedFrameH264({
1076
1079
  configureDecoder(existingDecoderInfo.decoder);
1077
1080
  existingDecoderInfo.timing.clear();
1078
1081
  existingDecoderInfo.transformations.clear();
1082
+ existingDecoderInfo.pendingCallbacks.clear();
1083
+ existingDecoderInfo.callback = callback;
1084
+ existingDecoderInfo.onError = onError;
1079
1085
  } catch (error) {
1080
1086
  closeTopicDecoder$1(topic, topicDecoders);
1081
1087
  onError(new DecoderRuntimeError(topic, error instanceof Error ? error.message : "Failed to reconfigure H.264 decoder."));
@@ -1086,6 +1092,8 @@ async function deserializeEncodedFrameH264({
1086
1092
  if (!decoderInfo) {
1087
1093
  return;
1088
1094
  }
1095
+ decoderInfo.callback = callback;
1096
+ decoderInfo.onError = onError;
1089
1097
  if (decoderInfo.decoder.decodeQueueSize > 60) {
1090
1098
  decoderInfo.decoder.reset();
1091
1099
  decoderInfo.timing.clear();
@@ -1095,6 +1103,7 @@ async function deserializeEncodedFrameH264({
1095
1103
  const microTimestamp = receiveTime.sec * 1000000 + Math.floor(receiveTime.nsec / 1000);
1096
1104
  decoderInfo.timing.set(microTimestamp, receiveTime);
1097
1105
  decoderInfo.transformations.set(microTimestamp, message.transformation);
1106
+ decoderInfo.pendingCallbacks.set(microTimestamp, callback);
1098
1107
  const frame = {
1099
1108
  type: 'key',
1100
1109
  data: message.data,
@@ -1136,24 +1145,27 @@ function closeTopicDecoder(topic, topicDecoders) {
1136
1145
  closeDecoder(decoderInfo === null || decoderInfo === void 0 ? void 0 : decoderInfo.decoder);
1137
1146
  decoderInfo === null || decoderInfo === void 0 || decoderInfo.timing.clear();
1138
1147
  decoderInfo === null || decoderInfo === void 0 || decoderInfo.transformations.clear();
1148
+ decoderInfo === null || decoderInfo === void 0 || decoderInfo.pendingCallbacks.clear();
1139
1149
  }
1140
1150
  function createVideoDecoder({
1141
1151
  topic,
1142
- callback,
1143
- topicDecoders,
1144
- onError
1152
+ topicDecoders
1145
1153
  }) {
1146
1154
  return new VideoDecoder({
1147
1155
  output: async frame => {
1148
- var _topicDecoders$get$ti, _topicDecoders$get, _topicDecoders$get2, _topicDecoders$get3;
1156
+ var _decoderInfo$timing$g, _decoderInfo$pendingC;
1149
1157
  const {
1150
1158
  data: buffer,
1151
1159
  width,
1152
1160
  height
1153
- } = await copyVideoFrameToI420(frame, "H265");
1154
- 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);
1155
- const transformation = (_topicDecoders$get2 = topicDecoders.get(topic)) === null || _topicDecoders$get2 === void 0 ? void 0 : _topicDecoders$get2.transformations.get(frame.timestamp);
1156
- (_topicDecoders$get3 = topicDecoders.get(topic)) === null || _topicDecoders$get3 === void 0 || _topicDecoders$get3.transformations.delete(frame.timestamp);
1161
+ } = await copyVideoFrameToI420(frame);
1162
+ const decoderInfo = topicDecoders.get(topic);
1163
+ const receiveTime = (_decoderInfo$timing$g = decoderInfo === null || decoderInfo === void 0 ? void 0 : decoderInfo.timing.get(frame.timestamp)) !== null && _decoderInfo$timing$g !== void 0 ? _decoderInfo$timing$g : dist.fromMicros(frame.timestamp);
1164
+ const transformation = decoderInfo === null || decoderInfo === void 0 ? void 0 : decoderInfo.transformations.get(frame.timestamp);
1165
+ const callback = (_decoderInfo$pendingC = decoderInfo === null || decoderInfo === void 0 ? void 0 : decoderInfo.pendingCallbacks.get(frame.timestamp)) !== null && _decoderInfo$pendingC !== void 0 ? _decoderInfo$pendingC : decoderInfo === null || decoderInfo === void 0 ? void 0 : decoderInfo.callback;
1166
+ decoderInfo === null || decoderInfo === void 0 || decoderInfo.timing.delete(frame.timestamp);
1167
+ decoderInfo === null || decoderInfo === void 0 || decoderInfo.transformations.delete(frame.timestamp);
1168
+ decoderInfo === null || decoderInfo === void 0 || decoderInfo.pendingCallbacks.delete(frame.timestamp);
1157
1169
  const foxgloveMessage = {
1158
1170
  timestamp: receiveTime,
1159
1171
  frame_id: `h265-${topic}-frame`,
@@ -1163,7 +1175,7 @@ function createVideoDecoder({
1163
1175
  encoding: "yuv420p",
1164
1176
  step: width
1165
1177
  };
1166
- callback({
1178
+ callback === null || callback === void 0 || callback({
1167
1179
  topic,
1168
1180
  receiveTime,
1169
1181
  message: foxgloveMessage,
@@ -1174,9 +1186,10 @@ function createVideoDecoder({
1174
1186
  frame.close();
1175
1187
  },
1176
1188
  error: error => {
1189
+ var _topicDecoders$get;
1177
1190
  logger$1.error(error);
1178
1191
  closeTopicDecoder(topic, topicDecoders);
1179
- onError(new DecoderRuntimeError(topic, error.message));
1192
+ (_topicDecoders$get = topicDecoders.get(topic)) === null || _topicDecoders$get === void 0 || _topicDecoders$get.onError(new DecoderRuntimeError(topic, error.message));
1180
1193
  }
1181
1194
  });
1182
1195
  }
@@ -1198,9 +1211,7 @@ async function deserializeEncodedFrameH265({
1198
1211
  if (!existingDecoderInfo || existingDecoderInfo.decoder.state === "closed") {
1199
1212
  const decoder = createVideoDecoder({
1200
1213
  topic,
1201
- callback,
1202
- topicDecoders,
1203
- onError
1214
+ topicDecoders
1204
1215
  });
1205
1216
  try {
1206
1217
  decoder.configure({
@@ -1216,11 +1227,17 @@ async function deserializeEncodedFrameH265({
1216
1227
  existingDecoderInfo.decoder = decoder;
1217
1228
  existingDecoderInfo.timing.clear();
1218
1229
  existingDecoderInfo.transformations.clear();
1230
+ existingDecoderInfo.pendingCallbacks.clear();
1231
+ existingDecoderInfo.callback = callback;
1232
+ existingDecoderInfo.onError = onError;
1219
1233
  } else {
1220
1234
  topicDecoders.set(topic, {
1221
1235
  decoder,
1222
1236
  timing: new Map(),
1223
- transformations: new Map()
1237
+ transformations: new Map(),
1238
+ pendingCallbacks: new Map(),
1239
+ callback,
1240
+ onError
1224
1241
  });
1225
1242
  }
1226
1243
  }
@@ -1228,6 +1245,8 @@ async function deserializeEncodedFrameH265({
1228
1245
  if (!decoderInfo) {
1229
1246
  return;
1230
1247
  }
1248
+ decoderInfo.callback = callback;
1249
+ decoderInfo.onError = onError;
1231
1250
  if (decoderInfo.decoder.decodeQueueSize > 60) {
1232
1251
  decoderInfo.decoder.reset();
1233
1252
  return;
@@ -1235,6 +1254,7 @@ async function deserializeEncodedFrameH265({
1235
1254
  const microTimestamp = receiveTime.sec * 1000000 + Math.floor(receiveTime.nsec / 1000);
1236
1255
  decoderInfo.timing.set(microTimestamp, receiveTime);
1237
1256
  decoderInfo.transformations.set(microTimestamp, message.transformation);
1257
+ decoderInfo.pendingCallbacks.set(microTimestamp, callback);
1238
1258
  const frame = {
1239
1259
  type: 'key',
1240
1260
  data: message.data,
@@ -1276,7 +1296,7 @@ async function deserializeMJPEGFrame({
1276
1296
  data: buffer,
1277
1297
  width,
1278
1298
  height
1279
- } = await copyVideoFrameToI420(frame, "MJPEG");
1299
+ } = await copyVideoFrameToI420(frame);
1280
1300
  const foxgloveMessage = {
1281
1301
  timestamp: receiveTime,
1282
1302
  frame_id: "camera",
@@ -1297,12 +1317,19 @@ async function deserializeMJPEGFrame({
1297
1317
  });
1298
1318
  }
1299
1319
 
1300
- const RGBD_POINTCLOUD_WORKER_COUNT = 4;
1320
+ const RGBD_POINTCLOUD_WORKER_COUNT = 6;
1321
+ const RGBD_POINTCLOUD_WORKER_TIMEOUT_MS = 15000;
1322
+ const RGBD_POINTCLOUD_SCHEDULE_DELAY_MS = 0;
1323
+ const RGBD_GPU_BATCH_SIZE = 2;
1324
+ const RGBD_GPU_BATCH_FLUSH_DELAY_MS = 8;
1325
+ const RGBD_POINTCLOUD_IDLE_CLEANUP_MS = 30000;
1301
1326
  let cachedRGBDHasGPU;
1302
1327
  let rgbdHasGPUPromise;
1303
1328
  let rgbdPointCloudWorkers;
1304
1329
  let rgbdPointCloudWorkerIndex = 0;
1305
- Logger.getLogger();
1330
+ let rgbdPointCloudIdleCleanupTimeoutId;
1331
+ const rgbdIntrinsicsByTopic = new Map();
1332
+ const pendingRGBDBatches = new Map();
1306
1333
  function ensureEvenByteLength(data) {
1307
1334
  if (data.length % 2 === 0) {
1308
1335
  return data;
@@ -1311,12 +1338,9 @@ function ensureEvenByteLength(data) {
1311
1338
  padded.set(data);
1312
1339
  return padded;
1313
1340
  }
1314
- async function detectRGBDGPUSupport() {
1315
- if (cachedRGBDHasGPU != undefined) {
1316
- return cachedRGBDHasGPU;
1317
- }
1318
- if (rgbdHasGPUPromise) {
1319
- return await rgbdHasGPUPromise;
1341
+ function ensureRGBDGPUSupportDetection() {
1342
+ if (cachedRGBDHasGPU != undefined || rgbdHasGPUPromise) {
1343
+ return;
1320
1344
  }
1321
1345
  rgbdHasGPUPromise = (async () => {
1322
1346
  if (typeof navigator.gpu === "undefined") {
@@ -1327,53 +1351,116 @@ async function detectRGBDGPUSupport() {
1327
1351
  const adapter = await navigator.gpu.requestAdapter();
1328
1352
  cachedRGBDHasGPU = adapter != undefined;
1329
1353
  return cachedRGBDHasGPU;
1330
- } catch (_unused) {
1354
+ } catch (error) {
1331
1355
  cachedRGBDHasGPU = false;
1332
1356
  return false;
1333
1357
  } finally {
1334
1358
  rgbdHasGPUPromise = undefined;
1335
1359
  }
1336
1360
  })();
1337
- return await rgbdHasGPUPromise;
1338
1361
  }
1339
- function getRGBDPointCloudWorkerSlot() {
1362
+ function getRGBDGPUSupport() {
1363
+ ensureRGBDGPUSupportDetection();
1364
+ return cachedRGBDHasGPU !== null && cachedRGBDHasGPU !== void 0 ? cachedRGBDHasGPU : false;
1365
+ }
1366
+ function ensureRGBDPointCloudWorkers() {
1340
1367
  if (!rgbdPointCloudWorkers) {
1341
1368
  rgbdPointCloudWorkers = Array.from({
1342
1369
  length: RGBD_POINTCLOUD_WORKER_COUNT
1343
1370
  }, () => {
1344
- const worker = new Worker(new URL("pointcloudFromDepth.worker-60RA4Ief.js", import.meta.url), {
1345
- type: "module"
1346
- });
1347
- return {
1348
- worker,
1349
- remote: wrap(worker),
1350
- activeJobs: 0
1351
- };
1371
+ return createRGBDPointCloudWorkerSlot();
1352
1372
  });
1353
1373
  }
1354
- const slots = rgbdPointCloudWorkers;
1355
- const candidateSlots = slots.map((slot, index) => ({
1356
- slot,
1357
- index
1358
- })).sort((left, right) => {
1359
- if (left.slot.activeJobs !== right.slot.activeJobs) {
1360
- return left.slot.activeJobs - right.slot.activeJobs;
1361
- }
1362
- const leftDistance = (left.index - rgbdPointCloudWorkerIndex + slots.length) % slots.length;
1363
- const rightDistance = (right.index - rgbdPointCloudWorkerIndex + slots.length) % slots.length;
1364
- return leftDistance - rightDistance;
1374
+ return rgbdPointCloudWorkers;
1375
+ }
1376
+ function createRGBDPointCloudWorkerSlot() {
1377
+ const worker = new Worker(new URL("pointcloudFromDepth.worker-wzSOsJVb.js", import.meta.url), {
1378
+ type: "module"
1365
1379
  });
1366
- const selected = candidateSlots[0];
1367
- rgbdPointCloudWorkerIndex = (selected.index + 1) % slots.length;
1368
- return selected.slot;
1380
+ const remote = wrap(worker);
1381
+ return {
1382
+ worker,
1383
+ remote,
1384
+ activeJobs: 0,
1385
+ dispose: () => {
1386
+ remote[releaseProxy]();
1387
+ worker.terminate();
1388
+ }
1389
+ };
1390
+ }
1391
+ function clearRGBDPointCloudIdleCleanupTimeout() {
1392
+ if (rgbdPointCloudIdleCleanupTimeoutId != undefined) {
1393
+ clearTimeout(rgbdPointCloudIdleCleanupTimeoutId);
1394
+ rgbdPointCloudIdleCleanupTimeoutId = undefined;
1395
+ }
1396
+ }
1397
+ function hasActiveRGBDPointCloudWork() {
1398
+ var _rgbdPointCloudWorker, _rgbdPointCloudWorker2;
1399
+ const hasActiveJobs = (_rgbdPointCloudWorker = (_rgbdPointCloudWorker2 = rgbdPointCloudWorkers) === null || _rgbdPointCloudWorker2 === void 0 ? void 0 : _rgbdPointCloudWorker2.some(slot => slot.activeJobs > 0)) !== null && _rgbdPointCloudWorker !== void 0 ? _rgbdPointCloudWorker : false;
1400
+ return hasActiveJobs || pendingRGBDBatches.size > 0;
1401
+ }
1402
+ function disposeRGBDPointCloudWorkers() {
1403
+ clearRGBDPointCloudIdleCleanupTimeout();
1404
+ for (const batch of pendingRGBDBatches.values()) {
1405
+ clearRGBDBatchFlush(batch);
1406
+ }
1407
+ pendingRGBDBatches.clear();
1408
+ rgbdIntrinsicsByTopic.clear();
1409
+ if (rgbdPointCloudWorkers) {
1410
+ for (const slot of rgbdPointCloudWorkers) {
1411
+ slot.dispose();
1412
+ }
1413
+ rgbdPointCloudWorkers = undefined;
1414
+ }
1415
+ rgbdPointCloudWorkerIndex = 0;
1416
+ }
1417
+ function scheduleRGBDPointCloudWorkersCleanup() {
1418
+ clearRGBDPointCloudIdleCleanupTimeout();
1419
+ rgbdPointCloudIdleCleanupTimeoutId = setTimeout(() => {
1420
+ if (hasActiveRGBDPointCloudWork()) {
1421
+ scheduleRGBDPointCloudWorkersCleanup();
1422
+ return;
1423
+ }
1424
+ disposeRGBDPointCloudWorkers();
1425
+ }, RGBD_POINTCLOUD_IDLE_CLEANUP_MS);
1426
+ }
1427
+ function markRGBDPointCloudWorkersActive() {
1428
+ scheduleRGBDPointCloudWorkersCleanup();
1429
+ }
1430
+ function replaceRGBDPointCloudWorker(index) {
1431
+ const slots = ensureRGBDPointCloudWorkers();
1432
+ const currentSlot = slots[index];
1433
+ currentSlot === null || currentSlot === void 0 || currentSlot.dispose();
1434
+ const replacementSlot = createRGBDPointCloudWorkerSlot();
1435
+ slots[index] = replacementSlot;
1436
+ markRGBDPointCloudWorkersActive();
1437
+ return replacementSlot;
1438
+ }
1439
+ function tryAcquireRGBDPointCloudWorkerSlot() {
1440
+ const ensuredSlots = ensureRGBDPointCloudWorkers();
1441
+ markRGBDPointCloudWorkersActive();
1442
+ for (let offset = 0; offset < ensuredSlots.length; offset++) {
1443
+ const index = (rgbdPointCloudWorkerIndex + offset) % ensuredSlots.length;
1444
+ const slot = ensuredSlots[index];
1445
+ if (!slot || slot.activeJobs > 0) {
1446
+ continue;
1447
+ }
1448
+ slot.activeJobs = 1;
1449
+ rgbdPointCloudWorkerIndex = (index + 1) % ensuredSlots.length;
1450
+ return {
1451
+ slot,
1452
+ index
1453
+ };
1454
+ }
1455
+ return undefined;
1369
1456
  }
1370
1457
  function repackYuv420pToI420(imageFrame, width, height) {
1371
1458
  var _imageFrame$fb;
1372
1459
  const specs = (_imageFrame$fb = imageFrame.fb) !== null && _imageFrame$fb !== void 0 ? _imageFrame$fb : imageFrame.sourceFb;
1373
1460
  const source = ensureEvenByteLength(imageFrame.data);
1374
1461
  const yStride = (specs === null || specs === void 0 ? void 0 : specs.stride) || width;
1375
- const uvWidth = Math.floor(width / 2);
1376
- const uvHeight = Math.floor(height / 2);
1462
+ const uvWidth = Math.ceil(width / 2);
1463
+ const uvHeight = Math.ceil(height / 2);
1377
1464
  const uvStride = yStride > width ? Math.floor(yStride / 2) : uvWidth;
1378
1465
  const yPlaneSize = width * height;
1379
1466
  const uvPlaneSize = uvWidth * uvHeight;
@@ -1445,9 +1532,21 @@ function extractIntrinsicsFromTransformation(transformation) {
1445
1532
  }
1446
1533
  };
1447
1534
  }
1448
- function resolveRGBDIntrinsics(message, fallbackIntrinsics) {
1449
- var _ref, _ref2, _ref3, _extractIntrinsicsFro, _message$depthImgFram, _message$depthEncoded, _message$colorImgFram, _message$colorEncoded;
1450
- return (_ref = (_ref2 = (_ref3 = (_extractIntrinsicsFro = extractIntrinsicsFromTransformation((_message$depthImgFram = message.depthImgFrame) === null || _message$depthImgFram === void 0 ? void 0 : _message$depthImgFram.transformation)) !== null && _extractIntrinsicsFro !== void 0 ? _extractIntrinsicsFro : extractIntrinsicsFromTransformation((_message$depthEncoded = message.depthEncodedFrame) === null || _message$depthEncoded === void 0 ? void 0 : _message$depthEncoded.transformation)) !== null && _ref3 !== void 0 ? _ref3 : extractIntrinsicsFromTransformation((_message$colorImgFram = message.colorImgFrame) === null || _message$colorImgFram === void 0 ? void 0 : _message$colorImgFram.transformation)) !== null && _ref2 !== void 0 ? _ref2 : extractIntrinsicsFromTransformation((_message$colorEncoded = message.colorEncodedFrame) === null || _message$colorEncoded === void 0 ? void 0 : _message$colorEncoded.transformation)) !== null && _ref !== void 0 ? _ref : fallbackIntrinsics;
1535
+ function resolveRGBDIntrinsicsFromMessage(message) {
1536
+ var _ref, _ref2, _extractIntrinsicsFro, _message$depthImgFram, _message$depthEncoded, _message$colorImgFram, _message$colorEncoded;
1537
+ return (_ref = (_ref2 = (_extractIntrinsicsFro = extractIntrinsicsFromTransformation((_message$depthImgFram = message.depthImgFrame) === null || _message$depthImgFram === void 0 ? void 0 : _message$depthImgFram.transformation)) !== null && _extractIntrinsicsFro !== void 0 ? _extractIntrinsicsFro : extractIntrinsicsFromTransformation((_message$depthEncoded = message.depthEncodedFrame) === null || _message$depthEncoded === void 0 ? void 0 : _message$depthEncoded.transformation)) !== null && _ref2 !== void 0 ? _ref2 : extractIntrinsicsFromTransformation((_message$colorImgFram = message.colorImgFrame) === null || _message$colorImgFram === void 0 ? void 0 : _message$colorImgFram.transformation)) !== null && _ref !== void 0 ? _ref : extractIntrinsicsFromTransformation((_message$colorEncoded = message.colorEncodedFrame) === null || _message$colorEncoded === void 0 ? void 0 : _message$colorEncoded.transformation);
1538
+ }
1539
+ function getRGBDIntrinsics(topic, message, fallbackIntrinsics) {
1540
+ const cachedIntrinsics = rgbdIntrinsicsByTopic.get(topic);
1541
+ if (cachedIntrinsics) {
1542
+ return cachedIntrinsics;
1543
+ }
1544
+ const resolvedIntrinsics = resolveRGBDIntrinsicsFromMessage(message);
1545
+ if (resolvedIntrinsics) {
1546
+ rgbdIntrinsicsByTopic.set(topic, resolvedIntrinsics);
1547
+ return resolvedIntrinsics;
1548
+ }
1549
+ return fallbackIntrinsics;
1451
1550
  }
1452
1551
  async function extractEncodedColorFrame(encodedFrame, topicDecoders, topic) {
1453
1552
  const decodeFrame = async () => await new Promise((resolve, reject) => {
@@ -1557,16 +1656,252 @@ function parseDimensions(message) {
1557
1656
  }
1558
1657
  return obj;
1559
1658
  }
1659
+ function emitRGBDDepthPreview(topic, message, maxStereoDepth, callback, onError) {
1660
+ if (!message.depthImgFrame) {
1661
+ return;
1662
+ }
1663
+ const depthFrameForPreview = _objectSpread2(_objectSpread2({}, message.depthImgFrame), {}, {
1664
+ data: message.depthImgFrame.data.slice()
1665
+ });
1666
+ void deserializeDepthFrame({
1667
+ topic,
1668
+ message: depthFrameForPreview,
1669
+ callback,
1670
+ maxStereoDepth: maxStereoDepth / 1000
1671
+ }).catch(onError);
1672
+ }
1673
+ function emitRGBDPointCloud(frame, pointCloudData) {
1674
+ var _frame$timestamp;
1675
+ const foxgloveMessage = {
1676
+ timestamp: (_frame$timestamp = frame.timestamp) !== null && _frame$timestamp !== void 0 ? _frame$timestamp : frame.receiveTime,
1677
+ frame_id: `pointcloud-${frame.topic}-frame`,
1678
+ point_stride: 16,
1679
+ pose: {
1680
+ position: {
1681
+ x: 0,
1682
+ y: 0,
1683
+ z: 0
1684
+ },
1685
+ orientation: {
1686
+ x: 0,
1687
+ y: 0,
1688
+ z: 1,
1689
+ w: 0
1690
+ }
1691
+ },
1692
+ width: frame.depthWidth,
1693
+ height: frame.depthHeight,
1694
+ fields: [{
1695
+ name: "x",
1696
+ offset: 0,
1697
+ type: typescript.NumericType.FLOAT32
1698
+ }, {
1699
+ name: "y",
1700
+ offset: 4,
1701
+ type: typescript.NumericType.FLOAT32
1702
+ }, {
1703
+ name: "z",
1704
+ offset: 8,
1705
+ type: typescript.NumericType.FLOAT32
1706
+ }, {
1707
+ name: "red",
1708
+ offset: 12,
1709
+ type: typescript.NumericType.UINT8
1710
+ }, {
1711
+ name: "green",
1712
+ offset: 13,
1713
+ type: typescript.NumericType.UINT8
1714
+ }, {
1715
+ name: "blue",
1716
+ offset: 14,
1717
+ type: typescript.NumericType.UINT8
1718
+ }, {
1719
+ name: "alpha",
1720
+ offset: 15,
1721
+ type: typescript.NumericType.UINT8
1722
+ }],
1723
+ data: pointCloudData
1724
+ };
1725
+ frame.callback({
1726
+ topic: frame.topic,
1727
+ receiveTime: frame.receiveTime,
1728
+ message: foxgloveMessage,
1729
+ sizeInBytes: estimateObjectSize(foxgloveMessage),
1730
+ schemaName: "foxglove.PointCloud.Colored"
1731
+ });
1732
+ }
1733
+ function getRGBDBatchSignature(frame) {
1734
+ const intrinsics = frame.rgbdIntrinsics.right;
1735
+ return [frame.depthWidth, frame.depthHeight, frame.colorFrame.width, frame.colorFrame.height, intrinsics.focalLenght.x, intrinsics.focalLenght.y, intrinsics.principalPoint.x, intrinsics.principalPoint.y, frame.maxStereoDepth, frame.hasGPU].join(":");
1736
+ }
1737
+ function clearRGBDBatchFlush(batch) {
1738
+ if (batch.flushTimeoutId != undefined) {
1739
+ clearTimeout(batch.flushTimeoutId);
1740
+ batch.flushTimeoutId = undefined;
1741
+ }
1742
+ }
1743
+ async function processRGBDPointCloudBatchOnWorker(workerSlot, workerIndex, frames) {
1744
+ const firstFrame = frames[0];
1745
+ if (!firstFrame) {
1746
+ workerSlot.activeJobs = Math.max(0, workerSlot.activeJobs - 1);
1747
+ return;
1748
+ }
1749
+ const intrinsics = firstFrame.rgbdIntrinsics.right;
1750
+ let timeoutId;
1751
+ try {
1752
+ const pointClouds = await Promise.race([workerSlot.remote.depthToPointcloudGPU(frames.map(frame => frame.depthFrame), firstFrame.depthWidth, firstFrame.depthHeight, intrinsics.focalLenght.x, intrinsics.focalLenght.y, intrinsics.principalPoint.x, intrinsics.principalPoint.y, frames.map(frame => frame.colorFrame.data), firstFrame.colorFrame.width, firstFrame.colorFrame.height, firstFrame.maxStereoDepth, {
1753
+ hasGPU: firstFrame.hasGPU
1754
+ }), new Promise((_, reject) => {
1755
+ timeoutId = setTimeout(() => {
1756
+ reject(new Error(`RGBD pointcloud worker ${workerIndex} timed out after ${RGBD_POINTCLOUD_WORKER_TIMEOUT_MS}ms for topic ${firstFrame.topic} ` + `(batch=${frames.length}, depth=${firstFrame.depthWidth}x${firstFrame.depthHeight}, color=${firstFrame.colorFrame.width}x${firstFrame.colorFrame.height}, hasGPU=${firstFrame.hasGPU})`));
1757
+ }, RGBD_POINTCLOUD_WORKER_TIMEOUT_MS);
1758
+ })]);
1759
+ if (timeoutId) {
1760
+ clearTimeout(timeoutId);
1761
+ timeoutId = undefined;
1762
+ }
1763
+ if (pointClouds.length !== frames.length) {
1764
+ throw new Error(`RGBD pointcloud worker returned ${pointClouds.length} frames for batch size ${frames.length}`);
1765
+ }
1766
+ for (let index = 0; index < frames.length; index++) {
1767
+ const frame = frames[index];
1768
+ const pointCloud = pointClouds[index];
1769
+ if (!frame || !pointCloud) {
1770
+ continue;
1771
+ }
1772
+ emitRGBDPointCloud(frame, pointCloud);
1773
+ }
1774
+ } catch (error) {
1775
+ if (timeoutId) {
1776
+ clearTimeout(timeoutId);
1777
+ timeoutId = undefined;
1778
+ }
1779
+ if (error instanceof Error && error.message.includes("timed out")) {
1780
+ replaceRGBDPointCloudWorker(workerIndex);
1781
+ console.error(error);
1782
+ }
1783
+ const normalizedError = error instanceof Error ? error : new Error(String(error));
1784
+ for (const frame of frames) {
1785
+ frame.onError(normalizedError);
1786
+ }
1787
+ } finally {
1788
+ workerSlot.activeJobs = Math.max(0, workerSlot.activeJobs - 1);
1789
+ markRGBDPointCloudWorkersActive();
1790
+ }
1791
+ }
1792
+ async function processRGBDPointCloudOnWorker(workerSlot, workerIndex, frame) {
1793
+ const intrinsics = frame.rgbdIntrinsics.right;
1794
+ let timeoutId;
1795
+ try {
1796
+ const pointClouds = await Promise.race([workerSlot.remote.depthToPointcloudGPU([frame.depthFrame], frame.depthWidth, frame.depthHeight, intrinsics.focalLenght.x, intrinsics.focalLenght.y, intrinsics.principalPoint.x, intrinsics.principalPoint.y, [frame.colorFrame.data], frame.colorFrame.width, frame.colorFrame.height, frame.maxStereoDepth, {
1797
+ hasGPU: frame.hasGPU
1798
+ }), new Promise((_, reject) => {
1799
+ timeoutId = setTimeout(() => {
1800
+ reject(new Error(`RGBD pointcloud worker ${workerIndex} timed out after ${RGBD_POINTCLOUD_WORKER_TIMEOUT_MS}ms for topic ${frame.topic} ` + `(depth=${frame.depthWidth}x${frame.depthHeight}, color=${frame.colorFrame.width}x${frame.colorFrame.height}, hasGPU=${frame.hasGPU})`));
1801
+ }, RGBD_POINTCLOUD_WORKER_TIMEOUT_MS);
1802
+ })]);
1803
+ if (timeoutId) {
1804
+ clearTimeout(timeoutId);
1805
+ timeoutId = undefined;
1806
+ }
1807
+ if (pointClouds.length !== 1 || !pointClouds[0]) {
1808
+ throw new Error(`RGBD pointcloud worker returned ${pointClouds.length} frames for single-frame request`);
1809
+ }
1810
+ emitRGBDPointCloud(frame, pointClouds[0]);
1811
+ } catch (error) {
1812
+ if (timeoutId) {
1813
+ clearTimeout(timeoutId);
1814
+ timeoutId = undefined;
1815
+ }
1816
+ if (error instanceof Error && error.message.includes("timed out")) {
1817
+ replaceRGBDPointCloudWorker(workerIndex);
1818
+ console.error(error);
1819
+ }
1820
+ frame.onError(error instanceof Error ? error : new Error(String(error)));
1821
+ } finally {
1822
+ workerSlot.activeJobs = Math.max(0, workerSlot.activeJobs - 1);
1823
+ markRGBDPointCloudWorkersActive();
1824
+ }
1825
+ }
1826
+ function flushRGBDPointCloudBatch(topic) {
1827
+ const batch = pendingRGBDBatches.get(topic);
1828
+ if (!batch || batch.frames.length === 0) {
1829
+ pendingRGBDBatches.delete(topic);
1830
+ return;
1831
+ }
1832
+ clearRGBDBatchFlush(batch);
1833
+ pendingRGBDBatches.delete(topic);
1834
+ const reservedWorkerSelection = tryAcquireRGBDPointCloudWorkerSlot();
1835
+ if (!reservedWorkerSelection) {
1836
+ console.warn(`[RGBD] Dropping pointcloud frame for topic ${topic}: all RGBD pointcloud workers are busy.`);
1837
+ return;
1838
+ }
1839
+ void processRGBDPointCloudBatchOnWorker(reservedWorkerSelection.slot, reservedWorkerSelection.index, batch.frames);
1840
+ }
1841
+ function enqueueRGBDPointCloudFrame(frame) {
1842
+ var _pendingRGBDBatches$g;
1843
+ if (!frame.hasGPU) {
1844
+ const reservedWorkerSelection = tryAcquireRGBDPointCloudWorkerSlot();
1845
+ if (!reservedWorkerSelection) {
1846
+ console.warn(`[RGBD] Dropping pointcloud frame for topic ${frame.topic}: all RGBD pointcloud workers are busy.`);
1847
+ return;
1848
+ }
1849
+ globalRenderMetricsManager.ensureTopic(constructKeyForTopicRenderMetrics("renderPointCloudFrame", "Point Cloud"));
1850
+ globalInputEventMetricsManager.registerEvent(constructKeyForTopicRenderMetrics("incomingPointCloudFrame", "Point Cloud"));
1851
+ globalDecodeMetricsManager.registerEvent("Point Cloud");
1852
+ void processRGBDPointCloudOnWorker(reservedWorkerSelection.slot, reservedWorkerSelection.index, frame);
1853
+ return;
1854
+ }
1855
+ const existingBatch = pendingRGBDBatches.get(frame.topic);
1856
+ if (existingBatch && existingBatch.frames.length > 0 && getRGBDBatchSignature(existingBatch.frames[0]) !== getRGBDBatchSignature(frame)) {
1857
+ flushRGBDPointCloudBatch(frame.topic);
1858
+ }
1859
+ const batch = (_pendingRGBDBatches$g = pendingRGBDBatches.get(frame.topic)) !== null && _pendingRGBDBatches$g !== void 0 ? _pendingRGBDBatches$g : {
1860
+ frames: []
1861
+ };
1862
+ batch.frames.push(frame);
1863
+ pendingRGBDBatches.set(frame.topic, batch);
1864
+ if (batch.frames.length >= RGBD_GPU_BATCH_SIZE) {
1865
+ flushRGBDPointCloudBatch(frame.topic);
1866
+ return;
1867
+ }
1868
+ clearRGBDBatchFlush(batch);
1869
+ batch.flushTimeoutId = setTimeout(() => {
1870
+ flushRGBDPointCloudBatch(frame.topic);
1871
+ }, RGBD_GPU_BATCH_FLUSH_DELAY_MS);
1872
+ }
1560
1873
  async function deserializeRGBDFrameToPointCloud({
1561
1874
  topic,
1562
1875
  topicDecoders,
1563
1876
  cameraIntrinsics,
1564
1877
  maxStereoDepth,
1565
1878
  message,
1566
- callback
1879
+ callback,
1880
+ onError
1881
+ }) {
1882
+ markRGBDPointCloudWorkersActive();
1883
+ emitRGBDDepthPreview(topic, message, maxStereoDepth, callback, onError);
1884
+ setTimeout(() => {
1885
+ void processScheduledRGBDPointCloud({
1886
+ topic,
1887
+ topicDecoders,
1888
+ cameraIntrinsics,
1889
+ maxStereoDepth,
1890
+ message,
1891
+ callback,
1892
+ onError
1893
+ });
1894
+ }, RGBD_POINTCLOUD_SCHEDULE_DELAY_MS);
1895
+ }
1896
+ async function processScheduledRGBDPointCloud({
1897
+ topic,
1898
+ topicDecoders,
1899
+ cameraIntrinsics,
1900
+ maxStereoDepth,
1901
+ message,
1902
+ callback,
1903
+ onError
1567
1904
  }) {
1568
- const workerSlot = getRGBDPointCloudWorkerSlot();
1569
- workerSlot.activeJobs += 1;
1570
1905
  const {
1571
1906
  receiveTime
1572
1907
  } = parseMessage(message);
@@ -1574,83 +1909,29 @@ async function deserializeRGBDFrameToPointCloud({
1574
1909
  depthWidth,
1575
1910
  depthHeight
1576
1911
  } = parseDimensions(message);
1577
- const rgbdIntrinsics = resolveRGBDIntrinsics(message, cameraIntrinsics);
1578
- const hasGPU = await detectRGBDGPUSupport();
1579
- const colorFrame = await extractColorFrame(message.colorEncodedFrame, message.colorImgFrame, topicDecoders, topic);
1580
- const uint8DepthFrames = extractDepthFrame(message.depthEncodedFrame, message.depthImgFrame);
1581
- const depthFrames = uint8ArrayToUint16Array(uint8DepthFrames);
1912
+ const rgbdIntrinsics = getRGBDIntrinsics(topic, message, cameraIntrinsics);
1913
+ const hasGPU = getRGBDGPUSupport();
1582
1914
  try {
1583
- var _message$tsDevice;
1584
- const pointCloud = await workerSlot.remote.depthToPointcloudGPU([depthFrames], depthWidth, depthHeight, rgbdIntrinsics.right.focalLenght.x, rgbdIntrinsics.right.focalLenght.y, rgbdIntrinsics.right.principalPoint.x, rgbdIntrinsics.right.principalPoint.y, [colorFrame.data], colorFrame.width, colorFrame.height, maxStereoDepth, {
1585
- hasGPU
1586
- });
1587
- const foxgloveMessage = {
1588
- timestamp: (_message$tsDevice = message.tsDevice) !== null && _message$tsDevice !== void 0 ? _message$tsDevice : receiveTime,
1589
- frame_id: `pointcloud-${topic}-frame`,
1590
- point_stride: 16,
1591
- pose: {
1592
- position: {
1593
- x: 0,
1594
- y: 0,
1595
- z: 0
1596
- },
1597
- orientation: {
1598
- x: 0,
1599
- y: 0,
1600
- z: 1,
1601
- w: 0
1602
- }
1603
- },
1604
- width: depthWidth,
1605
- height: depthHeight,
1606
- fields: [{
1607
- name: "x",
1608
- offset: 0,
1609
- type: typescript.NumericType.FLOAT32
1610
- }, {
1611
- name: "y",
1612
- offset: 4,
1613
- type: typescript.NumericType.FLOAT32
1614
- }, {
1615
- name: "z",
1616
- offset: 8,
1617
- type: typescript.NumericType.FLOAT32
1618
- }, {
1619
- name: "red",
1620
- offset: 12,
1621
- type: typescript.NumericType.UINT8
1622
- }, {
1623
- name: "green",
1624
- offset: 13,
1625
- type: typescript.NumericType.UINT8
1626
- }, {
1627
- name: "blue",
1628
- offset: 14,
1629
- type: typescript.NumericType.UINT8
1630
- }, {
1631
- name: "alpha",
1632
- offset: 15,
1633
- type: typescript.NumericType.UINT8
1634
- }],
1635
- data: pointCloud[0]
1636
- };
1637
- callback({
1915
+ const colorFrame = await extractColorFrame(message.colorEncodedFrame, message.colorImgFrame, topicDecoders, topic);
1916
+ const uint8DepthFrames = extractDepthFrame(message.depthEncodedFrame, message.depthImgFrame);
1917
+ const depthFrame = uint8ArrayToUint16Array(uint8DepthFrames);
1918
+ const pendingFrame = {
1638
1919
  topic,
1639
1920
  receiveTime,
1640
- message: foxgloveMessage,
1641
- sizeInBytes: estimateObjectSize(foxgloveMessage),
1642
- schemaName: "foxglove.PointCloud.Colored"
1643
- });
1644
- if (message.depthImgFrame) {
1645
- void deserializeDepthFrame({
1646
- topic,
1647
- message: message.depthImgFrame,
1648
- callback,
1649
- maxStereoDepth: maxStereoDepth / 1000
1650
- });
1651
- }
1652
- } finally {
1653
- workerSlot.activeJobs = Math.max(0, workerSlot.activeJobs - 1);
1921
+ timestamp: message.tsDevice,
1922
+ depthWidth,
1923
+ depthHeight,
1924
+ rgbdIntrinsics,
1925
+ colorFrame,
1926
+ depthFrame,
1927
+ maxStereoDepth,
1928
+ hasGPU,
1929
+ callback,
1930
+ onError
1931
+ };
1932
+ enqueueRGBDPointCloudFrame(pendingFrame);
1933
+ } catch (error) {
1934
+ onError(error instanceof Error ? error : new Error(String(error)));
1654
1935
  }
1655
1936
  }
1656
1937