import { e as expose } from './comlink-CsH1ih07.js';
import { t as typescript } from './index-CYJDY0hm.js';
import { U as parseMessage, e as estimateObjectSize, V as fromMillis, d as dist, W as parsePixelFormat, X as deserializeDepthFrame } from './depth-CFY2W_Vf.js';
import { P as PointsAnnotationType, p as protobufsBySchema, T as Type, b as Profile } from './protobuf-BFCtaU7c.js';
import { i as isCapableOfEncodedStream } from './encoding-DqlhpFR2.js';
import 'react';
import 'zustand';
import 'react-mosaic-component';
import '@mui/material';
import './isArrayLikeObject-Bytw9p-q.js';
import 'protobufjs/minimal';

// 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);

// 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 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 = [{
  label: "Person",
  ...GROUP_COLORS.entity
}, {
  label: "Bicycle",
  ...GROUP_COLORS.bulk
}, {
  label: "Car",
  ...GROUP_COLORS.bulk
}, {
  label: "Motorbike",
  ...GROUP_COLORS.bulk
}, {
  label: "Aeroplane",
  ...GROUP_COLORS.bulk
}, {
  label: "Bus",
  ...GROUP_COLORS.bulk
}, {
  label: "Train",
  ...GROUP_COLORS.bulk
}, {
  label: "Truck",
  ...GROUP_COLORS.bulk
}, {
  label: "Boat",
  ...GROUP_COLORS.bulk
}, {
  label: "Traffic Light",
  ...GROUP_COLORS.item
}, {
  label: "Fire Hydrant",
  ...GROUP_COLORS.item
}, {
  label: "Stop Sign",
  ...GROUP_COLORS.item
}, {
  label: "Parking Meter",
  ...GROUP_COLORS.item
}, {
  label: "Bench",
  ...GROUP_COLORS.bulk
}, {
  label: "Bird",
  ...GROUP_COLORS.entity
}, {
  label: "Cat",
  ...GROUP_COLORS.entity
}, {
  label: "Dog",
  ...GROUP_COLORS.entity
}, {
  label: "Horse",
  ...GROUP_COLORS.entity
}, {
  label: "Sheep",
  ...GROUP_COLORS.entity
}, {
  label: "Cow",
  ...GROUP_COLORS.entity
}, {
  label: "Elephant",
  ...GROUP_COLORS.entity
}, {
  label: "Bear",
  ...GROUP_COLORS.entity
}, {
  label: "Zebra",
  ...GROUP_COLORS.entity
}, {
  label: "Giraffe",
  ...GROUP_COLORS.entity
}, {
  label: "Backpack",
  ...GROUP_COLORS.item
}, {
  label: "Umbrella",
  ...GROUP_COLORS.item
}, {
  label: "Handbag",
  ...GROUP_COLORS.item
}, {
  label: "Tie",
  ...GROUP_COLORS.item
}, {
  label: "Suitcase",
  ...GROUP_COLORS.item
}, {
  label: "Frisbee",
  ...GROUP_COLORS.item
}, {
  label: "Skis",
  ...GROUP_COLORS.bulk
}, {
  label: "Snowboard",
  ...GROUP_COLORS.bulk
}, {
  label: "Sports Ball",
  ...GROUP_COLORS.item
}, {
  label: "Lite",
  ...GROUP_COLORS.item
}, {
  label: "Baseball Bat",
  ...GROUP_COLORS.item
}, {
  label: "Baseball Glove",
  ...GROUP_COLORS.item
}, {
  label: "Skateboard",
  ...GROUP_COLORS.item
}, {
  label: "Surfboard",
  ...GROUP_COLORS.bulk
}, {
  label: "Tennis Racket",
  ...GROUP_COLORS.item
}, {
  label: "Bottle",
  ...GROUP_COLORS.item
}, {
  label: "Wine Glass",
  ...GROUP_COLORS.item
}, {
  label: "Cup",
  ...GROUP_COLORS.item
}, {
  label: "Fork",
  ...GROUP_COLORS.item
}, {
  label: "Knife",
  ...GROUP_COLORS.item
}, {
  label: "Spoon",
  ...GROUP_COLORS.item
}, {
  label: "Bowl",
  ...GROUP_COLORS.item
}, {
  label: "Banana",
  ...GROUP_COLORS.item
}, {
  label: "Apple",
  ...GROUP_COLORS.item
}, {
  label: "Sandwich",
  ...GROUP_COLORS.item
}, {
  label: "Orange",
  ...GROUP_COLORS.item
}, {
  label: "Broccoli",
  ...GROUP_COLORS.item
}, {
  label: "Carrot",
  ...GROUP_COLORS.item
}, {
  label: "Hot Dog",
  ...GROUP_COLORS.item
}, {
  label: "Pizza",
  ...GROUP_COLORS.item
}, {
  label: "Donut",
  ...GROUP_COLORS.item
}, {
  label: "Cake",
  ...GROUP_COLORS.item
}, {
  label: "Chair",
  ...GROUP_COLORS.bulk
}, {
  label: "Sofa",
  ...GROUP_COLORS.bulk
}, {
  label: "Potted Plant",
  ...GROUP_COLORS.item
}, {
  label: "Bed",
  ...GROUP_COLORS.bulk
}, {
  label: "Diningtable",
  ...GROUP_COLORS.bulk
}, {
  label: "Toilet",
  ...GROUP_COLORS.bulk
}, {
  label: "TV Monitor",
  ...GROUP_COLORS.item
}, {
  label: "Laptop",
  ...GROUP_COLORS.item
}, {
  label: "Mouse",
  ...GROUP_COLORS.item
}, {
  label: "Remote",
  ...GROUP_COLORS.item
}, {
  label: "Keyboard",
  ...GROUP_COLORS.item
}, {
  label: "Cell Phone",
  ...GROUP_COLORS.item
}, {
  label: "Microwave",
  ...GROUP_COLORS.item
}, {
  label: "Oven",
  ...GROUP_COLORS.item
}, {
  label: "Toaster",
  ...GROUP_COLORS.item
}, {
  label: "Sink",
  ...GROUP_COLORS.item
}, {
  label: "Refrigerator",
  ...GROUP_COLORS.bulk
}, {
  label: "Book",
  ...GROUP_COLORS.item
}, {
  label: "Clock",
  ...GROUP_COLORS.item
}, {
  label: "Vase",
  ...GROUP_COLORS.item
}, {
  label: "Scissors",
  ...GROUP_COLORS.item
}, {
  label: "Teddy Bear",
  ...GROUP_COLORS.item
}, {
  label: "Hair Drier",
  ...GROUP_COLORS.item
}, {
  label: "Toothbrush",
  ...GROUP_COLORS.item
}];
const DEBUG_COLOR = {
  r: 0,
  g: 0.5,
  b: 0,
  a: 1
};
const DEFAULT_STYLE = {
  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
}) {
  const {
    receiveTime
  } = parseMessage(message);
  const {
    width,
    height
  } = topicSizes.values().next().value ?? {
    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 => ({
      timestamp: receiveTime,
      type: annotation.type === PointsAnnotationType.UNRECOGNIZED ? typescript.PointsAnnotationType.UNKNOWN : Number(annotation.type),
      points: annotation.points,
      outline_color: annotation.outlineColor ?? DEFAULT_STYLE.outline,
      outline_colors: [],
      fill_color: annotation.fillColor ?? DEFAULT_STYLE.fill,
      thickness: annotation.thickness
    })));
    texts.push(...annotations.texts.map(annotation => ({
      timestamp: receiveTime,
      position: annotation.position ?? {
        x: 0,
        y: 0
      },
      text: annotation.text,
      font_size: annotation.fontSize ?? getTextSize(width, height),
      text_color: annotation.textColor ?? DEFAULT_TEXT_COLOR,
      background_color: annotation.backgroundColor ?? DEFAULT_BACKGROUND_COLOR
    })));
    circles.push(...annotations.circles.map(annotation => ({
      timestamp: receiveTime,
      xMultiplier,
      yMultiplier,
      position: annotation.position ?? {
        x: 0,
        y: 0
      },
      diameter: annotation.diameter,
      thickness: annotation.thickness,
      fill_color: annotation.fillColor ?? DEFAULT_STYLE.fill,
      outline_color: annotation.outlineColor ?? DEFAULT_STYLE.outline
    })));
  }
  const foxgloveMessage = {
    points,
    texts,
    circles
  };
  callback({
    topic,
    receiveTime,
    message: foxgloveMessage,
    sizeInBytes: estimateObjectSize(foxgloveMessage),
    schemaName: "foxglove.ImageAnnotations"
  });
}

// 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 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) {
      const detectionWidth = detection.xmax - detection.xmin;
      const {
        width,
        height
      } = topicSizes.values().next().value ?? {
        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, detection.ymax - detection.ymin);
      const style = DETECTION_STYLE[detection.label] ?? DEFAULT_STYLE;
      if (detection.labelName) {
        style.label = detection.labelName;
      }
      foxgloveMessage.points.push({
        timestamp: receiveTime,
        points: [{
          x: detection.xmin,
          y: detection.ymin
        }, {
          x: detection.xmin,
          y: detection.ymax
        }, {
          x: detection.xmax,
          y: detection.ymax
        }, {
          x: detection.xmax,
          y: detection.ymin
        }],
        type: typescript.PointsAnnotationType.LINE_LOOP,
        outline_colors: [],
        thickness: 0,
        outline_color: DEBUG_COLOR,
        fill_color: style.fill
      });
      const baseHighlightConfig = {
        timestamp: receiveTime,
        type: typescript.PointsAnnotationType.LINE_LIST,
        outline_colors: [],
        thickness: getBorderThickness(width, height),
        outline_color: style.outline,
        fill_color: DEBUG_COLOR
      };
      foxgloveMessage.points.push({
        ...baseHighlightConfig,
        points: [{
          x: detection.xmin,
          y: detection.ymin
        }, {
          x: detection.xmin + highlightSizeX,
          y: detection.ymin
        }]
      });
      foxgloveMessage.points.push({
        ...baseHighlightConfig,
        points: [{
          x: detection.xmin,
          y: detection.ymin
        }, {
          x: detection.xmin,
          y: detection.ymin + highlightSizeY
        }]
      });
      foxgloveMessage.points.push({
        ...baseHighlightConfig,
        points: [{
          x: detection.xmax,
          y: detection.ymin
        }, {
          x: detection.xmax - highlightSizeX,
          y: detection.ymin
        }]
      });
      foxgloveMessage.points.push({
        ...baseHighlightConfig,
        points: [{
          x: detection.xmax,
          y: detection.ymin
        }, {
          x: detection.xmax,
          y: detection.ymin + highlightSizeY
        }]
      });
      foxgloveMessage.points.push({
        ...baseHighlightConfig,
        points: [{
          x: detection.xmax,
          y: detection.ymax
        }, {
          x: detection.xmax - highlightSizeX,
          y: detection.ymax
        }]
      });
      foxgloveMessage.points.push({
        ...baseHighlightConfig,
        points: [{
          x: detection.xmax,
          y: detection.ymax
        }, {
          x: detection.xmax,
          y: detection.ymax - highlightSizeY
        }]
      });
      foxgloveMessage.points.push({
        ...baseHighlightConfig,
        points: [{
          x: detection.xmin,
          y: detection.ymax
        }, {
          x: detection.xmin + highlightSizeX,
          y: detection.ymax
        }]
      });
      foxgloveMessage.points.push({
        ...baseHighlightConfig,
        points: [{
          x: detection.xmin,
          y: detection.ymax
        }, {
          x: detection.xmin,
          y: detection.ymax - highlightSizeY
        }]
      });
      const label = `${style.label ?? `Unknown #${detection.label}`} ${Math.round(detection.confidence * 100)}%`;
      foxgloveMessage.texts.push({
        timestamp: receiveTime,
        position: {
          x: detection.xmin + highligtLength / 2,
          y: detection.ymin + highlightSizeY
        },
        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"
  });
}

