diff options
author | sergeyu@chromium.org <sergeyu@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-04-27 03:48:08 +0000 |
---|---|---|
committer | sergeyu@chromium.org <sergeyu@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-04-27 03:48:08 +0000 |
commit | 4b40fccbc3dce6f081cd741b2404d82e02eb7e5b (patch) | |
tree | 07d60996c1a317e4ba28bf84beedfdb9e3c7cbc2 /media | |
parent | 562b222ad53049a87f695e450e8698d3cb2aa1d6 (diff) | |
download | chromium_src-4b40fccbc3dce6f081cd741b2404d82e02eb7e5b.zip chromium_src-4b40fccbc3dce6f081cd741b2404d82e02eb7e5b.tar.gz chromium_src-4b40fccbc3dce6f081cd741b2404d82e02eb7e5b.tar.bz2 |
Merging SeekableBuffer and BufferQueue:
1. Removed SeekableBuffer::Buffer.
2. Extended SeekableBuffer to support all the features of BufferQueue.
3. BufferQueue removed and replaced with SeekableBuffer.
BUG=28654
TEST=none
Review URL: http://codereview.chromium.org/1736012
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@45669 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'media')
-rw-r--r-- | media/base/buffer_queue.cc | 121 | ||||
-rw-r--r-- | media/base/buffer_queue.h | 70 | ||||
-rw-r--r-- | media/base/buffer_queue_unittest.cc | 181 | ||||
-rw-r--r-- | media/base/seekable_buffer.cc | 126 | ||||
-rw-r--r-- | media/base/seekable_buffer.h | 62 | ||||
-rw-r--r-- | media/base/seekable_buffer_unittest.cc | 112 | ||||
-rw-r--r-- | media/filters/audio_renderer_algorithm_base.cc | 17 | ||||
-rw-r--r-- | media/filters/audio_renderer_algorithm_base.h | 4 | ||||
-rw-r--r-- | media/media.gyp | 3 |
9 files changed, 236 insertions, 460 deletions
diff --git a/media/base/buffer_queue.cc b/media/base/buffer_queue.cc deleted file mode 100644 index 26317c2..0000000 --- a/media/base/buffer_queue.cc +++ /dev/null @@ -1,121 +0,0 @@ -// Copyright (c) 2009 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/buffer_queue.h" - -#include "media/base/buffers.h" - -namespace media { - -BufferQueue::BufferQueue() - : data_offset_(0), - size_in_bytes_(0), - most_recent_time_() { -} - -BufferQueue::~BufferQueue() { -} - -void BufferQueue::Consume(size_t bytes_to_be_consumed) { - // Make sure user isn't trying to consume more than we have. - DCHECK(size_in_bytes_ >= bytes_to_be_consumed); - - // As we have enough data to consume, adjust |size_in_bytes_|. - size_in_bytes_ -= bytes_to_be_consumed; - - // Now consume them. - while (bytes_to_be_consumed > 0) { - // Calculate number of usable bytes in the front of the |queue_|. - size_t front_remaining = queue_.front()->GetDataSize() - data_offset_; - - // If there is enough data in our first buffer to advance into it, do so. - // Otherwise, advance into the queue. - if (front_remaining > bytes_to_be_consumed) { - data_offset_ += bytes_to_be_consumed; - bytes_to_be_consumed = 0; - // Garbage values are unavoidable, so this check will remain. - if (queue_.front()->GetTimestamp().InMicroseconds() > 0) { - int64 offset = (queue_.front()->GetDuration().InMicroseconds() * - data_offset_) / queue_.front()->GetDataSize(); - - most_recent_time_ = queue_.front()->GetTimestamp() + - base::TimeDelta::FromMicroseconds(offset); - } - } else { - data_offset_ = 0; - // Garbage values are unavoidable, so this check will remain. - if (queue_.front()->GetTimestamp().InMicroseconds() > 0) { - most_recent_time_ = queue_.front()->GetTimestamp() + - queue_.front()->GetDuration(); - } - queue_.pop_front(); - bytes_to_be_consumed -= front_remaining; - } - } -} - -size_t BufferQueue::Copy(uint8* dest, size_t bytes) { - if (bytes == 0) - return 0; - - DCHECK(!queue_.empty()); - - size_t current_remaining = 0; - const uint8* current = NULL; - size_t copied = 0; - - for (size_t i = 0; i < queue_.size() && bytes > 0; ++i) { - // Calculate number of usable bytes in the front of the |queue_|. Special - // case for front due to |data_offset_|. - if (i == 0) { - current_remaining = queue_.front()->GetDataSize() - data_offset_; - current = queue_.front()->GetData() + data_offset_; - } else { - current_remaining = queue_[i]->GetDataSize(); - current = queue_[i]->GetData(); - } - - // Prevent writing over the end of the buffer. - if (current_remaining > bytes) - current_remaining = bytes; - - memcpy(dest + copied, current, current_remaining); - - // Modify counts and pointers. - copied += current_remaining; - bytes -= current_remaining; - } - return copied; -} - -void BufferQueue::Enqueue(Buffer* buffer_in) { - if (queue_.empty() && buffer_in->GetTimestamp().InMicroseconds() > 0) { - most_recent_time_ = buffer_in->GetTimestamp(); - } - queue_.push_back(buffer_in); - size_in_bytes_ += buffer_in->GetDataSize(); -} - -base::TimeDelta BufferQueue::GetTime() { - return most_recent_time_; -} - -void BufferQueue::Clear() { - queue_.clear(); - size_in_bytes_ = 0; - data_offset_ = 0; - most_recent_time_ = base::TimeDelta(); -} - -bool BufferQueue::IsEmpty() { - // Since we keep track of the number of bytes, this is easier than calling - // into |queue_|. - return size_in_bytes_ == 0; -} - -size_t BufferQueue::SizeInBytes() { - return size_in_bytes_; -} - -} // namespace media diff --git a/media/base/buffer_queue.h b/media/base/buffer_queue.h deleted file mode 100644 index e6018c9..0000000 --- a/media/base/buffer_queue.h +++ /dev/null @@ -1,70 +0,0 @@ -// Copyright (c) 2009 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. - -// BufferQueue is a simple Buffer manager that handles requests for data -// while hiding Buffer boundaries, treating its internal queue of Buffers -// as a contiguous region. -// -// This class is not threadsafe and requires external locking. - -#ifndef MEDIA_BASE_BUFFER_QUEUE_H_ -#define MEDIA_BASE_BUFFER_QUEUE_H_ - -#include <deque> - -#include "base/ref_counted.h" -#include "base/time.h" - -namespace media { - -class Buffer; - -class BufferQueue { - public: - BufferQueue(); - ~BufferQueue(); - - // Clears |queue_|. - void Clear(); - - // Advances front pointer |bytes_to_be_consumed| bytes and discards - // "consumed" buffers. - void Consume(size_t bytes_to_be_consumed); - - // Tries to copy |bytes| bytes from our data to |dest|. Returns the number - // of bytes successfully copied. - size_t Copy(uint8* dest, size_t bytes); - - // Enqueues |buffer_in| and adds a reference. - void Enqueue(Buffer* buffer_in); - - // Returns the current timestamp, taking into account |data_offset_|. - base::TimeDelta GetTime(); - - // Returns true if the |queue_| is empty. - bool IsEmpty(); - - // Returns the number of bytes in the |queue_|. - size_t SizeInBytes(); - - private: - // Queued audio data. - std::deque< scoped_refptr<Buffer> > queue_; - - // Remembers the amount of remaining audio data in the front buffer. - size_t data_offset_; - - // Keeps track of the |queue_| size in bytes. - size_t size_in_bytes_; - - // Keeps track of the most recent time we've seen in case the |queue_| is - // empty when our owner asks what time it is. - base::TimeDelta most_recent_time_; - - DISALLOW_COPY_AND_ASSIGN(BufferQueue); -}; - -} // namespace media - -#endif // MEDIA_BASE_BUFFER_QUEUE_H_ diff --git a/media/base/buffer_queue_unittest.cc b/media/base/buffer_queue_unittest.cc deleted file mode 100644 index d50d5a0..0000000 --- a/media/base/buffer_queue_unittest.cc +++ /dev/null @@ -1,181 +0,0 @@ -// Copyright (c) 2009 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 "base/scoped_ptr.h" -#include "base/string_util.h" -#include "base/time.h" -#include "media/base/buffer_queue.h" -#include "media/base/data_buffer.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace media { - -class BufferQueueTest : public testing::Test { - protected: - BufferQueueTest() { - buffer1 = new DataBuffer(kDataSize); - buffer1->SetDataSize(kDataSize); - data1 = buffer1->GetWritableData(); - - buffer2 = new DataBuffer(kNewDataSize); - buffer2->SetDataSize(kNewDataSize); - data2 = buffer2->GetWritableData(); - - bufferBig = new DataBuffer(2 * (kDataSize + kNewDataSize)); - bufferBig->SetDataSize(2 * (kDataSize + kNewDataSize)); - dataBig = bufferBig->GetWritableData(); - - memcpy(data1, kData, kDataSize); - memcpy(data2, kNewData, kNewDataSize); - } - - BufferQueue queue_; - - static const char kData[]; - static const size_t kDataSize; - static const char kNewData[]; - static const size_t kNewDataSize; - scoped_refptr<DataBuffer> buffer1; - scoped_refptr<DataBuffer> buffer2; - scoped_refptr<DataBuffer> bufferBig; - uint8* data1; - uint8* data2; - uint8* dataBig; - - private: - DISALLOW_COPY_AND_ASSIGN(BufferQueueTest); -}; - -const char BufferQueueTest::kData[] = "hello"; -const size_t BufferQueueTest::kDataSize = arraysize(BufferQueueTest::kData); -const char BufferQueueTest::kNewData[] = "chromium"; -const size_t BufferQueueTest::kNewDataSize = - arraysize(BufferQueueTest::kNewData); - -TEST_F(BufferQueueTest, ValidTestData) { - ASSERT_TRUE(kNewDataSize > kDataSize); - ASSERT_TRUE(buffer1.get()); - ASSERT_TRUE(data1); - ASSERT_TRUE(buffer2.get()); - ASSERT_TRUE(data2); - ASSERT_TRUE(bufferBig.get()); - ASSERT_TRUE(dataBig); -} - -TEST_F(BufferQueueTest, Ctor) { - EXPECT_TRUE(queue_.IsEmpty()); - EXPECT_EQ(0u, queue_.SizeInBytes()); -} - -TEST_F(BufferQueueTest, Enqueue) { - queue_.Enqueue(buffer1.get()); - EXPECT_FALSE(queue_.IsEmpty()); - EXPECT_EQ(kDataSize, queue_.SizeInBytes()); -} - -TEST_F(BufferQueueTest, CopyWithOneBuffer) { - queue_.Enqueue(buffer1.get()); - - EXPECT_EQ(kDataSize, queue_.Copy(data2, kDataSize)); - EXPECT_EQ(0, memcmp(data2, kData, kDataSize)); -} - -TEST_F(BufferQueueTest, Clear) { - queue_.Enqueue(buffer1.get()); - - queue_.Clear(); - EXPECT_TRUE(queue_.IsEmpty()); - EXPECT_EQ(0u, queue_.SizeInBytes()); -} - -TEST_F(BufferQueueTest, MultipleEnqueues) { - queue_.Enqueue(buffer2.get()); - queue_.Enqueue(buffer1.get()); - EXPECT_EQ(kDataSize + kNewDataSize, queue_.SizeInBytes()); -} - -TEST_F(BufferQueueTest, CopyWithMultipleBuffers) { - queue_.Enqueue(buffer2.get()); - queue_.Enqueue(buffer1.get()); - - EXPECT_EQ(kDataSize + kNewDataSize, - queue_.Copy(dataBig, kDataSize + kNewDataSize)); - EXPECT_EQ(0, memcmp(dataBig, kNewData, kNewDataSize)); - dataBig += kNewDataSize; - EXPECT_EQ(0, memcmp(dataBig, kData, kDataSize)); -} - -TEST_F(BufferQueueTest, Consume) { - queue_.Enqueue(buffer2.get()); - queue_.Enqueue(buffer1.get()); - - queue_.Consume(kDataSize); - EXPECT_EQ(kNewDataSize, queue_.SizeInBytes()); -} - -TEST_F(BufferQueueTest, CopyFromMiddleOfBuffer) { - queue_.Enqueue(buffer2.get()); - queue_.Enqueue(buffer1.get()); - queue_.Consume(kDataSize); - - EXPECT_EQ(kNewDataSize, queue_.Copy(dataBig, kNewDataSize)); - EXPECT_EQ(0, memcmp(dataBig, - kNewData + kDataSize, - kNewDataSize - kDataSize)); - dataBig += (kNewDataSize - kDataSize); - EXPECT_EQ(0, memcmp(dataBig, kData, kDataSize)); -} - - -TEST_F(BufferQueueTest, GetTime) { - const struct { - int64 first_time_useconds; - int64 duration_useconds; - size_t consume_bytes; - } tests[] = { - // Timestamps of 0 are treated as garbage. - { 0, 1000000, 0 }, - { 0, 4000000, 0 }, - { 0, 8000000, 0 }, - // { 0, 1000000, 4 }, - // { 0, 4000000, 4 }, - // { 0, 8000000, 4 }, - // { 0, 1000000, kNewDataSize }, - // { 0, 4000000, kNewDataSize }, - // { 0, 8000000, kNewDataSize }, - { 5, 1000000, 0 }, - { 5, 4000000, 0 }, - { 5, 8000000, 0 }, - { 5, 1000000, 4 }, - { 5, 4000000, 4 }, - { 5, 8000000, 4 }, - { 5, 1000000, kNewDataSize }, - { 5, 4000000, kNewDataSize }, - { 5, 8000000, kNewDataSize }, - }; - - for (size_t i = 0; i < ARRAYSIZE_UNSAFE(tests); ++i) { - buffer2->SetTimestamp(base::TimeDelta::FromMicroseconds( - tests[i].first_time_useconds)); - buffer2->SetDuration(base::TimeDelta::FromMicroseconds( - tests[i].duration_useconds)); - queue_.Enqueue(buffer2.get()); - queue_.Consume(tests[i].consume_bytes); - - int64 expected = base::TimeDelta::FromMicroseconds(static_cast<int64>( - tests[i].first_time_useconds + (tests[i].consume_bytes * - tests[i].duration_useconds) / kNewDataSize)).ToInternalValue(); - - int64 actual = queue_.GetTime().ToInternalValue(); - - EXPECT_EQ(expected, actual) << "With test = { start:" - << tests[i].first_time_useconds << ", duration:" - << tests[i].duration_useconds << ", consumed:" - << tests[i].consume_bytes << "}\n"; - - queue_.Clear(); - } -} - -} // namespace media diff --git a/media/base/seekable_buffer.cc b/media/base/seekable_buffer.cc index ec8c578..0f1cc33c 100644 --- a/media/base/seekable_buffer.cc +++ b/media/base/seekable_buffer.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2009 The Chromium Authors. All rights reserved. +// Copyright (c) 2010 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. @@ -7,7 +7,7 @@ #include <algorithm> #include "base/logging.h" -#include "base/stl_util-inl.h" +#include "media/base/data_buffer.h" namespace media { @@ -22,20 +22,36 @@ SeekableBuffer::SeekableBuffer(size_t backward_capacity, } SeekableBuffer::~SeekableBuffer() { - STLDeleteElements(&buffers_); } -size_t SeekableBuffer::Read(size_t size, uint8* data) { +void SeekableBuffer::Clear() { + buffers_.clear(); + current_buffer_ = buffers_.begin(); + current_buffer_offset_ = 0; + backward_bytes_ = 0; + forward_bytes_ = 0; + current_time_ = base::TimeDelta(); +} + + +size_t SeekableBuffer::Read(uint8* data, size_t size) { DCHECK(data); - return InternalRead(size, data); + return InternalRead(data, size, true); } -bool SeekableBuffer::Append(size_t size, const uint8* data) { +size_t SeekableBuffer::Peek(uint8* data, size_t size) { + DCHECK(data); + return InternalRead(data, size, false); +} + +bool SeekableBuffer::Append(Buffer* buffer_in) { + if (buffers_.empty() && buffer_in->GetTimestamp().InMicroseconds() > 0) { + current_time_ = buffer_in->GetTimestamp(); + } + // Since the forward capacity is only used to check the criteria for buffer // full, we always append data to the buffer. - Buffer* buffer = new Buffer(size); - memcpy(buffer->data.get(), data, size); - buffers_.push_back(buffer); + buffers_.push_back(scoped_refptr<Buffer>(buffer_in)); // After we have written the first buffer, update |current_buffer_| to point // to it. @@ -45,7 +61,7 @@ bool SeekableBuffer::Append(size_t size, const uint8* data) { } // Update the |forward_bytes_| counter since we have more bytes. - forward_bytes_ += size; + forward_bytes_ += buffer_in->GetDataSize(); // Advise the user to stop append if the amount of forward bytes exceeds // the forward capacity. A false return value means the user should stop @@ -55,6 +71,13 @@ bool SeekableBuffer::Append(size_t size, const uint8* data) { return true; } +bool SeekableBuffer::Append(const uint8* data, size_t size) { + DataBuffer* data_buffer = new DataBuffer(size); + memcpy(data_buffer->GetWritableData(), data, size); + data_buffer->SetDataSize(size); + return Append(data_buffer); +} + bool SeekableBuffer::Seek(int32 offset) { if (offset > 0) return SeekForward(offset); @@ -69,7 +92,7 @@ bool SeekableBuffer::SeekForward(size_t size) { return false; // Do a read of |size| bytes. - size_t taken = InternalRead(size, NULL); + size_t taken = InternalRead(NULL, size, true); DCHECK_EQ(taken, size); return true; } @@ -114,9 +137,12 @@ bool SeekableBuffer::SeekBackward(size_t size) { --current_buffer_; // Set the offset into the current buffer to be the buffer size as we // are preparing for rewind for next iteration. - current_buffer_offset_ = (*current_buffer_)->size; + current_buffer_offset_ = (*current_buffer_)->GetDataSize(); } } + + UpdateCurrentTime(current_buffer_, current_buffer_offset_); + DCHECK_EQ(taken, size); return true; } @@ -127,66 +153,96 @@ void SeekableBuffer::EvictBackwardBuffers() { BufferQueue::iterator i = buffers_.begin(); if (i == current_buffer_) break; - Buffer* buffer = *i; - backward_bytes_ -= buffer->size; + scoped_refptr<Buffer> buffer = *i; + backward_bytes_ -= buffer->GetDataSize(); DCHECK_GE(backward_bytes_, 0u); - delete buffer; buffers_.erase(i); } } -size_t SeekableBuffer::InternalRead(size_t size, uint8* data) { +size_t SeekableBuffer::InternalRead(uint8* data, size_t size, + bool advance_position) { // Counts how many bytes are actually read from the buffer queue. size_t taken = 0; + BufferQueue::iterator current_buffer = current_buffer_; + size_t current_buffer_offset = current_buffer_offset_; + while (taken < size) { - // |current_buffer_| is valid since the first time this buffer is appended + // |current_buffer| is valid since the first time this buffer is appended // with data. - if (current_buffer_ == buffers_.end()) { - DCHECK_EQ(0u, forward_bytes_); + if (current_buffer == buffers_.end()) break; - } - Buffer* buffer = *current_buffer_; + + scoped_refptr<Buffer> buffer = *current_buffer; // Find the right amount to copy from the current buffer referenced by // |buffer|. We shall copy no more than |size| bytes in total and each // single step copied no more than the current buffer size. size_t copied = std::min(size - taken, - buffer->size - current_buffer_offset_); + buffer->GetDataSize() - current_buffer_offset); // |data| is NULL if we are seeking forward, so there's no need to copy. if (data) - memcpy(data + taken, buffer->data.get() + current_buffer_offset_, copied); + memcpy(data + taken, buffer->GetData() + current_buffer_offset, copied); // Increase total number of bytes copied, which regulates when to end this // loop. taken += copied; // We have read |copied| bytes from the current buffer. Advances the offset. - current_buffer_offset_ += copied; - - // We have less forward bytes and more backward bytes. Updates these - // counters by |copied|. - forward_bytes_ -= copied; - backward_bytes_ += copied; - DCHECK_GE(forward_bytes_, 0u); + current_buffer_offset += copied; // The buffer has been consumed. - if (current_buffer_offset_ == buffer->size) { - BufferQueue::iterator next = current_buffer_; + if (current_buffer_offset == buffer->GetDataSize()) { + if (advance_position) { + // Next buffer may not have timestamp, so we need to update current + // timestamp before switching to the next buffer. + UpdateCurrentTime(current_buffer, current_buffer_offset); + } + + BufferQueue::iterator next = current_buffer; ++next; // If we are at the last buffer, don't advance. if (next == buffers_.end()) break; // Advances the iterator. - current_buffer_ = next; - current_buffer_offset_ = 0; + current_buffer = next; + current_buffer_offset = 0; } } - EvictBackwardBuffers(); + + if (advance_position) { + // We have less forward bytes and more backward bytes. Updates these + // counters by |taken|. + forward_bytes_ -= taken; + backward_bytes_ += taken; + DCHECK_GE(forward_bytes_, 0u); + DCHECK(current_buffer_ != buffers_.end() || forward_bytes_ == 0u); + + current_buffer_ = current_buffer; + current_buffer_offset_ = current_buffer_offset; + + UpdateCurrentTime(current_buffer_, current_buffer_offset_); + EvictBackwardBuffers(); + } + return taken; } +void SeekableBuffer::UpdateCurrentTime(BufferQueue::iterator buffer, + size_t offset) { + // Garbage values are unavoidable, so this check will remain. + if (buffer != buffers_.end() && + (*buffer)->GetTimestamp().InMicroseconds() > 0) { + int64 time_offset = ((*buffer)->GetDuration().InMicroseconds() * + offset) / (*buffer)->GetDataSize(); + + current_time_ = (*buffer)->GetTimestamp() + + base::TimeDelta::FromMicroseconds(time_offset); + } +} + } // namespace media diff --git a/media/base/seekable_buffer.h b/media/base/seekable_buffer.h index 58b0be9..9275cf8 100644 --- a/media/base/seekable_buffer.h +++ b/media/base/seekable_buffer.h @@ -1,4 +1,4 @@ -// Copyright (c) 2009 The Chromium Authors. All rights reserved. +// Copyright (c) 2010 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. @@ -37,7 +37,8 @@ #include "base/basictypes.h" #include "base/lock.h" -#include "base/scoped_ptr.h" +#include "base/ref_counted.h" +#include "media/base/buffers.h" namespace media { @@ -49,19 +50,28 @@ class SeekableBuffer { ~SeekableBuffer(); - // Reads a maximum of |size| bytes into |buffer| from the current read + // Clears the buffer queue. + void Clear(); + + // Reads a maximum of |size| bytes into |data| from the current read // position. Returns the number of bytes read. // The current read position will advance by the amount of bytes read. If // reading caused backward_bytes() to exceed backward_capacity(), an eviction // of the backward buffer will be done internally. - size_t Read(size_t size, uint8* buffer); + size_t Read(uint8* data, size_t size); + + // Copies up to |size| bytes from current position to |data|. Returns + // number of bytes copied. Doesn't advance current position. + size_t Peek(uint8* data, size_t size); - // Appends |data| with |size| bytes to this buffer. If this buffer becomes - // full or is already full then returns false, otherwise returns true. - // Append operations are always successful. A return value of false only means - // that forward_bytes() is greater than or equals to forward_capacity(). Data - // appended is still in this buffer but user is advised not to write any more. - bool Append(size_t size, const uint8* data); + // Appends |buffer_in| to this buffer. Returns false if forward_bytes() is + // greater than or equals to forward_capacity(), true otherwise. The data + // is added to the buffer in any case. + bool Append(Buffer* buffer_in); + + // Appends |size| bytes of |data| to the buffer. Result is the same + // as for Append(Buffer*). + bool Append(const uint8* data, size_t size); // Moves the read position by |offset| bytes. If |offset| is positive, the // current read position is moved forward. If negative, the current read @@ -90,18 +100,18 @@ class SeekableBuffer { // direction. size_t backward_capacity() const { return backward_capacity_; } - private: - // A structure that contains a block of data. - struct Buffer { - explicit Buffer(size_t len) : data(new uint8[len]), size(len) {} - // Pointer to data. - scoped_array<uint8> data; - // Size of this block. - size_t size; - }; + // Returns the current timestamp, taking into account current offset. The + // value calculated based on the timestamp of the current buffer. If + // timestamp for the current buffer is set to 0 or the data was added with + // Append(const uint*, size_t), then returns value that corresponds to the + // last position in a buffer that had timestamp set. 0 is returned if no + // buffers we read from had timestamp set. + // TODO(sergeyu): Use StreamSample::kInvalidTimestamp here. + base::TimeDelta current_time() const { return current_time_; } + private: // Definition of the buffer queue. - typedef std::list<Buffer*> BufferQueue; + typedef std::list<scoped_refptr<Buffer> > BufferQueue; // A helper method to evict buffers in the backward direction until backward // bytes is within the backward capacity. @@ -112,7 +122,7 @@ class SeekableBuffer { // of bytes read. The current read position will be moved forward by the // number of bytes read. If |data| is NULL, only the current read position // will advance but no data will be copied. - size_t InternalRead(size_t size, uint8* data); + size_t InternalRead(uint8* data, size_t size, bool advance_position); // A helper method that moves the current read position forward by |size| // bytes. @@ -128,6 +138,10 @@ class SeekableBuffer { // the seek operation failed. The current read position is not updated. bool SeekBackward(size_t size); + // Updates |current_time_| with the time that corresponds to the + // specified position in the buffer. + void UpdateCurrentTime(BufferQueue::iterator buffer, size_t offset); + BufferQueue::iterator current_buffer_; BufferQueue buffers_; size_t current_buffer_offset_; @@ -137,6 +151,12 @@ class SeekableBuffer { size_t forward_capacity_; size_t forward_bytes_; + + // Keeps track of the most recent time we've seen in case the |buffers_| is + // empty when our owner asks what time it is. + base::TimeDelta current_time_; + + DISALLOW_COPY_AND_ASSIGN(SeekableBuffer); }; } // namespace media diff --git a/media/base/seekable_buffer_unittest.cc b/media/base/seekable_buffer_unittest.cc index 943c179..333833e 100644 --- a/media/base/seekable_buffer_unittest.cc +++ b/media/base/seekable_buffer_unittest.cc @@ -1,10 +1,11 @@ -// Copyright (c) 2009 The Chromium Authors. All rights reserved. +// Copyright (c) 2010 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 "base/logging.h" #include "base/scoped_ptr.h" #include "base/time.h" +#include "media/base/data_buffer.h" #include "media/base/seekable_buffer.h" #include "testing/gtest/include/gtest/gtest.h" @@ -47,16 +48,22 @@ TEST_F(SeekableBufferTest, RandomReadWrite) { // Write a random amount of data. size_t write_size = GetRandomInt(kBufferSize); write_size = std::min(write_size, kDataSize - write_position); - bool should_append = buffer_.Append(write_size, data_ + write_position); + bool should_append = buffer_.Append(data_ + write_position, write_size); write_position += write_size; EXPECT_GE(write_position, read_position); EXPECT_EQ(write_position - read_position, buffer_.forward_bytes()); EXPECT_EQ(should_append, buffer_.forward_bytes() < kBufferSize) << "Incorrect buffer full reported"; + // Peek a random amount of data. + size_t copy_size = GetRandomInt(kBufferSize); + size_t bytes_copied = buffer_.Peek(write_buffer_, copy_size); + EXPECT_GE(copy_size, bytes_copied); + EXPECT_EQ(0, memcmp(write_buffer_, data_ + read_position, bytes_copied)); + // Read a random amount of data. size_t read_size = GetRandomInt(kBufferSize); - size_t bytes_read = buffer_.Read(read_size, write_buffer_); + size_t bytes_read = buffer_.Read(write_buffer_, read_size); EXPECT_GE(read_size, bytes_read); EXPECT_EQ(0, memcmp(write_buffer_, data_ + read_position, bytes_read)); read_position += bytes_read; @@ -71,7 +78,7 @@ TEST_F(SeekableBufferTest, ReadWriteSeek) { for (int i = 0; i < 10; ++i) { // Write until buffer is full. for (size_t j = 0; j < kBufferSize; j += kWriteSize) { - bool should_append = buffer_.Append(kWriteSize, data_ + j); + bool should_append = buffer_.Append(data_ + j, kWriteSize); EXPECT_EQ(j < kBufferSize - kWriteSize, should_append) << "Incorrect buffer full reported"; EXPECT_EQ(j + kWriteSize, buffer_.forward_bytes()); @@ -83,7 +90,7 @@ TEST_F(SeekableBufferTest, ReadWriteSeek) { size_t forward_bytes = kBufferSize; for (size_t j = 0; j < kBufferSize; j += kWriteSize) { // Read. - EXPECT_EQ(kReadSize, buffer_.Read(kReadSize, write_buffer_)); + EXPECT_EQ(kReadSize, buffer_.Read(write_buffer_, kReadSize)); forward_bytes -= kReadSize; EXPECT_EQ(forward_bytes, buffer_.forward_bytes()); EXPECT_EQ(0, memcmp(write_buffer_, data_ + read_position, kReadSize)); @@ -95,8 +102,13 @@ TEST_F(SeekableBufferTest, ReadWriteSeek) { read_position += 2 * kReadSize; EXPECT_EQ(forward_bytes, buffer_.forward_bytes()); + // Copy. + EXPECT_EQ(kReadSize, buffer_.Peek(write_buffer_, kReadSize)); + EXPECT_EQ(forward_bytes, buffer_.forward_bytes()); + EXPECT_EQ(0, memcmp(write_buffer_, data_ + read_position, kReadSize)); + // Read. - EXPECT_EQ(kReadSize, buffer_.Read(kReadSize, write_buffer_)); + EXPECT_EQ(kReadSize, buffer_.Read(write_buffer_, kReadSize)); forward_bytes -= kReadSize; EXPECT_EQ(forward_bytes, buffer_.forward_bytes()); EXPECT_EQ(0, memcmp(write_buffer_, data_ + read_position, kReadSize)); @@ -108,15 +120,25 @@ TEST_F(SeekableBufferTest, ReadWriteSeek) { read_position -= 3 * kReadSize; EXPECT_EQ(forward_bytes, buffer_.forward_bytes()); + // Copy. + EXPECT_EQ(kReadSize, buffer_.Peek(write_buffer_, kReadSize)); + EXPECT_EQ(forward_bytes, buffer_.forward_bytes()); + EXPECT_EQ(0, memcmp(write_buffer_, data_ + read_position, kReadSize)); + // Read. - EXPECT_EQ(kReadSize, buffer_.Read(kReadSize, write_buffer_)); + EXPECT_EQ(kReadSize, buffer_.Read(write_buffer_, kReadSize)); forward_bytes -= kReadSize; EXPECT_EQ(forward_bytes, buffer_.forward_bytes()); EXPECT_EQ(0, memcmp(write_buffer_, data_ + read_position, kReadSize)); read_position += kReadSize; + // Copy. + EXPECT_EQ(kReadSize, buffer_.Peek(write_buffer_, kReadSize)); + EXPECT_EQ(forward_bytes, buffer_.forward_bytes()); + EXPECT_EQ(0, memcmp(write_buffer_, data_ + read_position, kReadSize)); + // Read. - EXPECT_EQ(kReadSize, buffer_.Read(kReadSize, write_buffer_)); + EXPECT_EQ(kReadSize, buffer_.Read(write_buffer_, kReadSize)); forward_bytes -= kReadSize; EXPECT_EQ(forward_bytes, buffer_.forward_bytes()); EXPECT_EQ(0, memcmp(write_buffer_, data_ + read_position, kReadSize)); @@ -136,14 +158,14 @@ TEST_F(SeekableBufferTest, BufferFull) { // Write and expect the buffer to be not full. for (size_t i = 0; i < kBufferSize - kWriteSize; i += kWriteSize) { - EXPECT_TRUE(buffer_.Append(kWriteSize, data_ + i)); + EXPECT_TRUE(buffer_.Append(data_ + i, kWriteSize)); EXPECT_EQ(i + kWriteSize, buffer_.forward_bytes()); } // Write until we have kMaxWriteSize bytes in the buffer. Buffer is full in // these writes. for (size_t i = buffer_.forward_bytes(); i < kMaxWriteSize; i += kWriteSize) { - EXPECT_FALSE(buffer_.Append(kWriteSize, data_ + i)); + EXPECT_FALSE(buffer_.Append(data_ + i, kWriteSize)); EXPECT_EQ(i + kWriteSize, buffer_.forward_bytes()); } @@ -153,7 +175,7 @@ TEST_F(SeekableBufferTest, BufferFull) { // Read a random amount of data. size_t read_size = GetRandomInt(kBufferSize); size_t forward_bytes = buffer_.forward_bytes(); - size_t bytes_read = buffer_.Read(read_size, write_buffer_); + size_t bytes_read = buffer_.Read(write_buffer_, read_size); EXPECT_EQ(0, memcmp(write_buffer_, data_ + read_position, bytes_read)); if (read_size > forward_bytes) EXPECT_EQ(forward_bytes, bytes_read); @@ -166,7 +188,7 @@ TEST_F(SeekableBufferTest, BufferFull) { // Expects we have no bytes left. EXPECT_EQ(0u, buffer_.forward_bytes()); - EXPECT_EQ(0u, buffer_.Read(1, write_buffer_)); + EXPECT_EQ(0u, buffer_.Read(write_buffer_, 1)); } TEST_F(SeekableBufferTest, SeekBackward) { @@ -180,12 +202,12 @@ TEST_F(SeekableBufferTest, SeekBackward) { // Write into buffer until it's full. for (size_t i = 0; i < kBufferSize; i += kWriteSize) { // Write a random amount of data. - buffer_.Append(kWriteSize, data_ + i); + buffer_.Append(data_ + i, kWriteSize); } // Read until buffer is empty. for (size_t i = 0; i < kBufferSize; i += kReadSize) { - EXPECT_EQ(kReadSize, buffer_.Read(kReadSize, write_buffer_)); + EXPECT_EQ(kReadSize, buffer_.Read(write_buffer_, kReadSize)); EXPECT_EQ(0, memcmp(write_buffer_, data_ + i, kReadSize)); } @@ -195,7 +217,7 @@ TEST_F(SeekableBufferTest, SeekBackward) { // Read again. for (size_t i = 0; i < kBufferSize; i += kReadSize) { - EXPECT_EQ(kReadSize, buffer_.Read(kReadSize, write_buffer_)); + EXPECT_EQ(kReadSize, buffer_.Read(write_buffer_, kReadSize)); EXPECT_EQ(0, memcmp(write_buffer_, data_ + i, kReadSize)); } } @@ -209,7 +231,7 @@ TEST_F(SeekableBufferTest, SeekForward) { size_t write_size = GetRandomInt(kBufferSize); write_size = std::min(write_size, kDataSize - write_position); - bool should_append = buffer_.Append(write_size, data_ + write_position); + bool should_append = buffer_.Append(data_ + write_position, write_size); write_position += write_size; EXPECT_GE(write_position, read_position); EXPECT_EQ(write_position - read_position, buffer_.forward_bytes()); @@ -226,7 +248,7 @@ TEST_F(SeekableBufferTest, SeekForward) { // Read a random amount of data. size_t read_size = GetRandomInt(kBufferSize); - size_t bytes_read = buffer_.Read(read_size, write_buffer_); + size_t bytes_read = buffer_.Read(write_buffer_, read_size); EXPECT_GE(read_size, bytes_read); EXPECT_EQ(0, memcmp(write_buffer_, data_ + read_position, bytes_read)); read_position += bytes_read; @@ -236,8 +258,8 @@ TEST_F(SeekableBufferTest, SeekForward) { } TEST_F(SeekableBufferTest, AllMethods) { - EXPECT_EQ(0u, buffer_.Read(0, write_buffer_)); - EXPECT_EQ(0u, buffer_.Read(1, write_buffer_)); + EXPECT_EQ(0u, buffer_.Read(write_buffer_, 0)); + EXPECT_EQ(0u, buffer_.Read(write_buffer_, 1)); EXPECT_TRUE(buffer_.Seek(0)); EXPECT_FALSE(buffer_.Seek(-1)); EXPECT_FALSE(buffer_.Seek(1)); @@ -245,4 +267,56 @@ TEST_F(SeekableBufferTest, AllMethods) { EXPECT_EQ(0u, buffer_.backward_bytes()); } + +TEST_F(SeekableBufferTest, GetTime) { + const struct { + int64 first_time_useconds; + int64 duration_useconds; + size_t consume_bytes; + int64 expected_time; + } tests[] = { + // Timestamps of 0 are treated as garbage. + { 0, 1000000, 0, 0 }, + { 0, 4000000, 0, 0 }, + { 0, 8000000, 0, 0 }, + { 0, 1000000, 4, 0 }, + { 0, 4000000, 4, 0 }, + { 0, 8000000, 4, 0 }, + { 0, 1000000, kWriteSize, 0 }, + { 0, 4000000, kWriteSize, 0 }, + { 0, 8000000, kWriteSize, 0 }, + { 5, 1000000, 0, 5 }, + { 5, 4000000, 0, 5 }, + { 5, 8000000, 0, 5 }, + { 5, 1000000, kWriteSize / 2, 500005 }, + { 5, 4000000, kWriteSize / 2, 2000005 }, + { 5, 8000000, kWriteSize / 2, 4000005 }, + { 5, 1000000, kWriteSize, 1000005 }, + { 5, 4000000, kWriteSize, 4000005 }, + { 5, 8000000, kWriteSize, 8000005 }, + }; + + scoped_refptr<media::DataBuffer> buffer = new media::DataBuffer(kWriteSize); + memcpy(buffer->GetWritableData(), data_, kWriteSize); + buffer->SetDataSize(kWriteSize); + + for (size_t i = 0; i < ARRAYSIZE_UNSAFE(tests); ++i) { + buffer->SetTimestamp(base::TimeDelta::FromMicroseconds( + tests[i].first_time_useconds)); + buffer->SetDuration(base::TimeDelta::FromMicroseconds( + tests[i].duration_useconds)); + buffer_.Append(buffer.get()); + EXPECT_TRUE(buffer_.Seek(tests[i].consume_bytes)); + + int64 actual = buffer_.current_time().ToInternalValue(); + + EXPECT_EQ(tests[i].expected_time, actual) << "With test = { start:" + << tests[i].first_time_useconds << ", duration:" + << tests[i].duration_useconds << ", consumed:" + << tests[i].consume_bytes << "}\n"; + + buffer_.Clear(); + } +} + } // namespace diff --git a/media/filters/audio_renderer_algorithm_base.cc b/media/filters/audio_renderer_algorithm_base.cc index fe6131c..71ba5ce 100644 --- a/media/filters/audio_renderer_algorithm_base.cc +++ b/media/filters/audio_renderer_algorithm_base.cc @@ -17,7 +17,8 @@ AudioRendererAlgorithmBase::AudioRendererAlgorithmBase() : channels_(0), sample_rate_(0), sample_bytes_(0), - playback_rate_(0.0f) { + playback_rate_(0.0f), + queue_(0, kDefaultMinQueueSizeInBytes) { } AudioRendererAlgorithmBase::~AudioRendererAlgorithmBase() {} @@ -52,13 +53,13 @@ void AudioRendererAlgorithmBase::FlushBuffers() { } base::TimeDelta AudioRendererAlgorithmBase::GetTime() { - return queue_.GetTime(); + return queue_.current_time(); } void AudioRendererAlgorithmBase::EnqueueBuffer(Buffer* buffer_in) { // If we're at end of stream, |buffer_in| contains no data. if (!buffer_in->IsEndOfStream()) - queue_.Enqueue(buffer_in); + queue_.Append(buffer_in); // If we still don't have enough data, request more. if (!IsQueueFull()) @@ -75,26 +76,26 @@ void AudioRendererAlgorithmBase::set_playback_rate(float new_rate) { } bool AudioRendererAlgorithmBase::IsQueueEmpty() { - return queue_.IsEmpty(); + return queue_.forward_bytes() == 0; } bool AudioRendererAlgorithmBase::IsQueueFull() { - return (queue_.SizeInBytes() >= kDefaultMinQueueSizeInBytes); + return (queue_.forward_bytes() >= kDefaultMinQueueSizeInBytes); } uint32 AudioRendererAlgorithmBase::QueueSize() { - return queue_.SizeInBytes(); + return queue_.forward_bytes(); } void AudioRendererAlgorithmBase::AdvanceInputPosition(uint32 bytes) { - queue_.Consume(bytes); + queue_.Seek(bytes); if (!IsQueueFull()) request_read_callback_->Run(); } uint32 AudioRendererAlgorithmBase::CopyFromInput(uint8* dest, uint32 bytes) { - return queue_.Copy(dest, bytes); + return queue_.Peek(dest, bytes); } int AudioRendererAlgorithmBase::channels() { diff --git a/media/filters/audio_renderer_algorithm_base.h b/media/filters/audio_renderer_algorithm_base.h index b84e63c..042f856 100644 --- a/media/filters/audio_renderer_algorithm_base.h +++ b/media/filters/audio_renderer_algorithm_base.h @@ -28,7 +28,7 @@ #include "base/callback.h" #include "base/ref_counted.h" #include "base/scoped_ptr.h" -#include "media/base/buffer_queue.h" +#include "media/base/seekable_buffer.h" namespace media { @@ -107,7 +107,7 @@ class AudioRendererAlgorithmBase { scoped_ptr<RequestReadCallback> request_read_callback_; // Queued audio data. - BufferQueue queue_; + SeekableBuffer queue_; DISALLOW_COPY_AND_ASSIGN(AudioRendererAlgorithmBase); }; diff --git a/media/media.gyp b/media/media.gyp index dbb6856..0ca27e0 100644 --- a/media/media.gyp +++ b/media/media.gyp @@ -44,8 +44,6 @@ 'audio/win/audio_output_win.cc', 'audio/win/waveout_output_win.cc', 'audio/win/waveout_output_win.h', - 'base/buffer_queue.cc', - 'base/buffer_queue.h', 'base/buffers.cc', 'base/buffers.h', 'base/callback.h', @@ -187,7 +185,6 @@ 'audio/mac/audio_output_mac_unittest.cc', 'audio/simple_sources_unittest.cc', 'audio/win/audio_output_win_unittest.cc', - 'base/buffer_queue_unittest.cc', 'base/clock_impl_unittest.cc', 'base/data_buffer_unittest.cc', 'base/djb2_unittest.cc', |