From 867244645a1ef0557c1506c6762c00d369fa9a3a Mon Sep 17 00:00:00 2001 From: KongQun Yang Date: Sun, 22 Oct 2017 22:07:14 -0700 Subject: [PATCH] Implement BitWriter Change-Id: I5b7dfc2bc07227c2fe05f6de8857042bcab944c4 --- packager/media/base/bit_writer.cc | 42 +++++++++++++++ packager/media/base/bit_writer.h | 60 +++++++++++++++++++++ packager/media/base/bit_writer_unittest.cc | 62 ++++++++++++++++++++++ packager/media/base/media_base.gyp | 3 ++ 4 files changed, 167 insertions(+) create mode 100644 packager/media/base/bit_writer.cc create mode 100644 packager/media/base/bit_writer.h create mode 100644 packager/media/base/bit_writer_unittest.cc diff --git a/packager/media/base/bit_writer.cc b/packager/media/base/bit_writer.cc new file mode 100644 index 0000000000..6a93c04755 --- /dev/null +++ b/packager/media/base/bit_writer.cc @@ -0,0 +1,42 @@ +// Copyright 2017 Google Inc. All rights reserved. +// +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file or at +// https://developers.google.com/open-source/licenses/bsd + +#include "packager/media/base/bit_writer.h" + +namespace shaka { +namespace media { + +BitWriter::BitWriter(std::vector* storage) + : storage_(storage), initial_storage_size_(storage_->size()) {} + +void BitWriter::WriteBits(uint32_t bits, size_t number_of_bits) { + DCHECK_NE(number_of_bits, 0u); + DCHECK_LE(number_of_bits, 32u); + DCHECK_LT(bits, 1ULL << number_of_bits); + + num_bits_ += number_of_bits; + DCHECK_LE(num_bits_, 64); + bits_ |= static_cast(bits) << (64 - num_bits_); + + while (num_bits_ >= 8) { + storage_->push_back(bits_ >> 56); + bits_ <<= 8; + num_bits_ -= 8; + } +} + +void BitWriter::Flush() { + while (num_bits_ > 0) { + storage_->push_back(bits_ >> 56); + bits_ <<= 8; + num_bits_ -= 8; + } + bits_ = 0; + num_bits_ = 0; +} + +} // namespace media +} // namespace shaka diff --git a/packager/media/base/bit_writer.h b/packager/media/base/bit_writer.h new file mode 100644 index 0000000000..8ab32ef4b8 --- /dev/null +++ b/packager/media/base/bit_writer.h @@ -0,0 +1,60 @@ +// Copyright 2017 Google Inc. All rights reserved. +// +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file or at +// https://developers.google.com/open-source/licenses/bsd + +#ifndef PACKAGER_MEDIA_BASE_BIT_WRITER_H_ +#define PACKAGER_MEDIA_BASE_BIT_WRITER_H_ + +#include + +#include + +#include "packager/base/logging.h" + +namespace shaka { +namespace media { + +class BitWriter { + public: + /// Constructor a BitWriter instance which writes to the provided storage. + /// @param storage points to vector this BitWriter writes to. Cannot be + /// nullptr. + explicit BitWriter(std::vector* storage); + ~BitWriter() = default; + + /// Appends the sequence 'bits' of length 'number_of_bits' <= 32. + /// Note that 'bits' should contain at most 'number_of_bits' bits, i.e. + /// bits should be less than 1 << number_of_bits. + /// @param bits is the data to write. + /// @param number_of_bits is the number of LSB to write, capped at 32. Cannot + /// be zero. + void WriteBits(uint32_t bits, size_t number_of_bits); + + /// Write pending bits, and align bitstream with extra zero bits. + void Flush(); + + /// @return last written position, in bits. + size_t BitPos() const { return BytePos() * 8 + num_bits_; } + + /// @return last written position, in bytes. + size_t BytePos() const { return storage_->size() - initial_storage_size_; } + + private: + BitWriter(const BitWriter&) = delete; + BitWriter& operator=(const BitWriter&) = delete; + + // Accumulator for unwritten bits. + uint64_t bits_ = 0; + // Number of unwritten bits. + int num_bits_ = 0; + // Buffer contains the written bits. + std::vector* const storage_ = nullptr; + const size_t initial_storage_size_ = 0; +}; + +} // namespace media +} // namespace shaka + +#endif // PACKAGER_MEDIA_BASE_BIT_WRITER_H_ diff --git a/packager/media/base/bit_writer_unittest.cc b/packager/media/base/bit_writer_unittest.cc new file mode 100644 index 0000000000..408059ec58 --- /dev/null +++ b/packager/media/base/bit_writer_unittest.cc @@ -0,0 +1,62 @@ +// Copyright 2017 Google Inc. All rights reserved. +// +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file or at +// https://developers.google.com/open-source/licenses/bsd + +#include "packager/media/base/bit_writer.h" + +#include +#include + +using testing::ElementsAreArray; + +namespace shaka { +namespace media { + +TEST(BitWriterTest, Simple) { + std::vector storage; + BitWriter writer(&storage); + writer.WriteBits(1, 1); + EXPECT_EQ(1u, writer.BitPos()); + EXPECT_EQ(0u, writer.BytePos()); + writer.Flush(); + // Bits are byte-aligned after flush. + EXPECT_EQ(8u, writer.BitPos()); + EXPECT_EQ(1u, writer.BytePos()); + + EXPECT_THAT(storage, ElementsAreArray({0x80})); +} + +TEST(BitWriterTest, Test) { + std::vector storage; + BitWriter writer(&storage); + writer.WriteBits(0, 1); + EXPECT_EQ(1u, writer.BitPos()); + EXPECT_EQ(0u, writer.BytePos()); + writer.WriteBits(0xab, 8); + EXPECT_EQ(9u, writer.BitPos()); + EXPECT_EQ(1u, writer.BytePos()); + writer.WriteBits(0x34, 6); + EXPECT_EQ(15u, writer.BitPos()); + EXPECT_EQ(1u, writer.BytePos()); + writer.WriteBits(0x55995599, 32); + EXPECT_EQ(47u, writer.BitPos()); + EXPECT_EQ(5u, writer.BytePos()); + writer.WriteBits(1, 1); + EXPECT_EQ(48u, writer.BitPos()); + EXPECT_EQ(6u, writer.BytePos()); + writer.WriteBits(0x13, 21); + EXPECT_EQ(69u, writer.BitPos()); + EXPECT_EQ(8u, writer.BytePos()); + writer.Flush(); + // Bits are byte-aligned after flush. + EXPECT_EQ(72u, writer.BitPos()); + EXPECT_EQ(9u, writer.BytePos()); + + EXPECT_THAT(storage, ElementsAreArray({0x55, 0xe8, 0xab, 0x32, 0xab, 0x33, + 0x00, 0x00, 0x98})); +} + +} // namespace media +} // namespace shaka diff --git a/packager/media/base/media_base.gyp b/packager/media/base/media_base.gyp index 4ed58579d3..459406e599 100644 --- a/packager/media/base/media_base.gyp +++ b/packager/media/base/media_base.gyp @@ -27,6 +27,8 @@ 'audio_timestamp_helper.h', 'bit_reader.cc', 'bit_reader.h', + 'bit_writer.cc', + 'bit_writer.h', 'buffer_reader.cc', 'buffer_reader.h', 'buffer_writer.cc', @@ -138,6 +140,7 @@ 'aes_pattern_cryptor_unittest.cc', 'audio_timestamp_helper_unittest.cc', 'bit_reader_unittest.cc', + 'bit_writer_unittest.cc', 'buffer_writer_unittest.cc', 'closure_thread_unittest.cc', 'container_names_unittest.cc',