'use client';
import { b as _objectSpread2, P as PointsAnnotationType, T as Type, h as Profile, p as protobufsBySchema } from './protobuf-OcbVtxg1.js';
import { w as wrap, e as expose } from './comlink-jf8bdrAf.js';
import { t as typescript } from './index-B5oN0fQm.js';
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';
import { L as Logger } from './logger-Bqy1nuLj.js';
import { i as isCapableOfEncodedStream } from './encoding-jXImCIb4.js';
import { u as uint8ArrayToUint16Array } from './utils-DmlHZWuo.js';
import 'react';
import 'zustand';
import 'react-mosaic-component';
import '@mui/material';
import './isArrayLikeObject-n9ytTioB.js';

// This Source Code Form is subject to the terms of the Mozilla Public
// License, v2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/

const glColor = (r, g, b, a) => ({
  r: r / 255,
  g: g / 255,
  b: b / 255,
  a
});
const DEFAULT_WIDTH = 1920;
const DEFAULT_HEIGHT = 1080;
function interpolate(width, height, base) {
  const widthScale = width / DEFAULT_WIDTH;
  const heightScale = height / DEFAULT_HEIGHT;
  const scale = (widthScale + heightScale) / 2;
  return base * scale;
}
const DEFAULT_SIZE = 42;
const DEFAULT_THICKNESS = 10;
const getTextSize = (width, height) => interpolate(width, height, DEFAULT_SIZE);
const getBorderThickness = (width, height) => interpolate(width, height, DEFAULT_THICKNESS);

const GROUP_COLORS = {
  entity: {
    fill: glColor(21, 56, 127, 0.1),
    outline: glColor(21, 56, 127, 1)
  },
  item: {
    fill: glColor(21, 127, 88, 0.1),
    outline: glColor(21, 127, 88, 1)
  },
  bulk: {
    fill: glColor(127, 21, 42, 0.1),
    outline: glColor(127, 21, 42, 1)
  }
};
const DETECTION_STYLE = [_objectSpread2({
  label: "Person"
}, GROUP_COLORS.entity), _objectSpread2({
  label: "Bicycle"
}, GROUP_COLORS.bulk), _objectSpread2({
  label: "Car"
}, GROUP_COLORS.bulk), _objectSpread2({
  label: "Motorbike"
}, GROUP_COLORS.bulk), _objectSpread2({
  label: "Aeroplane"
}, GROUP_COLORS.bulk), _objectSpread2({
  label: "Bus"
}, GROUP_COLORS.bulk), _objectSpread2({
  label: "Train"
}, GROUP_COLORS.bulk), _objectSpread2({
  label: "Truck"
}, GROUP_COLORS.bulk), _objectSpread2({
  label: "Boat"
}, GROUP_COLORS.bulk), _objectSpread2({
  label: "Traffic Light"
}, GROUP_COLORS.item), _objectSpread2({
  label: "Fire Hydrant"
}, GROUP_COLORS.item), _objectSpread2({
  label: "Stop Sign"
}, GROUP_COLORS.item), _objectSpread2({
  label: "Parking Meter"
}, GROUP_COLORS.item), _objectSpread2({
  label: "Bench"
}, GROUP_COLORS.bulk), _objectSpread2({
  label: "Bird"
}, GROUP_COLORS.entity), _objectSpread2({
  label: "Cat"
}, GROUP_COLORS.entity), _objectSpread2({
  label: "Dog"
}, GROUP_COLORS.entity), _objectSpread2({
  label: "Horse"
}, GROUP_COLORS.entity), _objectSpread2({
  label: "Sheep"
}, GROUP_COLORS.entity), _objectSpread2({
  label: "Cow"
}, GROUP_COLORS.entity), _objectSpread2({
  label: "Elephant"
}, GROUP_COLORS.entity), _objectSpread2({
  label: "Bear"
}, GROUP_COLORS.entity), _objectSpread2({
  label: "Zebra"
}, GROUP_COLORS.entity), _objectSpread2({
  label: "Giraffe"
}, GROUP_COLORS.entity), _objectSpread2({
  label: "Backpack"
}, GROUP_COLORS.item), _objectSpread2({
  label: "Umbrella"
}, GROUP_COLORS.item), _objectSpread2({
  label: "Handbag"
}, GROUP_COLORS.item), _objectSpread2({
  label: "Tie"
}, GROUP_COLORS.item), _objectSpread2({
  label: "Suitcase"
}, GROUP_COLORS.item), _objectSpread2({
  label: "Frisbee"
}, GROUP_COLORS.item), _objectSpread2({
  label: "Skis"
}, GROUP_COLORS.bulk), _objectSpread2({
  label: "Snowboard"
}, GROUP_COLORS.bulk), _objectSpread2({
  label: "Sports Ball"
}, GROUP_COLORS.item), _objectSpread2({
  label: "Lite"
}, GROUP_COLORS.item), _objectSpread2({
  label: "Baseball Bat"
}, GROUP_COLORS.item), _objectSpread2({
  label: "Baseball Glove"
}, GROUP_COLORS.item), _objectSpread2({
  label: "Skateboard"
}, GROUP_COLORS.item), _objectSpread2({
  label: "Surfboard"
}, GROUP_COLORS.bulk), _objectSpread2({
  label: "Tennis Racket"
}, GROUP_COLORS.item), _objectSpread2({
  label: "Bottle"
}, GROUP_COLORS.item), _objectSpread2({
  label: "Wine Glass"
}, GROUP_COLORS.item), _objectSpread2({
  label: "Cup"
}, GROUP_COLORS.item), _objectSpread2({
  label: "Fork"
}, GROUP_COLORS.item), _objectSpread2({
  label: "Knife"
}, GROUP_COLORS.item), _objectSpread2({
  label: "Spoon"
}, GROUP_COLORS.item), _objectSpread2({
  label: "Bowl"
}, GROUP_COLORS.item), _objectSpread2({
  label: "Banana"
}, GROUP_COLORS.item), _objectSpread2({
  label: "Apple"
}, GROUP_COLORS.item), _objectSpread2({
  label: "Sandwich"
}, GROUP_COLORS.item), _objectSpread2({
  label: "Orange"
}, GROUP_COLORS.item), _objectSpread2({
  label: "Broccoli"
}, GROUP_COLORS.item), _objectSpread2({
  label: "Carrot"
}, GROUP_COLORS.item), _objectSpread2({
  label: "Hot Dog"
}, GROUP_COLORS.item), _objectSpread2({
  label: "Pizza"
}, GROUP_COLORS.item), _objectSpread2({
  label: "Donut"
}, GROUP_COLORS.item), _objectSpread2({
  label: "Cake"
}, GROUP_COLORS.item), _objectSpread2({
  label: "Chair"
}, GROUP_COLORS.bulk), _objectSpread2({
  label: "Sofa"
}, GROUP_COLORS.bulk), _objectSpread2({
  label: "Potted Plant"
}, GROUP_COLORS.item), _objectSpread2({
  label: "Bed"
}, GROUP_COLORS.bulk), _objectSpread2({
  label: "Diningtable"
}, GROUP_COLORS.bulk), _objectSpread2({
  label: "Toilet"
}, GROUP_COLORS.bulk), _objectSpread2({
  label: "TV Monitor"
}, GROUP_COLORS.item), _objectSpread2({
  label: "Laptop"
}, GROUP_COLORS.item), _objectSpread2({
  label: "Mouse"
}, GROUP_COLORS.item), _objectSpread2({
  label: "Remote"
}, GROUP_COLORS.item), _objectSpread2({
  label: "Keyboard"
}, GROUP_COLORS.item), _objectSpread2({
  label: "Cell Phone"
}, GROUP_COLORS.item), _objectSpread2({
  label: "Microwave"
}, GROUP_COLORS.item), _objectSpread2({
  label: "Oven"
}, GROUP_COLORS.item), _objectSpread2({
  label: "Toaster"
}, GROUP_COLORS.item), _objectSpread2({
  label: "Sink"
}, GROUP_COLORS.item), _objectSpread2({
  label: "Refrigerator"
}, GROUP_COLORS.bulk), _objectSpread2({
  label: "Book"
}, GROUP_COLORS.item), _objectSpread2({
  label: "Clock"
}, GROUP_COLORS.item), _objectSpread2({
  label: "Vase"
}, GROUP_COLORS.item), _objectSpread2({
  label: "Scissors"
}, GROUP_COLORS.item), _objectSpread2({
  label: "Teddy Bear"
}, GROUP_COLORS.item), _objectSpread2({
  label: "Hair Drier"
}, GROUP_COLORS.item), _objectSpread2({
  label: "Toothbrush"
}, GROUP_COLORS.item)];
const DEBUG_COLOR = {
  r: 0,
  g: 0.5,
  b: 0,
  a: 1
};
const DEFAULT_STYLE = _objectSpread2({
  label: null
}, GROUP_COLORS.item);
const DEFAULT_TEXT_COLOR = {
  r: 1,
  g: 1,
  b: 1,
  a: 1
};
const DEFAULT_BACKGROUND_COLOR = {
  r: 0,
  g: 0,
  b: 0,
  a: 0
};

