| /* |
| * Copyright 2015 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/bit_buffer.h" |
| |
| #include <limits> |
| |
| #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" |
| |
| namespace rtc { |
| |
| using ::testing::ElementsAre; |
| using ::webrtc::BitstreamReader; |
| |
| 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)); |
| total_bits -= 3; |
| EXPECT_EQ(total_bits, buffer.RemainingBitCount()); |
| EXPECT_TRUE(buffer.ConsumeBits(3)); |
| total_bits -= 3; |
| EXPECT_EQ(total_bits, buffer.RemainingBitCount()); |
| EXPECT_TRUE(buffer.ConsumeBits(15)); |
| total_bits -= 15; |
| EXPECT_EQ(total_bits, buffer.RemainingBitCount()); |
| EXPECT_TRUE(buffer.ConsumeBits(37)); |
| total_bits -= 37; |
| EXPECT_EQ(total_bits, buffer.RemainingBitCount()); |
| |
| EXPECT_FALSE(buffer.ConsumeBits(32 * 8)); |
| EXPECT_EQ(total_bits, buffer.RemainingBitCount()); |
| } |
| |
| TEST(BitBufferWriterDeathTest, SetOffsetValues) { |
| uint8_t bytes[4] = {0}; |
| BitBufferWriter buffer(bytes, 4); |
| |
| size_t byte_offset, bit_offset; |
| // Bit offsets are [0,7]. |
| EXPECT_TRUE(buffer.Seek(0, 0)); |
| EXPECT_TRUE(buffer.Seek(0, 7)); |
| buffer.GetCurrentOffset(&byte_offset, &bit_offset); |
| EXPECT_EQ(0u, byte_offset); |
| EXPECT_EQ(7u, bit_offset); |
| EXPECT_FALSE(buffer.Seek(0, 8)); |
| buffer.GetCurrentOffset(&byte_offset, &bit_offset); |
| EXPECT_EQ(0u, byte_offset); |
| EXPECT_EQ(7u, bit_offset); |
| // Byte offsets are [0,length]. At byte offset length, the bit offset must be |
| // 0. |
| EXPECT_TRUE(buffer.Seek(0, 0)); |
| EXPECT_TRUE(buffer.Seek(2, 4)); |
| buffer.GetCurrentOffset(&byte_offset, &bit_offset); |
| EXPECT_EQ(2u, byte_offset); |
| EXPECT_EQ(4u, bit_offset); |
| EXPECT_TRUE(buffer.Seek(4, 0)); |
| EXPECT_FALSE(buffer.Seek(5, 0)); |
| buffer.GetCurrentOffset(&byte_offset, &bit_offset); |
| EXPECT_EQ(4u, byte_offset); |
| EXPECT_EQ(0u, bit_offset); |
| EXPECT_FALSE(buffer.Seek(4, 1)); |
| |
| // Disable death test on Android because it relies on fork() and doesn't play |
| // nicely. |
| #if GTEST_HAS_DEATH_TEST |
| #if !defined(WEBRTC_ANDROID) |
| // Passing a null out parameter is death. |
| EXPECT_DEATH(buffer.GetCurrentOffset(&byte_offset, nullptr), ""); |
| #endif |
| #endif |
| } |
| |
| TEST(BitBufferWriterTest, |
| WriteNonSymmetricSameNumberOfBitsWhenNumValuesPowerOf2) { |
| uint8_t bytes[2] = {}; |
| BitBufferWriter writer(bytes, 2); |
| |
| ASSERT_EQ(writer.RemainingBitCount(), 16u); |
| EXPECT_TRUE(writer.WriteNonSymmetric(0xf, /*num_values=*/1 << 4)); |
| ASSERT_EQ(writer.RemainingBitCount(), 12u); |
| EXPECT_TRUE(writer.WriteNonSymmetric(0x3, /*num_values=*/1 << 4)); |
| ASSERT_EQ(writer.RemainingBitCount(), 8u); |
| EXPECT_TRUE(writer.WriteNonSymmetric(0xa, /*num_values=*/1 << 4)); |
| ASSERT_EQ(writer.RemainingBitCount(), 4u); |
| EXPECT_TRUE(writer.WriteNonSymmetric(0x0, /*num_values=*/1 << 4)); |
| ASSERT_EQ(writer.RemainingBitCount(), 0u); |
| |
| EXPECT_THAT(bytes, ElementsAre(0xf3, 0xa0)); |
| } |
| |
| TEST(BitBufferWriterTest, NonSymmetricReadsMatchesWrites) { |
| uint8_t bytes[2] = {}; |
| BitBufferWriter writer(bytes, 2); |
| |
| EXPECT_EQ(BitBufferWriter::SizeNonSymmetricBits(/*val=*/1, /*num_values=*/6), |
| 2u); |
| EXPECT_EQ(BitBufferWriter::SizeNonSymmetricBits(/*val=*/2, /*num_values=*/6), |
| 3u); |
| // Values [0, 1] can fit into two bit. |
| ASSERT_EQ(writer.RemainingBitCount(), 16u); |
| EXPECT_TRUE(writer.WriteNonSymmetric(/*val=*/0, /*num_values=*/6)); |
| ASSERT_EQ(writer.RemainingBitCount(), 14u); |
| EXPECT_TRUE(writer.WriteNonSymmetric(/*val=*/1, /*num_values=*/6)); |
| ASSERT_EQ(writer.RemainingBitCount(), 12u); |
| // Values [2, 5] require 3 bits. |
| EXPECT_TRUE(writer.WriteNonSymmetric(/*val=*/2, /*num_values=*/6)); |
| ASSERT_EQ(writer.RemainingBitCount(), 9u); |
| EXPECT_TRUE(writer.WriteNonSymmetric(/*val=*/3, /*num_values=*/6)); |
| ASSERT_EQ(writer.RemainingBitCount(), 6u); |
| EXPECT_TRUE(writer.WriteNonSymmetric(/*val=*/4, /*num_values=*/6)); |
| ASSERT_EQ(writer.RemainingBitCount(), 3u); |
| EXPECT_TRUE(writer.WriteNonSymmetric(/*val=*/5, /*num_values=*/6)); |
| ASSERT_EQ(writer.RemainingBitCount(), 0u); |
| |
| // Bit values are |
| // 00.01.100.101.110.111 = 00011001|01110111 = 0x19|77 |
| EXPECT_THAT(bytes, ElementsAre(0x19, 0x77)); |
| |
| 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) { |
| uint8_t bytes[2] = {}; |
| BitBufferWriter writer(bytes, 2); |
| ASSERT_EQ(writer.RemainingBitCount(), 16u); |
| |
| EXPECT_TRUE(writer.WriteNonSymmetric(0, /*num_values=*/1)); |
| |
| EXPECT_EQ(writer.RemainingBitCount(), 16u); |
| } |
| |
| TEST(BitBufferWriterTest, SymmetricReadWrite) { |
| uint8_t bytes[16] = {0}; |
| BitBufferWriter buffer(bytes, 4); |
| |
| // Write some bit data at various sizes. |
| EXPECT_TRUE(buffer.WriteBits(0x2u, 3)); |
| EXPECT_TRUE(buffer.WriteBits(0x1u, 2)); |
| EXPECT_TRUE(buffer.WriteBits(0x53u, 7)); |
| EXPECT_TRUE(buffer.WriteBits(0x0u, 2)); |
| EXPECT_TRUE(buffer.WriteBits(0x1u, 1)); |
| EXPECT_TRUE(buffer.WriteBits(0x1ABCDu, 17)); |
| // That should be all that fits in the buffer. |
| EXPECT_FALSE(buffer.WriteBits(1, 1)); |
| |
| 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_EQ(reader.RemainingBitCount(), 0); |
| } |
| |
| TEST(BitBufferWriterTest, SymmetricBytesMisaligned) { |
| uint8_t bytes[16] = {0}; |
| BitBufferWriter buffer(bytes, 16); |
| |
| // Offset 3, to get things misaligned. |
| EXPECT_TRUE(buffer.ConsumeBits(3)); |
| EXPECT_TRUE(buffer.WriteUInt8(0x12u)); |
| EXPECT_TRUE(buffer.WriteUInt16(0x3456u)); |
| EXPECT_TRUE(buffer.WriteUInt32(0x789ABCDEu)); |
| |
| BitstreamReader reader(bytes); |
| reader.ConsumeBits(3); |
| EXPECT_EQ(reader.Read<uint8_t>(), 0x12u); |
| EXPECT_EQ(reader.Read<uint16_t>(), 0x3456u); |
| EXPECT_EQ(reader.Read<uint32_t>(), 0x789ABCDEu); |
| EXPECT_TRUE(reader.Ok()); |
| } |
| |
| TEST(BitBufferWriterTest, SymmetricGolomb) { |
| char test_string[] = "my precious"; |
| uint8_t bytes[64] = {0}; |
| BitBufferWriter buffer(bytes, 64); |
| for (size_t i = 0; i < arraysize(test_string); ++i) { |
| EXPECT_TRUE(buffer.WriteExponentialGolomb(test_string[i])); |
| } |
| BitstreamReader reader(bytes); |
| for (size_t i = 0; i < arraysize(test_string); ++i) { |
| EXPECT_EQ(int64_t{reader.ReadExponentialGolomb()}, int64_t{test_string[i]}); |
| } |
| EXPECT_TRUE(reader.Ok()); |
| } |
| |
| TEST(BitBufferWriterTest, WriteClearsBits) { |
| uint8_t bytes[] = {0xFF, 0xFF}; |
| BitBufferWriter buffer(bytes, 2); |
| EXPECT_TRUE(buffer.ConsumeBits(3)); |
| EXPECT_TRUE(buffer.WriteBits(0, 1)); |
| EXPECT_EQ(0xEFu, bytes[0]); |
| EXPECT_TRUE(buffer.WriteBits(0, 3)); |
| EXPECT_EQ(0xE1u, bytes[0]); |
| EXPECT_TRUE(buffer.WriteBits(0, 2)); |
| EXPECT_EQ(0xE0u, bytes[0]); |
| EXPECT_EQ(0x7F, bytes[1]); |
| } |
| |
| } // namespace rtc |