summaryrefslogtreecommitdiffstats
path: root/media
diff options
context:
space:
mode:
authorjiesun@google.com <jiesun@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2010-05-26 21:37:54 +0000
committerjiesun@google.com <jiesun@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2010-05-26 21:37:54 +0000
commit5c84b7e13f3525b84f7928e946727b5b8b77899b (patch)
tree44bb458aeb239c69a85a5c505916d1516b5b526e /media
parent00ae7a50fe5aa9b15046dff5e805d8cbb1bb4906 (diff)
downloadchromium_src-5c84b7e13f3525b84f7928e946727b5b8b77899b.zip
chromium_src-5c84b7e13f3525b84f7928e946727b5b8b77899b.tar.gz
chromium_src-5c84b7e13f3525b84f7928e946727b5b8b77899b.tar.bz2
refactoring decoder interface
1. install permanent buffer exchange callback. 2. render provide buffer in read=>fillthisbuffer. 3. for ffmpeg path, the provided buffer is just dummy. it had no relation to decoded buffer. so as to keep the code almost same. Review URL: http://codereview.chromium.org/2101022 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@48328 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'media')
-rw-r--r--media/base/filters.h44
-rw-r--r--media/base/mock_filters.h10
-rw-r--r--media/filters/audio_renderer_base.cc10
-rw-r--r--media/filters/audio_renderer_base.h4
-rw-r--r--media/filters/audio_renderer_base_unittest.cc48
-rw-r--r--media/filters/decoder_base.h37
-rw-r--r--media/filters/decoder_base_unittest.cc46
-rw-r--r--media/filters/video_renderer_base.cc10
-rw-r--r--media/filters/video_renderer_base.h5
-rw-r--r--media/filters/video_renderer_base_unittest.cc15
10 files changed, 136 insertions, 93 deletions
diff --git a/media/base/filters.h b/media/base/filters.h
index 980e700..c4da5d9 100644
--- a/media/base/filters.h
+++ b/media/base/filters.h
@@ -265,10 +265,24 @@ class VideoDecoder : public MediaFilter {
// Returns the MediaFormat for this filter.
virtual const MediaFormat& media_format() = 0;
- // Schedules a read. Decoder takes ownership of the callback.
- //
- // TODO(scherkus): switch Read() callback to scoped_refptr<>.
- virtual void Read(Callback1<VideoFrame*>::Type* read_callback) = 0;
+ // |set_fill_buffer_done_callback| install permanent callback from downstream
+ // filter (i.e. Renderer). The callback is used to deliver video frames at
+ // runtime to downstream filter
+ typedef Callback1<scoped_refptr<VideoFrame> >::Type FillBufferDoneCallback;
+ void set_fill_buffer_done_callback(FillBufferDoneCallback* callback) {
+ fill_buffer_done_callback_.reset(callback);
+ }
+ FillBufferDoneCallback* fill_buffer_done_callback() {
+ return fill_buffer_done_callback_.get();
+ }
+
+ // Render provides an output buffer for Decoder to write to. These buffers
+ // will be recycled to renderer by fill_buffer_done_callback_;
+ // We could also pass empty pointer here to let decoder provide buffers pool.
+ virtual void FillThisBuffer(scoped_refptr<VideoFrame> frame) = 0;
+
+ private:
+ scoped_ptr<FillBufferDoneCallback> fill_buffer_done_callback_;
};
@@ -289,10 +303,24 @@ class AudioDecoder : public MediaFilter {
// Returns the MediaFormat for this filter.
virtual const MediaFormat& media_format() = 0;
- // Schedules a read. Decoder takes ownership of the callback.
- //
- // TODO(scherkus): switch Read() callback to scoped_refptr<>.
- virtual void Read(Callback1<Buffer*>::Type* read_callback) = 0;
+ // |set_fill_buffer_done_callback| install permanent callback from downstream
+ // filter (i.e. Renderer). The callback is used to deliver buffers at
+ // runtime to downstream filter.
+ typedef Callback1<scoped_refptr<Buffer> >::Type FillBufferDoneCallback;
+ void set_fill_buffer_done_callback(FillBufferDoneCallback* callback) {
+ fill_buffer_done_callback_.reset(callback);
+ }
+ FillBufferDoneCallback* fill_buffer_done_callback() {
+ return fill_buffer_done_callback_.get();
+ }
+
+ // Render provides an output buffer for Decoder to write to. These buffers
+ // will be recycled to renderer by fill_buffer_done_callback_;
+ // We could also pass empty pointer here to let decoder provide buffers pool.
+ virtual void FillThisBuffer(scoped_refptr<Buffer> buffer) = 0;
+
+ private:
+ scoped_ptr<FillBufferDoneCallback> fill_buffer_done_callback_;
};
diff --git a/media/base/mock_filters.h b/media/base/mock_filters.h
index 7f49fcf..9aeaeec 100644
--- a/media/base/mock_filters.h
+++ b/media/base/mock_filters.h
@@ -18,6 +18,7 @@
#include "base/callback.h"
#include "media/base/factory.h"
#include "media/base/filters.h"
+#include "media/base/video_frame.h"
#include "testing/gmock/include/gmock/gmock.h"
namespace media {
@@ -170,7 +171,7 @@ class MockVideoDecoder : public VideoDecoder {
MOCK_METHOD2(Initialize, void(DemuxerStream* stream,
FilterCallback* callback));
MOCK_METHOD0(media_format, const MediaFormat&());
- MOCK_METHOD1(Read, void(Callback1<VideoFrame*>::Type* read_callback));
+ MOCK_METHOD1(FillThisBuffer, void(scoped_refptr<VideoFrame>));
protected:
virtual ~MockVideoDecoder() {}
@@ -193,7 +194,12 @@ class MockAudioDecoder : public AudioDecoder {
MOCK_METHOD2(Initialize, void(DemuxerStream* stream,
FilterCallback* callback));
MOCK_METHOD0(media_format, const MediaFormat&());
- MOCK_METHOD1(Read, void(Callback1<Buffer*>::Type* read_callback));
+ MOCK_METHOD1(FillThisBuffer, void(scoped_refptr<Buffer>));
+
+ // change to public to allow unittest for access;
+ FillBufferDoneCallback* fill_buffer_done_callback() {
+ return AudioDecoder::fill_buffer_done_callback();
+ }
protected:
virtual ~MockAudioDecoder() {}
diff --git a/media/filters/audio_renderer_base.cc b/media/filters/audio_renderer_base.cc
index f07a4c2..7e530a8 100644
--- a/media/filters/audio_renderer_base.cc
+++ b/media/filters/audio_renderer_base.cc
@@ -79,6 +79,8 @@ void AudioRendererBase::Initialize(AudioDecoder* decoder,
scoped_ptr<FilterCallback> c(callback);
decoder_ = decoder;
+ decoder_->set_fill_buffer_done_callback(
+ NewCallback(this, &AudioRendererBase::OnFillBufferDone));
// Get the media properties to initialize our algorithms.
int channels = 0;
int sample_rate = 0;
@@ -126,7 +128,7 @@ bool AudioRendererBase::HasEnded() {
return recieved_end_of_stream_ && rendered_end_of_stream_;
}
-void AudioRendererBase::OnReadComplete(Buffer* buffer_in) {
+void AudioRendererBase::OnFillBufferDone(scoped_refptr<Buffer> buffer_in) {
AutoLock auto_lock(lock_);
DCHECK(state_ == kPaused || state_ == kSeeking || state_ == kPlaying);
DCHECK_GT(pending_reads_, 0u);
@@ -229,7 +231,11 @@ uint32 AudioRendererBase::FillBuffer(uint8* dest,
void AudioRendererBase::ScheduleRead_Locked() {
lock_.AssertAcquired();
++pending_reads_;
- decoder_->Read(NewCallback(this, &AudioRendererBase::OnReadComplete));
+ // TODO(jiesun): We use dummy buffer to feed decoder to let decoder to
+ // provide buffer pools. In the future, we may want to implement real
+ // buffer pool to recycle buffers.
+ scoped_refptr<Buffer> buffer;
+ decoder_->FillThisBuffer(buffer);
}
// static
diff --git a/media/filters/audio_renderer_base.h b/media/filters/audio_renderer_base.h
index 3b3b593..3762679 100644
--- a/media/filters/audio_renderer_base.h
+++ b/media/filters/audio_renderer_base.h
@@ -55,9 +55,9 @@ class AudioRendererBase : public AudioRenderer {
// this time, such as stopping any running threads.
virtual void OnStop() = 0;
- // Called when a AudioDecoder::Read() completes and decrements
+ // Called when a AudioDecoder completes decoding and decrements
// |pending_reads_|.
- virtual void OnReadComplete(Buffer* buffer_in);
+ virtual void OnFillBufferDone(scoped_refptr<Buffer> buffer_in);
// Fills the given buffer with audio data by delegating to its |algorithm_|.
// FillBuffer() also takes care of updating the clock. Returns the number of
diff --git a/media/filters/audio_renderer_base_unittest.cc b/media/filters/audio_renderer_base_unittest.cc
index 62889d0..064f7a6 100644
--- a/media/filters/audio_renderer_base_unittest.cc
+++ b/media/filters/audio_renderer_base_unittest.cc
@@ -49,11 +49,12 @@ class AudioRendererBaseTest : public ::testing::Test {
// Give the decoder some non-garbage media properties.
AudioRendererBaseTest()
: renderer_(new MockAudioRendererBase()),
- decoder_(new MockAudioDecoder()) {
+ decoder_(new MockAudioDecoder()),
+ pending_reads_(0) {
renderer_->set_host(&host_);
// Queue all reads from the decoder.
- EXPECT_CALL(*decoder_, Read(NotNull()))
+ EXPECT_CALL(*decoder_, FillThisBuffer(_))
.WillRepeatedly(Invoke(this, &AudioRendererBaseTest::EnqueueCallback));
// Sets the essential media format keys for this decoder.
@@ -67,8 +68,6 @@ class AudioRendererBaseTest : public ::testing::Test {
}
virtual ~AudioRendererBaseTest() {
- STLDeleteElements(&read_queue_);
-
// Expect a call into the subclass.
EXPECT_CALL(*renderer_, OnStop());
renderer_->Stop();
@@ -84,12 +83,12 @@ class AudioRendererBaseTest : public ::testing::Test {
StrictMock<MockFilterCallback> callback_;
MediaFormat decoder_media_format_;
- // Receives asynchronous read requests sent to |decoder_|.
- std::deque<Callback1<Buffer*>::Type*> read_queue_;
+ // Number of asynchronous read requests sent to |decoder_|.
+ size_t pending_reads_;
private:
- void EnqueueCallback(Callback1<Buffer*>::Type* callback) {
- read_queue_.push_back(callback);
+ void EnqueueCallback(scoped_refptr<Buffer> buffer) {
+ ++pending_reads_;
}
DISALLOW_COPY_AND_ASSIGN(AudioRendererBaseTest);
@@ -113,7 +112,7 @@ TEST_F(AudioRendererBaseTest, Initialize_Failed) {
// Initialize, we expect to have no reads.
renderer_->Initialize(decoder_, callback_.NewCallback());
- EXPECT_EQ(0u, read_queue_.size());
+ EXPECT_EQ(0u, pending_reads_);
}
TEST_F(AudioRendererBaseTest, Initialize_Successful) {
@@ -136,23 +135,22 @@ TEST_F(AudioRendererBaseTest, Initialize_Successful) {
// Initialize, we shouldn't have any reads.
renderer_->Initialize(decoder_, callback_.NewCallback());
- EXPECT_EQ(0u, read_queue_.size());
+ EXPECT_EQ(0u, pending_reads_);
// Now seek to trigger prerolling.
renderer_->Seek(base::TimeDelta(), seek_callback.NewCallback());
- EXPECT_EQ(kMaxQueueSize, read_queue_.size());
+ EXPECT_EQ(kMaxQueueSize, pending_reads_);
// Verify our seek callback hasn't been executed yet.
renderer_->CheckPoint(0);
// Now satisfy the read requests. Our callback should be executed after
// exiting this loop.
- while (!read_queue_.empty()) {
+ while (pending_reads_) {
scoped_refptr<DataBuffer> buffer = new DataBuffer(1024);
buffer->SetDataSize(1024);
- read_queue_.front()->Run(buffer);
- delete read_queue_.front();
- read_queue_.pop_front();
+ --pending_reads_;
+ decoder_->fill_buffer_done_callback()->Run(buffer);
}
}
@@ -176,11 +174,11 @@ TEST_F(AudioRendererBaseTest, OneCompleteReadCycle) {
// Initialize, we shouldn't have any reads.
renderer_->Initialize(decoder_, callback_.NewCallback());
- EXPECT_EQ(0u, read_queue_.size());
+ EXPECT_EQ(0u, pending_reads_);
// Now seek to trigger prerolling.
renderer_->Seek(base::TimeDelta(), seek_callback.NewCallback());
- EXPECT_EQ(kMaxQueueSize, read_queue_.size());
+ EXPECT_EQ(kMaxQueueSize, pending_reads_);
// Verify our seek callback hasn't been executed yet.
renderer_->CheckPoint(0);
@@ -189,12 +187,11 @@ TEST_F(AudioRendererBaseTest, OneCompleteReadCycle) {
// exiting this loop.
const uint32 kDataSize = 1024;
uint32 bytes_buffered = 0;
- while (!read_queue_.empty()) {
+ while (pending_reads_) {
scoped_refptr<DataBuffer> buffer = new DataBuffer(kDataSize);
buffer->SetDataSize(kDataSize);
- read_queue_.front()->Run(buffer);
- delete read_queue_.front();
- read_queue_.pop_front();
+ decoder_->fill_buffer_done_callback()->Run(buffer);
+ --pending_reads_;
bytes_buffered += kDataSize;
}
@@ -216,19 +213,18 @@ TEST_F(AudioRendererBaseTest, OneCompleteReadCycle) {
}
// Make sure the read request queue is full.
- EXPECT_EQ(kMaxQueueSize, read_queue_.size());
+ EXPECT_EQ(kMaxQueueSize, pending_reads_);
// Fulfill the read with an end-of-stream packet.
scoped_refptr<DataBuffer> last_buffer = new DataBuffer(0);
- read_queue_.front()->Run(last_buffer);
- delete read_queue_.front();
- read_queue_.pop_front();
+ decoder_->fill_buffer_done_callback()->Run(last_buffer);
+ --pending_reads_;
// We shouldn't report ended until all data has been flushed out.
EXPECT_FALSE(renderer_->HasEnded());
// We should have one less read request in the queue.
- EXPECT_EQ(kMaxQueueSize - 1, read_queue_.size());
+ EXPECT_EQ(kMaxQueueSize - 1, pending_reads_);
// Flush the entire internal buffer and verify NotifyEnded() isn't called
// right away.
diff --git a/media/filters/decoder_base.h b/media/filters/decoder_base.h
index 5642651..cc0e3cb 100644
--- a/media/filters/decoder_base.h
+++ b/media/filters/decoder_base.h
@@ -52,14 +52,15 @@ class DecoderBase : public Decoder {
virtual const MediaFormat& media_format() { return media_format_; }
// Audio or video decoder.
- virtual void Read(ReadCallback* read_callback) {
+ virtual void FillThisBuffer(scoped_refptr<Output> output) {
this->message_loop()->PostTask(FROM_HERE,
- NewRunnableMethod(this, &DecoderBase::ReadTask, read_callback));
+ NewRunnableMethod(this, &DecoderBase::ReadTask, output));
}
protected:
DecoderBase()
: pending_reads_(0),
+ pending_requests_(0),
expecting_discontinuous_(false),
state_(kUninitialized) {
}
@@ -67,7 +68,6 @@ class DecoderBase : public Decoder {
virtual ~DecoderBase() {
DCHECK(state_ == kUninitialized || state_ == kStopped);
DCHECK(result_queue_.empty());
- DCHECK(read_queue_.empty());
}
// This method is called by the derived class from within the OnDecode method.
@@ -124,9 +124,9 @@ class DecoderBase : public Decoder {
// Note that it's possible for us to decode but not produce a frame, in
// which case |pending_reads_| will remain less than |read_queue_| so we
// need to schedule an additional read.
- DCHECK_LE(pending_reads_, read_queue_.size());
+ DCHECK_LE(pending_reads_, pending_requests_);
if (!fulfilled) {
- DCHECK_LT(pending_reads_, read_queue_.size());
+ DCHECK_LT(pending_reads_, pending_requests_);
demuxer_stream_->Read(NewCallback(this, &DecoderBase::OnReadComplete));
++pending_reads_;
}
@@ -154,14 +154,13 @@ class DecoderBase : public Decoder {
// Throw away all buffers in all queues.
result_queue_.clear();
- STLDeleteElements(&read_queue_);
state_ = kStopped;
}
void SeekTask(base::TimeDelta time, FilterCallback* callback) {
DCHECK_EQ(MessageLoop::current(), this->message_loop());
DCHECK_EQ(0u, pending_reads_) << "Pending reads should have completed";
- DCHECK(read_queue_.empty()) << "Read requests should be empty";
+ DCHECK_EQ(0u, pending_requests_) << "Pending requests should be empty";
// Delegate to the subclass first.
//
@@ -215,17 +214,16 @@ class DecoderBase : public Decoder {
}
}
- void ReadTask(ReadCallback* read_callback) {
+ void ReadTask(scoped_refptr<Output> output) {
DCHECK_EQ(MessageLoop::current(), this->message_loop());
// TODO(scherkus): should reply with a null operation (empty buffer).
- if (IsStopped()) {
- delete read_callback;
+ if (IsStopped())
return;
- }
- // Enqueue the callback and attempt to fulfill it immediately.
- read_queue_.push_back(read_callback);
+ ++pending_requests_;
+
+ // Try to fulfill it immediately.
if (FulfillPendingRead())
return;
@@ -260,24 +258,25 @@ class DecoderBase : public Decoder {
// Return true if one read request is fulfilled.
bool FulfillPendingRead() {
DCHECK_EQ(MessageLoop::current(), this->message_loop());
- if (read_queue_.empty() || result_queue_.empty()) {
+ if (!pending_requests_ || result_queue_.empty()) {
return false;
}
// Dequeue a frame and read callback pair.
scoped_refptr<Output> output = result_queue_.front();
- scoped_ptr<ReadCallback> read_callback(read_queue_.front());
result_queue_.pop_front();
- read_queue_.pop_front();
// Execute the callback!
- read_callback->Run(output);
+ --pending_requests_;
+ Decoder::fill_buffer_done_callback()->Run(output);
return true;
}
// Tracks the number of asynchronous reads issued to |demuxer_stream_|.
// Using size_t since it is always compared against deque::size().
size_t pending_reads_;
+ // Tracks the number of asynchronous reads issued from renderer.
+ size_t pending_requests_;
// A flag used for debugging that we expect our next read to be discontinuous.
bool expecting_discontinuous_;
@@ -296,10 +295,6 @@ class DecoderBase : public Decoder {
typedef std::deque<scoped_refptr<Output> > ResultQueue;
ResultQueue result_queue_;
- // Queue of callbacks supplied by the renderer through the Read() method.
- typedef std::deque<ReadCallback*> ReadQueue;
- ReadQueue read_queue_;
-
// Pause callback.
scoped_ptr<FilterCallback> pause_callback_;
diff --git a/media/filters/decoder_base_unittest.cc b/media/filters/decoder_base_unittest.cc
index 5468602..e771989 100644
--- a/media/filters/decoder_base_unittest.cc
+++ b/media/filters/decoder_base_unittest.cc
@@ -9,6 +9,7 @@
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
+using ::testing::_;
using ::testing::NotNull;
using ::testing::StrictMock;
@@ -25,8 +26,6 @@ class MockDecoderOutput : public media::StreamSample {
MOCK_CONST_METHOD0(IsEndOfStream, bool());
};
-class MockDecoder : public media::MediaFilter {};
-
class MockBuffer : public media::Buffer {
public:
MockBuffer() {}
@@ -38,6 +37,24 @@ class MockBuffer : public media::Buffer {
DISALLOW_COPY_AND_ASSIGN(MockBuffer);
};
+class MockDecoder : public media::MediaFilter {
+ public:
+ typedef Callback1<scoped_refptr<MockDecoderOutput> >::Type
+ FillBufferDoneCallback;
+ void set_fill_buffer_done_callback_(FillBufferDoneCallback* callback) {
+ fill_buffer_done_callback_.reset(callback);
+ }
+ FillBufferDoneCallback* fill_buffer_done_callback() {
+ return fill_buffer_done_callback_.get();
+ }
+ scoped_ptr<FillBufferDoneCallback> fill_buffer_done_callback_;
+};
+
+class MockDecoderCallback {
+ public:
+ MOCK_METHOD1(OnReadComplete, void(scoped_refptr<MockDecoderOutput> output));
+};
+
class MockDecoderImpl : public media::DecoderBase<
MockDecoder, MockDecoderOutput> {
public:
@@ -62,16 +79,6 @@ class MockDecoderImpl : public media::DecoderBase<
DISALLOW_COPY_AND_ASSIGN(MockDecoderImpl);
};
-class MockDecoderReadCallback {
- public:
- MockDecoderReadCallback() {}
- virtual ~MockDecoderReadCallback() {}
- MOCK_METHOD1(ReadCallback, void(MockDecoderOutput* output));
-
- private:
- DISALLOW_COPY_AND_ASSIGN(MockDecoderReadCallback);
-};
-
} // namespace
namespace media {
@@ -107,6 +114,9 @@ ACTION(CompleteDemuxRequest) {
TEST(DecoderBaseTest, FlowControl) {
MessageLoop message_loop;
scoped_refptr<MockDecoderImpl> decoder = new MockDecoderImpl();
+ MockDecoderCallback read_callback;
+ decoder->set_fill_buffer_done_callback_(
+ NewCallback(&read_callback, &MockDecoderCallback::OnReadComplete));
scoped_refptr<MockDemuxerStream> demuxer_stream = new MockDemuxerStream();
StrictMock<MockFilterCallback> callback;
decoder->set_message_loop(&message_loop);
@@ -120,7 +130,6 @@ TEST(DecoderBaseTest, FlowControl) {
message_loop.RunAllPending();
// Read.
- StrictMock<MockDecoderReadCallback> read_callback;
std::vector<scoped_refptr<Buffer> > decode_requests;
EXPECT_CALL(*demuxer_stream, Read(NotNull()))
.Times(2)
@@ -128,16 +137,13 @@ TEST(DecoderBaseTest, FlowControl) {
EXPECT_CALL(*decoder, DoDecode(NotNull()))
.Times(2)
.WillRepeatedly(SaveDecodeRequest(&decode_requests));
- decoder->Read(
- NewCallback(reinterpret_cast<MockDecoderReadCallback*>(&read_callback),
- &MockDecoderReadCallback::ReadCallback));
- decoder->Read(
- NewCallback(reinterpret_cast<MockDecoderReadCallback*>(&read_callback),
- &MockDecoderReadCallback::ReadCallback));
+ scoped_refptr<MockDecoderOutput> output;
+ decoder->FillThisBuffer(output);
+ decoder->FillThisBuffer(output);
message_loop.RunAllPending();
// Fulfill the decode request.
- EXPECT_CALL(read_callback, ReadCallback(NotNull())).Times(2);
+ EXPECT_CALL(read_callback, OnReadComplete(_)).Times(2);
for (size_t i = 0; i < decode_requests.size(); ++i) {
decoder->EnqueueResult(new MockDecoderOutput());
decoder->OnDecodeComplete();
diff --git a/media/filters/video_renderer_base.cc b/media/filters/video_renderer_base.cc
index 683a170..4833d34 100644
--- a/media/filters/video_renderer_base.cc
+++ b/media/filters/video_renderer_base.cc
@@ -146,6 +146,8 @@ void VideoRendererBase::Initialize(VideoDecoder* decoder,
decoder_ = decoder;
scoped_ptr<FilterCallback> c(callback);
+ decoder_->set_fill_buffer_done_callback(
+ NewCallback(this, &VideoRendererBase::OnFillBufferDone));
// Notify the pipeline of the video dimensions.
if (!ParseMediaFormat(decoder->media_format(), &width_, &height_,
&uses_egl_image_)) {
@@ -312,7 +314,7 @@ void VideoRendererBase::GetCurrentFrame(scoped_refptr<VideoFrame>* frame_out) {
*frame_out = current_frame_;
}
-void VideoRendererBase::OnReadComplete(VideoFrame* frame) {
+void VideoRendererBase::OnFillBufferDone(scoped_refptr<VideoFrame> frame) {
AutoLock auto_lock(lock_);
// TODO(ajwong): Work around cause we don't synchronize on stop. Correct
@@ -367,7 +369,11 @@ void VideoRendererBase::ScheduleRead_Locked() {
DCHECK_NE(kEnded, state_);
DCHECK_LT(pending_reads_, kMaxFrames);
++pending_reads_;
- decoder_->Read(NewCallback(this, &VideoRendererBase::OnReadComplete));
+ // TODO(jiesun): We use dummy buffer to feed decoder to let decoder to
+ // provide buffer pools. In the future, we may want to implement real
+ // buffer pool to recycle buffers.
+ scoped_refptr<VideoFrame> video_frame;
+ decoder_->FillThisBuffer(video_frame);
}
base::TimeDelta VideoRendererBase::CalculateSleepDuration(
diff --git a/media/filters/video_renderer_base.h b/media/filters/video_renderer_base.h
index 24e914d..f66d1cd 100644
--- a/media/filters/video_renderer_base.h
+++ b/media/filters/video_renderer_base.h
@@ -82,8 +82,9 @@ class VideoRendererBase : public VideoRenderer,
virtual void OnFrameAvailable() = 0;
private:
- // Read complete callback from video decoder and decrements |pending_reads_|.
- void OnReadComplete(VideoFrame* frame);
+ // Callback from video decoder to deliver decoded video frames and decrements
+ // |pending_reads_|.
+ void OnFillBufferDone(scoped_refptr<VideoFrame> frame);
// Helper method that schedules an asynchronous read from the decoder and
// increments |pending_reads_|.
diff --git a/media/filters/video_renderer_base_unittest.cc b/media/filters/video_renderer_base_unittest.cc
index 2cdde22..111df56 100644
--- a/media/filters/video_renderer_base_unittest.cc
+++ b/media/filters/video_renderer_base_unittest.cc
@@ -48,7 +48,7 @@ class VideoRendererBaseTest : public ::testing::Test {
renderer_->set_host(&host_);
// Queue all reads from the decoder.
- EXPECT_CALL(*decoder_, Read(NotNull()))
+ EXPECT_CALL(*decoder_, FillThisBuffer(_))
.WillRepeatedly(Invoke(this, &VideoRendererBaseTest::EnqueueCallback));
// Sets the essential media format keys for this decoder.
@@ -61,7 +61,7 @@ class VideoRendererBaseTest : public ::testing::Test {
}
virtual ~VideoRendererBaseTest() {
- STLDeleteElements(&read_queue_);
+ read_queue_.clear();
// Expect a call into the subclass.
EXPECT_CALL(*renderer_, OnStop());
@@ -79,12 +79,12 @@ class VideoRendererBaseTest : public ::testing::Test {
StrictMock<MockFilterCallback> callback_;
MediaFormat decoder_media_format_;
- // Receives asynchronous read requests sent to |decoder_|.
- std::deque<Callback1<VideoFrame*>::Type*> read_queue_;
+ // Receives all the buffers that renderer had provided to |decoder_|.
+ std::deque<scoped_refptr<VideoFrame> > read_queue_;
private:
- void EnqueueCallback(Callback1<VideoFrame*>::Type* callback) {
- read_queue_.push_back(callback);
+ void EnqueueCallback(scoped_refptr<VideoFrame> frame) {
+ read_queue_.push_back(frame);
}
DISALLOW_COPY_AND_ASSIGN(VideoRendererBaseTest);
@@ -191,8 +191,7 @@ TEST_F(VideoRendererBaseTest, Initialize_Successful) {
scoped_refptr<VideoFrame> frame;
VideoFrame::CreateFrame(VideoFrame::RGB32, kWidth, kHeight, kZero,
kZero, &frame);
- read_queue_.front()->Run(frame);
- delete read_queue_.front();
+ decoder_->fill_buffer_done_callback()->Run(frame);
read_queue_.pop_front();
}
}