// This Source Code Form is subject to the terms of the Mozilla Public
// License, v2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/

function deserializeImgDetectionsCustom({
  topic,
  message,
  callback,
  topicSizes
}) {
  var _message$transformati, _message$transformati2, _topicSizes$values$ne;
  const {
    receiveTime
  } = parseMessage(message);
  const {
    width,
    height
  } = (_message$transformati = message.transformation) !== null && _message$transformati !== void 0 && _message$transformati.width && (_message$transformati2 = message.transformation) !== null && _message$transformati2 !== void 0 && _message$transformati2.height ? {
    width: message.transformation.width,
    height: message.transformation.height
  } : (_topicSizes$values$ne = topicSizes.values().next().value) !== null && _topicSizes$values$ne !== void 0 ? _topicSizes$values$ne : {
    width: DEFAULT_WIDTH,
    height: DEFAULT_HEIGHT
  };
  const xMultiplier = width >= height ? 1 : height / width;
  const yMultiplier = height >= width ? 1 : width / height;
  const points = [];
  const texts = [];
  const circles = [];
  for (const annotations of message.annotations) {
    points.push(...annotations.points.map(annotation => {
      var _annotation$outlineCo, _annotation$fillColor;
      return {
        timestamp: receiveTime,
        type: annotation.type === PointsAnnotationType.UNRECOGNIZED ? typescript.PointsAnnotationType.UNKNOWN : Number(annotation.type),
        points: annotation.points,
        outline_color: (_annotation$outlineCo = annotation.outlineColor) !== null && _annotation$outlineCo !== void 0 ? _annotation$outlineCo : DEFAULT_STYLE.outline,
        outline_colors: [],
        fill_color: (_annotation$fillColor = annotation.fillColor) !== null && _annotation$fillColor !== void 0 ? _annotation$fillColor : DEFAULT_STYLE.fill,
        thickness: annotation.thickness
      };
    }));
    texts.push(...annotations.texts.map(annotation => {
      var _annotation$position, _annotation$textColor, _annotation$backgroun;
      return {
        timestamp: receiveTime,
        position: (_annotation$position = annotation.position) !== null && _annotation$position !== void 0 ? _annotation$position : {
          x: 0,
          y: 0
        },
        text: annotation.text,
        font_size: annotation.fontSize != undefined ? annotation.fontSize : getTextSize(width, height),
        text_color: (_annotation$textColor = annotation.textColor) !== null && _annotation$textColor !== void 0 ? _annotation$textColor : DEFAULT_TEXT_COLOR,
        background_color: (_annotation$backgroun = annotation.backgroundColor) !== null && _annotation$backgroun !== void 0 ? _annotation$backgroun : DEFAULT_BACKGROUND_COLOR
      };
    }));
    circles.push(...annotations.circles.map(annotation => {
      var _annotation$position2, _annotation$fillColor2, _annotation$outlineCo2;
      return {
        timestamp: receiveTime,
        xMultiplier,
        yMultiplier,
        position: (_annotation$position2 = annotation.position) !== null && _annotation$position2 !== void 0 ? _annotation$position2 : {
          x: 0,
          y: 0
        },
        diameter: annotation.diameter,
        thickness: annotation.thickness,
        fill_color: (_annotation$fillColor2 = annotation.fillColor) !== null && _annotation$fillColor2 !== void 0 ? _annotation$fillColor2 : DEFAULT_STYLE.fill,
        outline_color: (_annotation$outlineCo2 = annotation.outlineColor) !== null && _annotation$outlineCo2 !== void 0 ? _annotation$outlineCo2 : DEFAULT_STYLE.outline
      };
    }));
  }
  const foxgloveMessage = {
    points,
    texts,
    circles
  };
  callback({
    topic,
    receiveTime,
    message: foxgloveMessage,
    sizeInBytes: estimateObjectSize(foxgloveMessage),
    schemaName: "foxglove.ImageAnnotations",
    depthaiTransformation: message.transformation
  });
}

