diff options
author | scherkus@chromium.org <scherkus@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-10-20 23:46:32 +0000 |
---|---|---|
committer | scherkus@chromium.org <scherkus@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-10-20 23:46:32 +0000 |
commit | 2785c5e2912a74a78c669f2ee0fe8fbf09df39e9 (patch) | |
tree | 43c0c5b3d3e5ce1a28eabb5dd539cc3fa7359562 /media | |
parent | 115d4ca4a7732b1aac2a8ab92e3ae827d106b7dd (diff) | |
download | chromium_src-2785c5e2912a74a78c669f2ee0fe8fbf09df39e9.zip chromium_src-2785c5e2912a74a78c669f2ee0fe8fbf09df39e9.tar.gz chromium_src-2785c5e2912a74a78c669f2ee0fe8fbf09df39e9.tar.bz2 |
Prevent buffered time from being less than the current time.
Patch by acolwell@chromium.org:
http://codereview.chromium.org/3897002/show
BUG=56804
TEST=PipelineImplTest.GetBufferedTime
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@63292 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'media')
-rw-r--r-- | media/base/pipeline_impl.cc | 30 | ||||
-rw-r--r-- | media/base/pipeline_impl.h | 4 | ||||
-rw-r--r-- | media/base/pipeline_impl_unittest.cc | 92 |
3 files changed, 88 insertions, 38 deletions
diff --git a/media/base/pipeline_impl.cc b/media/base/pipeline_impl.cc index 64a1ecd..bc825f6 100644 --- a/media/base/pipeline_impl.cc +++ b/media/base/pipeline_impl.cc @@ -207,6 +207,10 @@ base::TimeDelta PipelineImpl::GetCurrentTime() const { // is set/get under the lock, because this is breaching the contract that // |state_| is only accessed on |message_loop_|. AutoLock auto_lock(lock_); + return GetCurrentTime_Locked(); +} + +base::TimeDelta PipelineImpl::GetCurrentTime_Locked() const { base::TimeDelta elapsed = clock_.Elapsed(); if (state_ == kEnded || elapsed > duration_) { return duration_; @@ -223,33 +227,31 @@ base::TimeDelta PipelineImpl::GetBufferedTime() { return duration_; } + base::TimeDelta current_time = GetCurrentTime_Locked(); + // If buffered time was set, we report that value directly. - if (buffered_time_.ToInternalValue() > 0) - return buffered_time_; + if (buffered_time_.ToInternalValue() > 0) { + return std::max(buffered_time_, current_time); + } if (total_bytes_ == 0) return base::TimeDelta(); // If buffered time was not set, we use current time, current bytes, and // buffered bytes to estimate the buffered time. - double current_time = static_cast<double>(current_bytes_) / total_bytes_ * - duration_.InMilliseconds(); - double rate = 0.0; - if (current_bytes_ == 0) { - // If we haven't read any bytes, use the length/size of entire video to - // estimate rate. - rate = static_cast<double>(duration_.InMilliseconds()) / total_bytes_; - } else { - rate = current_time / current_bytes_; - } + double estimated_rate = duration_.InMillisecondsF() / total_bytes_; + double estimated_current_time = estimated_rate * current_bytes_; DCHECK_GE(buffered_bytes_, current_bytes_); base::TimeDelta buffered_time = base::TimeDelta::FromMilliseconds( - static_cast<int64>(rate * (buffered_bytes_ - current_bytes_) + - current_time)); + static_cast<int64>(estimated_rate * (buffered_bytes_ - current_bytes_) + + estimated_current_time)); // Cap approximated buffered time at the length of the video. buffered_time = std::min(buffered_time, duration_); + // Make sure buffered_time is at least the current time + buffered_time = std::max(buffered_time, current_time); + // Only print the max buffered time for smooth buffering. max_buffered_time_ = std::max(buffered_time, max_buffered_time_); diff --git a/media/base/pipeline_impl.h b/media/base/pipeline_impl.h index b7f4de3..2060cef 100644 --- a/media/base/pipeline_impl.h +++ b/media/base/pipeline_impl.h @@ -309,6 +309,10 @@ class PipelineImpl : public Pipeline, public FilterHost { // This will remove the race condition during stop between filters. void TearDownPipeline(); + // Compute the current time. Assumes that the lock has been acquired by the + // caller. + base::TimeDelta GetCurrentTime_Locked() const; + // Message loop used to execute pipeline tasks. MessageLoop* message_loop_; diff --git a/media/base/pipeline_impl_unittest.cc b/media/base/pipeline_impl_unittest.cc index 36869e9..dc5783f 100644 --- a/media/base/pipeline_impl_unittest.cc +++ b/media/base/pipeline_impl_unittest.cc @@ -221,6 +221,43 @@ class PipelineImplTest : public ::testing::Test { return video_stream_; } + void ExpectSeek(const base::TimeDelta& seek_time) { + // Every filter should receive a call to Seek(). + EXPECT_CALL(*mocks_->data_source(), Seek(seek_time, NotNull())) + .WillOnce(Invoke(&RunFilterCallback)); + EXPECT_CALL(*mocks_->demuxer(), Seek(seek_time, NotNull())) + .WillOnce(Invoke(&RunFilterCallback)); + + if (audio_stream_) { + EXPECT_CALL(*mocks_->audio_decoder(), Seek(seek_time, NotNull())) + .WillOnce(Invoke(&RunFilterCallback)); + EXPECT_CALL(*mocks_->audio_renderer(), Seek(seek_time, NotNull())) + .WillOnce(Invoke(&RunFilterCallback)); + } + + if (video_stream_) { + EXPECT_CALL(*mocks_->video_decoder(), Seek(seek_time, NotNull())) + .WillOnce(Invoke(&RunFilterCallback)); + EXPECT_CALL(*mocks_->video_renderer(), Seek(seek_time, NotNull())) + .WillOnce(Invoke(&RunFilterCallback)); + } + + // We expect a successful seek callback. + EXPECT_CALL(callbacks_, OnSeek()); + + } + + void DoSeek(const base::TimeDelta& seek_time) { + pipeline_->Seek(seek_time, + NewCallback(reinterpret_cast<CallbackHelper*>(&callbacks_), + &CallbackHelper::OnSeek)); + + // We expect the time to be updated only after the seek has completed. + EXPECT_TRUE(seek_time != pipeline_->GetCurrentTime()); + message_loop_.RunAllPending(); + EXPECT_TRUE(seek_time == pipeline_->GetCurrentTime()); + } + // Fixture members. StrictMock<CallbackHelper> callbacks_; MessageLoop message_loop_; @@ -432,32 +469,11 @@ TEST_F(PipelineImplTest, Seek) { // Every filter should receive a call to Seek(). base::TimeDelta expected = base::TimeDelta::FromSeconds(2000); - EXPECT_CALL(*mocks_->data_source(), Seek(expected, NotNull())) - .WillOnce(Invoke(&RunFilterCallback)); - EXPECT_CALL(*mocks_->demuxer(), Seek(expected, NotNull())) - .WillOnce(Invoke(&RunFilterCallback)); - EXPECT_CALL(*mocks_->audio_decoder(), Seek(expected, NotNull())) - .WillOnce(Invoke(&RunFilterCallback)); - EXPECT_CALL(*mocks_->audio_renderer(), Seek(expected, NotNull())) - .WillOnce(Invoke(&RunFilterCallback)); - EXPECT_CALL(*mocks_->video_decoder(), Seek(expected, NotNull())) - .WillOnce(Invoke(&RunFilterCallback)); - EXPECT_CALL(*mocks_->video_renderer(), Seek(expected, NotNull())) - .WillOnce(Invoke(&RunFilterCallback)); - - // We expect a successful seek callback. - EXPECT_CALL(callbacks_, OnSeek()); + ExpectSeek(expected); // Initialize then seek! InitializePipeline(); - pipeline_->Seek(expected, - NewCallback(reinterpret_cast<CallbackHelper*>(&callbacks_), - &CallbackHelper::OnSeek)); - - // We expect the time to be updated only after the seek has completed. - EXPECT_TRUE(expected != pipeline_->GetCurrentTime()); - message_loop_.RunAllPending(); - EXPECT_TRUE(expected == pipeline_->GetCurrentTime()); + DoSeek(expected); } TEST_F(PipelineImplTest, SetVolume) { @@ -526,12 +542,40 @@ TEST_F(PipelineImplTest, GetBufferedTime) { pipeline_->SetBufferedBytes(0); EXPECT_EQ(0, pipeline_->GetBufferedTime().ToInternalValue()); - // We should return buffered_time_ if it is set and valid. + // We should return buffered_time_ if it is set, valid and less than + // the current time. const base::TimeDelta buffered = base::TimeDelta::FromSeconds(10); pipeline_->SetBufferedTime(buffered); EXPECT_EQ(buffered.ToInternalValue(), pipeline_->GetBufferedTime().ToInternalValue()); + // Test the case where the current time is beyond the buffered time. + base::TimeDelta kSeekTime = buffered + base::TimeDelta::FromSeconds(5); + ExpectSeek(kSeekTime); + DoSeek(kSeekTime); + + // Verify that buffered time is equal to the current time. + EXPECT_EQ(kSeekTime, pipeline_->GetCurrentTime()); + EXPECT_EQ(kSeekTime, pipeline_->GetBufferedTime()); + + // Clear buffered time. + pipeline_->SetBufferedTime(base::TimeDelta()); + + double time_percent = + static_cast<double>(pipeline_->GetCurrentTime().ToInternalValue()) / + kDuration.ToInternalValue(); + + int estimated_bytes = static_cast<int>(time_percent * kTotalBytes); + + // Test VBR case where bytes have been consumed slower than the average rate. + pipeline_->SetBufferedBytes(estimated_bytes - 10); + EXPECT_EQ(pipeline_->GetCurrentTime(), pipeline_->GetBufferedTime()); + + // Test VBR case where the bytes have been consumed faster than the average + // rate. + pipeline_->SetBufferedBytes(estimated_bytes + 10); + EXPECT_LT(pipeline_->GetCurrentTime(), pipeline_->GetBufferedTime()); + // If media has been fully received, we should return the duration // of the media. pipeline_->SetBufferedBytes(kTotalBytes); |