blob: 8c0f66fa91802b2420a8cfd77a50682fc59d4ac5 [file] [log] [blame]
/*
* 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 &&
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 <>
ABSL_MUST_USE_RESULT bool Read<bool>() {
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_