From 0d691697e3a93dd76f57530805fb676a5d02f6cf Mon Sep 17 00:00:00 2001 From: Googler Date: Tue, 14 Jan 2025 11:36:07 -0500 Subject: [PATCH] Implement LoadBytesToBuffer for StreamBasedReadBitBuffer. 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 --- iamf/common/read_bit_buffer.cc | 22 ++++++++--------- iamf/common/read_bit_buffer.h | 30 +++++++---------------- iamf/common/tests/read_bit_buffer_test.cc | 21 +++++++++++++--- 3 files changed, 36 insertions(+), 37 deletions(-) diff --git a/iamf/common/read_bit_buffer.cc b/iamf/common/read_bit_buffer.cc index 3bb3e99..d22975d 100644 --- a/iamf/common/read_bit_buffer.cc +++ b/iamf/common/read_bit_buffer.cc @@ -450,32 +450,30 @@ std::unique_ptr 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& 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()) { + max_source_size_ = kEntireObuSizeMaxTwoMegabytes * 2 * 8; +} } // namespace iamf_tools diff --git a/iamf/common/read_bit_buffer.h b/iamf/common/read_bit_buffer.h index b7e1b00..f7f8f1c 100644 --- a/iamf/common/read_bit_buffer.h +++ b/iamf/common/read_bit_buffer.h @@ -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). @@ -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 source); - /*!\brief Load bytes from the source vector to the buffer. * * \param starting_byte Starting byte to load from source. @@ -303,7 +303,7 @@ class MemoryBasedReadBitBuffer : public ReadBitBuffer { int64_t num_bytes) override; // Source data stored in a vector. - const std::vector source_vector_; + std::vector source_vector_; }; /*!\brief File-based read bit buffer. @@ -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. * @@ -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 source_vector_; + // Specifies the maximum size of the source data in bits. + int64_t max_source_size_; }; } // namespace iamf_tools diff --git a/iamf/common/tests/read_bit_buffer_test.cc b/iamf/common/tests/read_bit_buffer_test.cc index f2fe0f0..9ba7c15 100644 --- a/iamf/common/tests/read_bit_buffer_test.cc +++ b/iamf/common/tests/read_bit_buffer_test.cc @@ -20,6 +20,7 @@ #include #include #include +#include #include #include "absl/status/status.h" @@ -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; @@ -100,6 +100,15 @@ std::unique_ptr CreateConcreteReadBitBuffer( return FileBasedReadBitBuffer::CreateFromFilePath(capacity, output_filename); } +template <> +std::unique_ptr CreateConcreteReadBitBuffer( + int64_t capacity, std::vector& source_data) { + auto rb = StreamBasedReadBitBuffer::Create(capacity); + EXPECT_NE(rb, nullptr); + EXPECT_THAT(rb->PushBytes(source_data), IsOk()); + return rb; +} + template class ReadBitBufferTest : public ::testing::Test { protected: @@ -117,7 +126,8 @@ class ReadBitBufferTest : public ::testing::Test { }; using BufferReaderTypes = - ::testing::Types; + ::testing::Types; TYPED_TEST_SUITE(ReadBitBufferTest, BufferReaderTypes); TYPED_TEST(ReadBitBufferTest, CreateReadBitBufferSucceeds) { @@ -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 source_data; uint32_t expected_size_of_instance; @@ -399,9 +409,12 @@ TEST_P(ReadIso14496_1ExpandedTest, ReadIso14496_1Expanded) { if (buffer_reader_type == kMemoryBased) { rb = CreateConcreteReadBitBuffer( source_data.size() * kBitsPerByte, source_data); - } else { + } else if (buffer_reader_type == kFileBased) { rb = CreateConcreteReadBitBuffer( source_data.size() * kBitsPerByte, source_data); + } else { + rb = CreateConcreteReadBitBuffer( + source_data.size() * kBitsPerByte, source_data); } uint32_t output_size_of_instance = 0;