diff --git a/rtc_base/bit_buffer.cc b/rtc_base/bit_buffer.cc index a73ef5d869..7dc7428fe9 100644 --- a/rtc_base/bit_buffer.cc +++ b/rtc_base/bit_buffer.cc @@ -18,21 +18,6 @@ namespace { -// Returns the lowest (right-most) `bit_count` bits in `byte`. -uint8_t LowestBits(uint8_t byte, size_t bit_count) { - RTC_DCHECK_LE(bit_count, 8); - return byte & ((1 << bit_count) - 1); -} - -// Returns the highest (left-most) `bit_count` bits in `byte`, shifted to the -// lowest bits (to the right). -uint8_t HighestBits(uint8_t byte, size_t bit_count) { - RTC_DCHECK_LE(bit_count, 8); - uint8_t shift = 8 - static_cast(bit_count); - uint8_t mask = 0xFF << shift; - return (byte & mask) >> shift; -} - // Returns the highest byte of `val` in a uint8_t. uint8_t HighestByte(uint64_t val) { return static_cast(val >> 56); @@ -64,121 +49,24 @@ uint8_t WritePartialByte(uint8_t source, namespace rtc { -BitBuffer::BitBuffer(const uint8_t* bytes, size_t byte_count) - : bytes_(bytes), byte_count_(byte_count), byte_offset_(), bit_offset_() { +BitBufferWriter::BitBufferWriter(uint8_t* bytes, size_t byte_count) + : writable_bytes_(bytes), + byte_count_(byte_count), + byte_offset_(), + bit_offset_() { RTC_DCHECK(static_cast(byte_count_) <= std::numeric_limits::max()); } -uint64_t BitBuffer::RemainingBitCount() const { +uint64_t BitBufferWriter::RemainingBitCount() const { return (static_cast(byte_count_) - byte_offset_) * 8 - bit_offset_; } -bool BitBuffer::ReadUInt8(uint8_t& val) { - uint32_t bit_val; - if (!ReadBits(sizeof(uint8_t) * 8, bit_val)) { - return false; - } - RTC_DCHECK(bit_val <= std::numeric_limits::max()); - val = static_cast(bit_val); - return true; -} - -bool BitBuffer::ReadUInt16(uint16_t& val) { - uint32_t bit_val; - if (!ReadBits(sizeof(uint16_t) * 8, bit_val)) { - return false; - } - RTC_DCHECK(bit_val <= std::numeric_limits::max()); - val = static_cast(bit_val); - return true; -} - -bool BitBuffer::ReadUInt32(uint32_t& val) { - return ReadBits(sizeof(uint32_t) * 8, val); -} - -bool BitBuffer::PeekBits(size_t bit_count, uint32_t& val) { - // TODO(nisse): Could allow bit_count == 0 and always return success. But - // current code reads one byte beyond end of buffer in the case that - // RemainingBitCount() == 0 and bit_count == 0. - RTC_DCHECK(bit_count > 0); - if (bit_count > RemainingBitCount() || bit_count > 32) { - return false; - } - const uint8_t* bytes = bytes_ + byte_offset_; - size_t remaining_bits_in_current_byte = 8 - bit_offset_; - uint32_t bits = LowestBits(*bytes++, remaining_bits_in_current_byte); - // If we're reading fewer bits than what's left in the current byte, just - // return the portion of this byte that we need. - if (bit_count < remaining_bits_in_current_byte) { - val = HighestBits(bits, bit_offset_ + bit_count); - return true; - } - // Otherwise, subtract what we've read from the bit count and read as many - // full bytes as we can into bits. - bit_count -= remaining_bits_in_current_byte; - while (bit_count >= 8) { - bits = (bits << 8) | *bytes++; - bit_count -= 8; - } - // Whatever we have left is smaller than a byte, so grab just the bits we need - // and shift them into the lowest bits. - if (bit_count > 0) { - bits <<= bit_count; - bits |= HighestBits(*bytes, bit_count); - } - val = bits; - return true; -} - -bool BitBuffer::PeekBits(size_t bit_count, uint64_t& val) { - // TODO(nisse): Could allow bit_count == 0 and always return success. But - // current code reads one byte beyond end of buffer in the case that - // RemainingBitCount() == 0 and bit_count == 0. - RTC_DCHECK(bit_count > 0); - if (bit_count > RemainingBitCount() || bit_count > 64) { - return false; - } - const uint8_t* bytes = bytes_ + byte_offset_; - size_t remaining_bits_in_current_byte = 8 - bit_offset_; - uint64_t bits = LowestBits(*bytes++, remaining_bits_in_current_byte); - // If we're reading fewer bits than what's left in the current byte, just - // return the portion of this byte that we need. - if (bit_count < remaining_bits_in_current_byte) { - val = HighestBits(bits, bit_offset_ + bit_count); - return true; - } - // Otherwise, subtract what we've read from the bit count and read as many - // full bytes as we can into bits. - bit_count -= remaining_bits_in_current_byte; - while (bit_count >= 8) { - bits = (bits << 8) | *bytes++; - bit_count -= 8; - } - // Whatever we have left is smaller than a byte, so grab just the bits we need - // and shift them into the lowest bits. - if (bit_count > 0) { - bits <<= bit_count; - bits |= HighestBits(*bytes, bit_count); - } - val = bits; - return true; -} - -bool BitBuffer::ReadBits(size_t bit_count, uint32_t& val) { - return PeekBits(bit_count, val) && ConsumeBits(bit_count); -} - -bool BitBuffer::ReadBits(size_t bit_count, uint64_t& val) { - return PeekBits(bit_count, val) && ConsumeBits(bit_count); -} - -bool BitBuffer::ConsumeBytes(size_t byte_count) { +bool BitBufferWriter::ConsumeBytes(size_t byte_count) { return ConsumeBits(byte_count * 8); } -bool BitBuffer::ConsumeBits(size_t bit_count) { +bool BitBufferWriter::ConsumeBits(size_t bit_count) { if (bit_count > RemainingBitCount()) { return false; } @@ -188,86 +76,15 @@ bool BitBuffer::ConsumeBits(size_t bit_count) { return true; } -bool BitBuffer::ReadNonSymmetric(uint32_t num_values, uint32_t& val) { - RTC_DCHECK_GT(num_values, 0); - RTC_DCHECK_LE(num_values, uint32_t{1} << 31); - if (num_values == 1) { - // When there is only one possible value, it requires zero bits to store it. - // But ReadBits doesn't support reading zero bits. - val = 0; - return true; - } - size_t count_bits = absl::bit_width(num_values); - uint32_t num_min_bits_values = (uint32_t{1} << count_bits) - num_values; - - if (!ReadBits(count_bits - 1, val)) { - return false; - } - - if (val < num_min_bits_values) { - return true; - } - - uint32_t extra_bit; - if (!ReadBits(/*bit_count=*/1, extra_bit)) { - return false; - } - - val = (val << 1) + extra_bit - num_min_bits_values; - return true; -} - -bool BitBuffer::ReadExponentialGolomb(uint32_t& val) { - // Store off the current byte/bit offset, in case we want to restore them due - // to a failed parse. - size_t original_byte_offset = byte_offset_; - size_t original_bit_offset = bit_offset_; - - // Count the number of leading 0 bits by peeking/consuming them one at a time. - size_t zero_bit_count = 0; - uint32_t peeked_bit; - while (PeekBits(1, peeked_bit) && peeked_bit == 0) { - zero_bit_count++; - ConsumeBits(1); - } - - // We should either be at the end of the stream, or the next bit should be 1. - RTC_DCHECK(!PeekBits(1, peeked_bit) || peeked_bit == 1); - - // The bit count of the value is the number of zeros + 1. Make sure that many - // bits fits in a uint32_t and that we have enough bits left for it, and then - // read the value. - size_t value_bit_count = zero_bit_count + 1; - if (value_bit_count > 32 || !ReadBits(value_bit_count, val)) { - RTC_CHECK(Seek(original_byte_offset, original_bit_offset)); - return false; - } - val -= 1; - return true; -} - -bool BitBuffer::ReadSignedExponentialGolomb(int32_t& val) { - uint32_t unsigned_val; - if (!ReadExponentialGolomb(unsigned_val)) { - return false; - } - if ((unsigned_val & 1) == 0) { - val = -static_cast(unsigned_val / 2); - } else { - val = (unsigned_val + 1) / 2; - } - return true; -} - -void BitBuffer::GetCurrentOffset(size_t* out_byte_offset, - size_t* out_bit_offset) { +void BitBufferWriter::GetCurrentOffset(size_t* out_byte_offset, + size_t* out_bit_offset) { RTC_CHECK(out_byte_offset != nullptr); RTC_CHECK(out_bit_offset != nullptr); *out_byte_offset = byte_offset_; *out_bit_offset = bit_offset_; } -bool BitBuffer::Seek(size_t byte_offset, size_t bit_offset) { +bool BitBufferWriter::Seek(size_t byte_offset, size_t bit_offset) { if (byte_offset > byte_count_ || bit_offset > 7 || (byte_offset == byte_count_ && bit_offset > 0)) { return false; @@ -277,9 +94,6 @@ bool BitBuffer::Seek(size_t byte_offset, size_t bit_offset) { return true; } -BitBufferWriter::BitBufferWriter(uint8_t* bytes, size_t byte_count) - : BitBuffer(bytes, byte_count), writable_bytes_(bytes) {} - bool BitBufferWriter::WriteUInt8(uint8_t val) { return WriteBits(val, sizeof(uint8_t) * 8); } diff --git a/rtc_base/bit_buffer.h b/rtc_base/bit_buffer.h index 57366161c9..5375550608 100644 --- a/rtc_base/bit_buffer.h +++ b/rtc_base/bit_buffer.h @@ -14,21 +14,18 @@ #include // For size_t. #include // For integer types. -#include "absl/base/attributes.h" #include "rtc_base/constructor_magic.h" namespace rtc { -// A class, similar to ByteBuffer, that can parse bit-sized data out of a set of -// bytes. Has a similar API to ByteBuffer, plus methods for reading bit-sized -// and exponential golomb encoded data. For a writable version, use -// BitBufferWriter. Unlike ByteBuffer, this class doesn't make a copy of the -// source bytes, so it can be used on read-only data. +// A BitBuffer API for write operations. Supports symmetric write APIs to the +// reading APIs of BitstreamReader. // Sizes/counts specify bits/bytes, for clarity. // Byte order is assumed big-endian/network. -class BitBuffer { +class BitBufferWriter { public: - BitBuffer(const uint8_t* bytes, size_t byte_count); + // Constructs a bit buffer for the writable buffer of `bytes`. + BitBufferWriter(uint8_t* bytes, size_t byte_count); // Gets the current offset, in bytes/bits, from the start of the buffer. The // bit offset is the offset into the current byte, in the range [0,7]. @@ -37,75 +34,6 @@ class BitBuffer { // The remaining bits in the byte buffer. uint64_t RemainingBitCount() const; - // Reads byte-sized values from the buffer. Returns false if there isn't - // enough data left for the specified type. - bool ReadUInt8(uint8_t& val); - bool ReadUInt16(uint16_t& val); - bool ReadUInt32(uint32_t& val); - ABSL_DEPRECATED("") bool ReadUInt8(uint8_t* val) { - return val ? ReadUInt8(*val) : false; - } - ABSL_DEPRECATED("") bool ReadUInt16(uint16_t* val) { - return val ? ReadUInt16(*val) : false; - } - ABSL_DEPRECATED("") bool ReadUInt32(uint32_t* val) { - return val ? ReadUInt32(*val) : false; - } - - // Reads bit-sized values from the buffer. Returns false if there isn't enough - // data left for the specified bit count. - bool ReadBits(size_t bit_count, uint32_t& val); - bool ReadBits(size_t bit_count, uint64_t& val); - ABSL_DEPRECATED("") bool ReadBits(uint32_t* val, size_t bit_count) { - return val ? ReadBits(bit_count, *val) : false; - } - - // Peeks bit-sized values from the buffer. Returns false if there isn't enough - // data left for the specified number of bits. Doesn't move the current - // offset. - bool PeekBits(size_t bit_count, uint32_t& val); - bool PeekBits(size_t bit_count, uint64_t& val); - ABSL_DEPRECATED("") bool PeekBits(uint32_t* val, size_t bit_count) { - return val ? PeekBits(bit_count, *val) : false; - } - - // Reads value in range [0, num_values - 1]. - // This encoding is similar to ReadBits(val, Ceil(Log2(num_values)), - // but reduces wastage incurred when encoding non-power of two value ranges - // Non symmetric values are encoded as: - // 1) n = countbits(num_values) - // 2) k = (1 << n) - num_values - // Value v in range [0, k - 1] is encoded in (n-1) bits. - // Value v in range [k, num_values - 1] is encoded as (v+k) in n bits. - // https://aomediacodec.github.io/av1-spec/#nsn - // Returns false if there isn't enough data left. - bool ReadNonSymmetric(uint32_t num_values, uint32_t& val); - ABSL_DEPRECATED("") - bool ReadNonSymmetric(uint32_t* val, uint32_t num_values) { - return val ? ReadNonSymmetric(num_values, *val) : false; - } - - // Reads the exponential golomb encoded value at the current offset. - // Exponential golomb values are encoded as: - // 1) x = source val + 1 - // 2) In binary, write [countbits(x) - 1] 0s, then x - // To decode, we count the number of leading 0 bits, read that many + 1 bits, - // and increment the result by 1. - // Returns false if there isn't enough data left for the specified type, or if - // the value wouldn't fit in a uint32_t. - bool ReadExponentialGolomb(uint32_t& val); - ABSL_DEPRECATED("") bool ReadExponentialGolomb(uint32_t* val) { - return val ? ReadExponentialGolomb(*val) : false; - } - - // Reads signed exponential golomb values at the current offset. Signed - // exponential golomb values are just the unsigned values mapped to the - // sequence 0, 1, -1, 2, -2, etc. in order. - bool ReadSignedExponentialGolomb(int32_t& val); - ABSL_DEPRECATED("") bool ReadSignedExponentialGolomb(int32_t* val) { - return val ? ReadSignedExponentialGolomb(*val) : false; - } - // Moves current position `byte_count` bytes forward. Returns false if // there aren't enough bytes left in the buffer. bool ConsumeBytes(size_t byte_count); @@ -117,26 +45,6 @@ class BitBuffer { // offset is from the given byte, in the range [0,7]. bool Seek(size_t byte_offset, size_t bit_offset); - protected: - const uint8_t* const bytes_; - // The total size of `bytes_`. - size_t byte_count_; - // The current offset, in bytes, from the start of `bytes_`. - size_t byte_offset_; - // The current offset, in bits, into the current byte. - size_t bit_offset_; - - RTC_DISALLOW_COPY_AND_ASSIGN(BitBuffer); -}; - -// A BitBuffer API for write operations. Supports symmetric write APIs to the -// reading APIs of BitBuffer. Note that the read/write offset is shared with the -// BitBuffer API, so both reading and writing will consume bytes/bits. -class BitBufferWriter : public BitBuffer { - public: - // Constructs a bit buffer for the writable buffer of `bytes`. - BitBufferWriter(uint8_t* bytes, size_t byte_count); - // Writes byte-sized values from the buffer. Returns false if there isn't // enough data left for the specified type. bool WriteUInt8(uint8_t val); @@ -166,6 +74,12 @@ class BitBufferWriter : public BitBuffer { private: // The buffer, as a writable array. uint8_t* const writable_bytes_; + // The total size of `bytes_`. + const size_t byte_count_; + // The current offset, in bytes, from the start of `bytes_`. + size_t byte_offset_; + // The current offset, in bits, into the current byte. + size_t bit_offset_; RTC_DISALLOW_COPY_AND_ASSIGN(BitBufferWriter); }; diff --git a/rtc_base/bit_buffer_unittest.cc b/rtc_base/bit_buffer_unittest.cc index e6bb4270c7..198be50e11 100644 --- a/rtc_base/bit_buffer_unittest.cc +++ b/rtc_base/bit_buffer_unittest.cc @@ -12,7 +12,9 @@ #include +#include "api/array_view.h" #include "rtc_base/arraysize.h" +#include "rtc_base/bitstream_reader.h" #include "rtc_base/byte_buffer.h" #include "test/gmock.h" #include "test/gtest.h" @@ -20,10 +22,11 @@ namespace rtc { using ::testing::ElementsAre; +using ::webrtc::BitstreamReader; -TEST(BitBufferTest, ConsumeBits) { - const uint8_t bytes[64] = {0}; - BitBuffer buffer(bytes, 32); +TEST(BitBufferWriterTest, ConsumeBits) { + uint8_t bytes[64] = {0}; + BitBufferWriter buffer(bytes, 32); uint64_t total_bits = 32 * 8; EXPECT_EQ(total_bits, buffer.RemainingBitCount()); EXPECT_TRUE(buffer.ConsumeBits(3)); @@ -43,138 +46,7 @@ TEST(BitBufferTest, ConsumeBits) { EXPECT_EQ(total_bits, buffer.RemainingBitCount()); } -TEST(BitBufferTest, ReadBytesAligned) { - const uint8_t bytes[] = {0x0A, 0xBC, 0xDE, 0xF1, 0x23, 0x45, 0x67, 0x89}; - uint8_t val8; - uint16_t val16; - uint32_t val32; - BitBuffer buffer(bytes, 8); - EXPECT_TRUE(buffer.ReadUInt8(val8)); - EXPECT_EQ(0x0Au, val8); - EXPECT_TRUE(buffer.ReadUInt8(val8)); - EXPECT_EQ(0xBCu, val8); - EXPECT_TRUE(buffer.ReadUInt16(val16)); - EXPECT_EQ(0xDEF1u, val16); - EXPECT_TRUE(buffer.ReadUInt32(val32)); - EXPECT_EQ(0x23456789u, val32); -} - -TEST(BitBufferTest, ReadBytesOffset4) { - const uint8_t bytes[] = {0x0A, 0xBC, 0xDE, 0xF1, 0x23, - 0x45, 0x67, 0x89, 0x0A}; - uint8_t val8; - uint16_t val16; - uint32_t val32; - BitBuffer buffer(bytes, 9); - EXPECT_TRUE(buffer.ConsumeBits(4)); - - EXPECT_TRUE(buffer.ReadUInt8(val8)); - EXPECT_EQ(0xABu, val8); - EXPECT_TRUE(buffer.ReadUInt8(val8)); - EXPECT_EQ(0xCDu, val8); - EXPECT_TRUE(buffer.ReadUInt16(val16)); - EXPECT_EQ(0xEF12u, val16); - EXPECT_TRUE(buffer.ReadUInt32(val32)); - EXPECT_EQ(0x34567890u, val32); -} - -TEST(BitBufferTest, ReadBytesOffset3) { - // The pattern we'll check against is counting down from 0b1111. It looks - // weird here because it's all offset by 3. - // Byte pattern is: - // 56701234 - // 0b00011111, - // 0b11011011, - // 0b10010111, - // 0b01010011, - // 0b00001110, - // 0b11001010, - // 0b10000110, - // 0b01000010 - // xxxxx <-- last 5 bits unused. - - // The bytes. It almost looks like counting down by two at a time, except the - // jump at 5->3->0, since that's when the high bit is turned off. - const uint8_t bytes[] = {0x1F, 0xDB, 0x97, 0x53, 0x0E, 0xCA, 0x86, 0x42}; - - uint8_t val8; - uint16_t val16; - uint32_t val32; - BitBuffer buffer(bytes, 8); - EXPECT_TRUE(buffer.ConsumeBits(3)); - EXPECT_TRUE(buffer.ReadUInt8(val8)); - EXPECT_EQ(0xFEu, val8); - EXPECT_TRUE(buffer.ReadUInt16(val16)); - EXPECT_EQ(0xDCBAu, val16); - EXPECT_TRUE(buffer.ReadUInt32(val32)); - EXPECT_EQ(0x98765432u, val32); - // 5 bits left unread. Not enough to read a uint8_t. - EXPECT_EQ(5u, buffer.RemainingBitCount()); - EXPECT_FALSE(buffer.ReadUInt8(val8)); -} - -TEST(BitBufferTest, ReadBits) { - // Bit values are: - // 0b01001101, - // 0b00110010 - const uint8_t bytes[] = {0x4D, 0x32}; - uint32_t val; - BitBuffer buffer(bytes, 2); - EXPECT_TRUE(buffer.ReadBits(3, val)); - // 0b010 - EXPECT_EQ(0x2u, val); - EXPECT_TRUE(buffer.ReadBits(2, val)); - // 0b01 - EXPECT_EQ(0x1u, val); - EXPECT_TRUE(buffer.ReadBits(7, val)); - // 0b1010011 - EXPECT_EQ(0x53u, val); - EXPECT_TRUE(buffer.ReadBits(2, val)); - // 0b00 - EXPECT_EQ(0x0u, val); - EXPECT_TRUE(buffer.ReadBits(1, val)); - // 0b1 - EXPECT_EQ(0x1u, val); - EXPECT_TRUE(buffer.ReadBits(1, val)); - // 0b0 - EXPECT_EQ(0x0u, val); - - EXPECT_FALSE(buffer.ReadBits(1, val)); -} - -TEST(BitBufferTest, ReadBits64) { - const uint8_t bytes[] = {0x4D, 0x32, 0xAB, 0x54, 0x00, 0xFF, 0xFE, 0x01, - 0xAB, 0xCD, 0xEF, 0x01, 0x23, 0x45, 0x67, 0x89}; - BitBuffer buffer(bytes, 16); - uint64_t val; - - // Peek and read first 33 bits. - EXPECT_TRUE(buffer.PeekBits(33, val)); - EXPECT_EQ(0x4D32AB5400FFFE01ull >> (64 - 33), val); - val = 0; - EXPECT_TRUE(buffer.ReadBits(33, val)); - EXPECT_EQ(0x4D32AB5400FFFE01ull >> (64 - 33), val); - - // Peek and read next 31 bits. - constexpr uint64_t kMask31Bits = (1ull << 32) - 1; - EXPECT_TRUE(buffer.PeekBits(31, val)); - EXPECT_EQ(0x4D32AB5400FFFE01ull & kMask31Bits, val); - val = 0; - EXPECT_TRUE(buffer.ReadBits(31, val)); - EXPECT_EQ(0x4D32AB5400FFFE01ull & kMask31Bits, val); - - // Peek and read remaining 64 bits. - EXPECT_TRUE(buffer.PeekBits(64, val)); - EXPECT_EQ(0xABCDEF0123456789ull, val); - val = 0; - EXPECT_TRUE(buffer.ReadBits(64, val)); - EXPECT_EQ(0xABCDEF0123456789ull, val); - - // Nothing more to read. - EXPECT_FALSE(buffer.ReadBits(1, val)); -} - -TEST(BitBufferDeathTest, SetOffsetValues) { +TEST(BitBufferWriterDeathTest, SetOffsetValues) { uint8_t bytes[4] = {0}; BitBufferWriter buffer(bytes, 4); @@ -213,21 +85,6 @@ TEST(BitBufferDeathTest, SetOffsetValues) { #endif } -TEST(BitBufferTest, ReadNonSymmetricSameNumberOfBitsWhenNumValuesPowerOf2) { - const uint8_t bytes[2] = {0xf3, 0xa0}; - BitBuffer reader(bytes, 2); - - uint32_t values[4]; - ASSERT_EQ(reader.RemainingBitCount(), 16u); - EXPECT_TRUE(reader.ReadNonSymmetric(/*num_values=*/1 << 4, values[0])); - EXPECT_TRUE(reader.ReadNonSymmetric(/*num_values=*/1 << 4, values[1])); - EXPECT_TRUE(reader.ReadNonSymmetric(/*num_values=*/1 << 4, values[2])); - EXPECT_TRUE(reader.ReadNonSymmetric(/*num_values=*/1 << 4, values[3])); - ASSERT_EQ(reader.RemainingBitCount(), 0u); - - EXPECT_THAT(values, ElementsAre(0xf, 0x3, 0xa, 0x0)); -} - TEST(BitBufferWriterTest, WriteNonSymmetricSameNumberOfBitsWhenNumValuesPowerOf2) { uint8_t bytes[2] = {}; @@ -274,28 +131,14 @@ TEST(BitBufferWriterTest, NonSymmetricReadsMatchesWrites) { // 00.01.100.101.110.111 = 00011001|01110111 = 0x19|77 EXPECT_THAT(bytes, ElementsAre(0x19, 0x77)); - rtc::BitBuffer reader(bytes, 2); - uint32_t values[6]; - EXPECT_TRUE(reader.ReadNonSymmetric(/*num_values=*/6, values[0])); - EXPECT_TRUE(reader.ReadNonSymmetric(/*num_values=*/6, values[1])); - EXPECT_TRUE(reader.ReadNonSymmetric(/*num_values=*/6, values[2])); - EXPECT_TRUE(reader.ReadNonSymmetric(/*num_values=*/6, values[3])); - EXPECT_TRUE(reader.ReadNonSymmetric(/*num_values=*/6, values[4])); - EXPECT_TRUE(reader.ReadNonSymmetric(/*num_values=*/6, values[5])); - - EXPECT_THAT(values, ElementsAre(0, 1, 2, 3, 4, 5)); -} - -TEST(BitBufferTest, ReadNonSymmetricOnlyValueConsumesNoBits) { - const uint8_t bytes[2] = {}; - BitBuffer reader(bytes, 2); - uint32_t value = 0xFFFFFFFF; - ASSERT_EQ(reader.RemainingBitCount(), 16u); - - EXPECT_TRUE(reader.ReadNonSymmetric(/*num_values=*/1, value)); - - EXPECT_EQ(value, 0u); - EXPECT_EQ(reader.RemainingBitCount(), 16u); + BitstreamReader reader(bytes); + EXPECT_EQ(reader.ReadNonSymmetric(/*num_values=*/6), 0u); + EXPECT_EQ(reader.ReadNonSymmetric(/*num_values=*/6), 1u); + EXPECT_EQ(reader.ReadNonSymmetric(/*num_values=*/6), 2u); + EXPECT_EQ(reader.ReadNonSymmetric(/*num_values=*/6), 3u); + EXPECT_EQ(reader.ReadNonSymmetric(/*num_values=*/6), 4u); + EXPECT_EQ(reader.ReadNonSymmetric(/*num_values=*/6), 5u); + EXPECT_TRUE(reader.Ok()); } TEST(BitBufferWriterTest, WriteNonSymmetricOnlyValueConsumesNoBits) { @@ -308,74 +151,6 @@ TEST(BitBufferWriterTest, WriteNonSymmetricOnlyValueConsumesNoBits) { EXPECT_EQ(writer.RemainingBitCount(), 16u); } -uint64_t GolombEncoded(uint32_t val) { - val++; - uint32_t bit_counter = val; - uint64_t bit_count = 0; - while (bit_counter > 0) { - bit_count++; - bit_counter >>= 1; - } - return static_cast(val) << (64 - (bit_count * 2 - 1)); -} - -TEST(BitBufferTest, GolombUint32Values) { - ByteBufferWriter byteBuffer; - byteBuffer.Resize(16); - BitBuffer buffer(reinterpret_cast(byteBuffer.Data()), - byteBuffer.Capacity()); - // Test over the uint32_t range with a large enough step that the test doesn't - // take forever. Around 20,000 iterations should do. - const int kStep = std::numeric_limits::max() / 20000; - for (uint32_t i = 0; i < std::numeric_limits::max() - kStep; - i += kStep) { - uint64_t encoded_val = GolombEncoded(i); - byteBuffer.Clear(); - byteBuffer.WriteUInt64(encoded_val); - uint32_t decoded_val; - EXPECT_TRUE(buffer.Seek(0, 0)); - EXPECT_TRUE(buffer.ReadExponentialGolomb(decoded_val)); - EXPECT_EQ(i, decoded_val); - } -} - -TEST(BitBufferTest, SignedGolombValues) { - uint8_t golomb_bits[] = { - 0x80, // 1 - 0x40, // 010 - 0x60, // 011 - 0x20, // 00100 - 0x38, // 00111 - }; - int32_t expected[] = {0, 1, -1, 2, -3}; - for (size_t i = 0; i < sizeof(golomb_bits); ++i) { - BitBuffer buffer(&golomb_bits[i], 1); - int32_t decoded_val; - ASSERT_TRUE(buffer.ReadSignedExponentialGolomb(decoded_val)); - EXPECT_EQ(expected[i], decoded_val) - << "Mismatch in expected/decoded value for golomb_bits[" << i - << "]: " << static_cast(golomb_bits[i]); - } -} - -TEST(BitBufferTest, NoGolombOverread) { - const uint8_t bytes[] = {0x00, 0xFF, 0xFF}; - // Make sure the bit buffer correctly enforces byte length on golomb reads. - // If it didn't, the above buffer would be valid at 3 bytes. - BitBuffer buffer(bytes, 1); - uint32_t decoded_val; - EXPECT_FALSE(buffer.ReadExponentialGolomb(decoded_val)); - - BitBuffer longer_buffer(bytes, 2); - EXPECT_FALSE(longer_buffer.ReadExponentialGolomb(decoded_val)); - - BitBuffer longest_buffer(bytes, 3); - EXPECT_TRUE(longest_buffer.ReadExponentialGolomb(decoded_val)); - // Golomb should have read 9 bits, so 0x01FF, and since it is golomb, the - // result is 0x01FF - 1 = 0x01FE. - EXPECT_EQ(0x01FEu, decoded_val); -} - TEST(BitBufferWriterTest, SymmetricReadWrite) { uint8_t bytes[16] = {0}; BitBufferWriter buffer(bytes, 4); @@ -390,22 +165,15 @@ TEST(BitBufferWriterTest, SymmetricReadWrite) { // That should be all that fits in the buffer. EXPECT_FALSE(buffer.WriteBits(1, 1)); - EXPECT_TRUE(buffer.Seek(0, 0)); - uint32_t val; - EXPECT_TRUE(buffer.ReadBits(3, val)); - EXPECT_EQ(0x2u, val); - EXPECT_TRUE(buffer.ReadBits(2, val)); - EXPECT_EQ(0x1u, val); - EXPECT_TRUE(buffer.ReadBits(7, val)); - EXPECT_EQ(0x53u, val); - EXPECT_TRUE(buffer.ReadBits(2, val)); - EXPECT_EQ(0x0u, val); - EXPECT_TRUE(buffer.ReadBits(1, val)); - EXPECT_EQ(0x1u, val); - EXPECT_TRUE(buffer.ReadBits(17, val)); - EXPECT_EQ(0x1ABCDu, val); + BitstreamReader reader(rtc::MakeArrayView(bytes, 4)); + EXPECT_EQ(reader.ReadBits(3), 0x2u); + EXPECT_EQ(reader.ReadBits(2), 0x1u); + EXPECT_EQ(reader.ReadBits(7), 0x53u); + EXPECT_EQ(reader.ReadBits(2), 0x0u); + EXPECT_EQ(reader.ReadBits(1), 0x1u); + EXPECT_EQ(reader.ReadBits(17), 0x1ABCDu); // And there should be nothing left. - EXPECT_FALSE(buffer.ReadBits(1, val)); + EXPECT_EQ(reader.RemainingBitCount(), 0); } TEST(BitBufferWriterTest, SymmetricBytesMisaligned) { @@ -418,16 +186,12 @@ TEST(BitBufferWriterTest, SymmetricBytesMisaligned) { EXPECT_TRUE(buffer.WriteUInt16(0x3456u)); EXPECT_TRUE(buffer.WriteUInt32(0x789ABCDEu)); - buffer.Seek(0, 3); - uint8_t val8; - uint16_t val16; - uint32_t val32; - EXPECT_TRUE(buffer.ReadUInt8(val8)); - EXPECT_EQ(0x12u, val8); - EXPECT_TRUE(buffer.ReadUInt16(val16)); - EXPECT_EQ(0x3456u, val16); - EXPECT_TRUE(buffer.ReadUInt32(val32)); - EXPECT_EQ(0x789ABCDEu, val32); + BitstreamReader reader(bytes); + reader.ConsumeBits(3); + EXPECT_EQ(reader.Read(), 0x12u); + EXPECT_EQ(reader.Read(), 0x3456u); + EXPECT_EQ(reader.Read(), 0x789ABCDEu); + EXPECT_TRUE(reader.Ok()); } TEST(BitBufferWriterTest, SymmetricGolomb) { @@ -437,13 +201,11 @@ TEST(BitBufferWriterTest, SymmetricGolomb) { for (size_t i = 0; i < arraysize(test_string); ++i) { EXPECT_TRUE(buffer.WriteExponentialGolomb(test_string[i])); } - buffer.Seek(0, 0); + BitstreamReader reader(bytes); for (size_t i = 0; i < arraysize(test_string); ++i) { - uint32_t val; - EXPECT_TRUE(buffer.ReadExponentialGolomb(val)); - EXPECT_LE(val, std::numeric_limits::max()); - EXPECT_EQ(test_string[i], static_cast(val)); + EXPECT_EQ(int64_t{reader.ReadExponentialGolomb()}, int64_t{test_string[i]}); } + EXPECT_TRUE(reader.Ok()); } TEST(BitBufferWriterTest, WriteClearsBits) {