mirror of
https://github.com/arcodange-org/mediabunny.git
synced 2026-09-27 02:43:48 +02:00
98 lines
1.9 KiB
TypeScript
98 lines
1.9 KiB
TypeScript
/*!
|
|
* Copyright (c) 2026-present, Vanilagy and contributors
|
|
*
|
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
*/
|
|
|
|
export class Bitstream {
|
|
/** Current offset in bits. */
|
|
pos = 0;
|
|
|
|
constructor(public bytes: Uint8Array) {}
|
|
|
|
seekToByte(byteOffset: number) {
|
|
this.pos = 8 * byteOffset;
|
|
}
|
|
|
|
private readBit() {
|
|
const byteIndex = Math.floor(this.pos / 8);
|
|
const byte = this.bytes[byteIndex] ?? 0;
|
|
const bitIndex = 0b111 - (this.pos & 0b111);
|
|
const bit = (byte & (1 << bitIndex)) >> bitIndex;
|
|
|
|
this.pos++;
|
|
return bit;
|
|
}
|
|
|
|
readBits(n: number) {
|
|
if (n === 1) {
|
|
return this.readBit();
|
|
}
|
|
|
|
let result = 0;
|
|
|
|
for (let i = 0; i < n; i++) {
|
|
result <<= 1;
|
|
result |= this.readBit();
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
writeBits(n: number, value: number) {
|
|
const end = this.pos + n;
|
|
|
|
for (let i = this.pos; i < end; i++) {
|
|
const byteIndex = Math.floor(i / 8);
|
|
let byte = this.bytes[byteIndex]!;
|
|
const bitIndex = 0b111 - (i & 0b111);
|
|
|
|
byte &= ~(1 << bitIndex);
|
|
byte |= ((value & (1 << (end - i - 1))) >> (end - i - 1)) << bitIndex;
|
|
this.bytes[byteIndex] = byte;
|
|
}
|
|
|
|
this.pos = end;
|
|
}
|
|
|
|
copyBits(n: number, other: Bitstream) {
|
|
let i = 0;
|
|
for (i; i < n - 7; i += 8) {
|
|
this.writeBits(8, other.readBits(8));
|
|
}
|
|
|
|
const leftover = n - i;
|
|
if (leftover > 0) {
|
|
this.writeBits(leftover, other.readBits(leftover));
|
|
}
|
|
}
|
|
|
|
readAlignedByte() {
|
|
if (this.pos % 8 !== 0) {
|
|
throw new Error('Bitstream is not byte-aligned.');
|
|
}
|
|
|
|
const byteIndex = this.pos / 8;
|
|
const byte = this.bytes[byteIndex] ?? 0;
|
|
|
|
this.pos += 8;
|
|
return byte;
|
|
}
|
|
|
|
skipBits(n: number) {
|
|
this.pos += n;
|
|
}
|
|
|
|
getBitsLeft() {
|
|
return this.bytes.length * 8 - this.pos;
|
|
}
|
|
|
|
clone() {
|
|
const clone = new Bitstream(this.bytes);
|
|
clone.pos = this.pos;
|
|
return clone;
|
|
}
|
|
}
|