summaryrefslogtreecommitdiffstats
path: root/media
diff options
context:
space:
mode:
authorscherkus@chromium.org <scherkus@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-10-20 23:46:32 +0000
committerscherkus@chromium.org <scherkus@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-10-20 23:46:32 +0000
commit2785c5e2912a74a78c669f2ee0fe8fbf09df39e9 (patch)
tree43c0c5b3d3e5ce1a28eabb5dd539cc3fa7359562 /media
parent115d4ca4a7732b1aac2a8ab92e3ae827d106b7dd (diff)
downloadchromium_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.cc30
-rw-r--r--media/base/pipeline_impl.h4
-rw-r--r--media/base/pipeline_impl_unittest.cc92
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);