mirror of
https://github.com/bytedance/xgplayer.git
synced 2025-04-05 03:05:02 +08:00
116 lines
3.7 KiB
JavaScript
116 lines
3.7 KiB
JavaScript
/*
|
|
* Copyright (C) 2016 Bilibili. All Rights Reserved.
|
|
*
|
|
* @author zheng qian <xqq@xqq.im>
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
import {IllegalStateException, InvalidArgumentException} from '../utils/exception.js';
|
|
|
|
// Exponential-Golomb buffer decoder
|
|
class ExpGolomb {
|
|
|
|
constructor(uint8array) {
|
|
this.TAG = 'ExpGolomb';
|
|
|
|
this._buffer = uint8array;
|
|
this._buffer_index = 0;
|
|
this._total_bytes = uint8array.byteLength;
|
|
this._total_bits = uint8array.byteLength * 8;
|
|
this._current_word = 0;
|
|
this._current_word_bits_left = 0;
|
|
}
|
|
|
|
destroy() {
|
|
this._buffer = null;
|
|
}
|
|
|
|
_fillCurrentWord() {
|
|
let buffer_bytes_left = this._total_bytes - this._buffer_index;
|
|
if (buffer_bytes_left <= 0)
|
|
throw new IllegalStateException('ExpGolomb: _fillCurrentWord() but no bytes available');
|
|
|
|
let bytes_read = Math.min(4, buffer_bytes_left);
|
|
let word = new Uint8Array(4);
|
|
word.set(this._buffer.subarray(this._buffer_index, this._buffer_index + bytes_read));
|
|
this._current_word = new DataView(word.buffer).getUint32(0, false);
|
|
|
|
this._buffer_index += bytes_read;
|
|
this._current_word_bits_left = bytes_read * 8;
|
|
}
|
|
|
|
readBits(bits) {
|
|
if (bits > 32)
|
|
throw new InvalidArgumentException('ExpGolomb: readBits() bits exceeded max 32bits!');
|
|
|
|
if (bits <= this._current_word_bits_left) {
|
|
let result = this._current_word >>> (32 - bits);
|
|
this._current_word <<= bits;
|
|
this._current_word_bits_left -= bits;
|
|
return result;
|
|
}
|
|
|
|
let result = this._current_word_bits_left ? this._current_word : 0;
|
|
result = result >>> (32 - this._current_word_bits_left);
|
|
let bits_need_left = bits - this._current_word_bits_left;
|
|
|
|
this._fillCurrentWord();
|
|
let bits_read_next = Math.min(bits_need_left, this._current_word_bits_left);
|
|
|
|
let result2 = this._current_word >>> (32 - bits_read_next);
|
|
this._current_word <<= bits_read_next;
|
|
this._current_word_bits_left -= bits_read_next;
|
|
|
|
result = (result << bits_read_next) | result2;
|
|
return result;
|
|
}
|
|
|
|
readBool() {
|
|
return this.readBits(1) === 1;
|
|
}
|
|
|
|
readByte() {
|
|
return this.readBits(8);
|
|
}
|
|
|
|
_skipLeadingZero() {
|
|
let zero_count;
|
|
for (zero_count = 0; zero_count < this._current_word_bits_left; zero_count++) {
|
|
if (0 !== (this._current_word & (0x80000000 >>> zero_count))) {
|
|
this._current_word <<= zero_count;
|
|
this._current_word_bits_left -= zero_count;
|
|
return zero_count;
|
|
}
|
|
}
|
|
this._fillCurrentWord();
|
|
return zero_count + this._skipLeadingZero();
|
|
}
|
|
|
|
readUEG() { // unsigned exponential golomb
|
|
let leading_zeros = this._skipLeadingZero();
|
|
return this.readBits(leading_zeros + 1) - 1;
|
|
}
|
|
|
|
readSEG() { // signed exponential golomb
|
|
let value = this.readUEG();
|
|
if (value & 0x01) {
|
|
return (value + 1) >>> 1;
|
|
} else {
|
|
return -1 * (value >>> 1);
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
export default ExpGolomb; |