mirror of
https://github.com/mollyim/webrtc.git
synced 2025-05-12 13:20:44 +01:00

Bug: webrtc:14801 Change-Id: I7c14597e39b312c26573f034dca444cc1d90e332 Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/295480 Commit-Queue: Philip Eliasson <philipel@webrtc.org> Reviewed-by: Mirko Bonadei <mbonadei@webrtc.org> Reviewed-by: Björn Terelius <terelius@webrtc.org> Cr-Commit-Position: refs/heads/main@{#39449}
373 lines
12 KiB
C++
373 lines
12 KiB
C++
/*
|
|
* 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 <stddef.h>
|
|
#include <stdint.h>
|
|
|
|
#include <array>
|
|
#include <limits>
|
|
|
|
#include "absl/numeric/bits.h"
|
|
#include "absl/types/optional.h"
|
|
#include "api/array_view.h"
|
|
#include "rtc_base/checks.h"
|
|
#include "test/gmock.h"
|
|
#include "test/gtest.h"
|
|
|
|
namespace webrtc {
|
|
namespace {
|
|
|
|
TEST(BitstreamReaderTest, InDebugModeRequiresToCheckOkStatusBeforeDestruction) {
|
|
const uint8_t bytes[32] = {};
|
|
absl::optional<BitstreamReader> reader(absl::in_place, bytes);
|
|
|
|
EXPECT_GE(reader->ReadBits(7), 0u);
|
|
#if RTC_DCHECK_IS_ON && GTEST_HAS_DEATH_TEST && !defined(OS_ANDROID)
|
|
EXPECT_DEATH(reader = absl::nullopt, "");
|
|
#endif
|
|
EXPECT_TRUE(reader->Ok());
|
|
reader = absl::nullopt;
|
|
}
|
|
|
|
TEST(BitstreamReaderTest, InDebugModeMayCheckRemainingBitsInsteadOfOkStatus) {
|
|
const uint8_t bytes[32] = {};
|
|
absl::optional<BitstreamReader> reader(absl::in_place, bytes);
|
|
|
|
EXPECT_GE(reader->ReadBit(), 0);
|
|
#if RTC_DCHECK_IS_ON && GTEST_HAS_DEATH_TEST && !defined(OS_ANDROID)
|
|
EXPECT_DEATH(reader = absl::nullopt, "");
|
|
#endif
|
|
EXPECT_GE(reader->RemainingBitCount(), 0);
|
|
reader = absl::nullopt;
|
|
}
|
|
|
|
TEST(BitstreamReaderTest, ConsumeBits) {
|
|
const uint8_t bytes[32] = {};
|
|
BitstreamReader reader(bytes);
|
|
|
|
int total_bits = 32 * 8;
|
|
EXPECT_EQ(reader.RemainingBitCount(), total_bits);
|
|
reader.ConsumeBits(3);
|
|
total_bits -= 3;
|
|
EXPECT_EQ(reader.RemainingBitCount(), total_bits);
|
|
reader.ConsumeBits(3);
|
|
total_bits -= 3;
|
|
EXPECT_EQ(reader.RemainingBitCount(), total_bits);
|
|
reader.ConsumeBits(15);
|
|
total_bits -= 15;
|
|
EXPECT_EQ(reader.RemainingBitCount(), total_bits);
|
|
reader.ConsumeBits(67);
|
|
total_bits -= 67;
|
|
EXPECT_EQ(reader.RemainingBitCount(), total_bits);
|
|
EXPECT_TRUE(reader.Ok());
|
|
|
|
reader.ConsumeBits(32 * 8);
|
|
EXPECT_FALSE(reader.Ok());
|
|
EXPECT_LT(reader.RemainingBitCount(), 0);
|
|
}
|
|
|
|
TEST(BitstreamReaderTest, ConsumeLotsOfBits) {
|
|
const uint8_t bytes[1] = {};
|
|
BitstreamReader reader(bytes);
|
|
|
|
reader.ConsumeBits(std::numeric_limits<int>::max());
|
|
reader.ConsumeBits(std::numeric_limits<int>::max());
|
|
EXPECT_GE(reader.ReadBit(), 0);
|
|
EXPECT_FALSE(reader.Ok());
|
|
}
|
|
|
|
TEST(BitstreamReaderTest, ReadBit) {
|
|
const uint8_t bytes[] = {0b0100'0001, 0b1011'0001};
|
|
BitstreamReader reader(bytes);
|
|
// First byte.
|
|
EXPECT_EQ(reader.ReadBit(), 0);
|
|
EXPECT_EQ(reader.ReadBit(), 1);
|
|
EXPECT_EQ(reader.ReadBit(), 0);
|
|
EXPECT_EQ(reader.ReadBit(), 0);
|
|
|
|
EXPECT_EQ(reader.ReadBit(), 0);
|
|
EXPECT_EQ(reader.ReadBit(), 0);
|
|
EXPECT_EQ(reader.ReadBit(), 0);
|
|
EXPECT_EQ(reader.ReadBit(), 1);
|
|
|
|
// Second byte.
|
|
EXPECT_EQ(reader.ReadBit(), 1);
|
|
EXPECT_EQ(reader.ReadBit(), 0);
|
|
EXPECT_EQ(reader.ReadBit(), 1);
|
|
EXPECT_EQ(reader.ReadBit(), 1);
|
|
|
|
EXPECT_EQ(reader.ReadBit(), 0);
|
|
EXPECT_EQ(reader.ReadBit(), 0);
|
|
EXPECT_EQ(reader.ReadBit(), 0);
|
|
EXPECT_EQ(reader.ReadBit(), 1);
|
|
|
|
EXPECT_TRUE(reader.Ok());
|
|
// Try to read beyound the buffer.
|
|
EXPECT_EQ(reader.ReadBit(), 0);
|
|
EXPECT_FALSE(reader.Ok());
|
|
}
|
|
|
|
TEST(BitstreamReaderTest, ReadBoolConsumesSingleBit) {
|
|
const uint8_t bytes[] = {0b1010'1010};
|
|
BitstreamReader reader(bytes);
|
|
ASSERT_EQ(reader.RemainingBitCount(), 8);
|
|
EXPECT_TRUE(reader.Read<bool>());
|
|
EXPECT_EQ(reader.RemainingBitCount(), 7);
|
|
}
|
|
|
|
TEST(BitstreamReaderTest, ReadBytesAligned) {
|
|
const uint8_t bytes[] = {0x0A, //
|
|
0xBC, //
|
|
0xDE, 0xF1, //
|
|
0x23, 0x45, 0x67, 0x89};
|
|
BitstreamReader reader(bytes);
|
|
EXPECT_EQ(reader.Read<uint8_t>(), 0x0Au);
|
|
EXPECT_EQ(reader.Read<uint8_t>(), 0xBCu);
|
|
EXPECT_EQ(reader.Read<uint16_t>(), 0xDEF1u);
|
|
EXPECT_EQ(reader.Read<uint32_t>(), 0x23456789u);
|
|
EXPECT_TRUE(reader.Ok());
|
|
}
|
|
|
|
TEST(BitstreamReaderTest, ReadBytesOffset4) {
|
|
const uint8_t bytes[] = {0x0A, 0xBC, 0xDE, 0xF1, 0x23,
|
|
0x45, 0x67, 0x89, 0x0A};
|
|
BitstreamReader reader(bytes);
|
|
reader.ConsumeBits(4);
|
|
|
|
EXPECT_EQ(reader.Read<uint8_t>(), 0xABu);
|
|
EXPECT_EQ(reader.Read<uint8_t>(), 0xCDu);
|
|
EXPECT_EQ(reader.Read<uint16_t>(), 0xEF12u);
|
|
EXPECT_EQ(reader.Read<uint32_t>(), 0x34567890u);
|
|
EXPECT_TRUE(reader.Ok());
|
|
}
|
|
|
|
TEST(BitstreamReaderTest, 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};
|
|
|
|
BitstreamReader reader(bytes);
|
|
reader.ConsumeBits(3);
|
|
EXPECT_EQ(reader.Read<uint8_t>(), 0xFEu);
|
|
EXPECT_EQ(reader.Read<uint16_t>(), 0xDCBAu);
|
|
EXPECT_EQ(reader.Read<uint32_t>(), 0x98765432u);
|
|
EXPECT_TRUE(reader.Ok());
|
|
|
|
// 5 bits left unread. Not enough to read a uint8_t.
|
|
EXPECT_EQ(reader.RemainingBitCount(), 5);
|
|
EXPECT_EQ(reader.Read<uint8_t>(), 0);
|
|
EXPECT_FALSE(reader.Ok());
|
|
}
|
|
|
|
TEST(BitstreamReaderTest, ReadBits) {
|
|
const uint8_t bytes[] = {0b010'01'101, 0b0011'00'1'0};
|
|
BitstreamReader reader(bytes);
|
|
EXPECT_EQ(reader.ReadBits(3), 0b010u);
|
|
EXPECT_EQ(reader.ReadBits(2), 0b01u);
|
|
EXPECT_EQ(reader.ReadBits(7), 0b101'0011u);
|
|
EXPECT_EQ(reader.ReadBits(2), 0b00u);
|
|
EXPECT_EQ(reader.ReadBits(1), 0b1u);
|
|
EXPECT_EQ(reader.ReadBits(1), 0b0u);
|
|
EXPECT_TRUE(reader.Ok());
|
|
|
|
EXPECT_EQ(reader.ReadBits(1), 0u);
|
|
EXPECT_FALSE(reader.Ok());
|
|
}
|
|
|
|
TEST(BitstreamReaderTest, ReadZeroBits) {
|
|
BitstreamReader reader(rtc::ArrayView<const uint8_t>(nullptr, 0));
|
|
|
|
EXPECT_EQ(reader.ReadBits(0), 0u);
|
|
EXPECT_TRUE(reader.Ok());
|
|
}
|
|
|
|
TEST(BitstreamReaderTest, ReadBitFromEmptyArray) {
|
|
BitstreamReader reader(rtc::ArrayView<const uint8_t>(nullptr, 0));
|
|
|
|
// Trying to read from the empty array shouldn't dereference the pointer,
|
|
// i.e. shouldn't crash.
|
|
EXPECT_EQ(reader.ReadBit(), 0);
|
|
EXPECT_FALSE(reader.Ok());
|
|
}
|
|
|
|
TEST(BitstreamReaderTest, ReadBitsFromEmptyArray) {
|
|
BitstreamReader reader(rtc::ArrayView<const uint8_t>(nullptr, 0));
|
|
|
|
// Trying to read from the empty array shouldn't dereference the pointer,
|
|
// i.e. shouldn't crash.
|
|
EXPECT_EQ(reader.ReadBits(1), 0u);
|
|
EXPECT_FALSE(reader.Ok());
|
|
}
|
|
|
|
TEST(BitstreamReaderTest, ReadBits64) {
|
|
const uint8_t bytes[] = {0x4D, 0x32, 0xAB, 0x54, 0x00, 0xFF, 0xFE, 0x01,
|
|
0xAB, 0xCD, 0xEF, 0x01, 0x23, 0x45, 0x67, 0x89};
|
|
BitstreamReader reader(bytes);
|
|
|
|
EXPECT_EQ(reader.ReadBits(33), 0x4D32AB5400FFFE01u >> (64 - 33));
|
|
|
|
constexpr uint64_t kMask31Bits = (1ull << 32) - 1;
|
|
EXPECT_EQ(reader.ReadBits(31), 0x4D32AB5400FFFE01ull & kMask31Bits);
|
|
|
|
EXPECT_EQ(reader.ReadBits(64), 0xABCDEF0123456789ull);
|
|
EXPECT_TRUE(reader.Ok());
|
|
|
|
// Nothing more to read.
|
|
EXPECT_EQ(reader.ReadBit(), 0);
|
|
EXPECT_FALSE(reader.Ok());
|
|
}
|
|
|
|
TEST(BitstreamReaderTest, CanPeekBitsUsingCopyConstructor) {
|
|
// BitstreamReader doesn't have peek function. To simulate it, user may use
|
|
// cheap BitstreamReader copy constructor.
|
|
const uint8_t bytes[] = {0x0A, 0xBC};
|
|
BitstreamReader reader(bytes);
|
|
reader.ConsumeBits(4);
|
|
ASSERT_EQ(reader.RemainingBitCount(), 12);
|
|
|
|
BitstreamReader peeker = reader;
|
|
EXPECT_EQ(peeker.ReadBits(8), 0xABu);
|
|
EXPECT_EQ(peeker.RemainingBitCount(), 4);
|
|
|
|
EXPECT_EQ(reader.RemainingBitCount(), 12);
|
|
// Can resume reading from before peeker was created.
|
|
EXPECT_EQ(reader.ReadBits(4), 0xAu);
|
|
EXPECT_EQ(reader.RemainingBitCount(), 8);
|
|
}
|
|
|
|
TEST(BitstreamReaderTest,
|
|
ReadNonSymmetricSameNumberOfBitsWhenNumValuesPowerOf2) {
|
|
const uint8_t bytes[2] = {0xf3, 0xa0};
|
|
BitstreamReader reader(bytes);
|
|
|
|
ASSERT_EQ(reader.RemainingBitCount(), 16);
|
|
EXPECT_EQ(reader.ReadNonSymmetric(/*num_values=*/1 << 4), 0xfu);
|
|
EXPECT_EQ(reader.ReadNonSymmetric(/*num_values=*/1 << 4), 0x3u);
|
|
EXPECT_EQ(reader.ReadNonSymmetric(/*num_values=*/1 << 4), 0xau);
|
|
EXPECT_EQ(reader.ReadNonSymmetric(/*num_values=*/1 << 4), 0x0u);
|
|
EXPECT_EQ(reader.RemainingBitCount(), 0);
|
|
EXPECT_TRUE(reader.Ok());
|
|
}
|
|
|
|
TEST(BitstreamReaderTest, ReadNonSymmetricOnlyValueConsumesZeroBits) {
|
|
const uint8_t bytes[2] = {};
|
|
BitstreamReader reader(bytes);
|
|
|
|
ASSERT_EQ(reader.RemainingBitCount(), 16);
|
|
EXPECT_EQ(reader.ReadNonSymmetric(/*num_values=*/1), 0u);
|
|
EXPECT_EQ(reader.RemainingBitCount(), 16);
|
|
}
|
|
|
|
std::array<uint8_t, 8> GolombEncoded(uint32_t val) {
|
|
int val_width = absl::bit_width(val + 1);
|
|
int total_width = 2 * val_width - 1;
|
|
uint64_t representation = (uint64_t{val} + 1) << (64 - total_width);
|
|
std::array<uint8_t, 8> result;
|
|
for (int i = 0; i < 8; ++i) {
|
|
result[i] = representation >> (7 - i) * 8;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
TEST(BitstreamReaderTest, GolombUint32Values) {
|
|
// 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<uint32_t>::max() / 20000;
|
|
for (uint32_t i = 0; i < std::numeric_limits<uint32_t>::max() - kStep;
|
|
i += kStep) {
|
|
std::array<uint8_t, 8> buffer = GolombEncoded(i);
|
|
BitstreamReader reader(buffer);
|
|
// Use assert instead of EXPECT to avoid spamming thousands of failed
|
|
// expectation when this test fails.
|
|
ASSERT_EQ(reader.ReadExponentialGolomb(), i);
|
|
EXPECT_TRUE(reader.Ok());
|
|
}
|
|
}
|
|
|
|
TEST(BitstreamReaderTest, SignedGolombValues) {
|
|
uint8_t golomb_bits[][1] = {
|
|
{0b1'0000000}, {0b010'00000}, {0b011'00000}, {0b00100'000}, {0b00111'000},
|
|
};
|
|
int expected[] = {0, 1, -1, 2, -3};
|
|
for (size_t i = 0; i < sizeof(golomb_bits); ++i) {
|
|
BitstreamReader reader(golomb_bits[i]);
|
|
EXPECT_EQ(reader.ReadSignedExponentialGolomb(), expected[i])
|
|
<< "Mismatch in expected/decoded value for golomb_bits[" << i
|
|
<< "]: " << static_cast<int>(golomb_bits[i][0]);
|
|
EXPECT_TRUE(reader.Ok());
|
|
}
|
|
}
|
|
|
|
TEST(BitstreamReaderTest, 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.
|
|
BitstreamReader reader1(rtc::MakeArrayView(bytes, 1));
|
|
// When parse fails, `ReadExponentialGolomb` may return any number.
|
|
reader1.ReadExponentialGolomb();
|
|
EXPECT_FALSE(reader1.Ok());
|
|
|
|
BitstreamReader reader2(rtc::MakeArrayView(bytes, 2));
|
|
reader2.ReadExponentialGolomb();
|
|
EXPECT_FALSE(reader2.Ok());
|
|
|
|
BitstreamReader reader3(bytes);
|
|
// Golomb should have read 9 bits, so 0x01FF, and since it is golomb, the
|
|
// result is 0x01FF - 1 = 0x01FE.
|
|
EXPECT_EQ(reader3.ReadExponentialGolomb(), 0x01FEu);
|
|
EXPECT_TRUE(reader3.Ok());
|
|
}
|
|
|
|
TEST(BitstreamReaderTest, ReadLeb128) {
|
|
const uint8_t bytes[] = {0xFF, 0x7F};
|
|
BitstreamReader reader(bytes);
|
|
EXPECT_EQ(reader.ReadLeb128(), 0x3FFFu);
|
|
EXPECT_TRUE(reader.Ok());
|
|
}
|
|
|
|
TEST(BitstreamReaderTest, ReadLeb128Large) {
|
|
const uint8_t max_uint64[] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
|
0xFF, 0xFF, 0xFF, 0xFF, 0x1};
|
|
BitstreamReader max_reader(max_uint64);
|
|
EXPECT_EQ(max_reader.ReadLeb128(), std::numeric_limits<uint64_t>::max());
|
|
EXPECT_TRUE(max_reader.Ok());
|
|
|
|
const uint8_t overflow_unit64_t[] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
|
0xFF, 0xFF, 0xFF, 0xFF, 0x2};
|
|
BitstreamReader overflow_reader(overflow_unit64_t);
|
|
EXPECT_EQ(overflow_reader.ReadLeb128(), uint64_t{0});
|
|
EXPECT_FALSE(overflow_reader.Ok());
|
|
}
|
|
|
|
TEST(BitstreamReaderTest, ReadLeb128NoEndByte) {
|
|
const uint8_t bytes[] = {0xFF, 0xFF};
|
|
BitstreamReader reader(bytes);
|
|
EXPECT_EQ(reader.ReadLeb128(), uint64_t{0});
|
|
EXPECT_FALSE(reader.Ok());
|
|
}
|
|
|
|
} // namespace
|
|
} // namespace webrtc
|