function rotatePoint(point, centerX, centerY, angleDegrees) {
  const angleRad = angleDegrees * Math.PI / 180;
  const xTranslated = point.x - centerX;
  const yTranslated = point.y - centerY;
  const xRotated = xTranslated * Math.cos(angleRad) - yTranslated * Math.sin(angleRad);
  const yRotated = xTranslated * Math.sin(angleRad) + yTranslated * Math.cos(angleRad);
  return {
    x: xRotated + centerX,
    y: yRotated + centerY
  };
}
function getDetectionGeometry(detection, highlightSizeX, highlightSizeY) {
  const rotatedBoundingBox = detection.boundingBox;
  if (rotatedBoundingBox !== null && rotatedBoundingBox !== void 0 && rotatedBoundingBox.center && rotatedBoundingBox.size) {
    const {
      center,
      size,
      angle
    } = rotatedBoundingBox;
    const halfWidth = size.width / 2;
    const halfHeight = size.height / 2;
    const topLeft = rotatePoint({
      x: center.x - halfWidth,
      y: center.y - halfHeight
    }, center.x, center.y, angle);
    const bottomLeft = rotatePoint({
      x: center.x - halfWidth,
      y: center.y + halfHeight
    }, center.x, center.y, angle);
    const bottomRight = rotatePoint({
      x: center.x + halfWidth,
      y: center.y + halfHeight
    }, center.x, center.y, angle);
    const topRight = rotatePoint({
      x: center.x + halfWidth,
      y: center.y - halfHeight
    }, center.x, center.y, angle);
    const _outline = [topLeft, bottomLeft, bottomRight, topRight];
    const highlightTopWidth = Math.min(highlightSizeX, size.width);
    const highlightSideHeight = Math.min(highlightSizeY, size.height);
    const highlightSegments = [[topLeft, rotatePoint({
      x: center.x - halfWidth + highlightTopWidth,
      y: center.y - halfHeight
    }, center.x, center.y, angle)], [topLeft, rotatePoint({
      x: center.x - halfWidth,
      y: center.y - halfHeight + highlightSideHeight
    }, center.x, center.y, angle)], [topRight, rotatePoint({
      x: center.x + halfWidth - highlightTopWidth,
      y: center.y - halfHeight
    }, center.x, center.y, angle)], [topRight, rotatePoint({
      x: center.x + halfWidth,
      y: center.y - halfHeight + highlightSideHeight
    }, center.x, center.y, angle)], [bottomRight, rotatePoint({
      x: center.x + halfWidth - highlightTopWidth,
      y: center.y + halfHeight
    }, center.x, center.y, angle)], [bottomRight, rotatePoint({
      x: center.x + halfWidth,
      y: center.y + halfHeight - highlightSideHeight
    }, center.x, center.y, angle)], [bottomLeft, rotatePoint({
      x: center.x - halfWidth + highlightTopWidth,
      y: center.y + halfHeight
    }, center.x, center.y, angle)], [bottomLeft, rotatePoint({
      x: center.x - halfWidth,
      y: center.y + halfHeight - highlightSideHeight
    }, center.x, center.y, angle)]];
    const minX = Math.min(..._outline.map(point => point.x));
    const minY = Math.min(..._outline.map(point => point.y));
    return {
      outline: _outline,
      highlightSegments,
      labelPosition: {
        x: minX + highlightSizeX / 2,
        y: minY + highlightSizeY
      }
    };
  }
  const outline = [{
    x: detection.xmin,
    y: detection.ymin
  }, {
    x: detection.xmin,
    y: detection.ymax
  }, {
    x: detection.xmax,
    y: detection.ymax
  }, {
    x: detection.xmax,
    y: detection.ymin
  }];
  return {
    outline,
    highlightSegments: [[{
      x: detection.xmin,
      y: detection.ymin
    }, {
      x: detection.xmin + highlightSizeX,
      y: detection.ymin
    }], [{
      x: detection.xmin,
      y: detection.ymin
    }, {
      x: detection.xmin,
      y: detection.ymin + highlightSizeY
    }], [{
      x: detection.xmax,
      y: detection.ymin
    }, {
      x: detection.xmax - highlightSizeX,
      y: detection.ymin
    }], [{
      x: detection.xmax,
      y: detection.ymin
    }, {
      x: detection.xmax,
      y: detection.ymin + highlightSizeY
    }], [{
      x: detection.xmax,
      y: detection.ymax
    }, {
      x: detection.xmax - highlightSizeX,
      y: detection.ymax
    }], [{
      x: detection.xmax,
      y: detection.ymax
    }, {
      x: detection.xmax,
      y: detection.ymax - highlightSizeY
    }], [{
      x: detection.xmin,
      y: detection.ymax
    }, {
      x: detection.xmin + highlightSizeX,
      y: detection.ymax
    }], [{
      x: detection.xmin,
      y: detection.ymax
    }, {
      x: detection.xmin,
      y: detection.ymax - highlightSizeY
    }]],
    labelPosition: {
      x: detection.xmin + highlightSizeX / 2,
      y: detection.ymin + highlightSizeY
    }
  };
}
function deserializeImgDetections({
  topic,
  message,
  callback,
  topicSizes
}) {
  const {
    receiveTime
  } = parseMessage(message);
  const foxgloveMessage = {
    points: [],
    texts: [],
    circles: []
  };
  if (message.detections.length > 0) {
    for (const detection of message.detections) {
      var _detection$boundingBo, _detection$boundingBo2, _detection$boundingBo3, _detection$boundingBo4, _message$transformati, _topicSizes$values$ne, _DETECTION_STYLE$dete, _style$label;
      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;
      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;
      const {
        width,
        height
      } = (_message$transformati = message.transformation) !== null && _message$transformati !== void 0 && _message$transformati.width && message.transformation.height ? {
        width: message.transformation.width,
        height: message.transformation.height
      } : (_topicSizes$values$ne = topicSizes.values().next().value) !== null && _topicSizes$values$ne !== void 0 ? _topicSizes$values$ne : {
        width: DEFAULT_WIDTH,
        height: DEFAULT_HEIGHT
      };
      const ratio = width / height;
      const highligtLength = 0.035;
      const highlightSizeX = Math.min(highligtLength, detectionWidth);
      const highlightSizeY = Math.min(highligtLength * ratio, detectionHeight);
      const geometry = getDetectionGeometry(detection, highlightSizeX, highlightSizeY);
      const style = (_DETECTION_STYLE$dete = DETECTION_STYLE[detection.label]) !== null && _DETECTION_STYLE$dete !== void 0 ? _DETECTION_STYLE$dete : DEFAULT_STYLE;
      if (detection.labelName) {
        style.label = detection.labelName;
      }
      foxgloveMessage.points.push({
        timestamp: receiveTime,
        points: geometry.outline,
        type: typescript.PointsAnnotationType.LINE_LOOP,
        outline_colors: [],
        thickness: 0,
        outline_color: DEBUG_COLOR,
        fill_color: style.fill
      });
      if (detection.keypoints) {
        const {
          keypoints,
          edges
        } = detection.keypoints;

        // Add keypoints as circles
        for (const keypoint of keypoints) {
          if (keypoint.imageCoordinates) {
            foxgloveMessage.circles.push({
              timestamp: receiveTime,
              position: {
                x: keypoint.imageCoordinates.x,
                y: keypoint.imageCoordinates.y
              },
              diameter: 0.01,
              thickness: 2,
              fill_color: style.outline,
              outline_color: style.outline
            });
          }
        }

        // Add edges as line segments
        for (const edge of edges) {
          const srcKeypoint = keypoints[edge.src];
          const dstKeypoint = keypoints[edge.dst];
          if (srcKeypoint !== null && srcKeypoint !== void 0 && srcKeypoint.imageCoordinates && dstKeypoint !== null && dstKeypoint !== void 0 && dstKeypoint.imageCoordinates) {
            foxgloveMessage.points.push({
              timestamp: receiveTime,
              points: [{
                x: srcKeypoint.imageCoordinates.x,
                y: srcKeypoint.imageCoordinates.y
              }, {
                x: dstKeypoint.imageCoordinates.x,
                y: dstKeypoint.imageCoordinates.y
              }],
              type: typescript.PointsAnnotationType.LINE_LIST,
              outline_colors: [],
              thickness: 2,
              outline_color: style.outline,
              fill_color: DEBUG_COLOR
            });
          }
        }
      }
      const baseHighlightConfig = {
        timestamp: receiveTime,
        type: typescript.PointsAnnotationType.LINE_LIST,
        outline_colors: [],
        thickness: getBorderThickness(width, height),
        outline_color: style.outline,
        fill_color: DEBUG_COLOR
      };
      for (const segment of geometry.highlightSegments) {
        foxgloveMessage.points.push(_objectSpread2(_objectSpread2({}, baseHighlightConfig), {}, {
          points: segment
        }));
      }
      const label = `${(_style$label = style.label) !== null && _style$label !== void 0 ? _style$label : `Unknown #${detection.label}`} ${Math.round(detection.confidence * 100)}%`;
      foxgloveMessage.texts.push({
        timestamp: receiveTime,
        position: geometry.labelPosition,
        text: label,
        font_size: getTextSize(width, height),
        text_color: DEFAULT_TEXT_COLOR,
        background_color: DEFAULT_BACKGROUND_COLOR
      });
    }
  }
  callback({
    topic,
    receiveTime,
    message: foxgloveMessage,
    sizeInBytes: estimateObjectSize(foxgloveMessage),
    schemaName: "foxglove.ImageAnnotations",
    depthaiTransformation: message.transformation
  });
}

// This Source Code Form is subject to the terms of the Mozilla Public
// License, v2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/

function deserializePointCloudData({
  topic,
  message,
  callback
}) {
  const receiveTime = fromMillis(Date.now());
  const foxgloveMessage = {
    timestamp: receiveTime,
    frame_id: `pointcloud-${topic}-frame`,
    point_stride: 12,
    pose: {
      position: {
        x: 0,
        y: 0,
        z: 0
      },
      orientation: {
        x: 0,
        y: 0,
        z: 1,
        w: 0
      }
    },
    fields: [{
      name: "x",
      offset: 0,
      type: typescript.NumericType.FLOAT32
    }, {
      name: "y",
      offset: 4,
      type: typescript.NumericType.FLOAT32
    }, {
      name: "z",
      offset: 8,
      type: typescript.NumericType.FLOAT32
    }],
    data: message.data
  };
  if (message.color) {
    foxgloveMessage.fields.push({
      name: "red",
      offset: 12,
      type: typescript.NumericType.UINT8
    }, {
      name: "green",
      offset: 13,
      type: typescript.NumericType.UINT8
    }, {
      name: "blue",
      offset: 14,
      type: typescript.NumericType.UINT8
    }, {
      name: "alpha",
      offset: 15,
      type: typescript.NumericType.UINT8
    });
    foxgloveMessage.point_stride = 16;
  }
  callback({
    topic,
    receiveTime,
    message: foxgloveMessage,
    sizeInBytes: estimateObjectSize(foxgloveMessage),
    schemaName: "foxglove.PointCloud.Colored"
  });
}

// This Source Code Form is subject to the terms of the Mozilla Public
// License, v2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/

function deserializeColorFrame({
  topic,
  message,
  callback
}) {
  const {
    receiveTime,
    encoding,
    step,
    width,
    height,
    stride,
    planeStride
  } = parseMessage(message);
  const foxgloveMessage = {
    timestamp: receiveTime,
    frame_id: `color-${topic}-frame`,
    width,
    height,
    encoding,
    step: width * step,
    data: message.data,
    stride,
    planeStride
  };
  callback({
    topic,
    receiveTime,
    message: foxgloveMessage,
    sizeInBytes: estimateObjectSize(foxgloveMessage),
    schemaName: "foxglove.RawImage",
    depthaiTransformation: message.transformation
  });
}

// This Source Code Form is subject to the terms of the Mozilla Public
// License, v2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/

