Skip to content

Commit

Permalink
Implement LoadBytesToBuffer for StreamBasedReadBitBuffer.
Browse files Browse the repository at this point in the history
Also adds a max_source_size_ field to the steam based read bit buffer in order to decouple the current size of the source in the buffer (which will be represented by source_size_ and aligns with the current implementation of Seek()) and the maximum allowable source size, which is initialized with the max obu size const. The constructor is updated to reflect this, with the source_size_ starting at 0. PushBytes() is updated to grow the source_size_ as bytes are pushed.

In LoadBytesToBuffer, we then distinguish between cases in which we are being asked to load data that could not fit in the source with respect to the max size and the case in which we could theoretically have that data in source but we do not. In this case, pushing more bytes is necessary (and perhaps flushing).

Finally, the typed tests framework is updated to include our new buffer in the suite and ensure that all base functionality works. More class specific tests will be added as more implementation is completed.

PiperOrigin-RevId: 715394768
  • Loading branch information
Googler authored and jwcullen committed Jan 14, 2025
1 parent 283d8ff commit 0d69169
Show file tree
Hide file tree
Showing 3 changed files with 36 additions and 37 deletions.
22 changes: 10 additions & 12 deletions iamf/common/read_bit_buffer.cc
Original file line number Diff line number Diff line change
Expand Up @@ -450,32 +450,30 @@ std::unique_ptr<StreamBasedReadBitBuffer> StreamBasedReadBitBuffer::Create(
LOG(ERROR) << "StreamBasedReadBitBuffer capacity must be >= 0.";
return nullptr;
}
// The buffer is sized to hold at most twice the size of the largest possible
// OBU. `source_size` is in bits while max size is in bytes, so we convert
// accordingly.
return absl::WrapUnique(new StreamBasedReadBitBuffer(
capacity, kEntireObuSizeMaxTwoMegabytes * 2 * 8));
// Since this is a stream based buffer, we do not initialize with any data,
// hence the source size is initially set to 0.
return absl::WrapUnique(
new StreamBasedReadBitBuffer(capacity, /*source_size=*/0));
}

