summaryrefslogtreecommitdiffstats
path: root/media
diff options
context:
space:
mode:
authorsergeyu@chromium.org <sergeyu@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-04-27 03:48:08 +0000
committersergeyu@chromium.org <sergeyu@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-04-27 03:48:08 +0000
commit4b40fccbc3dce6f081cd741b2404d82e02eb7e5b (patch)
tree07d60996c1a317e4ba28bf84beedfdb9e3c7cbc2 /media
parent562b222ad53049a87f695e450e8698d3cb2aa1d6 (diff)
downloadchromium_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.cc121
-rw-r--r--media/base/buffer_queue.h70
-rw-r--r--media/base/buffer_queue_unittest.cc181
-rw-r--r--media/base/seekable_buffer.cc126
-rw-r--r--media/base/seekable_buffer.h62
-rw-r--r--media/base/seekable_buffer_unittest.cc112
-rw-r--r--media/filters/audio_renderer_algorithm_base.cc17
-rw-r--r--media/filters/audio_renderer_algorithm_base.h4
-rw-r--r--media/media.gyp3
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',