Danil Chapovalov | 5af152c | 2021-08-31 15:27:51 +0200 | [diff] [blame] | 1 | /* |
| 2 | * Copyright 2021 The WebRTC Project Authors. All rights reserved. |
| 3 | * |
| 4 | * Use of this source code is governed by a BSD-style license |
| 5 | * that can be found in the LICENSE file in the root of the source |
| 6 | * tree. An additional intellectual property rights grant can be found |
| 7 | * in the file PATENTS. All contributing project authors may |
| 8 | * be found in the AUTHORS file in the root of the source tree. |
| 9 | */ |
| 10 | |
| 11 | #include "rtc_base/bitstream_reader.h" |
| 12 | |
| 13 | #include <stddef.h> |
| 14 | #include <stdint.h> |
| 15 | |
| 16 | #include <array> |
| 17 | #include <limits> |
| 18 | |
| 19 | #include "absl/numeric/bits.h" |
| 20 | #include "absl/types/optional.h" |
| 21 | #include "api/array_view.h" |
| 22 | #include "rtc_base/checks.h" |
| 23 | #include "test/gmock.h" |
| 24 | #include "test/gtest.h" |
| 25 | |
| 26 | namespace webrtc { |
| 27 | namespace { |
| 28 | |
| 29 | TEST(BitstreamReaderTest, InDebugModeRequiresToCheckOkStatusBeforeDestruction) { |
| 30 | const uint8_t bytes[32] = {}; |
| 31 | absl::optional<BitstreamReader> reader(absl::in_place, bytes); |
| 32 | |
| 33 | EXPECT_GE(reader->ReadBits(7), 0u); |
| 34 | #if RTC_DCHECK_IS_ON && GTEST_HAS_DEATH_TEST && !defined(OS_ANDROID) |
| 35 | EXPECT_DEATH(reader = absl::nullopt, ""); |
| 36 | #endif |
| 37 | EXPECT_TRUE(reader->Ok()); |
| 38 | reader = absl::nullopt; |
| 39 | } |
| 40 | |
| 41 | TEST(BitstreamReaderTest, InDebugModeMayCheckRemainingBitsInsteadOfOkStatus) { |
| 42 | const uint8_t bytes[32] = {}; |
| 43 | absl::optional<BitstreamReader> reader(absl::in_place, bytes); |
| 44 | |
| 45 | EXPECT_GE(reader->ReadBit(), 0); |
| 46 | #if RTC_DCHECK_IS_ON && GTEST_HAS_DEATH_TEST && !defined(OS_ANDROID) |
| 47 | EXPECT_DEATH(reader = absl::nullopt, ""); |
| 48 | #endif |
| 49 | EXPECT_GE(reader->RemainingBitCount(), 0); |
| 50 | reader = absl::nullopt; |
| 51 | } |
| 52 | |
| 53 | TEST(BitstreamReaderTest, ConsumeBits) { |
| 54 | const uint8_t bytes[32] = {}; |
| 55 | BitstreamReader reader(bytes); |
| 56 | |
| 57 | int total_bits = 32 * 8; |
| 58 | EXPECT_EQ(reader.RemainingBitCount(), total_bits); |
| 59 | reader.ConsumeBits(3); |
| 60 | total_bits -= 3; |
| 61 | EXPECT_EQ(reader.RemainingBitCount(), total_bits); |
| 62 | reader.ConsumeBits(3); |
| 63 | total_bits -= 3; |
| 64 | EXPECT_EQ(reader.RemainingBitCount(), total_bits); |
| 65 | reader.ConsumeBits(15); |
| 66 | total_bits -= 15; |
| 67 | EXPECT_EQ(reader.RemainingBitCount(), total_bits); |
| 68 | reader.ConsumeBits(67); |
| 69 | total_bits -= 67; |
| 70 | EXPECT_EQ(reader.RemainingBitCount(), total_bits); |
| 71 | EXPECT_TRUE(reader.Ok()); |
| 72 | |
| 73 | reader.ConsumeBits(32 * 8); |
| 74 | EXPECT_FALSE(reader.Ok()); |
| 75 | EXPECT_LT(reader.RemainingBitCount(), 0); |
| 76 | } |
| 77 | |
Danil Chapovalov | 1ce5859 | 2021-09-20 14:12:23 +0200 | [diff] [blame] | 78 | TEST(BitstreamReaderTest, ConsumeLotsOfBits) { |
| 79 | const uint8_t bytes[1] = {}; |
| 80 | BitstreamReader reader(bytes); |
| 81 | |
| 82 | reader.ConsumeBits(std::numeric_limits<int>::max()); |
| 83 | reader.ConsumeBits(std::numeric_limits<int>::max()); |
| 84 | EXPECT_GE(reader.ReadBit(), 0); |
| 85 | EXPECT_FALSE(reader.Ok()); |
| 86 | } |
| 87 | |
Danil Chapovalov | 5af152c | 2021-08-31 15:27:51 +0200 | [diff] [blame] | 88 | TEST(BitstreamReaderTest, ReadBit) { |
| 89 | const uint8_t bytes[] = {0b0100'0001, 0b1011'0001}; |
| 90 | BitstreamReader reader(bytes); |
| 91 | // First byte. |
| 92 | EXPECT_EQ(reader.ReadBit(), 0); |
| 93 | EXPECT_EQ(reader.ReadBit(), 1); |
| 94 | EXPECT_EQ(reader.ReadBit(), 0); |
| 95 | EXPECT_EQ(reader.ReadBit(), 0); |
| 96 | |
| 97 | EXPECT_EQ(reader.ReadBit(), 0); |
| 98 | EXPECT_EQ(reader.ReadBit(), 0); |
| 99 | EXPECT_EQ(reader.ReadBit(), 0); |
| 100 | EXPECT_EQ(reader.ReadBit(), 1); |
| 101 | |
| 102 | // Second byte. |
| 103 | EXPECT_EQ(reader.ReadBit(), 1); |
| 104 | EXPECT_EQ(reader.ReadBit(), 0); |
| 105 | EXPECT_EQ(reader.ReadBit(), 1); |
| 106 | EXPECT_EQ(reader.ReadBit(), 1); |
| 107 | |
| 108 | EXPECT_EQ(reader.ReadBit(), 0); |
| 109 | EXPECT_EQ(reader.ReadBit(), 0); |
| 110 | EXPECT_EQ(reader.ReadBit(), 0); |
| 111 | EXPECT_EQ(reader.ReadBit(), 1); |
| 112 | |
| 113 | EXPECT_TRUE(reader.Ok()); |
| 114 | // Try to read beyound the buffer. |
| 115 | EXPECT_EQ(reader.ReadBit(), 0); |
| 116 | EXPECT_FALSE(reader.Ok()); |
| 117 | } |
| 118 | |
| 119 | TEST(BitstreamReaderTest, ReadBoolConsumesSingleBit) { |
| 120 | const uint8_t bytes[] = {0b1010'1010}; |
| 121 | BitstreamReader reader(bytes); |
| 122 | ASSERT_EQ(reader.RemainingBitCount(), 8); |
| 123 | EXPECT_TRUE(reader.Read<bool>()); |
| 124 | EXPECT_EQ(reader.RemainingBitCount(), 7); |
| 125 | } |
| 126 | |
| 127 | TEST(BitstreamReaderTest, ReadBytesAligned) { |
| 128 | const uint8_t bytes[] = {0x0A, // |
| 129 | 0xBC, // |
| 130 | 0xDE, 0xF1, // |
| 131 | 0x23, 0x45, 0x67, 0x89}; |
| 132 | BitstreamReader reader(bytes); |
| 133 | EXPECT_EQ(reader.Read<uint8_t>(), 0x0Au); |
| 134 | EXPECT_EQ(reader.Read<uint8_t>(), 0xBCu); |
| 135 | EXPECT_EQ(reader.Read<uint16_t>(), 0xDEF1u); |
| 136 | EXPECT_EQ(reader.Read<uint32_t>(), 0x23456789u); |
| 137 | EXPECT_TRUE(reader.Ok()); |
| 138 | } |
| 139 | |
| 140 | TEST(BitstreamReaderTest, ReadBytesOffset4) { |
| 141 | const uint8_t bytes[] = {0x0A, 0xBC, 0xDE, 0xF1, 0x23, |
| 142 | 0x45, 0x67, 0x89, 0x0A}; |
| 143 | BitstreamReader reader(bytes); |
| 144 | reader.ConsumeBits(4); |
| 145 | |
| 146 | EXPECT_EQ(reader.Read<uint8_t>(), 0xABu); |
| 147 | EXPECT_EQ(reader.Read<uint8_t>(), 0xCDu); |
| 148 | EXPECT_EQ(reader.Read<uint16_t>(), 0xEF12u); |
| 149 | EXPECT_EQ(reader.Read<uint32_t>(), 0x34567890u); |
| 150 | EXPECT_TRUE(reader.Ok()); |
| 151 | } |
| 152 | |
| 153 | TEST(BitstreamReaderTest, ReadBytesOffset3) { |
| 154 | // The pattern we'll check against is counting down from 0b1111. It looks |
| 155 | // weird here because it's all offset by 3. |
| 156 | // Byte pattern is: |
| 157 | // 56701234 |
| 158 | // 0b00011111, |
| 159 | // 0b11011011, |
| 160 | // 0b10010111, |
| 161 | // 0b01010011, |
| 162 | // 0b00001110, |
| 163 | // 0b11001010, |
| 164 | // 0b10000110, |
| 165 | // 0b01000010 |
| 166 | // xxxxx <-- last 5 bits unused. |
| 167 | |
| 168 | // The bytes. It almost looks like counting down by two at a time, except the |
| 169 | // jump at 5->3->0, since that's when the high bit is turned off. |
| 170 | const uint8_t bytes[] = {0x1F, 0xDB, 0x97, 0x53, 0x0E, 0xCA, 0x86, 0x42}; |
| 171 | |
| 172 | BitstreamReader reader(bytes); |
| 173 | reader.ConsumeBits(3); |
| 174 | EXPECT_EQ(reader.Read<uint8_t>(), 0xFEu); |
| 175 | EXPECT_EQ(reader.Read<uint16_t>(), 0xDCBAu); |
| 176 | EXPECT_EQ(reader.Read<uint32_t>(), 0x98765432u); |
| 177 | EXPECT_TRUE(reader.Ok()); |
| 178 | |
| 179 | // 5 bits left unread. Not enough to read a uint8_t. |
| 180 | EXPECT_EQ(reader.RemainingBitCount(), 5); |
| 181 | EXPECT_EQ(reader.Read<uint8_t>(), 0); |
| 182 | EXPECT_FALSE(reader.Ok()); |
| 183 | } |
| 184 | |
| 185 | TEST(BitstreamReaderTest, ReadBits) { |
| 186 | const uint8_t bytes[] = {0b010'01'101, 0b0011'00'1'0}; |
| 187 | BitstreamReader reader(bytes); |
| 188 | EXPECT_EQ(reader.ReadBits(3), 0b010u); |
| 189 | EXPECT_EQ(reader.ReadBits(2), 0b01u); |
| 190 | EXPECT_EQ(reader.ReadBits(7), 0b101'0011u); |
| 191 | EXPECT_EQ(reader.ReadBits(2), 0b00u); |
| 192 | EXPECT_EQ(reader.ReadBits(1), 0b1u); |
| 193 | EXPECT_EQ(reader.ReadBits(1), 0b0u); |
| 194 | EXPECT_TRUE(reader.Ok()); |
| 195 | |
| 196 | EXPECT_EQ(reader.ReadBits(1), 0u); |
| 197 | EXPECT_FALSE(reader.Ok()); |
| 198 | } |
| 199 | |
| 200 | TEST(BitstreamReaderTest, ReadZeroBits) { |
| 201 | BitstreamReader reader(rtc::ArrayView<const uint8_t>(nullptr, 0)); |
| 202 | |
| 203 | EXPECT_EQ(reader.ReadBits(0), 0u); |
| 204 | EXPECT_TRUE(reader.Ok()); |
| 205 | } |
| 206 | |
| 207 | TEST(BitstreamReaderTest, ReadBitFromEmptyArray) { |
| 208 | BitstreamReader reader(rtc::ArrayView<const uint8_t>(nullptr, 0)); |
| 209 | |
| 210 | // Trying to read from the empty array shouldn't dereference the pointer, |
| 211 | // i.e. shouldn't crash. |
| 212 | EXPECT_EQ(reader.ReadBit(), 0); |
| 213 | EXPECT_FALSE(reader.Ok()); |
| 214 | } |
| 215 | |
| 216 | TEST(BitstreamReaderTest, ReadBitsFromEmptyArray) { |
| 217 | BitstreamReader reader(rtc::ArrayView<const uint8_t>(nullptr, 0)); |
| 218 | |
| 219 | // Trying to read from the empty array shouldn't dereference the pointer, |
| 220 | // i.e. shouldn't crash. |
| 221 | EXPECT_EQ(reader.ReadBits(1), 0u); |
| 222 | EXPECT_FALSE(reader.Ok()); |
| 223 | } |
| 224 | |
| 225 | TEST(BitstreamReaderTest, ReadBits64) { |
| 226 | const uint8_t bytes[] = {0x4D, 0x32, 0xAB, 0x54, 0x00, 0xFF, 0xFE, 0x01, |
| 227 | 0xAB, 0xCD, 0xEF, 0x01, 0x23, 0x45, 0x67, 0x89}; |
| 228 | BitstreamReader reader(bytes); |
| 229 | |
| 230 | EXPECT_EQ(reader.ReadBits(33), 0x4D32AB5400FFFE01u >> (64 - 33)); |
| 231 | |
| 232 | constexpr uint64_t kMask31Bits = (1ull << 32) - 1; |
| 233 | EXPECT_EQ(reader.ReadBits(31), 0x4D32AB5400FFFE01ull & kMask31Bits); |
| 234 | |
| 235 | EXPECT_EQ(reader.ReadBits(64), 0xABCDEF0123456789ull); |
| 236 | EXPECT_TRUE(reader.Ok()); |
| 237 | |
| 238 | // Nothing more to read. |
| 239 | EXPECT_EQ(reader.ReadBit(), 0); |
| 240 | EXPECT_FALSE(reader.Ok()); |
| 241 | } |
| 242 | |
| 243 | TEST(BitstreamReaderTest, CanPeekBitsUsingCopyConstructor) { |
| 244 | // BitstreamReader doesn't have peek function. To simulate it, user may use |
| 245 | // cheap BitstreamReader copy constructor. |
| 246 | const uint8_t bytes[] = {0x0A, 0xBC}; |
| 247 | BitstreamReader reader(bytes); |
| 248 | reader.ConsumeBits(4); |
| 249 | ASSERT_EQ(reader.RemainingBitCount(), 12); |
| 250 | |
| 251 | BitstreamReader peeker = reader; |
| 252 | EXPECT_EQ(peeker.ReadBits(8), 0xABu); |
| 253 | EXPECT_EQ(peeker.RemainingBitCount(), 4); |
| 254 | |
| 255 | EXPECT_EQ(reader.RemainingBitCount(), 12); |
| 256 | // Can resume reading from before peeker was created. |
| 257 | EXPECT_EQ(reader.ReadBits(4), 0xAu); |
| 258 | EXPECT_EQ(reader.RemainingBitCount(), 8); |
| 259 | } |
| 260 | |
| 261 | TEST(BitstreamReaderTest, |
| 262 | ReadNonSymmetricSameNumberOfBitsWhenNumValuesPowerOf2) { |
| 263 | const uint8_t bytes[2] = {0xf3, 0xa0}; |
| 264 | BitstreamReader reader(bytes); |
| 265 | |
| 266 | ASSERT_EQ(reader.RemainingBitCount(), 16); |
| 267 | EXPECT_EQ(reader.ReadNonSymmetric(/*num_values=*/1 << 4), 0xfu); |
| 268 | EXPECT_EQ(reader.ReadNonSymmetric(/*num_values=*/1 << 4), 0x3u); |
| 269 | EXPECT_EQ(reader.ReadNonSymmetric(/*num_values=*/1 << 4), 0xau); |
| 270 | EXPECT_EQ(reader.ReadNonSymmetric(/*num_values=*/1 << 4), 0x0u); |
| 271 | EXPECT_EQ(reader.RemainingBitCount(), 0); |
| 272 | EXPECT_TRUE(reader.Ok()); |
| 273 | } |
| 274 | |
| 275 | TEST(BitstreamReaderTest, ReadNonSymmetricOnlyValueConsumesZeroBits) { |
| 276 | const uint8_t bytes[2] = {}; |
| 277 | BitstreamReader reader(bytes); |
| 278 | |
| 279 | ASSERT_EQ(reader.RemainingBitCount(), 16); |
| 280 | EXPECT_EQ(reader.ReadNonSymmetric(/*num_values=*/1), 0u); |
| 281 | EXPECT_EQ(reader.RemainingBitCount(), 16); |
| 282 | } |
| 283 | |
| 284 | std::array<uint8_t, 8> GolombEncoded(uint32_t val) { |
| 285 | int val_width = absl::bit_width(val + 1); |
| 286 | int total_width = 2 * val_width - 1; |
| 287 | uint64_t representation = (uint64_t{val} + 1) << (64 - total_width); |
| 288 | std::array<uint8_t, 8> result; |
| 289 | for (int i = 0; i < 8; ++i) { |
| 290 | result[i] = representation >> (7 - i) * 8; |
| 291 | } |
| 292 | return result; |
| 293 | } |
| 294 | |
| 295 | TEST(BitstreamReaderTest, GolombUint32Values) { |
| 296 | // Test over the uint32_t range with a large enough step that the test doesn't |
| 297 | // take forever. Around 20,000 iterations should do. |
| 298 | const int kStep = std::numeric_limits<uint32_t>::max() / 20000; |
| 299 | for (uint32_t i = 0; i < std::numeric_limits<uint32_t>::max() - kStep; |
| 300 | i += kStep) { |
| 301 | std::array<uint8_t, 8> buffer = GolombEncoded(i); |
| 302 | BitstreamReader reader(buffer); |
| 303 | // Use assert instead of EXPECT to avoid spamming thousands of failed |
| 304 | // expectation when this test fails. |
| 305 | ASSERT_EQ(reader.ReadExponentialGolomb(), i); |
| 306 | EXPECT_TRUE(reader.Ok()); |
| 307 | } |
| 308 | } |
| 309 | |
| 310 | TEST(BitstreamReaderTest, SignedGolombValues) { |
| 311 | uint8_t golomb_bits[][1] = { |
| 312 | {0b1'0000000}, {0b010'00000}, {0b011'00000}, {0b00100'000}, {0b00111'000}, |
| 313 | }; |
| 314 | int expected[] = {0, 1, -1, 2, -3}; |
| 315 | for (size_t i = 0; i < sizeof(golomb_bits); ++i) { |
| 316 | BitstreamReader reader(golomb_bits[i]); |
| 317 | EXPECT_EQ(reader.ReadSignedExponentialGolomb(), expected[i]) |
| 318 | << "Mismatch in expected/decoded value for golomb_bits[" << i |
| 319 | << "]: " << static_cast<int>(golomb_bits[i][0]); |
| 320 | EXPECT_TRUE(reader.Ok()); |
| 321 | } |
| 322 | } |
| 323 | |
| 324 | TEST(BitstreamReaderTest, NoGolombOverread) { |
| 325 | const uint8_t bytes[] = {0x00, 0xFF, 0xFF}; |
| 326 | // Make sure the bit buffer correctly enforces byte length on golomb reads. |
| 327 | // If it didn't, the above buffer would be valid at 3 bytes. |
| 328 | BitstreamReader reader1(rtc::MakeArrayView(bytes, 1)); |
| 329 | // When parse fails, `ReadExponentialGolomb` may return any number. |
| 330 | reader1.ReadExponentialGolomb(); |
| 331 | EXPECT_FALSE(reader1.Ok()); |
| 332 | |
| 333 | BitstreamReader reader2(rtc::MakeArrayView(bytes, 2)); |
| 334 | reader2.ReadExponentialGolomb(); |
| 335 | EXPECT_FALSE(reader2.Ok()); |
| 336 | |
| 337 | BitstreamReader reader3(bytes); |
| 338 | // Golomb should have read 9 bits, so 0x01FF, and since it is golomb, the |
| 339 | // result is 0x01FF - 1 = 0x01FE. |
| 340 | EXPECT_EQ(reader3.ReadExponentialGolomb(), 0x01FEu); |
| 341 | EXPECT_TRUE(reader3.Ok()); |
| 342 | } |
| 343 | |
| 344 | } // namespace |
| 345 | } // namespace webrtc |