217 lines
6.6 KiB
C++
217 lines
6.6 KiB
C++
// Copyright 2016 The Draco Authors.
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
//
|
|
#ifndef DRACO_CORE_DECODER_BUFFER_H_
|
|
#define DRACO_CORE_DECODER_BUFFER_H_
|
|
|
|
#include <stdint.h>
|
|
|
|
#include <cstring>
|
|
#include <memory>
|
|
|
|
#include "draco/core/macros.h"
|
|
#include "draco/draco_features.h"
|
|
|
|
namespace draco {
|
|
|
|
// Class is a wrapper around input data used by MeshDecoder. It provides a
|
|
// basic interface for decoding either typed or variable-bit sized data.
|
|
class DecoderBuffer {
|
|
public:
|
|
DecoderBuffer();
|
|
DecoderBuffer(const DecoderBuffer &buf) = default;
|
|
|
|
DecoderBuffer &operator=(const DecoderBuffer &buf) = default;
|
|
|
|
// Sets the buffer's internal data. Note that no copy of the input data is
|
|
// made so the data owner needs to keep the data valid and unchanged for
|
|
// runtime of the decoder.
|
|
void Init(const char *data, size_t data_size);
|
|
|
|
// Sets the buffer's internal data. |version| is the Draco bitstream version.
|
|
void Init(const char *data, size_t data_size, uint16_t version);
|
|
|
|
// Starts decoding a bit sequence.
|
|
// decode_size must be true if the size of the encoded bit data was included,
|
|
// during encoding. The size is then returned to out_size.
|
|
// Returns false on error.
|
|
bool StartBitDecoding(bool decode_size, uint64_t *out_size);
|
|
|
|
// Ends the decoding of the bit sequence and return to the default
|
|
// byte-aligned decoding.
|
|
void EndBitDecoding();
|
|
|
|
// Decodes up to 32 bits into out_val. Can be called only in between
|
|
// StartBitDecoding and EndBitDecoding. Otherwise returns false.
|
|
bool DecodeLeastSignificantBits32(int nbits, uint32_t *out_value) {
|
|
if (!bit_decoder_active()) {
|
|
return false;
|
|
}
|
|
bit_decoder_.GetBits(nbits, out_value);
|
|
return true;
|
|
}
|
|
|
|
// Decodes an arbitrary data type.
|
|
// Can be used only when we are not decoding a bit-sequence.
|
|
// Returns false on error.
|
|
template <typename T>
|
|
bool Decode(T *out_val) {
|
|
if (!Peek(out_val)) {
|
|
return false;
|
|
}
|
|
pos_ += sizeof(T);
|
|
return true;
|
|
}
|
|
|
|
bool Decode(void *out_data, size_t size_to_decode) {
|
|
if (data_size_ < static_cast<int64_t>(pos_ + size_to_decode)) {
|
|
return false; // Buffer overflow.
|
|
}
|
|
memcpy(out_data, (data_ + pos_), size_to_decode);
|
|
pos_ += size_to_decode;
|
|
return true;
|
|
}
|
|
|
|
// Decodes an arbitrary data, but does not advance the reading position.
|
|
template <typename T>
|
|
bool Peek(T *out_val) {
|
|
const size_t size_to_decode = sizeof(T);
|
|
if (data_size_ < static_cast<int64_t>(pos_ + size_to_decode)) {
|
|
return false; // Buffer overflow.
|
|
}
|
|
memcpy(out_val, (data_ + pos_), size_to_decode);
|
|
return true;
|
|
}
|
|
|
|
bool Peek(void *out_data, size_t size_to_peek) {
|
|
if (data_size_ < static_cast<int64_t>(pos_ + size_to_peek)) {
|
|
return false; // Buffer overflow.
|
|
}
|
|
memcpy(out_data, (data_ + pos_), size_to_peek);
|
|
return true;
|
|
}
|
|
|
|
// Discards #bytes from the input buffer.
|
|
void Advance(int64_t bytes) { pos_ += bytes; }
|
|
|
|
// Moves the parsing position to a specific offset from the beginning of the
|
|
// input data.
|
|
void StartDecodingFrom(int64_t offset) { pos_ = offset; }
|
|
|
|
void set_bitstream_version(uint16_t version) { bitstream_version_ = version; }
|
|
|
|
// Returns the data array at the current decoder position.
|
|
const char *data_head() const { return data_ + pos_; }
|
|
int64_t remaining_size() const { return data_size_ - pos_; }
|
|
int64_t decoded_size() const { return pos_; }
|
|
bool bit_decoder_active() const { return bit_mode_; }
|
|
|
|
// Returns the bitstream associated with the data. Returns 0 if unknown.
|
|
uint16_t bitstream_version() const { return bitstream_version_; }
|
|
|
|
private:
|
|
// Internal helper class to decode bits from a bit buffer.
|
|
class BitDecoder {
|
|
public:
|
|
BitDecoder();
|
|
~BitDecoder();
|
|
|
|
// Sets the bit buffer to |b|. |s| is the size of |b| in bytes.
|
|
inline void reset(const void *b, size_t s) {
|
|
bit_offset_ = 0;
|
|
bit_buffer_ = static_cast<const uint8_t *>(b);
|
|
bit_buffer_end_ = bit_buffer_ + s;
|
|
}
|
|
|
|
// Returns number of bits decoded so far.
|
|
inline uint64_t BitsDecoded() const {
|
|
return static_cast<uint64_t>(bit_offset_);
|
|
}
|
|
|
|
// Return number of bits available for decoding
|
|
inline uint64_t AvailBits() const {
|
|
return ((bit_buffer_end_ - bit_buffer_) * 8) - bit_offset_;
|
|
}
|
|
|
|
inline uint32_t EnsureBits(int k) {
|
|
DRACO_DCHECK_LE(k, 24);
|
|
DRACO_DCHECK_LE(static_cast<uint64_t>(k), AvailBits());
|
|
|
|
uint32_t buf = 0;
|
|
for (int i = 0; i < k; ++i) {
|
|
buf |= PeekBit(i) << i;
|
|
}
|
|
return buf; // Okay to return extra bits
|
|
}
|
|
|
|
inline void ConsumeBits(int k) { bit_offset_ += k; }
|
|
|
|
// Returns |nbits| bits in |x|.
|
|
inline bool GetBits(int32_t nbits, uint32_t *x) {
|
|
DRACO_DCHECK_GE(nbits, 0);
|
|
DRACO_DCHECK_LE(nbits, 32);
|
|
uint32_t value = 0;
|
|
for (int32_t bit = 0; bit < nbits; ++bit) {
|
|
value |= GetBit() << bit;
|
|
}
|
|
*x = value;
|
|
return true;
|
|
}
|
|
|
|
private:
|
|
// TODO(fgalligan): Add support for error reporting on range check.
|
|
// Returns one bit from the bit buffer.
|
|
inline int GetBit() {
|
|
const size_t off = bit_offset_;
|
|
const size_t byte_offset = off >> 3;
|
|
const int bit_shift = static_cast<int>(off & 0x7);
|
|
if (bit_buffer_ + byte_offset < bit_buffer_end_) {
|
|
const int bit = (bit_buffer_[byte_offset] >> bit_shift) & 1;
|
|
bit_offset_ = off + 1;
|
|
return bit;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
inline int PeekBit(int offset) {
|
|
const size_t off = bit_offset_ + offset;
|
|
const size_t byte_offset = off >> 3;
|
|
const int bit_shift = static_cast<int>(off & 0x7);
|
|
if (bit_buffer_ + byte_offset < bit_buffer_end_) {
|
|
const int bit = (bit_buffer_[byte_offset] >> bit_shift) & 1;
|
|
return bit;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
const uint8_t *bit_buffer_;
|
|
const uint8_t *bit_buffer_end_;
|
|
size_t bit_offset_;
|
|
};
|
|
friend class BufferBitCodingTest;
|
|
|
|
const char *data_;
|
|
int64_t data_size_;
|
|
|
|
// Current parsing position of the decoder.
|
|
int64_t pos_;
|
|
BitDecoder bit_decoder_;
|
|
bool bit_mode_;
|
|
uint16_t bitstream_version_;
|
|
};
|
|
|
|
} // namespace draco
|
|
|
|
#endif // DRACO_CORE_DECODER_BUFFER_H_
|