Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
76 changes: 50 additions & 26 deletions apps/desktop/src/utils/socket.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,34 +27,58 @@ export function createImageDataWS(
ws.onmessage = (event) => {
const buffer = event.data as ArrayBuffer;
const clamped = new Uint8ClampedArray(buffer);
if (clamped.length < 12) {
console.error("Received frame too small to contain metadata");
return;
}

const widthArr = clamped.slice(clamped.length - 4);
const heightArr = clamped.slice(clamped.length - 8, clamped.length - 4);
const strideArr = clamped.slice(clamped.length - 12, clamped.length - 8);

const width =
widthArr[0] +
(widthArr[1] << 8) +
(widthArr[2] << 16) +
(widthArr[3] << 24);
const height =
heightArr[0] +
(heightArr[1] << 8) +
(heightArr[2] << 16) +
(heightArr[3] << 24);
const stride =
(strideArr[0] +
(strideArr[1] << 8) +
(strideArr[2] << 16) +
(strideArr[3] << 24)) /
4;

const imageData = new ImageData(
clamped.slice(0, clamped.length - 12),
stride,
height,
);
const metadataOffset = clamped.length - 12;
const meta = new DataView(buffer, metadataOffset, 12);
const strideBytes = meta.getUint32(0, true);
const height = meta.getUint32(4, true);
const width = meta.getUint32(8, true);

if (!width || !height) {
console.error("Received invalid frame dimensions", { width, height });
return;
}

const source = clamped.subarray(0, metadataOffset);
const expectedRowBytes = width * 4;
const expectedLength = expectedRowBytes * height;
const availableLength = strideBytes * height;

if (
strideBytes === 0 ||
strideBytes < expectedRowBytes ||
source.length < availableLength
) {
console.error("Received invalid frame stride", {
strideBytes,
expectedRowBytes,
height,
sourceLength: source.length,
});
return;
}

let pixels: Uint8ClampedArray;

if (strideBytes === expectedRowBytes) {
pixels = source.subarray(0, expectedLength);
} else {
pixels = new Uint8ClampedArray(expectedLength);
for (let row = 0; row < height; row += 1) {
const srcStart = row * strideBytes;
const destStart = row * expectedRowBytes;
pixels.set(
source.subarray(srcStart, srcStart + expectedRowBytes),
destStart,
);
}
}

const imageData = new ImageData(pixels, width, height);
onmessage({ width, data: imageData });
};

Expand Down