diff options
Diffstat (limited to 'third_party/libwebrtc/rtc_base/bitstream_reader.h')
-rw-r--r-- | third_party/libwebrtc/rtc_base/bitstream_reader.h | 145 |
1 files changed, 145 insertions, 0 deletions
diff --git a/third_party/libwebrtc/rtc_base/bitstream_reader.h b/third_party/libwebrtc/rtc_base/bitstream_reader.h new file mode 100644 index 0000000000..51c7914bd7 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/bitstream_reader.h @@ -0,0 +1,145 @@ +/* + * 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. + */ + +#ifndef RTC_BASE_BITSTREAM_READER_H_ +#define RTC_BASE_BITSTREAM_READER_H_ + +#include <stdint.h> + +#include "absl/base/attributes.h" +#include "absl/strings/string_view.h" +#include "api/array_view.h" +#include "rtc_base/checks.h" +#include "rtc_base/numerics/safe_conversions.h" + +namespace webrtc { + +// A class to parse sequence of bits. Byte order is assumed big-endian/network. +// This class is optimized for successful parsing and binary size. +// Individual calls to `Read` and `ConsumeBits` never fail. Instead they may +// change the class state into 'failure state'. User of this class should verify +// parsing by checking if class is in that 'failure state' by calling `Ok`. +// That verification can be done once after multiple reads. +class BitstreamReader { + public: + explicit BitstreamReader( + rtc::ArrayView<const uint8_t> bytes ABSL_ATTRIBUTE_LIFETIME_BOUND); + explicit BitstreamReader( + absl::string_view bytes ABSL_ATTRIBUTE_LIFETIME_BOUND); + BitstreamReader(const BitstreamReader&) = default; + BitstreamReader& operator=(const BitstreamReader&) = default; + ~BitstreamReader(); + + // Return number of unread bits in the buffer, or negative number if there + // was a reading error. + int RemainingBitCount() const; + + // Returns `true` iff all calls to `Read` and `ConsumeBits` were successful. + bool Ok() const { return RemainingBitCount() >= 0; } + + // Sets `BitstreamReader` into the failure state. + void Invalidate() { remaining_bits_ = -1; } + + // Moves current read position forward. `bits` must be non-negative. + void ConsumeBits(int bits); + + // Reads single bit. Returns 0 or 1. + ABSL_MUST_USE_RESULT int ReadBit(); + + // Reads `bits` from the bitstream. `bits` must be in range [0, 64]. + // Returns an unsigned integer in range [0, 2^bits - 1]. + // On failure sets `BitstreamReader` into the failure state and returns 0. + ABSL_MUST_USE_RESULT uint64_t ReadBits(int bits); + + // Reads unsigned integer of fixed width. + template <typename T, + typename std::enable_if<std::is_unsigned<T>::value && + !std::is_same<T, bool>::value && + sizeof(T) <= 8>::type* = nullptr> + ABSL_MUST_USE_RESULT T Read() { + return rtc::dchecked_cast<T>(ReadBits(sizeof(T) * 8)); + } + + // Reads single bit as boolean. + template < + typename T, + typename std::enable_if<std::is_same<T, bool>::value>::type* = nullptr> + ABSL_MUST_USE_RESULT bool Read() { + return ReadBit() != 0; + } + + // 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 = bit_width(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 + uint32_t ReadNonSymmetric(uint32_t num_values); + + // Reads exponential golomb encoded value. + // On failure sets `BitstreamReader` into the failure state and returns + // unspecified value. + // Exponential golomb values are encoded as: + // 1) x = source val + 1 + // 2) In binary, write [bit_width(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. + // Fails the parsing if the value wouldn't fit in a uint32_t. + uint32_t ReadExponentialGolomb(); + + // 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. + // On failure sets `BitstreamReader` into the failure state and returns + // unspecified value. + int ReadSignedExponentialGolomb(); + + private: + void set_last_read_is_verified(bool value) const; + + // Next byte with at least one unread bit. + const uint8_t* bytes_; + + // Number of bits remained to read. + int remaining_bits_; + + // Unused in release mode. + mutable bool last_read_is_verified_ = true; +}; + +inline BitstreamReader::BitstreamReader(rtc::ArrayView<const uint8_t> bytes) + : bytes_(bytes.data()), remaining_bits_(bytes.size() * 8) {} + +inline BitstreamReader::BitstreamReader(absl::string_view bytes) + : bytes_(reinterpret_cast<const uint8_t*>(bytes.data())), + remaining_bits_(bytes.size() * 8) {} + +inline BitstreamReader::~BitstreamReader() { + RTC_DCHECK(last_read_is_verified_) << "Latest calls to Read or ConsumeBit " + "were not checked with Ok function."; +} + +inline void BitstreamReader::set_last_read_is_verified(bool value) const { +#ifdef RTC_DCHECK_IS_ON + last_read_is_verified_ = value; +#endif +} + +inline int BitstreamReader::RemainingBitCount() const { + set_last_read_is_verified(true); + return remaining_bits_; +} + +} // namespace webrtc + +#endif // RTC_BASE_BITSTREAM_READER_H_ |