// 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"
  });
}

// 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
}) {
  const {
    receiveTime,
    width,
    height
  } = parseMessage(message);
  const foxgloveMessage = {
    timestamp: 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/

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\``;
    console.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/

function bgrxToI420(bgrx, width, height) {
  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 stride = width * 4;
  const clamp8 = x => x < 0 ? 0 : x > 255 ? 255 : x | 0;
  for (let y = 0; y < height; y += 2) {
    const row0 = y * stride;
    const row1 = (y + 1) * stride;
    for (let x = 0; x < width; x += 2) {
      const p00 = row0 + x * 4;
      const p01 = row0 + (x + 1) * 4;
      const p10 = row1 + x * 4;
      const p11 = row1 + (x + 1) * 4;
      const B00 = bgrx[p00 + 0],
        G00 = bgrx[p00 + 1],
        R00 = bgrx[p00 + 2];
      const B01 = bgrx[p01 + 0],
        G01 = bgrx[p01 + 1],
        R01 = bgrx[p01 + 2];
      const B10 = bgrx[p10 + 0],
        G10 = bgrx[p10 + 1],
        R10 = bgrx[p10 + 2];
      const B11 = bgrx[p11 + 0],
        G11 = bgrx[p11 + 1],
        R11 = bgrx[p11 + 2];
      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) {
  const ySize = width * height;
  const uvSize = ySize / 4;
  const i420Buffer = new Uint8Array(ySize + 2 * uvSize);

  // Copy Y plane (it's the same in both formats)
  i420Buffer.set(nv12Buffer.subarray(0, ySize));
  const uPlaneOffset = ySize;
  const vPlaneOffset = ySize + uvSize;

  // De-interleave UV plane
  for (let i = 0; i < uvSize; i++) {
    const uvIndex = ySize + i * 2;
    i420Buffer[uPlaneOffset + i] = nv12Buffer[uvIndex] ?? 0; // U
    i420Buffer[vPlaneOffset + i] = nv12Buffer[uvIndex + 1] ?? 0; // V
  }
  return i420Buffer;
}
function createVideoDecoder$1({
  topic,
  callback,
  topicDecoders
}) {
  return new VideoDecoder({
    output: async frame => {
      let finalBuffer = new Uint8Array(frame.allocationSize());
      if (frame.format === "I420") {
        finalBuffer = new Uint8Array(frame.allocationSize());
        await frame.copyTo(finalBuffer);
      } else if (frame.format === "NV12") {
        const nv12Buffer = new Uint8Array(frame.allocationSize());
        await frame.copyTo(nv12Buffer);
        finalBuffer = convertNv12ToI420(nv12Buffer, frame.codedWidth, frame.codedHeight);
      } else if (frame.format === "RGBX") {
        const bgrxBuffer = new Uint8Array(frame.allocationSize());
        await frame.copyTo(bgrxBuffer);
        console.warn("PointCloud decoder received RGBX frame.");
        finalBuffer = bgrxToI420(bgrxBuffer, frame.codedWidth, frame.codedHeight);
      }
      if (frame.format !== 'I420' && frame.format !== 'NV12' && frame.format !== 'RGBX') {
        console.warn("PointCloud decoder received unexpected frame format:", frame.format);
      }
      const receiveTime = topicDecoders.get(topic)?.timing.get(frame.timestamp) ?? dist.fromMicros(frame.timestamp);
      const foxgloveMessage = {
        timestamp: receiveTime,
        frame_id: `h264-${topic}-frame`,
        width: frame.displayWidth,
        height: frame.displayHeight,
        data: finalBuffer,
        encoding: "yuv420p",
        step: frame.displayWidth
      };
      callback({
        topic,
        receiveTime,
        message: foxgloveMessage,
        sizeInBytes: estimateObjectSize(foxgloveMessage),
        schemaName: "foxglove.RawImage"
      });
      frame.close();
    },
    error: console.error
  });
}
async function deserializeEncodedFrameH264({
  topic,
  message,
  topicDecoders,
  callback
}) {
  const {
    receiveTime
  } = parseMessage(message);
  const supported = ensureWebCodecsSupported("VideoDecoder");
  if (!supported) {
    return;
  }
  if (!topicDecoders.has(topic)) {
    const decoder = createVideoDecoder$1({
      topic,
      callback,
      topicDecoders
    });
    decoder.configure({
      codec: "avc1.42001E",
      optimizeForLatency: true
    });
    topicDecoders.set(topic, {
      decoder,
      timing: new Map()
    });
  }
  const decoderInfo = topicDecoders.get(topic);
  if (!decoderInfo) {
    return;
  }
  if (decoderInfo.decoder.decodeQueueSize > 60) {
    decoderInfo.decoder.reset();
    return;
  }
  const microTimestamp = receiveTime.sec * 1_000_000 + Math.floor(receiveTime.nsec / 1_000);
  decoderInfo.timing.set(microTimestamp, receiveTime);
  const frame = {
    type: 'key',
    data: message.data,
    timestamp: microTimestamp
  };
  try {
    const chunk = new EncodedVideoChunk(frame);
    decoderInfo.decoder.decode(chunk);
  } catch {
    topicDecoders.delete(topic);
  }
}

// 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 createVideoDecoder({
  topic,
  callback,
  topicDecoders
}) {
  return new VideoDecoder({
    output: async frame => {
      const buffer = new Uint8Array(frame.allocationSize());
      await frame.copyTo(buffer);
      const receiveTime = topicDecoders.get(topic)?.timing.get(frame.timestamp) ?? dist.fromMicros(frame.timestamp);
      const [encoding, step] = parsePixelFormat(frame.format);
      const foxgloveMessage = {
        timestamp: receiveTime,
        frame_id: `h265-${topic}-frame`,
        width: frame.displayWidth,
        height: frame.displayHeight,
        data: buffer,
        encoding,
        step: frame.displayWidth * step
      };
      callback({
        topic,
        receiveTime,
        message: foxgloveMessage,
        sizeInBytes: estimateObjectSize(foxgloveMessage),
        schemaName: "foxglove.RawImage"
      });
      frame.close();
    },
    error: console.error
  });
}
async function deserializeEncodedFrameH265({
  topic,
  message,
  topicDecoders,
  callback
}) {
  const {
    receiveTime
  } = parseMessage(message);
  const supported = ensureWebCodecsSupported("VideoDecoder");
  if (!supported) {
    return;
  }
  if (!topicDecoders.has(topic)) {
    const decoder = createVideoDecoder({
      topic,
      callback,
      topicDecoders
    });
    decoder.configure({
      codec: "hev1.1.6.L93.B0",
      optimizeForLatency: true
    });
    topicDecoders.set(topic, {
      decoder,
      timing: new Map()
    });
  }
  const decoderInfo = topicDecoders.get(topic);
  if (!decoderInfo) {
    return;
  }
  if (decoderInfo.decoder.decodeQueueSize > 60) {
    decoderInfo.decoder.reset();
    return;
  }
  const microTimestamp = receiveTime.sec * 1_000_000 + Math.floor(receiveTime.nsec / 1_000);
  decoderInfo.timing.set(microTimestamp, receiveTime);
  const frame = {
    type: 'key',
    data: message.data,
    timestamp: microTimestamp
  };
  try {
    const chunk = new EncodedVideoChunk(frame);
    decoderInfo.decoder.decode(chunk);
  } catch {
    topicDecoders.delete(topic);
  }
}

// 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 buffer = new Uint8Array(frame.allocationSize());
  await frame.copyTo(buffer);
  const [encoding, step] = parsePixelFormat(frame.format);
  const foxgloveMessage = {
    timestamp: receiveTime,
    frame_id: "camera",
    width: frame.displayWidth,
    height: frame.displayHeight,
    data: buffer,
    encoding,
    step: frame.displayWidth * step
  };
  frame.close();
  callback({
    topic,
    receiveTime,
    message: foxgloveMessage,
    sizeInBytes: estimateObjectSize(foxgloveMessage),
    schemaName: "foxglove.RawImage"
  });
}

class EncodedStreamNotSupportedError extends Error {
  name = "EncodedStreamNotSupportedError";
  errorType = "EncodedStreamNotSupportedError";
  constructor(topicName) {
    super("Encoded stream not supported on this platform");
    this.topicName = topicName;
    Object.setPrototypeOf(this, EncodedStreamNotSupportedError.prototype);
  }
}

// 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 errorInstanceToErrorCode(error) {
  if (error instanceof EncodedStreamNotSupportedError) {
    return "EncodedStreamNotSupported";
  }
  return "Error";
}
const topicDecoders = new Map();
const topicSizes = new Map();
let callback;
function initCallback(cb) {
  callback = cb;
}
function handleMessageToDecode({
  schema,
  buffer,
  topic,
  stereoDepthMaxValue
}, configStore, errorCallback) {
  const handleDecodingError = error => {
    // TODO: Enable this log once we fix topic unsubscription not working
    // console.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?.(errorInstanceToErrorCode(error), topic, {});
  };
  const protobufSchema = protobufsBySchema[schema];
  if (!protobufSchema) {
    console.warn(`Unsupported message schema "${schema}"`);
    handleDecodingError(new Error(`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) {
      console.debug(`[DepthAI Deserialization] Received message of type ${protobufSchema.type} on topic ${topic}`, {
        message
      });
    }

    // Handle the promise correctly
    deserializeDepthAiMessage({
      topic,
      topicSizes,
      topicDecoders,
      message,
      callback,
      type: protobufSchema.type,
      maxSteroDepth: stereoDepthMaxValue
    }).catch(handleDecodingError);
  } catch (error) {
    handleDecodingError(error);
  }
}
async function deserializeDepthAiMessage(args) {
  // eslint-disable-next-line @typescript-eslint/no-shadow
  const {
    topicDecoders,
    topicSizes,
    type,
    message,
    callback,
    topic,
    maxSteroDepth
  } = args;
  switch (type) {
    case "encodedFrame":
      {
        if (!isCapableOfEncodedStream()) {
          throw new EncodedStreamNotSupportedError(topic);
        }
        topicSizes.set(topic, {
          width: message.width,
          height: message.height
        });
        if (message.profile === Profile.AVC) {
          await deserializeEncodedFrameH264({
            topic,
            message,
            topicDecoders,
            callback
          });
        } else if (message.profile === Profile.JPEG) {
          await deserializeMJPEGFrame({
            topic,
            message,
            callback
          });
        } else if (message.profile === Profile.HEVC) {
          await deserializeEncodedFrameH265({
            topic,
            message,
            topicDecoders,
            callback
          });
        } else ;
        break;
      }
    case "imageFrame":
      {
        const {
          width,
          height,
          type: messageType
        } = parseMessage(message);
        topicSizes.set(topic, {
          width,
          height
        });
        switch (messageType) {
          case Type.BITSTREAM:
            {
              await deserializeEncodedFrameH264({
                topic,
                message,
                topicDecoders,
                callback
              });
              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: {
            ...message,
            detections: message.detections.map(detections => detections.detection)
          },
          callback
        });
        break;
      }
    case "pointCloud":
      {
        deserializePointCloudData({
          topic,
          message,
          callback
        });
        break;
      }
    case "imu":
      {
        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 ?? receiveTime
        });
        break;
      }
    default:
      {
        console.warn(`Message decoding failed: unsupported type "${type}"`);
        break;
      }
  }
}

// Update the exported API

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

export { errorInstanceToErrorCode };
