diff --git a/iamf/common/read_bit_buffer.cc b/iamf/common/read_bit_buffer.cc index 3bb3e994..d22975d6 100644 --- a/iamf/common/read_bit_buffer.cc +++ b/iamf/common/read_bit_buffer.cc @@ -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 diff --git a/iamf/common/read_bit_buffer.h b/iamf/common/read_bit_buffer.h index b7e1b001..f7f8f1c1 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<const uint8_t> 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<uint8_t> source_vector_; + std::vector<uint8_t> 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<uint8_t> 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 f2fe0f0f..9ba7c15d 100644 --- a/iamf/common/tests/read_bit_buffer_test.cc +++ b/iamf/common/tests/read_bit_buffer_test.cc @@ -20,6 +20,7 @@ #include <memory> #include <string> #include <tuple> +#include <utility> #include <vector> #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<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: @@ -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) { @@ -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; @@ -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;