summaryrefslogtreecommitdiffstats
path: root/media/filters
diff options
context:
space:
mode:
Diffstat (limited to 'media/filters')
-rw-r--r--media/filters/adaptive_demuxer.cc55
-rw-r--r--media/filters/adaptive_demuxer.h2
-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.cc4
-rw-r--r--media/filters/decoder_base.h18
-rw-r--r--media/filters/ffmpeg_demuxer.cc9
-rw-r--r--media/filters/ffmpeg_demuxer.h4
-rw-r--r--media/filters/ffmpeg_demuxer_unittest.cc4
-rw-r--r--media/filters/ffmpeg_video_decoder.cc17
-rw-r--r--media/filters/ffmpeg_video_decoder.h4
-rw-r--r--media/filters/ffmpeg_video_decoder_unittest.cc2
-rw-r--r--media/filters/file_data_source_unittest.cc2
-rw-r--r--media/filters/omx_video_decoder.cc13
-rw-r--r--media/filters/omx_video_decoder.h4
-rw-r--r--media/filters/rtc_video_decoder.cc12
-rw-r--r--media/filters/rtc_video_decoder.h3
-rw-r--r--media/filters/rtc_video_decoder_unittest.cc4
-rw-r--r--media/filters/video_renderer_base.cc66
-rw-r--r--media/filters/video_renderer_base.h4
-rw-r--r--media/filters/video_renderer_base_unittest.cc16
21 files changed, 154 insertions, 103 deletions
diff --git a/media/filters/adaptive_demuxer.cc b/media/filters/adaptive_demuxer.cc
index 9a94d11..5599b15 100644
--- a/media/filters/adaptive_demuxer.cc
+++ b/media/filters/adaptive_demuxer.cc
@@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include "base/bind.h"
#include "base/logging.h"
#include "base/string_number_conversions.h"
#include "base/string_split.h"
@@ -160,6 +161,8 @@ Demuxer* AdaptiveDemuxer::current_demuxer(DemuxerStream::Type type) {
// Helper class that wraps a FilterCallback and expects to get called a set
// number of times, after which the wrapped callback is fired (and deleted).
+//
+// TODO: Remove this class once Stop() is converted to FilterStatusCB.
class CountingCallback {
public:
CountingCallback(int count, FilterCallback* orig_cb)
@@ -191,21 +194,69 @@ class CountingCallback {
scoped_ptr<FilterCallback> orig_cb_;
};
+// Helper class that wraps FilterStatusCB and expects to get called a set
+// number of times, after which the wrapped callback is fired. If an error
+// is reported in any of the callbacks, only the first error code is passed
+// to the wrapped callback.
+class CountingStatusCB : public base::RefCountedThreadSafe<CountingStatusCB> {
+ public:
+ CountingStatusCB(int count, const FilterStatusCB& orig_cb)
+ : remaining_count_(count), orig_cb_(orig_cb),
+ overall_status_(PIPELINE_OK) {
+ DCHECK_GT(remaining_count_, 0);
+ DCHECK(!orig_cb.is_null());
+ }
+
+ FilterStatusCB GetACallback() {
+ return base::Bind(&CountingStatusCB::OnChildCallbackDone, this);
+ }
+
+ private:
+ void OnChildCallbackDone(PipelineStatus status) {
+ bool fire_orig_cb = false;
+ PipelineStatus overall_status = PIPELINE_OK;
+
+ {
+ base::AutoLock auto_lock(lock_);
+
+ if (overall_status_ == PIPELINE_OK && status != PIPELINE_OK)
+ overall_status_ = status;
+
+ if (--remaining_count_ == 0) {
+ fire_orig_cb = true;
+ overall_status = overall_status_;
+ }
+ }
+
+ if (fire_orig_cb)
+ orig_cb_.Run(overall_status);
+ }
+
+ base::Lock lock_;
+ int remaining_count_;
+ FilterStatusCB orig_cb_;
+ PipelineStatus overall_status_;
+
+ DISALLOW_COPY_AND_ASSIGN(CountingStatusCB);
+};
+
void AdaptiveDemuxer::Stop(FilterCallback* callback) {
// Stop() must be called on all of the demuxers even though only one demuxer
// is actively delivering audio and another one is delivering video. This
// just satisfies the contract that all demuxers must have Stop() called on
// them before they are destroyed.
+ //
+ // TODO: Remove CountingCallback once Stop() is converted to FilterStatusCB.
CountingCallback* wrapper = new CountingCallback(demuxers_.size(), callback);
for (size_t i = 0; i < demuxers_.size(); ++i)
demuxers_[i]->Stop(wrapper->GetACallback());
}
-void AdaptiveDemuxer::Seek(base::TimeDelta time, FilterCallback* callback) {
+void AdaptiveDemuxer::Seek(base::TimeDelta time, const FilterStatusCB& cb) {
Demuxer* audio = current_demuxer(DemuxerStream::AUDIO);
Demuxer* video = current_demuxer(DemuxerStream::VIDEO);
int count = (audio ? 1 : 0) + (video && audio != video ? 1 : 0);
- CountingCallback* wrapper = new CountingCallback(count, callback);
+ CountingStatusCB* wrapper = new CountingStatusCB(count, cb);
if (audio)
audio->Seek(time, wrapper->GetACallback());
if (video && audio != video)
diff --git a/media/filters/adaptive_demuxer.h b/media/filters/adaptive_demuxer.h
index b4836bb..6402b03 100644
--- a/media/filters/adaptive_demuxer.h
+++ b/media/filters/adaptive_demuxer.h
@@ -79,7 +79,7 @@ class AdaptiveDemuxer : public Demuxer {
// Filter implementation.
virtual void Stop(FilterCallback* callback);
- virtual void Seek(base::TimeDelta time, FilterCallback* callback);
+ virtual void Seek(base::TimeDelta time, const FilterStatusCB& cb);
virtual void OnAudioRendererDisabled();
virtual void set_host(FilterHost* filter_host);
virtual void SetPlaybackRate(float playback_rate);
diff --git a/media/filters/audio_renderer_base.cc b/media/filters/audio_renderer_base.cc
index 45dd699..a98b8a2 100644
--- a/media/filters/audio_renderer_base.cc
+++ b/media/filters/audio_renderer_base.cc
@@ -64,12 +64,13 @@ void AudioRendererBase::Stop(FilterCallback* callback) {
}
}
-void AudioRendererBase::Seek(base::TimeDelta time, FilterCallback* callback) {
+void AudioRendererBase::Seek(base::TimeDelta time, const FilterStatusCB& cb) {
base::AutoLock auto_lock(lock_);
DCHECK_EQ(kPaused, state_);
DCHECK_EQ(0u, pending_reads_) << "Pending reads should have completed";
+ DCHECK(seek_cb_.is_null());
state_ = kSeeking;
- seek_callback_.reset(callback);
+ seek_cb_ = cb;
seek_timestamp_ = time;
// Throw away everything and schedule our reads.
@@ -159,13 +160,12 @@ void AudioRendererBase::ConsumeAudioSamples(scoped_refptr<Buffer> buffer_in) {
// Check for our preroll complete condition.
if (state_ == kSeeking) {
- DCHECK(seek_callback_.get());
+ DCHECK(!seek_cb_.is_null());
if (algorithm_->IsQueueFull() || recieved_end_of_stream_) {
// Transition into paused whether we have data in |algorithm_| or not.
// FillBuffer() will play silence if there's nothing to fill.
state_ = kPaused;
- seek_callback_->Run();
- seek_callback_.reset();
+ ResetAndRunCB(&seek_cb_, PIPELINE_OK);
}
} else if (state_ == kPaused && pending_reads_ == 0) {
// No more pending reads! We're now officially "paused".
diff --git a/media/filters/audio_renderer_base.h b/media/filters/audio_renderer_base.h
index 0b13e02a..1882743 100644
--- a/media/filters/audio_renderer_base.h
+++ b/media/filters/audio_renderer_base.h
@@ -37,7 +37,7 @@ class AudioRendererBase : public AudioRenderer {
virtual void Pause(FilterCallback* callback);
virtual void Stop(FilterCallback* callback);
- virtual void Seek(base::TimeDelta time, FilterCallback* callback);
+ virtual void Seek(base::TimeDelta time, const FilterStatusCB& cb);
// AudioRenderer implementation.
virtual void Initialize(AudioDecoder* decoder, FilterCallback* callback);
@@ -125,7 +125,7 @@ class AudioRendererBase : public AudioRenderer {
// Filter callbacks.
scoped_ptr<FilterCallback> pause_callback_;
- scoped_ptr<FilterCallback> seek_callback_;
+ FilterStatusCB seek_cb_;
base::TimeDelta seek_timestamp_;
diff --git a/media/filters/audio_renderer_base_unittest.cc b/media/filters/audio_renderer_base_unittest.cc
index 9385f53f..da616ae 100644
--- a/media/filters/audio_renderer_base_unittest.cc
+++ b/media/filters/audio_renderer_base_unittest.cc
@@ -117,7 +117,7 @@ TEST_F(AudioRendererBaseTest, Initialize_Successful) {
// Now seek to trigger prerolling, verifying the callback hasn't been
// executed yet.
EXPECT_CALL(*renderer_, CheckPoint(0));
- renderer_->Seek(base::TimeDelta(), NewExpectedCallback());
+ renderer_->Seek(base::TimeDelta(), NewExpectedStatusCB(PIPELINE_OK));
EXPECT_EQ(kMaxQueueSize, pending_reads_);
renderer_->CheckPoint(0);
@@ -145,7 +145,7 @@ TEST_F(AudioRendererBaseTest, OneCompleteReadCycle) {
// Now seek to trigger prerolling, verifying the callback hasn't been
// executed yet.
EXPECT_CALL(*renderer_, CheckPoint(0));
- renderer_->Seek(base::TimeDelta(), NewExpectedCallback());
+ renderer_->Seek(base::TimeDelta(), NewExpectedStatusCB(PIPELINE_OK));
EXPECT_EQ(kMaxQueueSize, pending_reads_);
renderer_->CheckPoint(0);
diff --git a/media/filters/decoder_base.h b/media/filters/decoder_base.h
index 6cf4937..a889e19fb 100644
--- a/media/filters/decoder_base.h
+++ b/media/filters/decoder_base.h
@@ -34,11 +34,10 @@ class DecoderBase : public Decoder {
NewRunnableMethod(this, &DecoderBase::StopTask, callback));
}
- virtual void Seek(base::TimeDelta time,
- FilterCallback* callback) {
+ virtual void Seek(base::TimeDelta time, const FilterStatusCB& cb) {
message_loop_->PostTask(
FROM_HERE,
- NewRunnableMethod(this, &DecoderBase::SeekTask, time, callback));
+ NewRunnableMethod(this, &DecoderBase::SeekTask, time, cb));
}
// Decoder implementation.
@@ -170,25 +169,22 @@ class DecoderBase : public Decoder {
}
}
- void SeekTask(base::TimeDelta time, FilterCallback* callback) {
+ void SeekTask(base::TimeDelta time, const FilterStatusCB& cb) {
DCHECK_EQ(MessageLoop::current(), message_loop_);
DCHECK_EQ(0u, pending_reads_) << "Pending reads should have completed";
DCHECK_EQ(0u, pending_requests_) << "Pending requests should be empty";
// Delegate to the subclass first.
- DoSeek(time,
- NewRunnableMethod(this, &DecoderBase::OnSeekComplete, callback));
+ DoSeek(time, NewRunnableMethod(this, &DecoderBase::OnSeekComplete, cb));
}
- void OnSeekComplete(FilterCallback* callback) {
+ void OnSeekComplete(const FilterStatusCB& cb) {
// Flush our decoded results.
result_queue_.clear();
// Signal that we're done seeking.
- if (callback) {
- callback->Run();
- delete callback;
- }
+ if (!cb.is_null())
+ cb.Run(PIPELINE_OK);
}
void InitializeTask(DemuxerStream* demuxer_stream,
diff --git a/media/filters/ffmpeg_demuxer.cc b/media/filters/ffmpeg_demuxer.cc
index 98ec882..8347019 100644
--- a/media/filters/ffmpeg_demuxer.cc
+++ b/media/filters/ffmpeg_demuxer.cc
@@ -313,13 +313,13 @@ void FFmpegDemuxer::Stop(FilterCallback* callback) {
SignalReadCompleted(DataSource::kReadError);
}
-void FFmpegDemuxer::Seek(base::TimeDelta time, FilterCallback* callback) {
+void FFmpegDemuxer::Seek(base::TimeDelta time, const FilterStatusCB& cb) {
// TODO(hclam): by returning from this method, it is assumed that the seek
// operation is completed and filters behind the demuxer is good to issue
// more reads, but we are posting a task here, which makes the seek operation
// asynchronous, should change how seek works to make it fully asynchronous.
message_loop_->PostTask(FROM_HERE,
- NewRunnableMethod(this, &FFmpegDemuxer::SeekTask, time, callback));
+ NewRunnableMethod(this, &FFmpegDemuxer::SeekTask, time, cb));
}
void FFmpegDemuxer::SetPlaybackRate(float playback_rate) {
@@ -528,9 +528,8 @@ void FFmpegDemuxer::InitializeTask(DataSource* data_source,
callback->Run(PIPELINE_OK);
}
-void FFmpegDemuxer::SeekTask(base::TimeDelta time, FilterCallback* callback) {
+void FFmpegDemuxer::SeekTask(base::TimeDelta time, const FilterStatusCB& cb) {
DCHECK_EQ(MessageLoop::current(), message_loop_);
- scoped_ptr<FilterCallback> c(callback);
// Tell streams to flush buffers due to seeking.
StreamVector::iterator iter;
@@ -553,7 +552,7 @@ void FFmpegDemuxer::SeekTask(base::TimeDelta time, FilterCallback* callback) {
}
// Notify we're finished seeking.
- callback->Run();
+ cb.Run(PIPELINE_OK);
}
void FFmpegDemuxer::DemuxTask() {
diff --git a/media/filters/ffmpeg_demuxer.h b/media/filters/ffmpeg_demuxer.h
index 3fe2cf1..d96622c 100644
--- a/media/filters/ffmpeg_demuxer.h
+++ b/media/filters/ffmpeg_demuxer.h
@@ -142,7 +142,7 @@ class FFmpegDemuxer : public Demuxer,
// Filter implementation.
virtual void Stop(FilterCallback* callback);
- virtual void Seek(base::TimeDelta time, FilterCallback* callback);
+ virtual void Seek(base::TimeDelta time, const FilterStatusCB& cb);
virtual void OnAudioRendererDisabled();
virtual void set_host(FilterHost* filter_host);
virtual void SetPlaybackRate(float playback_rate);
@@ -171,7 +171,7 @@ class FFmpegDemuxer : public Demuxer,
DataSource* data_source, PipelineStatusCallback* callback);
// Carries out a seek on the demuxer thread.
- void SeekTask(base::TimeDelta time, FilterCallback* callback);
+ void SeekTask(base::TimeDelta time, const FilterStatusCB& cb);
// Carries out demuxing and satisfying stream reads on the demuxer thread.
void DemuxTask();
diff --git a/media/filters/ffmpeg_demuxer_unittest.cc b/media/filters/ffmpeg_demuxer_unittest.cc
index e13fbb1..74ce0ed 100644
--- a/media/filters/ffmpeg_demuxer_unittest.cc
+++ b/media/filters/ffmpeg_demuxer_unittest.cc
@@ -425,7 +425,7 @@ TEST_F(FFmpegDemuxerTest, Seek) {
.WillOnce(Return(0));
// ...then our callback will be executed...
- FilterCallback* seek_callback = NewExpectedCallback();
+ FilterStatusCB seek_cb = NewExpectedStatusCB(PIPELINE_OK);
EXPECT_CALL(mock_ffmpeg_, CheckPoint(2));
// ...followed by two audio packet reads we'll trigger...
@@ -468,7 +468,7 @@ TEST_F(FFmpegDemuxerTest, Seek) {
// Issue a simple forward seek, which should discard queued packets.
demuxer_->Seek(base::TimeDelta::FromMicroseconds(kExpectedTimestamp),
- seek_callback);
+ seek_cb);
message_loop_.RunAllPending();
mock_ffmpeg_.CheckPoint(2);
diff --git a/media/filters/ffmpeg_video_decoder.cc b/media/filters/ffmpeg_video_decoder.cc
index b281fb4..5487398 100644
--- a/media/filters/ffmpeg_video_decoder.cc
+++ b/media/filters/ffmpeg_video_decoder.cc
@@ -183,30 +183,27 @@ void FFmpegVideoDecoder::OnFlushComplete() {
state_ = kNormal;
}
-void FFmpegVideoDecoder::Seek(base::TimeDelta time,
- FilterCallback* callback) {
+void FFmpegVideoDecoder::Seek(base::TimeDelta time, const FilterStatusCB& cb) {
if (MessageLoop::current() != message_loop_) {
message_loop_->PostTask(FROM_HERE,
- NewRunnableMethod(this,
- &FFmpegVideoDecoder::Seek,
- time,
- callback));
+ NewRunnableMethod(this, &FFmpegVideoDecoder::Seek,
+ time, cb));
return;
}
DCHECK_EQ(MessageLoop::current(), message_loop_);
- DCHECK(!seek_callback_.get());
+ DCHECK(seek_cb_.is_null());
pts_stream_.Seek(time);
- seek_callback_.reset(callback);
+ seek_cb_ = cb;
decode_engine_->Seek();
}
void FFmpegVideoDecoder::OnSeekComplete() {
DCHECK_EQ(MessageLoop::current(), message_loop_);
- DCHECK(seek_callback_.get());
+ DCHECK(!seek_cb_.is_null());
- AutoCallbackRunner done_runner(seek_callback_.release());
+ ResetAndRunCB(&seek_cb_, PIPELINE_OK);
}
void FFmpegVideoDecoder::OnError() {
diff --git a/media/filters/ffmpeg_video_decoder.h b/media/filters/ffmpeg_video_decoder.h
index ab27aad..3281193 100644
--- a/media/filters/ffmpeg_video_decoder.h
+++ b/media/filters/ffmpeg_video_decoder.h
@@ -28,7 +28,7 @@ class FFmpegVideoDecoder : public VideoDecoder,
// Filter implementation.
virtual void Stop(FilterCallback* callback);
- virtual void Seek(base::TimeDelta time, FilterCallback* callback);
+ virtual void Seek(base::TimeDelta time, const FilterStatusCB& cb);
virtual void Pause(FilterCallback* callback);
virtual void Flush(FilterCallback* callback);
@@ -100,7 +100,7 @@ class FFmpegVideoDecoder : public VideoDecoder,
scoped_ptr<FilterCallback> initialize_callback_;
scoped_ptr<FilterCallback> uninitialize_callback_;
scoped_ptr<FilterCallback> flush_callback_;
- scoped_ptr<FilterCallback> seek_callback_;
+ FilterStatusCB seek_cb_;
scoped_ptr<StatisticsCallback> statistics_callback_;
// Hold video frames when flush happens.
diff --git a/media/filters/ffmpeg_video_decoder_unittest.cc b/media/filters/ffmpeg_video_decoder_unittest.cc
index 45869f4..38411d3 100644
--- a/media/filters/ffmpeg_video_decoder_unittest.cc
+++ b/media/filters/ffmpeg_video_decoder_unittest.cc
@@ -429,7 +429,7 @@ TEST_F(FFmpegVideoDecoderTest, DoSeek) {
// Expect Seek and verify the results.
EXPECT_CALL(*engine_, Seek())
.WillOnce(EngineSeek(engine_));
- decoder_->Seek(kZero, NewExpectedCallback());
+ decoder_->Seek(kZero, NewExpectedStatusCB(PIPELINE_OK));
EXPECT_TRUE(kZero == decoder_->pts_stream_.current_duration());
EXPECT_EQ(FFmpegVideoDecoder::kNormal, decoder_->state_);
diff --git a/media/filters/file_data_source_unittest.cc b/media/filters/file_data_source_unittest.cc
index 1ae111e..5cf012b 100644
--- a/media/filters/file_data_source_unittest.cc
+++ b/media/filters/file_data_source_unittest.cc
@@ -101,7 +101,7 @@ TEST(FileDataSourceTest, Seek) {
const base::TimeDelta kZero;
scoped_refptr<FileDataSource> filter(new FileDataSource());
- filter->Seek(kZero, NewExpectedCallback());
+ filter->Seek(kZero, NewExpectedStatusCB(PIPELINE_OK));
filter->Stop(NewExpectedCallback());
}
diff --git a/media/filters/omx_video_decoder.cc b/media/filters/omx_video_decoder.cc
index 43f8100..b185965 100644
--- a/media/filters/omx_video_decoder.cc
+++ b/media/filters/omx_video_decoder.cc
@@ -156,30 +156,29 @@ void OmxVideoDecoder::OnFlushComplete() {
pts_stream_.Flush();
}
-void OmxVideoDecoder::Seek(base::TimeDelta time,
- FilterCallback* callback) {
+void OmxVideoDecoder::Seek(base::TimeDelta time, const FilterStatusCB& cb) {
if (MessageLoop::current() != message_loop_) {
message_loop_->PostTask(FROM_HERE,
NewRunnableMethod(this,
&OmxVideoDecoder::Seek,
time,
- callback));
+ cb));
return;
}
DCHECK_EQ(MessageLoop::current(), message_loop_);
- DCHECK(!seek_callback_.get());
+ DCHECK(seek_cb_.is_null());
pts_stream_.Seek(time);
- seek_callback_.reset(callback);
+ seek_cb_ = cb;
decode_engine_->Seek();
}
void OmxVideoDecoder::OnSeekComplete() {
DCHECK_EQ(MessageLoop::current(), message_loop_);
- DCHECK(seek_callback_.get());
+ DCHECK(!seek_cb_.is_null());
- AutoCallbackRunner done_runner(seek_callback_.release());
+ ResetAndRunCB(&seek_cb_, PIPELINE_OK);
}
void OmxVideoDecoder::OnError() {
diff --git a/media/filters/omx_video_decoder.h b/media/filters/omx_video_decoder.h
index c86b2fe..40bf721 100644
--- a/media/filters/omx_video_decoder.h
+++ b/media/filters/omx_video_decoder.h
@@ -34,7 +34,7 @@ class OmxVideoDecoder : public VideoDecoder,
StatisticsCallback* stats_callback);
virtual void Stop(FilterCallback* callback);
virtual void Flush(FilterCallback* callback);
- virtual void Seek(base::TimeDelta time, FilterCallback* callback);
+ virtual void Seek(base::TimeDelta time, const FilterStatusCB& cb);
virtual void ProduceVideoFrame(scoped_refptr<VideoFrame> frame);
virtual bool ProvidesBuffer();
virtual const MediaFormat& media_format();
@@ -67,7 +67,7 @@ class OmxVideoDecoder : public VideoDecoder,
scoped_ptr<FilterCallback> initialize_callback_;
scoped_ptr<FilterCallback> uninitialize_callback_;
scoped_ptr<FilterCallback> flush_callback_;
- scoped_ptr<FilterCallback> seek_callback_;
+ FilterStatusCB seek_cb_;
scoped_ptr<StatisticsCallback> statistics_callback_;
VideoCodecInfo info_;
diff --git a/media/filters/rtc_video_decoder.cc b/media/filters/rtc_video_decoder.cc
index 0ddf630..6744569 100644
--- a/media/filters/rtc_video_decoder.cc
+++ b/media/filters/rtc_video_decoder.cc
@@ -113,14 +113,11 @@ void RTCVideoDecoder::Stop(FilterCallback* callback) {
// TODO(ronghuawu): Stop rtc
}
-void RTCVideoDecoder::Seek(base::TimeDelta time,
- FilterCallback* callback) {
+void RTCVideoDecoder::Seek(base::TimeDelta time, const FilterStatusCB& cb) {
if (MessageLoop::current() != message_loop_) {
message_loop_->PostTask(FROM_HERE,
- NewRunnableMethod(this,
- &RTCVideoDecoder::Seek,
- time,
- callback));
+ NewRunnableMethod(this, &RTCVideoDecoder::Seek,
+ time, cb));
return;
}
@@ -165,8 +162,7 @@ void RTCVideoDecoder::Seek(base::TimeDelta time,
state_ = kNormal;
- callback->Run();
- delete callback;
+ cb.Run(PIPELINE_OK);
// TODO(ronghuawu): Start rtc
}
diff --git a/media/filters/rtc_video_decoder.h b/media/filters/rtc_video_decoder.h
index 02bd96f..6b5b914 100644
--- a/media/filters/rtc_video_decoder.h
+++ b/media/filters/rtc_video_decoder.h
@@ -36,7 +36,7 @@ class RTCVideoDecoder : public VideoDecoder,
// Filter implementation.
virtual void Play(FilterCallback* callback);
- virtual void Seek(base::TimeDelta time, FilterCallback* callback);
+ virtual void Seek(base::TimeDelta time, const FilterStatusCB& cb);
virtual void Pause(FilterCallback* callback);
virtual void Stop(FilterCallback* callback);
@@ -91,4 +91,3 @@ class RTCVideoDecoder : public VideoDecoder,
} // namespace media
#endif // MEDIA_FILTERS_RTC_VIDEO_DECODER_H_
-
diff --git a/media/filters/rtc_video_decoder_unittest.cc b/media/filters/rtc_video_decoder_unittest.cc
index f0970ad..71287d0 100644
--- a/media/filters/rtc_video_decoder_unittest.cc
+++ b/media/filters/rtc_video_decoder_unittest.cc
@@ -111,7 +111,7 @@ TEST_F(RTCVideoDecoderTest, DoSeek) {
// Expect Seek and verify the results.
EXPECT_CALL(*renderer_.get(), ConsumeVideoFrame(_))
.Times(Limits::kMaxVideoFrames);
- decoder_->Seek(kZero, NewExpectedCallback());
+ decoder_->Seek(kZero, NewExpectedStatusCB(PIPELINE_OK));
message_loop_.RunAllPending();
EXPECT_EQ(RTCVideoDecoder::kNormal, decoder_->state_);
@@ -127,7 +127,7 @@ TEST_F(RTCVideoDecoderTest, DoDeliverFrame) {
decoder_->set_consume_video_frame_callback(
base::Bind(&RTCVideoDecoder::ProduceVideoFrame,
base::Unretained(decoder_.get())));
- decoder_->Seek(kZero, NewExpectedCallback());
+ decoder_->Seek(kZero, NewExpectedStatusCB(PIPELINE_OK));
decoder_->set_consume_video_frame_callback(
base::Bind(&MockVideoRenderer::ConsumeVideoFrame,
diff --git a/media/filters/video_renderer_base.cc b/media/filters/video_renderer_base.cc
index 92bedba..7705946 100644
--- a/media/filters/video_renderer_base.cc
+++ b/media/filters/video_renderer_base.cc
@@ -129,28 +129,37 @@ void VideoRendererBase::SetPlaybackRate(float playback_rate) {
playback_rate_ = playback_rate;
}
-void VideoRendererBase::Seek(base::TimeDelta time, FilterCallback* callback) {
- base::AutoLock auto_lock(lock_);
- // There is a race condition between filters to receive SeekTask().
- // It turns out we could receive buffer from decoder before seek()
- // is called on us. so we do the following:
- // kFlushed => ( Receive first buffer or Seek() ) => kSeeking and
- // kSeeking => ( Receive enough buffers) => kPrerolled. )
- DCHECK(kPrerolled == state_ || kFlushed == state_ || kSeeking == state_);
-
- if (state_ == kPrerolled) {
- // Already get enough buffers from decoder.
- callback->Run();
- delete callback;
- } else {
- // Otherwise we are either kFlushed or kSeeking, but without enough buffers;
- // we should save the callback function and call it later.
- state_ = kSeeking;
- seek_callback_.reset(callback);
+void VideoRendererBase::Seek(base::TimeDelta time, const FilterStatusCB& cb) {
+ bool run_callback = false;
+
+ {
+ base::AutoLock auto_lock(lock_);
+ // There is a race condition between filters to receive SeekTask().
+ // It turns out we could receive buffer from decoder before seek()
+ // is called on us. so we do the following:
+ // kFlushed => ( Receive first buffer or Seek() ) => kSeeking and
+ // kSeeking => ( Receive enough buffers) => kPrerolled. )
+ DCHECK(kPrerolled == state_ || kFlushed == state_ || kSeeking == state_);
+ DCHECK(!cb.is_null());
+ DCHECK(seek_cb_.is_null());
+
+ if (state_ == kPrerolled) {
+ // Already get enough buffers from decoder.
+ run_callback = true;
+
+ } else {
+ // Otherwise we are either kFlushed or kSeeking, but without enough
+ // buffers we should save the callback function and call it later.
+ state_ = kSeeking;
+ seek_cb_ = cb;
+ }
+
+ seek_timestamp_ = time;
+ ScheduleRead_Locked();
}
- seek_timestamp_ = time;
- ScheduleRead_Locked();
+ if (run_callback)
+ cb.Run(PIPELINE_OK);
}
void VideoRendererBase::Initialize(VideoDecoder* decoder,
@@ -462,9 +471,8 @@ void VideoRendererBase::ConsumeVideoFrame(scoped_refptr<VideoFrame> frame) {
// If we reach prerolled state before Seek() is called by pipeline,
// |seek_callback_| is not set, we will return immediately during
// when Seek() is eventually called.
- if ((seek_callback_.get())) {
- seek_callback_->Run();
- seek_callback_.reset();
+ if (!seek_cb_.is_null()) {
+ ResetAndRunCB(&seek_cb_, PIPELINE_OK);
}
}
} else if (state_ == kFlushing && pending_reads_ == 0 && !pending_paint_) {
@@ -578,7 +586,10 @@ void VideoRendererBase::EnterErrorState_Locked(PipelineStatus status) {
lock_.AssertAcquired();
scoped_ptr<FilterCallback> callback;
- switch (state_) {
+ State old_state = state_;
+ state_ = kError;
+
+ switch (old_state) {
case kUninitialized:
case kPrerolled:
case kPaused:
@@ -593,8 +604,9 @@ void VideoRendererBase::EnterErrorState_Locked(PipelineStatus status) {
break;
case kSeeking:
- CHECK(seek_callback_.get());
- callback.swap(seek_callback_);
+ CHECK(!seek_cb_.is_null());
+ ResetAndRunCB(&seek_cb_, status);
+ return;
break;
case kStopped:
@@ -604,7 +616,7 @@ void VideoRendererBase::EnterErrorState_Locked(PipelineStatus status) {
case kError:
return;
}
- state_ = kError;
+
host()->SetError(status);
if (callback.get())
diff --git a/media/filters/video_renderer_base.h b/media/filters/video_renderer_base.h
index 66eba6e..6a9a97e 100644
--- a/media/filters/video_renderer_base.h
+++ b/media/filters/video_renderer_base.h
@@ -51,7 +51,7 @@ class VideoRendererBase : public VideoRenderer,
virtual void Flush(FilterCallback* callback);
virtual void Stop(FilterCallback* callback);
virtual void SetPlaybackRate(float playback_rate);
- virtual void Seek(base::TimeDelta time, FilterCallback* callback);
+ virtual void Seek(base::TimeDelta time, const FilterStatusCB& cb);
// VideoRenderer implementation.
virtual void Initialize(VideoDecoder* decoder,
@@ -213,7 +213,7 @@ class VideoRendererBase : public VideoRenderer,
// Filter callbacks.
scoped_ptr<FilterCallback> flush_callback_;
- scoped_ptr<FilterCallback> seek_callback_;
+ FilterStatusCB seek_cb_;
scoped_ptr<StatisticsCallback> statistics_callback_;
base::TimeDelta seek_timestamp_;
diff --git a/media/filters/video_renderer_base_unittest.cc b/media/filters/video_renderer_base_unittest.cc
index c21d6c7..8a8c348 100644
--- a/media/filters/video_renderer_base_unittest.cc
+++ b/media/filters/video_renderer_base_unittest.cc
@@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include "base/bind.h"
#include "base/stl_util-inl.h"
#include "media/base/callback.h"
#include "media/base/data_buffer.h"
@@ -110,13 +111,15 @@ class VideoRendererBaseTest : public ::testing::Test {
Seek(0);
}
- void StartSeeking(int64 timestamp) {
+ void StartSeeking(int64 timestamp, PipelineStatus expected_status) {
EXPECT_FALSE(seeking_);
// Seek to trigger prerolling.
seeking_ = true;
renderer_->Seek(base::TimeDelta::FromMicroseconds(timestamp),
- NewCallback(this, &VideoRendererBaseTest::OnSeekComplete));
+ base::Bind(&VideoRendererBaseTest::OnSeekComplete,
+ base::Unretained(this),
+ expected_status));
}
void FinishSeeking() {
@@ -132,7 +135,7 @@ class VideoRendererBaseTest : public ::testing::Test {
}
void Seek(int64 timestamp) {
- StartSeeking(timestamp);
+ StartSeeking(timestamp, PIPELINE_OK);
FinishSeeking();
}
@@ -191,7 +194,8 @@ class VideoRendererBaseTest : public ::testing::Test {
read_queue_.push_back(frame);
}
- void OnSeekComplete() {
+ void OnSeekComplete(PipelineStatus expected_status, PipelineStatus status) {
+ EXPECT_EQ(status, expected_status);
EXPECT_TRUE(seeking_);
seeking_ = false;
}
@@ -269,9 +273,7 @@ TEST_F(VideoRendererBaseTest, Error_Playing) {
TEST_F(VideoRendererBaseTest, Error_Seeking) {
Initialize();
Flush();
- StartSeeking(0);
-
- EXPECT_CALL(host_, SetError(PIPELINE_ERROR_DECODE));
+ StartSeeking(0, PIPELINE_ERROR_DECODE);
CreateError();
Flush();
}