export const PIXEL_FRAME_HEADER_SIZE = 16;
export interface Pixel_Frame {width: number; height: number; stride: number; pixels: Uint8Array;}

export function decode_pixel_frame(buffer: ArrayBuffer): Pixel_Frame {
    if (buffer.byteLength < PIXEL_FRAME_HEADER_SIZE) throw new Error("RVP1 frame is shorter than its header");
    const bytes = new Uint8Array(buffer);
    if (String.fromCharCode(...bytes.subarray(0, 4)) !== "RVP1") throw new Error("RVP1 magic is invalid");
    const view = new DataView(buffer, 0, PIXEL_FRAME_HEADER_SIZE);
    const width = view.getUint32(4, true), height = view.getUint32(8, true), stride = view.getUint32(12, true);
    if (!width || !height || stride < width * 4) throw new Error("RVP1 dimensions or stride are invalid");
    const payload_size = stride * height;
    if (!Number.isSafeInteger(payload_size) || buffer.byteLength < PIXEL_FRAME_HEADER_SIZE + payload_size) throw new Error("RVP1 pixel payload is truncated");
    return {width, height, stride, pixels: bytes.subarray(PIXEL_FRAME_HEADER_SIZE, PIXEL_FRAME_HEADER_SIZE + payload_size)};
}
export function pack_pixel_rows(frame: Pixel_Frame): Uint8ClampedArray {
    const row_size = frame.width * 4;
    if (frame.stride === row_size) return new Uint8ClampedArray(frame.pixels.buffer, frame.pixels.byteOffset, row_size * frame.height);
    const packed = new Uint8ClampedArray(row_size * frame.height);
    for (let row = 0; row < frame.height; row++) packed.set(frame.pixels.subarray(row * frame.stride, row * frame.stride + row_size), row * row_size);
    return packed;
}
