Commit 12f3ede0 authored by kylep@chromium.org's avatar kylep@chromium.org

BufferQueue class to hide audio data micromanagement from scaling algorithms....

BufferQueue class to hide audio data micromanagement from scaling algorithms. May be useful in other contexts.
BUG=16011
TEST=src/media/base/buffer_queue_unittest.cc
Review URL: http://codereview.chromium.org/155193

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@20211 0039d316-1c4b-4281-b951-d872f2087c98
parent 1677984e
// 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) {
}
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;
} else {
data_offset_ = 0;
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) {
queue_.push_back(buffer_in);
size_in_bytes_ += buffer_in->GetDataSize();
}
void BufferQueue::Clear() {
queue_.clear();
size_in_bytes_ = 0;
data_offset_ = 0;
}
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
// 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"
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 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_;
DISALLOW_COPY_AND_ASSIGN(BufferQueue);
};
} // namespace media
#endif // MEDIA_BASE_BUFFER_QUEUE_H_
// 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 "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();
data1 = buffer1->GetWritableData(kDataSize);
buffer2 = new DataBuffer();
data2 = buffer2->GetWritableData(kNewDataSize);
bufferBig = new DataBuffer();
dataBig = bufferBig->GetWritableData(2 * (kDataSize + kNewDataSize));
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));
}
} // namespace media
......@@ -44,6 +44,8 @@
'audio/win/audio_output_win.cc',
'audio/win/waveout_output_win.cc',
'audio/win/waveout_output_win.h',
'base/buffer_queue.h',
'base/buffer_queue.cc',
'base/buffers.h',
'base/data_buffer.cc',
'base/data_buffer.h',
......@@ -150,6 +152,7 @@
'audio/win/audio_output_win_unittest.cc',
'audio/mac/audio_output_mac_unittest.cc',
'audio/simple_sources_unittest.cc',
'base/buffer_queue_unittest.cc',
'base/data_buffer_unittest.cc',
'base/mock_ffmpeg.cc',
'base/mock_ffmpeg.h',
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment