blob: d2c622d938f49574c1ab80108776f362d3ec4526 [file] [log] [blame]
/*
* Copyright 2021 The WebRTC Project Authors. All rights reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include "rtc_base/bitstream_reader.h"
#include <stdint.h>
#include <limits>
#include "absl/numeric/bits.h"
#include "rtc_base/checks.h"
#include "rtc_base/numerics/safe_conversions.h"
namespace webrtc {
uint64_t BitstreamReader::ReadBits(int bits) {
RTC_DCHECK_GE(bits, 0);
RTC_DCHECK_LE(bits, 64);
set_last_read_is_verified(false);
if (remaining_bits_ < bits) {
remaining_bits_ -= bits;
return 0;
}
int remaining_bits_in_first_byte = remaining_bits_ % 8;
remaining_bits_ -= bits;
if (bits < remaining_bits_in_first_byte) {
// Reading fewer bits than what's left in the current byte, just
// return the portion of this byte that is needed.
int offset = (remaining_bits_in_first_byte - bits);
return ((*bytes_) >> offset) & ((1 << bits) - 1);
}
uint64_t result = 0;
if (remaining_bits_in_first_byte > 0) {
// Read all bits that were left in the current byte and consume that byte.
bits -= remaining_bits_in_first_byte;
uint8_t mask = (1 << remaining_bits_in_first_byte) - 1;
result = static_cast<uint64_t>(*bytes_ & mask) << bits;
++bytes_;
}
// Read as many full bytes as we can.
while (bits >= 8) {
bits -= 8;
result |= uint64_t{*bytes_} << bits;
++bytes_;
}
// Whatever is left to read is smaller than a byte, so grab just the needed
// bits and shift them into the lowest bits.
if (bits > 0) {
result |= (*bytes_ >> (8 - bits));
}
return result;
}
int BitstreamReader::ReadBit() {
set_last_read_is_verified(false);
--remaining_bits_;
if (remaining_bits_ < 0) {
return 0;
}
int bit_position = remaining_bits_ % 8;
if (bit_position == 0) {
// Read the last bit from current byte and move to the next byte.
return (*bytes_++) & 0x01;
}
return (*bytes_ >> bit_position) & 0x01;
}
void BitstreamReader::ConsumeBits(int bits) {
RTC_DCHECK_GE(bits, 0);
set_last_read_is_verified(false);
if (remaining_bits_ < bits) {
Invalidate();
return;
}
int remaining_bytes = (remaining_bits_ + 7) / 8;
remaining_bits_ -= bits;
int new_remaining_bytes = (remaining_bits_ + 7) / 8;
bytes_ += (remaining_bytes - new_remaining_bytes);
}
uint32_t BitstreamReader::ReadNonSymmetric(uint32_t num_values) {
RTC_DCHECK_GT(num_values, 0);
RTC_DCHECK_LE(num_values, uint32_t{1} << 31);
int width = absl::bit_width(num_values);
uint32_t num_min_bits_values = (uint32_t{1} << width) - num_values;
uint64_t val = ReadBits(width - 1);
if (val < num_min_bits_values) {
return val;
}
return (val << 1) + ReadBit() - num_min_bits_values;
}
uint32_t BitstreamReader::ReadExponentialGolomb() {
// Count the number of leading 0.
int zero_bit_count = 0;
while (ReadBit() == 0) {
if (++zero_bit_count >= 32) {
// Golob value won't fit into 32 bits of the return value. Fail the parse.
Invalidate();
return 0;
}
}
// The bit count of the value is the number of zeros + 1.
// However the first '1' was already read above.
return (uint32_t{1} << zero_bit_count) +
rtc::dchecked_cast<uint32_t>(ReadBits(zero_bit_count)) - 1;
}
int BitstreamReader::ReadSignedExponentialGolomb() {
uint32_t unsigned_val = ReadExponentialGolomb();
if ((unsigned_val & 1) == 0) {
return -static_cast<int>(unsigned_val / 2);
} else {
return (unsigned_val + 1) / 2;
}
}
} // namespace webrtc