Commit 76f62954 authored by scherkus@chromium.org's avatar scherkus@chromium.org

Remove duration from media::Clock.

It has no business being in there. Instead let Pipeline track duration
and cap interpolated time values as needed.

BUG=370634

Review URL: https://codereview.chromium.org/375003002

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@281935 0039d316-1c4b-4281-b951-d872f2087c98
parent 21ef2114
......@@ -173,7 +173,7 @@ void MediaSourcePlayer::SeekTo(base::TimeDelta timestamp) {
}
base::TimeDelta MediaSourcePlayer::GetCurrentTime() {
return clock_.Elapsed();
return std::min(clock_.Elapsed(), duration_);
}
base::TimeDelta MediaSourcePlayer::GetDuration() {
......@@ -237,7 +237,6 @@ void MediaSourcePlayer::OnDemuxerConfigsAvailable(
DVLOG(1) << __FUNCTION__;
DCHECK(!HasAudio() && !HasVideo());
duration_ = configs.duration;
clock_.SetDuration(duration_);
audio_decoder_job_->SetDemuxerConfigs(configs);
video_decoder_job_->SetDemuxerConfigs(configs);
......@@ -257,7 +256,6 @@ void MediaSourcePlayer::OnDemuxerDataAvailable(const DemuxerData& data) {
void MediaSourcePlayer::OnDemuxerDurationChanged(base::TimeDelta duration) {
duration_ = duration;
clock_.SetDuration(duration_);
}
void MediaSourcePlayer::OnMediaCryptoReady() {
......
......@@ -17,8 +17,7 @@ Clock::Clock(base::TickClock* clock)
playing_(false),
underflow_(false),
playback_rate_(1.0f),
max_time_(kNoTimestamp()),
duration_(kNoTimestamp()) {
max_time_(kNoTimestamp()) {
DCHECK(clock_);
}
......@@ -57,9 +56,6 @@ void Clock::SetTime(base::TimeDelta current_time, base::TimeDelta max_time) {
}
base::TimeDelta Clock::Elapsed() {
if (duration_ == kNoTimestamp())
return base::TimeDelta();
// The clock is not advancing, so return the last recorded time.
if (!playing_ || underflow_)
return media_time_;
......@@ -85,15 +81,6 @@ void Clock::SetMaxTime(base::TimeDelta max_time) {
media_time_ = max_time_;
}
void Clock::SetDuration(base::TimeDelta duration) {
DCHECK(duration > base::TimeDelta());
duration_ = duration;
media_time_ = ClampToValidTimeRange(media_time_);
if (max_time_ != kNoTimestamp())
max_time_ = ClampToValidTimeRange(max_time_);
}
base::TimeDelta Clock::ElapsedViaProvidedTime(
const base::TimeTicks& time) const {
// TODO(scherkus): floating point badness scaling time by playback rate.
......@@ -103,15 +90,7 @@ base::TimeDelta Clock::ElapsedViaProvidedTime(
}
base::TimeDelta Clock::ClampToValidTimeRange(base::TimeDelta time) const {
if (duration_ == kNoTimestamp())
return base::TimeDelta();
return std::max(std::min(time, duration_), base::TimeDelta());
}
base::TimeDelta Clock::Duration() const {
if (duration_ == kNoTimestamp())
return base::TimeDelta();
return duration_;
return std::max(base::TimeDelta(), time);
}
void Clock::UpdateReferencePoints() {
......
......@@ -54,25 +54,14 @@ class MEDIA_EXPORT Clock {
// Forcefully sets the media time to |current_time|. The second parameter is
// the |max_time| that the clock should progress after a call to Play(). This
// value is often the time of the end of the last frame buffered and decoded.
//
// These values are clamped to the duration of the video, which is initially
// set to 0 (before SetDuration() is called).
void SetTime(base::TimeDelta current_time, base::TimeDelta max_time);
// Sets the |max_time| to be returned by a call to Elapsed().
void SetMaxTime(base::TimeDelta max_time);
// Returns the current elapsed media time. Returns 0 if SetDuration() has
// never been called.
// Returns the current elapsed media time.
base::TimeDelta Elapsed();
// Sets the duration of the video. Clock expects the duration will be set
// exactly once.
void SetDuration(base::TimeDelta duration);
// Returns the duration of the clock, or 0 if not set.
base::TimeDelta Duration() const;
private:
// Updates the reference points based on the current calculated time.
void UpdateReferencePoints();
......@@ -113,9 +102,6 @@ class MEDIA_EXPORT Clock {
// The maximum time that can be returned by calls to Elapsed().
base::TimeDelta max_time_;
// Duration of the media.
base::TimeDelta duration_;
DISALLOW_COPY_AND_ASSIGN(Clock);
};
......
......@@ -2,46 +2,18 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "base/compiler_specific.h"
#include "base/logging.h"
#include "base/test/simple_test_tick_clock.h"
#include "base/time/clock.h"
#include "media/base/clock.h"
#include "testing/gmock/include/gmock/gmock.h"
using ::testing::InSequence;
using ::testing::Return;
using ::testing::StrictMock;
namespace base {
// Provide a stream output operator so we can use EXPECT_EQ(...) with TimeDelta.
//
// TODO(scherkus): move this into the testing package.
static std::ostream& operator<<(std::ostream& stream, const TimeDelta& time) {
return (stream << time.ToInternalValue());
}
} // namespace
#include "testing/gtest/include/gtest/gtest.h"
namespace media {
static const int kDurationInSeconds = 120;
class ClockTest : public ::testing::Test {
public:
ClockTest() : clock_(&test_tick_clock_) {
SetDuration();
}
ClockTest() : clock_(&test_tick_clock_) {}
protected:
void SetDuration() {
const base::TimeDelta kDuration =
base::TimeDelta::FromSeconds(kDurationInSeconds);
clock_.SetDuration(kDuration);
EXPECT_EQ(kDuration, clock_.Duration());
}
void AdvanceSystemTime(base::TimeDelta delta) {
test_tick_clock_.Advance(delta);
}
......@@ -154,10 +126,11 @@ TEST_F(ClockTest, Pause) {
TEST_F(ClockTest, SetTime_Paused) {
const base::TimeDelta kFirstTime = base::TimeDelta::FromSeconds(4);
const base::TimeDelta kSecondTime = base::TimeDelta::FromSeconds(16);
const base::TimeDelta kArbitraryMaxTime = base::TimeDelta::FromSeconds(100);
clock_.SetTime(kFirstTime, clock_.Duration());
clock_.SetTime(kFirstTime, kArbitraryMaxTime);
EXPECT_EQ(kFirstTime, clock_.Elapsed());
clock_.SetTime(kSecondTime, clock_.Duration());
clock_.SetTime(kSecondTime, kArbitraryMaxTime);
EXPECT_EQ(kSecondTime, clock_.Elapsed());
}
......@@ -167,44 +140,17 @@ TEST_F(ClockTest, SetTime_Playing) {
const base::TimeDelta kZero;
const base::TimeDelta kPlayDuration = base::TimeDelta::FromSeconds(4);
const base::TimeDelta kUpdatedTime = base::TimeDelta::FromSeconds(12);
const base::TimeDelta kArbitraryMaxTime = base::TimeDelta::FromSeconds(100);
const base::TimeDelta kExpected = kUpdatedTime + kPlayDuration;
EXPECT_EQ(kZero, clock_.Play());
AdvanceSystemTime(kPlayDuration);
clock_.SetTime(kUpdatedTime, clock_.Duration());
clock_.SetTime(kUpdatedTime, kArbitraryMaxTime);
AdvanceSystemTime(kPlayDuration);
EXPECT_EQ(kExpected, clock_.Elapsed());
}
TEST_F(ClockTest, CapAtMediaDuration_Paused) {
const base::TimeDelta kDuration =
base::TimeDelta::FromSeconds(kDurationInSeconds);
const base::TimeDelta kTimeOverDuration =
base::TimeDelta::FromSeconds(kDurationInSeconds + 4);
// Elapsed time should always be capped at the duration of the media.
clock_.SetTime(kTimeOverDuration, kTimeOverDuration);
EXPECT_EQ(kDuration, clock_.Elapsed());
}
TEST_F(ClockTest, CapAtMediaDuration_Playing) {
const base::TimeDelta kZero;
const base::TimeDelta kDuration =
base::TimeDelta::FromSeconds(kDurationInSeconds);
const base::TimeDelta kTimeOverDuration =
base::TimeDelta::FromSeconds(kDurationInSeconds + 4);
// Play for twice as long as the duration of the media.
EXPECT_EQ(kZero, clock_.Play());
AdvanceSystemTime(2 * kDuration);
EXPECT_EQ(kDuration, clock_.Elapsed());
// Manually set the time past the duration.
clock_.SetTime(kTimeOverDuration, kTimeOverDuration);
EXPECT_EQ(kDuration, clock_.Elapsed());
}
TEST_F(ClockTest, SetMaxTime) {
const base::TimeDelta kZero;
const base::TimeDelta kTimeInterval = base::TimeDelta::FromSeconds(4);
......@@ -225,11 +171,12 @@ TEST_F(ClockTest, SetMaxTime) {
TEST_F(ClockTest, SetMaxTime_MultipleTimes) {
const base::TimeDelta kZero;
const base::TimeDelta kTimeInterval = base::TimeDelta::FromSeconds(4);
const base::TimeDelta kMaxTime0 = base::TimeDelta::FromSeconds(120);
const base::TimeDelta kMaxTime1 = base::TimeDelta::FromSeconds(6);
const base::TimeDelta kMaxTime2 = base::TimeDelta::FromSeconds(12);
EXPECT_EQ(kZero, clock_.Play());
clock_.SetMaxTime(clock_.Duration());
clock_.SetMaxTime(kMaxTime0);
AdvanceSystemTime(kTimeInterval);
EXPECT_EQ(kTimeInterval, clock_.Elapsed());
......
......@@ -156,7 +156,7 @@ void Pipeline::SetVolume(float volume) {
TimeDelta Pipeline::GetMediaTime() const {
base::AutoLock auto_lock(lock_);
return clock_->Elapsed();
return std::min(clock_->Elapsed(), duration_);
}
Ranges<TimeDelta> Pipeline::GetBufferedTimeRanges() const {
......@@ -166,7 +166,7 @@ Ranges<TimeDelta> Pipeline::GetBufferedTimeRanges() const {
TimeDelta Pipeline::GetMediaDuration() const {
base::AutoLock auto_lock(lock_);
return clock_->Duration();
return duration_;
}
bool Pipeline::DidLoadingProgress() {
......@@ -320,7 +320,7 @@ void Pipeline::SetDuration(TimeDelta duration) {
UMA_HISTOGRAM_LONG_TIMES("Media.Duration", duration);
base::AutoLock auto_lock(lock_);
clock_->SetDuration(duration);
duration_ = duration;
if (!duration_change_cb_.is_null())
duration_change_cb_.Run();
}
......@@ -705,7 +705,7 @@ void Pipeline::DoAudioRendererEnded() {
// Start clock since there is no more audio to trigger clock updates.
{
base::AutoLock auto_lock(lock_);
clock_->SetMaxTime(clock_->Duration());
clock_->SetMaxTime(duration_);
StartClockIfWaitingForTimeUpdate_Locked();
}
......@@ -751,7 +751,7 @@ void Pipeline::RunEndedCallbackIfNeeded() {
{
base::AutoLock auto_lock(lock_);
PauseClockAndStopRendering_Locked();
clock_->SetTime(clock_->Duration(), clock_->Duration());
clock_->SetTime(duration_, duration_);
}
DCHECK_EQ(status_, PIPELINE_OK);
......@@ -882,7 +882,7 @@ void Pipeline::StartPlayback() {
} else {
base::AutoLock auto_lock(lock_);
clock_state_ = CLOCK_PLAYING;
clock_->SetMaxTime(clock_->Duration());
clock_->SetMaxTime(duration_);
clock_->Play();
}
}
......
......@@ -346,6 +346,9 @@ class MEDIA_EXPORT Pipeline : public DemuxerHost {
// the filters.
float playback_rate_;
// Current duration as reported by |demuxer_|.
base::TimeDelta duration_;
// base::TickClock used by |clock_|.
base::DefaultTickClock default_tick_clock_;
......
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