diff options
author | xiaomings@google.com <xiaomings@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-07-09 22:57:24 +0000 |
---|---|---|
committer | xiaomings@google.com <xiaomings@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-07-09 22:57:24 +0000 |
commit | ecc703929354d51b5e48854d41e222c51497f5d3 (patch) | |
tree | ab65a0ecf2f03c629b3c87fe2fbd79472e2e5fa2 /media/base | |
parent | eb55b4927d8f7593ca386ac670673a4108c9bc7b (diff) | |
download | chromium_src-ecc703929354d51b5e48854d41e222c51497f5d3.zip chromium_src-ecc703929354d51b5e48854d41e222c51497f5d3.tar.gz chromium_src-ecc703929354d51b5e48854d41e222c51497f5d3.tar.bz2 |
Add HE AAC support to ISO BMFF.
Also abstract common code in H264BitReader into BitReader for reusing.
Was: https://chromiumcodereview.appspot.com/10710002/
In the submitted patch of the last issue, the media.gyp included a non-existing file. This error hadn't been caught by try but later got caught by the build process and reverted the commit. So I create this issue to submit the fixed patch.
BUG=134445
TEST=BitReaderTest, AACTest
Review URL: https://chromiumcodereview.appspot.com/10753005
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@145769 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'media/base')
-rw-r--r-- | media/base/bit_reader.cc | 74 | ||||
-rw-r--r-- | media/base/bit_reader.h | 110 | ||||
-rw-r--r-- | media/base/bit_reader_unittest.cc | 110 |
3 files changed, 294 insertions, 0 deletions
diff --git a/media/base/bit_reader.cc b/media/base/bit_reader.cc new file mode 100644 index 0000000..e4106fa --- /dev/null +++ b/media/base/bit_reader.cc @@ -0,0 +1,74 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "media/base/bit_reader.h" + +namespace media { + +BitReader::BitReader() + : data_(NULL), + bytes_left_(0), + position_(0), + curr_byte_(0), + num_remaining_bits_in_curr_byte_(0) { +} + +BitReader::BitReader(const uint8* data, off_t size) { + Initialize(data, size); +} + +BitReader::~BitReader() {} + +void BitReader::Initialize(const uint8* data, off_t size) { + DCHECK(data != NULL || size == 0); // Data cannot be NULL if size is not 0. + + data_ = data; + bytes_left_ = size; + position_ = 0; + num_remaining_bits_in_curr_byte_ = 0; + + UpdateCurrByte(); +} + +void BitReader::UpdateCurrByte() { + DCHECK_EQ(num_remaining_bits_in_curr_byte_, 0); + + if (bytes_left_ < 1) + return; + + // Load a new byte and advance pointers. + curr_byte_ = *data_; + ++data_; + --bytes_left_; + num_remaining_bits_in_curr_byte_ = 8; +} + +bool BitReader::SkipBits(int num_bits) { + int dummy; + const int kDummySize = static_cast<int>(sizeof(dummy)) * 8; + + while (num_bits > kDummySize) { + if (ReadBits(kDummySize, &dummy)) { + num_bits -= kDummySize; + } else { + return false; + } + } + + return ReadBits(num_bits, &dummy); +} + +off_t BitReader::Tell() const { + return position_; +} + +off_t BitReader::NumBitsLeft() const { + return (num_remaining_bits_in_curr_byte_ + bytes_left_ * 8); +} + +bool BitReader::HasMoreData() const { + return num_remaining_bits_in_curr_byte_ != 0; +} + +} // namespace media diff --git a/media/base/bit_reader.h b/media/base/bit_reader.h new file mode 100644 index 0000000..35c62a9 --- /dev/null +++ b/media/base/bit_reader.h @@ -0,0 +1,110 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef MEDIA_BASE_BIT_READER_H_ +#define MEDIA_BASE_BIT_READER_H_ + +#include <sys/types.h> +#include <algorithm> +#include <climits> + +#include "base/basictypes.h" +#include "base/logging.h" +#include "media/base/media_export.h" + + +namespace media { + +// A class to read bit streams. +// Classes inherited this class can override its UpdateCurrByte function +// to support specific escape mechanism, which is widely used by streaming +// formats like H.264 Annex B. +class MEDIA_EXPORT BitReader { + public: + BitReader(); + BitReader(const uint8* data, off_t size); + virtual ~BitReader(); + + // Initialize the reader to start reading at |data|, |size| being size + // of |data| in bytes. + void Initialize(const uint8* data, off_t size); + + // Read |num_bits| next bits from stream and return in |*out|, first bit + // from the stream starting at |num_bits| position in |*out|. + // |num_bits| cannot be larger than the bits the type can hold. + // Return false if the given number of bits cannot be read (not enough + // bits in the stream), true otherwise. When return false, the stream will + // enter a state where further ReadBits operations will always return false + // unless |num_bits| is 0. The type |T| has to be a primitive integer type. + template<typename T> + bool ReadBits(int num_bits, T *out) { + DCHECK(num_bits <= static_cast<int>(sizeof(T) * CHAR_BIT)); + + *out = 0; + position_ += num_bits; + + while (num_remaining_bits_in_curr_byte_ != 0 && num_bits != 0) { + int bits_to_take = std::min(num_remaining_bits_in_curr_byte_, num_bits); + *out = (*out << bits_to_take) + + (curr_byte_ >> (num_remaining_bits_in_curr_byte_ - bits_to_take)); + num_bits -= bits_to_take; + num_remaining_bits_in_curr_byte_ -= bits_to_take; + curr_byte_ &= (1 << num_remaining_bits_in_curr_byte_) - 1; + + if (num_remaining_bits_in_curr_byte_ == 0) + UpdateCurrByte(); + } + + if (num_bits == 0) + return true; + + *out = 0; + num_remaining_bits_in_curr_byte_ = 0; + bytes_left_ = 0; + + return false; + } + + bool SkipBits(int num_bits); + + // Return the current position in the stream in unit of bit. + // This includes the skipped escape bytes if there are any. + off_t Tell() const; + + // Return the number of bits left in the stream. + // This doesn't take any escape sequence into account. + off_t NumBitsLeft() const; + + bool HasMoreData() const; + + protected: + // Advance to the next byte, loading it into curr_byte_. + // This function can be overridden to support specific escape mechanism. + // If the num_remaining_bits_in_curr_byte_ is 0 after this function returns, + // the stream has reached the end. + virtual void UpdateCurrByte(); + + // Pointer to the next unread (not in curr_byte_) byte in the stream. + const uint8* data_; + + // Bytes left in the stream (without the curr_byte_). + off_t bytes_left_; + + // Current position in bits. + off_t position_; + + // Contents of the current byte; first unread bit starting at position + // 8 - num_remaining_bits_in_curr_byte_ from MSB. + uint8 curr_byte_; + + // Number of bits remaining in curr_byte_ + int num_remaining_bits_in_curr_byte_; + + private: + DISALLOW_COPY_AND_ASSIGN(BitReader); +}; + +} // namespace media + +#endif // MEDIA_BASE_BIT_READER_H_ diff --git a/media/base/bit_reader_unittest.cc b/media/base/bit_reader_unittest.cc new file mode 100644 index 0000000..00d425f --- /dev/null +++ b/media/base/bit_reader_unittest.cc @@ -0,0 +1,110 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "media/base/bit_reader.h" + +#include "testing/gtest/include/gtest/gtest.h" + +namespace media { + +TEST(BitReaderTest, EmptyStreamTest) { + BitReader reader(NULL, 0); + uint8 value8 = 0xff; + + ASSERT_FALSE(reader.HasMoreData()); + ASSERT_EQ(reader.Tell(), 0); + ASSERT_TRUE(reader.ReadBits(0, &value8)); + ASSERT_TRUE(reader.SkipBits(0)); + ASSERT_EQ(reader.Tell(), 0); + ASSERT_FALSE(reader.HasMoreData()); + ASSERT_FALSE(reader.ReadBits(1, &value8)); + ASSERT_FALSE(reader.SkipBits(1)); + ASSERT_EQ(value8, 0); +} + +TEST(BitReaderTest, NormalOperationTest) { + // 0101 0101 1001 1001 repeats 4 times + uint8 buffer[] = {0x55, 0x99, 0x55, 0x99, 0x55, 0x99, 0x55, 0x99}; + BitReader reader(buffer, 6); // Initialize with 6 bytes only + uint8 value8; + uint64 value64; + + ASSERT_TRUE(reader.HasMoreData()); + ASSERT_EQ(reader.Tell(), 0); + ASSERT_TRUE(reader.ReadBits(1, &value8)); + ASSERT_EQ(value8, 0); + ASSERT_TRUE(reader.ReadBits(8, &value8)); + ASSERT_EQ(value8, 0xab); // 1010 1011 + ASSERT_EQ(reader.Tell(), 9); + ASSERT_TRUE(reader.HasMoreData()); + ASSERT_TRUE(reader.SkipBits(7)); + ASSERT_EQ(reader.Tell(), 16); + ASSERT_TRUE(reader.ReadBits(32, &value64)); + ASSERT_EQ(value64, 0x55995599u); + ASSERT_EQ(reader.Tell(), 48); + ASSERT_FALSE(reader.HasMoreData()); + ASSERT_FALSE(reader.SkipBits(1)); + ASSERT_FALSE(reader.ReadBits(1, &value8)); + ASSERT_TRUE(reader.SkipBits(0)); + value8 = 0xff; + ASSERT_TRUE(reader.ReadBits(0, &value8)); + ASSERT_EQ(value8, 0); + + reader.Initialize(buffer, 8); + ASSERT_TRUE(reader.ReadBits(64, &value64)); + EXPECT_EQ(value64, 0x5599559955995599ull); + EXPECT_FALSE(reader.HasMoreData()); + EXPECT_EQ(reader.Tell(), 64); + EXPECT_FALSE(reader.ReadBits(1, &value8)); + EXPECT_FALSE(reader.SkipBits(1)); + EXPECT_TRUE(reader.ReadBits(0, &value8)); + EXPECT_TRUE(reader.SkipBits(0)); +} + +TEST(BitReaderTest, LongSkipTest) { + uint8 buffer[] = { + 0x12, 0x34, 0x56, 0x78, 0x12, 0x34, 0x56, 0x78, // 64 * 1 + 0x12, 0x34, 0x56, 0x78, 0x12, 0x34, 0x56, 0x78, // 64 * 2 + 0x12, 0x34, 0x56, 0x78, 0x12, 0x34, 0x56, 0x78, // 64 * 3 + 0x12, 0x34, 0x56, 0x78, 0x12, 0x34, 0x56, 0x78, // 64 * 4 + 0x12, 0x34, 0x56, 0x78, 0x12, 0x34, 0x56, 0x78, // 64 * 5 + 0x12, 0x34, 0x56, 0x78, 0x12, 0x34, 0x56, 0x78, // 64 * 6 + 0x12, 0x34, 0x56, 0x78, 0x12, 0x34, 0x56, 0x78, // 64 * 7 + 0x12, 0x34, 0x56, 0x78, 0x12, 0x34, 0x56, 0x78, // 64 * 8 + 0x87, 0x65 + }; + BitReader reader(buffer, sizeof(buffer)); + uint8 value8; + + EXPECT_TRUE(reader.SkipBits(64 * 8 + 8)); + EXPECT_EQ(reader.Tell(), 64 * 8 + 8); + EXPECT_TRUE(reader.ReadBits(8, &value8)); + EXPECT_EQ(value8, 0x65); + EXPECT_EQ(reader.Tell(), 64 * 8 + 16); + EXPECT_FALSE(reader.HasMoreData()); + EXPECT_EQ(reader.NumBitsLeft(), 0); +} + +TEST(BitReaderTest, ReadBeyondEndTest) { + uint8 buffer[] = {0x12}; + BitReader reader(buffer, sizeof(buffer)); + uint8 value8; + + EXPECT_TRUE(reader.SkipBits(4)); + EXPECT_FALSE(reader.ReadBits(5, &value8)); + EXPECT_FALSE(reader.ReadBits(1, &value8)); + EXPECT_FALSE(reader.SkipBits(1)); + EXPECT_TRUE(reader.ReadBits(0, &value8)); + EXPECT_TRUE(reader.SkipBits(0)); + + reader.Initialize(buffer, sizeof(buffer)); + EXPECT_TRUE(reader.SkipBits(4)); + EXPECT_FALSE(reader.SkipBits(5)); + EXPECT_FALSE(reader.ReadBits(1, &value8)); + EXPECT_FALSE(reader.SkipBits(1)); + EXPECT_TRUE(reader.ReadBits(0, &value8)); + EXPECT_TRUE(reader.SkipBits(0)); +} + +} // namespace media |