function ExpGolomInit(view: DataView, bitoffset: number): { zeros: number; skip: number; byt: number; byteoffset: number } { let bit = 0; let byteoffset = bitoffset >> 3; let skip = bitoffset & 7; let zeros = -1; let byt = view.getUint8(byteoffset) << skip; do { bit = byt & 0x80; byt <<= 1; zeros++; skip++; if (skip === 8) { skip = 0; byteoffset++; byt = view.getUint8(byteoffset); } } while (!bit); return { zeros, skip, byt, byteoffset }; } const shift16 = 2 ** 16; export class Bitstream { public bitoffset = 0; constructor (public view: DataView) {} ExpGolomb(): number { const { view } = this; let { zeros, skip, byt, byteoffset, } = ExpGolomInit(view, this.bitoffset); let code = 1; while (zeros > 0) { code = (code << 1) | ((byt & 0x80) >>> 7); byt <<= 1; skip++; zeros--; if (skip === 8) { skip = 0; byteoffset++; byt = view.getUint8(byteoffset); } } this.bitoffset = (byteoffset << 3) | skip; return code - 1; } SignedExpGolomb(): number { const code = this.ExpGolomb(); return code & 1 ? (code + 1) >>> 1 : -(code >>> 1); } readBit(): 0 | 1 { const skip = this.bitoffset & 7; const byteoffset = this.bitoffset >> 3; this.bitoffset++; return ((this.view.getUint8(byteoffset) >>> (7 - skip)) & 1) as 0|1; } readByte(): number { const skip = this.bitoffset & 7; const byteoffset = this.bitoffset >>> 3; this.bitoffset += 8; const high = this.view.getUint8(byteoffset); if (skip === 0) return high; const low = this.view.getUint8(byteoffset + 1); return (high << skip) | (low >>> (8 - skip)); } readNibble(): number { const skip = this.bitoffset & 7; const byteoffset = this.bitoffset >> 3; this.bitoffset += 4 const high = this.view.getUint8(byteoffset); if (skip === 0) return high >>> 4; if (skip <= 4) return (high >>> (4 - skip)) & 0xf; const low = this.view.getUint8(byteoffset + 1); return ((high << (skip - 4)) | (low >>> (12 - skip))) & 0xf; } read5(): number { const skip = this.bitoffset & 7; const byteoffset = this.bitoffset >> 3; this.bitoffset += 5; const high = this.view.getUint8(byteoffset); if (skip === 0) return high >>> 3; if (skip <= 3) return (high >>> (3 - skip)) & 0x1f; const low = this.view.getUint8(byteoffset + 1); return ((high << (skip - 3)) | (low >>> (11 - skip))) & 0x1f; } readWord(): number { const skip = this.bitoffset & 7; const byteoffset = this.bitoffset >>> 3; this.bitoffset += 32; const { view } = this; const tmp = (view.getUint16(byteoffset) * shift16) + view.getUint16(byteoffset + 2); if (skip === 0) return tmp; return (tmp * (2 ** skip)) + (view.getUint8(byteoffset + 4) >>> (8 - skip)); } more_rbsp_data(): boolean { const skip = this.bitoffset & 7; let byteoffset = this.bitoffset >> 3; const l = this.view.byteLength; if (byteoffset >= l) return false; let byte = (this.view.getUint8(byteoffset) << skip) & 0xff; let found_bit = byte > 0; if (found_bit && !Number.isInteger(Math.log2(byte))) return true; while (++byteoffset < l) { byte = this.view.getUint8(byteoffset); const has_bit = byte > 0; if (found_bit && has_bit) return true; if (has_bit && !Number.isInteger(Math.log2(byte))) return true; found_bit = found_bit || has_bit; } return false; } }