146 lines
5.3 KiB
C++
146 lines
5.3 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.
|
|
*/
|
|
|
|
#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_
|