function deserializeDepthFrameToPointCloud({
  topic,
  message,
  callback
}) {
  var _message$tsDevice;
  const {
    receiveTime,
    width,
    height
  } = parseMessage(message);
  const foxgloveMessage = {
    timestamp: (_message$tsDevice = message.tsDevice) !== null && _message$tsDevice !== void 0 ? _message$tsDevice : receiveTime,
    frame_id: `pointcloud-${topic}-frame`,
    point_stride: 16,
    pose: {
      position: {
        x: 0,
        y: 0,
        z: 0
      },
      orientation: {
        x: 0,
        y: 0,
        z: 1,
        w: 0
      }
    },
    width,
    height,
    fields: [{
      name: "x",
      offset: 0,
      type: typescript.NumericType.FLOAT32
    }, {
      name: "y",
      offset: 4,
      type: typescript.NumericType.FLOAT32
    }, {
      name: "z",
      offset: 8,
      type: typescript.NumericType.FLOAT32
    }, {
      name: "red",
      offset: 12,
      type: typescript.NumericType.UINT8
    }, {
      name: "green",
      offset: 13,
      type: typescript.NumericType.UINT8
    }, {
      name: "blue",
      offset: 14,
      type: typescript.NumericType.UINT8
    }, {
      name: "alpha",
      offset: 15,
      type: typescript.NumericType.UINT8
    }],
    data: message.data
  };
  callback({
    topic,
    receiveTime,
    message: foxgloveMessage,
    sizeInBytes: estimateObjectSize(foxgloveMessage),
    schemaName: "foxglove.PointCloud"
  });
}

// This Source Code Form is subject to the terms of the Mozilla Public
// License, v2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/
const logger$3 = Logger.getLogger();
function ensureWebCodecsSupported(target) {
  const supported = typeof target !== "undefined";
  if (!supported) {
    const isProtocolSupported = window.location.protocol === "https:" || window.location.protocol === "file:";
    const isLocalHostname = window.location.hostname === "127.0.0.1" || window.location.hostname === "localhost";
    const reason = isProtocolSupported || isLocalHostname ? "Unsupported browser" : `${target} only supports \`https\` or \`localhost\` or \`127.0.0.1\``;
    logger$3.error(`${target} is not available. Reason: ${reason}`);
    return false;
  }
  return true;
}

// This Source Code Form is subject to the terms of the Mozilla Public
// License, v2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/

