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;