absl::Status StreamBasedReadBitBuffer::PushBytes(
const std::vector<uint8_t>& bytes) {
if (bytes.size() > ((source_size_ / 8) - source_vector_.size())) {
if (bytes.size() > ((max_source_size_ / 8) - source_vector_.size())) {
return absl::InvalidArgumentError(
"Cannot push more bytes than the available space in the source.");
}
// Copy the bytes to the source vector; this is added to the end in case there
// are already some bytes in the source.
source_vector_.insert(source_vector_.end(), bytes.begin(), bytes.end());
// The source grows as bytes are pushed.
source_size_ += bytes.size() * 8;
return absl::OkStatus();
}

absl::Status StreamBasedReadBitBuffer::LoadBytesToBuffer(int64_t starting_byte,
int64_t num_bytes) {
return absl::UnimplementedError("Not implemented.");
}

StreamBasedReadBitBuffer::StreamBasedReadBitBuffer(size_t capacity,
int64_t source_size)
: ReadBitBuffer(capacity, source_size) {}
: MemoryBasedReadBitBuffer(capacity, absl::Span<const uint8_t>()) {
max_source_size_ = kEntireObuSizeMaxTwoMegabytes * 2 * 8;
}

} // namespace iamf_tools
30 changes: 9 additions & 21 deletions iamf/common/read_bit_buffer.h
Original file line number Diff line number Diff line change
Expand Up @@ -250,8 +250,9 @@ class ReadBitBuffer {

// Size of the source data in bits. It may refer to the total file size
// for a file-based buffer, or the total memory size for a memory-based
// buffer, etc.
const int64_t source_size_;
// buffer. For a stream-based buffer, it is the current size of the source
// data, which is updated as bytes are pushed or flushed.
int64_t source_size_;

// Specifies the next bit to consume from the source data (the actual storage
// type is subclass-specific).
Expand Down Expand Up @@ -283,15 +284,14 @@ class MemoryBasedReadBitBuffer : public ReadBitBuffer {
/*!\brief Destructor.*/
~MemoryBasedReadBitBuffer() override = default;

private:
/*!\brief Private constructor. Called by the factory method only.
protected:
/*!\brief Protected constructor. Called by the factory method or subclasses.
*
* \param capacity Capacity of the internal buffer in bytes.
* \param source Source span from which the buffer will load data. The
* entire contents will be copied into the constructed instance.
*/
MemoryBasedReadBitBuffer(size_t capacity, absl::Span<const uint8_t> source);

/*!\brief Load bytes from the source vector to the buffer.
*
* \param starting_byte Starting byte to load from source.
Expand All @@ -303,7 +303,7 @@ class MemoryBasedReadBitBuffer : public ReadBitBuffer {
int64_t num_bytes) override;

// Source data stored in a vector.
const std::vector<uint8_t> source_vector_;
std::vector<uint8_t> source_vector_;
};

/*!\brief File-based read bit buffer.
Expand Down Expand Up @@ -358,7 +358,7 @@ class FileBasedReadBitBuffer : public ReadBitBuffer {
* methods will read data from the stream and provide it to the caller, or else
* will instruct the caller to push more data if necessary.
*/
class StreamBasedReadBitBuffer : public ReadBitBuffer {
class StreamBasedReadBitBuffer : public MemoryBasedReadBitBuffer {
public:
/*!\brief Creates an instance of a stream-based read bit buffer.
*
Expand Down Expand Up @@ -398,20 +398,8 @@ class StreamBasedReadBitBuffer : public ReadBitBuffer {
*/
StreamBasedReadBitBuffer(size_t capacity, int64_t source_size);

/*!\brief Load bytes from the source stream to the buffer.
*
* \param starting_byte Starting byte to load from source.
* \param num_bytes Number of bytes to load.
* \return `absl::OkStatus()` on success. `absl::InvalidArgumentError()` if
* the stream reading fails. `absl::ResourceExhaustedError()` if there
* is not enough data in the stream to load the requested bytes.
*/
absl::Status LoadBytesToBuffer(int64_t starting_byte,
int64_t num_bytes) override;

// Source data stored in a vector. Calls to Flush() will remove the first
// `num_bytes` elements from this vector.
std::vector<uint8_t> source_vector_;
// Specifies the maximum size of the source data in bits.
int64_t max_source_size_;
};

} // namespace iamf_tools
Expand Down
21 changes: 17 additions & 4 deletions iamf/common/tests/read_bit_buffer_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
#include <memory>
#include <string>
#include <tuple>
#include <utility>
#include <vector>

#include "absl/status/status.h"
Expand All @@ -35,7 +36,6 @@ namespace iamf_tools {
namespace {
using absl::StatusCode::kInvalidArgument;
using absl::StatusCode::kResourceExhausted;
using testing::ElementsAreArray;

using ::absl_testing::IsOk;
using ::absl_testing::StatusIs;
Expand Down Expand Up @@ -100,6 +100,15 @@ std::unique_ptr<FileBasedReadBitBuffer> CreateConcreteReadBitBuffer(
return FileBasedReadBitBuffer::CreateFromFilePath(capacity, output_filename);
}

template <>
std::unique_ptr<StreamBasedReadBitBuffer> CreateConcreteReadBitBuffer(
int64_t capacity, std::vector<uint8_t>& source_data) {
auto rb = StreamBasedReadBitBuffer::Create(capacity);
EXPECT_NE(rb, nullptr);
EXPECT_THAT(rb->PushBytes(source_data), IsOk());
return rb;
}

template <typename BufferReaderType>
class ReadBitBufferTest : public ::testing::Test {
protected:
Expand All @@ -117,7 +126,8 @@ class ReadBitBufferTest : public ::testing::Test {
};

using BufferReaderTypes =
::testing::Types<MemoryBasedReadBitBuffer, FileBasedReadBitBuffer>;
::testing::Types<MemoryBasedReadBitBuffer, FileBasedReadBitBuffer,
StreamBasedReadBitBuffer>;
TYPED_TEST_SUITE(ReadBitBufferTest, BufferReaderTypes);

TYPED_TEST(ReadBitBufferTest, CreateReadBitBufferSucceeds) {
Expand Down Expand Up @@ -381,7 +391,7 @@ TYPED_TEST(ReadBitBufferTest, ReadUleb128NotEnoughDataInBufferOrSource) {
// is used to create different concrete types of buffer readers. Then we
// augment the tests by taking the cartesian product of {test values} and
// {types of buffer readers} (using `testing::Combine`).
enum BufferReaderType { kMemoryBased, kFileBased };
enum BufferReaderType { kMemoryBased, kFileBased, kStreamBased };
struct SourceAndSize {
std::vector<uint8_t> source_data;
uint32_t expected_size_of_instance;
Expand All @@ -399,9 +409,12 @@ TEST_P(ReadIso14496_1ExpandedTest, ReadIso14496_1Expanded) {
if (buffer_reader_type == kMemoryBased) {
rb = CreateConcreteReadBitBuffer<MemoryBasedReadBitBuffer>(
source_data.size() * kBitsPerByte, source_data);
} else {
} else if (buffer_reader_type == kFileBased) {
rb = CreateConcreteReadBitBuffer<FileBasedReadBitBuffer>(
source_data.size() * kBitsPerByte, source_data);
} else {
rb = CreateConcreteReadBitBuffer<StreamBasedReadBitBuffer>(
source_data.size() * kBitsPerByte, source_data);
}

uint32_t output_size_of_instance = 0;
Expand Down

0 comments on commit 0d69169

Please sign in to comment.