const logger$2 = Logger.getLogger();
function configureDecoder(decoder) {
  decoder.configure({
    codec: "avc1.42001E",
    optimizeForLatency: true
  });
}
function closeDecoder$1(decoder) {
  if (!decoder) {
    return;
  }
  if (decoder.state === "closed") {
    return;
  }
  try {
    decoder.close();
  } catch (error) {
    logger$2.warn("Failed to close H264 decoder cleanly.", error);
  }
}
function closeTopicDecoder$1(topic, topicDecoders) {
  const decoderInfo = topicDecoders.get(topic);
  closeDecoder$1(decoderInfo === null || decoderInfo === void 0 ? void 0 : decoderInfo.decoder);
  decoderInfo === null || decoderInfo === void 0 || decoderInfo.timing.clear();
  decoderInfo === null || decoderInfo === void 0 || decoderInfo.transformations.clear();
}
function isIgnorableInitialDecodeError(error) {
  const message = error instanceof Error ? error.message : String(error);
  return message.includes("A key frame is required after configure() or flush()");
}
function packedToI420(packed, width, height, stride, format, cropLeft = 0, cropTop = 0) {
  if ((width & 1) !== 0 || (height & 1) !== 0) {
    throw new Error("I420 requires even width and height.");
  }
  const ySize = width * height;
  const uvSize = width * height >> 2;
  const out = new Uint8Array(ySize + uvSize + uvSize);
  const Y = out.subarray(0, ySize);
  const U = out.subarray(ySize, ySize + uvSize);
  const V = out.subarray(ySize + uvSize);
  const isRgbLayout = format === "RGBX" || format === "RGBA";
  const clamp8 = x => x < 0 ? 0 : x > 255 ? 255 : x | 0;
  for (let y = 0; y < height; y += 2) {
    const row0 = (y + cropTop) * stride;
    const row1 = (y + cropTop + 1) * stride;
    for (let x = 0; x < width; x += 2) {
      const srcX = x + cropLeft;
      const p00 = row0 + srcX * 4;
      const p01 = row0 + (srcX + 1) * 4;
      const p10 = row1 + srcX * 4;
      const p11 = row1 + (srcX + 1) * 4;
      const R00 = packed[p00 + (isRgbLayout ? 0 : 2)];
      const G00 = packed[p00 + 1];
      const B00 = packed[p00 + (isRgbLayout ? 2 : 0)];
      const R01 = packed[p01 + (isRgbLayout ? 0 : 2)];
      const G01 = packed[p01 + 1];
      const B01 = packed[p01 + (isRgbLayout ? 2 : 0)];
      const R10 = packed[p10 + (isRgbLayout ? 0 : 2)];
      const G10 = packed[p10 + 1];
      const B10 = packed[p10 + (isRgbLayout ? 2 : 0)];
      const R11 = packed[p11 + (isRgbLayout ? 0 : 2)];
      const G11 = packed[p11 + 1];
      const B11 = packed[p11 + (isRgbLayout ? 2 : 0)];
      const Y00 = 77 * R00 + 150 * G00 + 29 * B00 + 128 >> 8;
      const Y01 = 77 * R01 + 150 * G01 + 29 * B01 + 128 >> 8;
      const Y10 = 77 * R10 + 150 * G10 + 29 * B10 + 128 >> 8;
      const Y11 = 77 * R11 + 150 * G11 + 29 * B11 + 128 >> 8;
      const yRow0 = y * width + x;
      const yRow1 = (y + 1) * width + x;
      Y[yRow0 + 0] = Y00;
      Y[yRow0 + 1] = Y01;
      Y[yRow1 + 0] = Y10;
      Y[yRow1 + 1] = Y11;
      const Ravg = R00 + R01 + R10 + R11 >> 2;
      const Gavg = G00 + G01 + G10 + G11 >> 2;
      const Bavg = B00 + B01 + B10 + B11 >> 2;
      const Uval = clamp8((-43 * Ravg - 85 * Gavg + 128 * Bavg >> 8) + 128);
      const Vval = clamp8((128 * Ravg - 107 * Gavg - 21 * Bavg >> 8) + 128);
      const uvCol = x >> 1;
      const uvRow = y >> 1;
      const uvW = width >> 1;
      const uvPos = uvRow * uvW + uvCol;
      U[uvPos] = Uval;
      V[uvPos] = Vval;
    }
  }
  return out;
}
function convertNv12ToI420(nv12Buffer, width, height, yStride, uvStride, yOffset = 0, uvOffset = yStride * height, cropLeft = 0, cropTop = 0) {
  const ySize = width * height;
  const uvSize = ySize / 4;
  const i420Buffer = new Uint8Array(ySize + 2 * uvSize);
  for (let row = 0; row < height; row++) {
    const srcOffset = yOffset + (row + cropTop) * yStride + cropLeft;
    const dstOffset = row * width;
    i420Buffer.set(nv12Buffer.subarray(srcOffset, srcOffset + width), dstOffset);
  }
  const uPlaneOffset = ySize;
  const vPlaneOffset = ySize + uvSize;
  const uvHeight = height / 2;
  const uvWidth = width / 2;
  const uvCropLeft = cropLeft >> 1;
  const uvCropTop = cropTop >> 1;
  for (let row = 0; row < uvHeight; row++) {
    for (let col = 0; col < uvWidth; col++) {
      var _nv12Buffer$srcIndex, _nv12Buffer;
      const srcIndex = uvOffset + (row + uvCropTop) * uvStride + (col + uvCropLeft) * 2;
      const dstIndex = row * uvWidth + col;
      i420Buffer[uPlaneOffset + dstIndex] = (_nv12Buffer$srcIndex = nv12Buffer[srcIndex]) !== null && _nv12Buffer$srcIndex !== void 0 ? _nv12Buffer$srcIndex : 0; // U
      i420Buffer[vPlaneOffset + dstIndex] = (_nv12Buffer = nv12Buffer[srcIndex + 1]) !== null && _nv12Buffer !== void 0 ? _nv12Buffer : 0; // V
    }
  }
  return i420Buffer;
}
function repackI420(source, width, height, yLayout, uLayout, vLayout, cropLeft = 0, cropTop = 0) {
  const ySize = width * height;
  const uvWidth = width >> 1;
  const uvHeight = height >> 1;
  const uvSize = uvWidth * uvHeight;
  const out = new Uint8Array(ySize + uvSize * 2);
  const uvCropLeft = cropLeft >> 1;
  const uvCropTop = cropTop >> 1;
  for (let row = 0; row < height; row++) {
    const srcOffset = yLayout.offset + (row + cropTop) * yLayout.stride + cropLeft;
    out.set(source.subarray(srcOffset, srcOffset + width), row * width);
  }
  for (let row = 0; row < uvHeight; row++) {
    const uSrcOffset = uLayout.offset + (row + uvCropTop) * uLayout.stride + uvCropLeft;
    const vSrcOffset = vLayout.offset + (row + uvCropTop) * vLayout.stride + uvCropLeft;
    const dstOffset = row * uvWidth;
    out.set(source.subarray(uSrcOffset, uSrcOffset + uvWidth), ySize + dstOffset);
    out.set(source.subarray(vSrcOffset, vSrcOffset + uvWidth), ySize + uvSize + dstOffset);
  }
  return out;
}
async function copyVideoFrameToI420(frame, logPrefix) {
  var _visibleRect$width, _visibleRect$height, _visibleRect$x, _visibleRect$y;
  const visibleRect = frame.visibleRect;
  const frameWidth = (_visibleRect$width = visibleRect === null || visibleRect === void 0 ? void 0 : visibleRect.width) !== null && _visibleRect$width !== void 0 ? _visibleRect$width : frame.codedWidth;
  const frameHeight = (_visibleRect$height = visibleRect === null || visibleRect === void 0 ? void 0 : visibleRect.height) !== null && _visibleRect$height !== void 0 ? _visibleRect$height : frame.codedHeight;
  const cropLeft = (_visibleRect$x = visibleRect === null || visibleRect === void 0 ? void 0 : visibleRect.x) !== null && _visibleRect$x !== void 0 ? _visibleRect$x : 0;
  const cropTop = (_visibleRect$y = visibleRect === null || visibleRect === void 0 ? void 0 : visibleRect.y) !== null && _visibleRect$y !== void 0 ? _visibleRect$y : 0;
  let finalBuffer = new Uint8Array(frame.allocationSize());
  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}`);
  switch (frame.format) {
    case "I420":
      {
        const i420Buffer = new Uint8Array(frame.allocationSize());
        const layouts = await frame.copyTo(i420Buffer);
        const [yLayout, uLayout, vLayout] = layouts;
        finalBuffer = yLayout != undefined && uLayout != undefined && vLayout != undefined ? repackI420(i420Buffer, frameWidth, frameHeight, yLayout, uLayout, vLayout, cropLeft, cropTop) : i420Buffer;
        break;
      }
    case "NV12":
      {
        var _yLayout$stride, _uvLayout$stride, _yLayout$offset, _uvLayout$offset, _yLayout$stride2;
        const nv12Buffer = new Uint8Array(frame.allocationSize());
        const layouts = await frame.copyTo(nv12Buffer);
        const [yLayout, uvLayout] = layouts;
        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);
        break;
      }
    case "RGBX":
    case "RGBA":
    case "BGRX":
    case "BGRA":
      {
        var _layout$stride;
        const packedBuffer = new Uint8Array(frame.allocationSize());
        const [layout] = await frame.copyTo(packedBuffer);
        logger$2.warn(`${logPrefix} decoder received ${frame.format} frame.`);
        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);
        break;
      }
    default:
      logger$2.warn(`${logPrefix} decoder received unexpected frame format:`, frame.format);
      break;
  }
  return {
    data: finalBuffer,
    width: frameWidth,
    height: frameHeight
  };
}
function createVideoDecoder$1({
  topic,
  callback,
  topicDecoders,
  onError
}) {
  let hasProducedFrame = false;
  return new VideoDecoder({
    output: async frame => {
      var _topicDecoders$get$ti, _topicDecoders$get, _topicDecoders$get2, _topicDecoders$get3;
      hasProducedFrame = true;
      const {
        data: finalBuffer,
        width: frameWidth,
        height: frameHeight
      } = await copyVideoFrameToI420(frame, "H264");
      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);
      const transformation = (_topicDecoders$get2 = topicDecoders.get(topic)) === null || _topicDecoders$get2 === void 0 ? void 0 : _topicDecoders$get2.transformations.get(frame.timestamp);
      (_topicDecoders$get3 = topicDecoders.get(topic)) === null || _topicDecoders$get3 === void 0 || _topicDecoders$get3.transformations.delete(frame.timestamp);
      const foxgloveMessage = {
        timestamp: receiveTime,
        frame_id: `h264-${topic}-frame`,
        width: frameWidth,
        height: frameHeight,
        data: finalBuffer,
        encoding: "yuv420p",
        step: frameWidth
      };
      callback({
        topic,
        receiveTime,
        message: foxgloveMessage,
        sizeInBytes: estimateObjectSize(foxgloveMessage),
        schemaName: "foxglove.RawImage",
        depthaiTransformation: transformation
      });
      frame.close();
    },
    error: error => {
      if (!hasProducedFrame && isIgnorableInitialDecodeError(error)) {
        logger$2.warn(`Ignoring initial H264 decoder error for topic ${topic}: ${error.message}`);
        closeTopicDecoder$1(topic, topicDecoders);
        return;
      }
      logger$2.error(error);
      closeTopicDecoder$1(topic, topicDecoders);
      onError(new DecoderRuntimeError(topic, error.message));
    }
  });
}
async function deserializeEncodedFrameH264({
  topic,
  message,
  topicDecoders,
  callback,
  onError
}) {
  const {
    receiveTime
  } = parseMessage(message);
  const supported = ensureWebCodecsSupported("VideoDecoder");
  if (!supported) {
    return;
  }
  const existingDecoderInfo = topicDecoders.get(topic);
  if (!existingDecoderInfo || existingDecoderInfo.decoder.state === "closed") {
    const decoder = createVideoDecoder$1({
      topic,
      callback,
      topicDecoders,
      onError
    });
    try {
      configureDecoder(decoder);
    } catch (error) {
      closeDecoder$1(decoder);
      onError(new DecoderRuntimeError(topic, error instanceof Error ? error.message : "Failed to configure H.264 decoder."));
      return;
    }
    if (existingDecoderInfo) {
      existingDecoderInfo.decoder = decoder;
      existingDecoderInfo.timing.clear();
      existingDecoderInfo.transformations.clear();
    } else {
      topicDecoders.set(topic, {
        decoder,
        timing: new Map(),
        transformations: new Map()
      });
    }
  } else if (existingDecoderInfo.decoder.state === "unconfigured") {
    try {
      configureDecoder(existingDecoderInfo.decoder);
      existingDecoderInfo.timing.clear();
      existingDecoderInfo.transformations.clear();
    } catch (error) {
      closeTopicDecoder$1(topic, topicDecoders);
      onError(new DecoderRuntimeError(topic, error instanceof Error ? error.message : "Failed to reconfigure H.264 decoder."));
      return;
    }
  }
  const decoderInfo = topicDecoders.get(topic);
  if (!decoderInfo) {
    return;
  }
  if (decoderInfo.decoder.decodeQueueSize > 60) {
    decoderInfo.decoder.reset();
    decoderInfo.timing.clear();
    decoderInfo.transformations.clear();
    return;
  }
  const microTimestamp = receiveTime.sec * 1000000 + Math.floor(receiveTime.nsec / 1000);
  decoderInfo.timing.set(microTimestamp, receiveTime);
  decoderInfo.transformations.set(microTimestamp, message.transformation);
  const frame = {
    type: 'key',
    data: message.data,
    timestamp: microTimestamp
  };
  try {
    const chunk = new EncodedVideoChunk(frame);
    decoderInfo.decoder.decode(chunk);
  } catch (error) {
    if (isIgnorableInitialDecodeError(error)) {
      closeTopicDecoder$1(topic, topicDecoders);
      return;
    }
    closeTopicDecoder$1(topic, topicDecoders);
    onError(new DecoderRuntimeError(topic, error instanceof Error ? error.message : "Failed to decode H.264 frame."));
  }
}

// This Source Code Form is subject to the terms of the Mozilla Public
// License, v2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/

const logger$1 = Logger.getLogger();
function closeDecoder(decoder) {
  if (!decoder) {
    return;
  }
  if (decoder.state === "closed") {
    return;
  }
  try {
    decoder.close();
  } catch (error) {
    logger$1.warn("Failed to close H265 decoder cleanly.", error);
  }
}
function closeTopicDecoder(topic, topicDecoders) {
  const decoderInfo = topicDecoders.get(topic);
  closeDecoder(decoderInfo === null || decoderInfo === void 0 ? void 0 : decoderInfo.decoder);
  decoderInfo === null || decoderInfo === void 0 || decoderInfo.timing.clear();
  decoderInfo === null || decoderInfo === void 0 || decoderInfo.transformations.clear();
}
function createVideoDecoder({
  topic,
  callback,
  topicDecoders,
  onError
}) {
  return new VideoDecoder({
    output: async frame => {
      var _topicDecoders$get$ti, _topicDecoders$get, _topicDecoders$get2, _topicDecoders$get3;
      const {
        data: buffer,
        width,
        height
      } = await copyVideoFrameToI420(frame, "H265");
      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);
      const transformation = (_topicDecoders$get2 = topicDecoders.get(topic)) === null || _topicDecoders$get2 === void 0 ? void 0 : _topicDecoders$get2.transformations.get(frame.timestamp);
      (_topicDecoders$get3 = topicDecoders.get(topic)) === null || _topicDecoders$get3 === void 0 || _topicDecoders$get3.transformations.delete(frame.timestamp);
      const foxgloveMessage = {
        timestamp: receiveTime,
        frame_id: `h265-${topic}-frame`,
        width,
        height,
        data: buffer,
        encoding: "yuv420p",
        step: width
      };
      callback({
        topic,
        receiveTime,
        message: foxgloveMessage,
        sizeInBytes: estimateObjectSize(foxgloveMessage),
        schemaName: "foxglove.RawImage",
        depthaiTransformation: transformation
      });
      frame.close();
    },
    error: error => {
      logger$1.error(error);
      closeTopicDecoder(topic, topicDecoders);
      onError(new DecoderRuntimeError(topic, error.message));
    }
  });
}
async function deserializeEncodedFrameH265({
  topic,
  message,
  topicDecoders,
  callback,
  onError
}) {
  const {
    receiveTime
  } = parseMessage(message);
  const supported = ensureWebCodecsSupported("VideoDecoder");
  if (!supported) {
    return;
  }
  const existingDecoderInfo = topicDecoders.get(topic);
  if (!existingDecoderInfo || existingDecoderInfo.decoder.state === "closed") {
    const decoder = createVideoDecoder({
      topic,
      callback,
      topicDecoders,
      onError
    });
    try {
      decoder.configure({
        codec: "hev1.1.6.L93.B0",
        optimizeForLatency: true
      });
    } catch (error) {
      closeDecoder(decoder);
      onError(new DecoderRuntimeError(topic, error instanceof Error ? error.message : "Failed to configure H.265 decoder."));
      return;
    }
    if (existingDecoderInfo) {
      existingDecoderInfo.decoder = decoder;
      existingDecoderInfo.timing.clear();
      existingDecoderInfo.transformations.clear();
    } else {
      topicDecoders.set(topic, {
        decoder,
        timing: new Map(),
        transformations: new Map()
      });
    }
  }
  const decoderInfo = topicDecoders.get(topic);
  if (!decoderInfo) {
    return;
  }
  if (decoderInfo.decoder.decodeQueueSize > 60) {
    decoderInfo.decoder.reset();
    return;
  }
  const microTimestamp = receiveTime.sec * 1000000 + Math.floor(receiveTime.nsec / 1000);
  decoderInfo.timing.set(microTimestamp, receiveTime);
  decoderInfo.transformations.set(microTimestamp, message.transformation);
  const frame = {
    type: 'key',
    data: message.data,
    timestamp: microTimestamp
  };
  try {
    const chunk = new EncodedVideoChunk(frame);
    decoderInfo.decoder.decode(chunk);
  } catch (error) {
    closeTopicDecoder(topic, topicDecoders);
    onError(new DecoderRuntimeError(topic, error instanceof Error ? error.message : "Failed to decode H.265 frame."));
  }
}

// This Source Code Form is subject to the terms of the Mozilla Public
// License, v2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/

async function deserializeMJPEGFrame({
  topic,
  message,
  callback
}) {
  const {
    receiveTime
  } = parseMessage(message);
  const supported = ensureWebCodecsSupported("ImageDecoder");
  if (!supported) {
    return;
  }
  const decoder = new ImageDecoder({
    type: "image/jpeg",
    data: message.data
  });
  const {
    image: frame
  } = await decoder.decode();
  const {
    data: buffer,
    width,
    height
  } = await copyVideoFrameToI420(frame, "MJPEG");
  const foxgloveMessage = {
    timestamp: receiveTime,
    frame_id: "camera",
    width,
    height,
    data: buffer,
    encoding: "yuv420p",
    step: width
  };
  frame.close();
  callback({
    topic,
    receiveTime,
    message: foxgloveMessage,
    sizeInBytes: estimateObjectSize(foxgloveMessage),
    schemaName: "foxglove.RawImage",
    depthaiTransformation: message.transformation
  });
}

const RGBD_POINTCLOUD_WORKER_COUNT = 4;
let cachedRGBDHasGPU;
let rgbdHasGPUPromise;
let rgbdPointCloudWorkers;
let rgbdPointCloudWorkerIndex = 0;
Logger.getLogger();
function ensureEvenByteLength(data) {
  if (data.length % 2 === 0) {
    return data;
  }
  const padded = new Uint8Array(data.length + 1);
  padded.set(data);
  return padded;
}
async function detectRGBDGPUSupport() {
  if (cachedRGBDHasGPU != undefined) {
    return cachedRGBDHasGPU;
  }
  if (rgbdHasGPUPromise) {
    return await rgbdHasGPUPromise;
  }
  rgbdHasGPUPromise = (async () => {
    if (typeof navigator.gpu === "undefined") {
      cachedRGBDHasGPU = false;
      return false;
    }
    try {
      const adapter = await navigator.gpu.requestAdapter();
      cachedRGBDHasGPU = adapter != undefined;
      return cachedRGBDHasGPU;
    } catch (_unused) {
      cachedRGBDHasGPU = false;
      return false;
    } finally {
      rgbdHasGPUPromise = undefined;
    }
  })();
  return await rgbdHasGPUPromise;
}
function getRGBDPointCloudWorkerSlot() {
  if (!rgbdPointCloudWorkers) {
    rgbdPointCloudWorkers = Array.from({
      length: RGBD_POINTCLOUD_WORKER_COUNT
    }, () => {
      const worker = new Worker(new URL("pointcloudFromDepth.worker-60RA4Ief.js", import.meta.url), {
        type: "module"
      });
      return {
        worker,
        remote: wrap(worker),
        activeJobs: 0
      };
    });
  }
  const slots = rgbdPointCloudWorkers;
  const candidateSlots = slots.map((slot, index) => ({
    slot,
    index
  })).sort((left, right) => {
    if (left.slot.activeJobs !== right.slot.activeJobs) {
      return left.slot.activeJobs - right.slot.activeJobs;
    }
    const leftDistance = (left.index - rgbdPointCloudWorkerIndex + slots.length) % slots.length;
    const rightDistance = (right.index - rgbdPointCloudWorkerIndex + slots.length) % slots.length;
    return leftDistance - rightDistance;
  });
  const selected = candidateSlots[0];
  rgbdPointCloudWorkerIndex = (selected.index + 1) % slots.length;
  return selected.slot;
}
function repackYuv420pToI420(imageFrame, width, height) {
  var _imageFrame$fb;
  const specs = (_imageFrame$fb = imageFrame.fb) !== null && _imageFrame$fb !== void 0 ? _imageFrame$fb : imageFrame.sourceFb;
  const source = ensureEvenByteLength(imageFrame.data);
  const yStride = (specs === null || specs === void 0 ? void 0 : specs.stride) || width;
  const uvWidth = Math.floor(width / 2);
  const uvHeight = Math.floor(height / 2);
  const uvStride = yStride > width ? Math.floor(yStride / 2) : uvWidth;
  const yPlaneSize = width * height;
  const uvPlaneSize = uvWidth * uvHeight;
  const uOffset = (specs === null || specs === void 0 ? void 0 : specs.p1Offset) || yStride * height;
  const vOffset = (specs === null || specs === void 0 ? void 0 : specs.p2Offset) || uOffset + uvStride * uvHeight;
  const i420 = new Uint8Array(yPlaneSize + 2 * uvPlaneSize);
  for (let row = 0; row < height; row++) {
    const srcOffset = row * yStride;
    const dstOffset = row * width;
    i420.set(source.subarray(srcOffset, srcOffset + width), dstOffset);
  }
  for (let row = 0; row < uvHeight; row++) {
    const srcUOffset = uOffset + row * uvStride;
    const srcVOffset = vOffset + row * uvStride;
    const dstOffset = row * uvWidth;
    i420.set(source.subarray(srcUOffset, srcUOffset + uvWidth), yPlaneSize + dstOffset);
    i420.set(source.subarray(srcVOffset, srcVOffset + uvWidth), yPlaneSize + uvPlaneSize + dstOffset);
  }
  return i420;
}
function toMatrix3x3(matrix) {
  const rows = matrix === null || matrix === void 0 ? void 0 : matrix.arrays;
  if (!rows || rows.length < 3) {
    return undefined;
  }
  const normalizedRows = rows.slice(0, 3).map(row => row === null || row === void 0 ? void 0 : row.values.slice(0, 3).map(value => value !== null && value !== void 0 ? value : 0));
  if (normalizedRows.some(row => !row || row.length < 3)) {
    return undefined;
  }
  return normalizedRows;
}
function multiply3x3(left, right) {
  return [[left[0][0] * right[0][0] + left[0][1] * right[1][0] + left[0][2] * right[2][0], left[0][0] * right[0][1] + left[0][1] * right[1][1] + left[0][2] * right[2][1], left[0][0] * right[0][2] + left[0][1] * right[1][2] + left[0][2] * right[2][2]], [left[1][0] * right[0][0] + left[1][1] * right[1][0] + left[1][2] * right[2][0], left[1][0] * right[0][1] + left[1][1] * right[1][1] + left[1][2] * right[2][1], left[1][0] * right[0][2] + left[1][1] * right[1][2] + left[1][2] * right[2][2]], [left[2][0] * right[0][0] + left[2][1] * right[1][0] + left[2][2] * right[2][0], left[2][0] * right[0][1] + left[2][1] * right[1][1] + left[2][2] * right[2][1], left[2][0] * right[0][2] + left[2][1] * right[1][2] + left[2][2] * right[2][2]]];
}
function extractIntrinsicsFromTransformation(transformation) {
  const sourceIntrinsicMatrix = toMatrix3x3(transformation === null || transformation === void 0 ? void 0 : transformation.sourceIntrinsicMatrix);
  if (!sourceIntrinsicMatrix) {
    return undefined;
  }
  const transformationMatrix = toMatrix3x3(transformation === null || transformation === void 0 ? void 0 : transformation.transformationMatrix);
  const effectiveIntrinsicMatrix = transformationMatrix ? multiply3x3(transformationMatrix, sourceIntrinsicMatrix) : sourceIntrinsicMatrix;
  const fx = effectiveIntrinsicMatrix[0][0];
  const fy = effectiveIntrinsicMatrix[1][1];
  const cx = effectiveIntrinsicMatrix[0][2];
  const cy = effectiveIntrinsicMatrix[1][2];
  if (![fx, fy, cx, cy].every(value => Number.isFinite(value))) {
    return undefined;
  }
  return {
    left: {
      focalLenght: {
        x: fx,
        y: fy
      },
      principalPoint: {
        x: cx,
        y: cy
      }
    },
    right: {
      focalLenght: {
        x: fx,
        y: fy
      },
      principalPoint: {
        x: cx,
        y: cy
      }
    }
  };
}
function resolveRGBDIntrinsics(message, fallbackIntrinsics) {
  var _ref, _ref2, _ref3, _extractIntrinsicsFro, _message$depthImgFram, _message$depthEncoded, _message$colorImgFram, _message$colorEncoded;
  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;
}
async function extractEncodedColorFrame(encodedFrame, topicDecoders, topic) {
  const decodeFrame = async () => await new Promise((resolve, reject) => {
    const callback = event => {
      resolve(event.message);
    };
    const rejectDecode = error => {
      reject(error);
    };
    const args = {
      topic,
      message: encodedFrame,
      callback
    };
    if (encodedFrame.profile === Profile.AVC) {
      void deserializeEncodedFrameH264(_objectSpread2(_objectSpread2({}, args), {}, {
        topicDecoders,
        onError: rejectDecode
      })).catch(rejectDecode);
    } else if (encodedFrame.profile === Profile.JPEG) {
      void deserializeMJPEGFrame(args).catch(rejectDecode);
    } else if (encodedFrame.profile === Profile.HEVC) {
      void deserializeEncodedFrameH265(_objectSpread2(_objectSpread2({}, args), {}, {
        topicDecoders,
        onError: rejectDecode
      })).catch(rejectDecode);
    } else {
      var _Profile$encodedFrame;
      reject(new Error(`Unsupported RGBD color profile ${(_Profile$encodedFrame = Profile[encodedFrame.profile]) !== null && _Profile$encodedFrame !== void 0 ? _Profile$encodedFrame : encodedFrame.profile}`));
    }
  });
  const decoded = await decodeFrame();
  return {
    data: ensureEvenByteLength(decoded.data),
    width: decoded.width,
    height: decoded.height
  };
}
function extractColorFrame(encodedFrame, imageFrame, topicDecoders, topic) {
  if (encodedFrame) {
    return extractEncodedColorFrame(encodedFrame, topicDecoders, topic);
  }
  if (imageFrame) {
    var _imageFrame$fb2;
    const {
      width,
      height,
      type
    } = parseMessage(imageFrame);
    const specs = (_imageFrame$fb2 = imageFrame.fb) !== null && _imageFrame$fb2 !== void 0 ? _imageFrame$fb2 : imageFrame.sourceFb;
    if (type === Type.NV12) {
      const stride = (specs === null || specs === void 0 ? void 0 : specs.stride) || width;
      const uvOffset = (specs === null || specs === void 0 ? void 0 : specs.p1Offset) || stride * height;
      return Promise.resolve({
        data: convertNv12ToI420(ensureEvenByteLength(imageFrame.data), width, height, stride, stride, 0, uvOffset),
        width,
        height
      });
    }
    if (type === Type.YUV420p) {
      return Promise.resolve({
        data: repackYuv420pToI420(imageFrame, width, height),
        width,
        height
      });
    }
    return Promise.reject(new Error(`Unsupported RGBD color ImgFrame type ${Type[type]}`));
  }
  return Promise.resolve({
    data: new Uint8Array(),
    width: 0,
    height: 0
  });
}
function extractDepthFrame(encodedFrame, imageFrame) {
  if (encodedFrame) {
    return ensureEvenByteLength(encodedFrame.data);
  }
  if (imageFrame) {
    return ensureEvenByteLength(imageFrame.data);
  }
  return new Uint8Array();
}
function parseDimensions(message) {
  const obj = {
    depthWidth: 0,
    depthHeight: 0
  };
  if (message.depthEncodedFrame) {
    var _message$depthEncoded2;
    const {
      width,
      height
    } = (_message$depthEncoded2 = message.depthEncodedFrame) !== null && _message$depthEncoded2 !== void 0 ? _message$depthEncoded2 : {
      width: 1920,
      height: 1200
    };
    obj.depthWidth = width;
    obj.depthHeight = height;
  } else if (message.depthImgFrame) {
    const {
      width,
      height
    } = parseMessage(message.depthImgFrame);
    obj.depthWidth = width;
    obj.depthHeight = height;
  }
  return obj;
}
async function deserializeRGBDFrameToPointCloud({
  topic,
  topicDecoders,
  cameraIntrinsics,
  maxStereoDepth,
  message,
  callback
}) {
  const workerSlot = getRGBDPointCloudWorkerSlot();
  workerSlot.activeJobs += 1;
  const {
    receiveTime
  } = parseMessage(message);
  const {
    depthWidth,
    depthHeight
  } = parseDimensions(message);
  const rgbdIntrinsics = resolveRGBDIntrinsics(message, cameraIntrinsics);
  const hasGPU = await detectRGBDGPUSupport();
  const colorFrame = await extractColorFrame(message.colorEncodedFrame, message.colorImgFrame, topicDecoders, topic);
  const uint8DepthFrames = extractDepthFrame(message.depthEncodedFrame, message.depthImgFrame);
  const depthFrames = uint8ArrayToUint16Array(uint8DepthFrames);
  try {
    var _message$tsDevice;
    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, {
      hasGPU
    });
    const foxgloveMessage = {
      timestamp: (_message$tsDevice = message.tsDevice) !== null && _message$tsDevice !== void 0 ? _message$tsDevice : receiveTime,
      frame_id: `pointcloud-${topic}-frame`,
      point_stride: 16,
      pose: {
        position: {
          x: 0,
          y: 0,
          z: 0
        },
        orientation: {
          x: 0,
          y: 0,
          z: 1,
          w: 0
        }
      },
      width: depthWidth,
      height: depthHeight,
      fields: [{
        name: "x",
        offset: 0,
        type: typescript.NumericType.FLOAT32
      }, {
        name: "y",
        offset: 4,
        type: typescript.NumericType.FLOAT32
      }, {
        name: "z",
        offset: 8,
        type: typescript.NumericType.FLOAT32
      }, {
        name: "red",
        offset: 12,
        type: typescript.NumericType.UINT8
      }, {
        name: "green",
        offset: 13,
        type: typescript.NumericType.UINT8
      }, {
        name: "blue",
        offset: 14,
        type: typescript.NumericType.UINT8
      }, {
        name: "alpha",
        offset: 15,
        type: typescript.NumericType.UINT8
      }],
      data: pointCloud[0]
    };
    callback({
      topic,
      receiveTime,
      message: foxgloveMessage,
      sizeInBytes: estimateObjectSize(foxgloveMessage),
      schemaName: "foxglove.PointCloud.Colored"
    });
    if (message.depthImgFrame) {
      void deserializeDepthFrame({
        topic,
        message: message.depthImgFrame,
        callback,
        maxStereoDepth: maxStereoDepth / 1000
      });
    }
  } finally {
    workerSlot.activeJobs = Math.max(0, workerSlot.activeJobs - 1);
  }
}

const logger = Logger.getLogger();
function errorInstanceToErrorCode(error) {
  if (error instanceof UnsupportedTopicError) {
    return "UnsupportedTopic";
  }
  if (error instanceof NotInSecureContextError) {
    return "NotInSecureContext";
  }
  if (error instanceof EncodedStreamNotSupportedError) {
    return "EncodedStreamNotSupported";
  }
  return "DecoderError";
}
const topicDecoders = new Map();
const topicSizes = new Map();
let callback;
function initCallback(cb) {
  callback = cb;
}
function ensureEncodedStreamSupport(topic) {
  if (!globalThis.isSecureContext) {
    throw new NotInSecureContextError(topic);
  }
  if (!isCapableOfEncodedStream()) {
    throw new EncodedStreamNotSupportedError(topic);
  }
}
function handleMessageToDecode({
  schema,
  buffer,
  topic,
  neuralCameraIntrinsics,
  stereoDepthMaxValue
}, configStore, errorCallback) {
  const handleDecodingError = error => {
    // TODO: Enable this log once we fix topic unsubscription not working
    // logger.error("An error occurred during DAI message decoding.", error);

    // Type information about an error gets lost during transfer from worker to main thread
    // This means that we have to remap the errors based on type here to an 'error enum'
    // Which can then be parsed on the main thread
    errorCallback === null || errorCallback === void 0 || errorCallback(errorInstanceToErrorCode(error), topic, {
      message: error.message
    });
  };
  const protobufSchema = protobufsBySchema[schema];
  if (!protobufSchema) {
    logger.warn(`Unsupported message schema "${schema}"`);
    handleDecodingError(new UnsupportedTopicError(topic, `Unsupported message schema "${schema}"`));
    return;
  }
  const bufferArray = new Uint8Array(buffer.buffer, buffer.byteOffset, buffer.byteLength);
  try {
    const message = protobufSchema.decoder.decode(bufferArray);
    if (configStore.connectionConfigValue.debugLogs) {
      logger.debug(`[DepthAI Deserialization] Received message of type ${protobufSchema.type} on topic ${topic}`, {
        message
      });
    }

    // Handle the promise correctly
    deserializeDepthAiMessage({
      topic,
      topicSizes,
      topicDecoders,
      neuralCameraIntrinsics,
      message,
      callback,
      type: protobufSchema.type,
      maxSteroDepth: stereoDepthMaxValue,
      onError: handleDecodingError
    }).catch(handleDecodingError);
  } catch (error) {
    handleDecodingError(error);
  }
}
async function deserializeDepthAiMessage(args) {
  const {
    topicDecoders,
    topicSizes,
    type,
    message,
    callback,
    topic,
    neuralCameraIntrinsics,
    maxSteroDepth,
    onError
  } = args;
  switch (type) {
    case "encodedFrame":
      {
        ensureEncodedStreamSupport(topic);
        topicSizes.set(topic, {
          width: message.width,
          height: message.height
        });
        if (message.profile === Profile.AVC) {
          await deserializeEncodedFrameH264({
            topic,
            message,
            topicDecoders,
            callback,
            onError
          });
        } else if (message.profile === Profile.JPEG) {
          await deserializeMJPEGFrame({
            topic,
            message,
            callback
          });
        } else if (message.profile === Profile.HEVC) {
          await deserializeEncodedFrameH265({
            topic,
            message,
            topicDecoders,
            callback,
            onError
          });
        } else ;
        break;
      }
    case "imageFrame":
      {
        const {
          width,
          height,
          type: messageType
        } = parseMessage(message);
        topicSizes.set(topic, {
          width,
          height
        });
        switch (messageType) {
          case Type.BITSTREAM:
            {
              ensureEncodedStreamSupport(topic);
              await deserializeEncodedFrameH264({
                topic,
                message,
                topicDecoders,
                callback,
                onError
              });
              break;
            }
          case Type.RAW16:
            {
              deserializeDepthFrameToPointCloud({
                topic,
                message,
                callback
              });
              void deserializeDepthFrame({
                topic,
                message,
                callback,
                maxStereoDepth: maxSteroDepth / 1000
              });
              break;
            }
          default:
            {
              deserializeColorFrame({
                topic,
                message,
                callback
              });
            }
        }
        break;
      }
    case "imageDetections":
      {
        deserializeImgDetections({
          topic,
          message,
          callback,
          topicSizes
        });
        break;
      }
    case "imageDetectionsCustom":
      {
        deserializeImgDetectionsCustom({
          topic,
          message,
          callback,
          topicSizes
        });
        break;
      }
    case "imageDetectionsSpatial":
      {
        // TODO: Use separate 3D detection deserializer
        deserializeImgDetections({
          topic,
          topicSizes,
          message: _objectSpread2(_objectSpread2({}, message), {}, {
            detections: message.detections.map(detections => detections.detection)
          }),
          callback
        });
        break;
      }
    case "pointCloud":
      {
        deserializePointCloudData({
          topic,
          message,
          callback
        });
        break;
      }
    case "imu":
      {
        var _message$tsDevice;
        const {
          receiveTime
        } = parseMessage(message);
        callback({
          topic,
          schemaName: "foxglove.IMU",
          message: message.packets,
          sizeInBytes: message.packets.length * 16,
          //FIXME: This is made up. But is that a issue?
          receiveTime,
          publishTime: (_message$tsDevice = message.tsDevice) !== null && _message$tsDevice !== void 0 ? _message$tsDevice : receiveTime
        });
        break;
      }
    case 'rgbd':
      {
        void deserializeRGBDFrameToPointCloud({
          topic,
          topicDecoders,
          cameraIntrinsics: neuralCameraIntrinsics,
          maxStereoDepth: maxSteroDepth,
          message,
          callback,
          onError
        });
        break;
      }
    default:
      {
        logger.warn(`Message decoding failed: unsupported type "${type}"`);
        throw new UnsupportedTopicError(topic, `Unsupported message type "${type}"`);
      }
  }
}

// Update the exported API

// Expose the updated API
expose({
  initCallback,
  handleMessageToDecode
});

export { errorInstanceToErrorCode };
