Commit 7ac4e532 authored by scherkus@chromium.org's avatar scherkus@chromium.org

Introduce media::TimeSource.

TimeSource represents the canonical source of time and will eventually
replace the time-updating callback from AudioRenderer and VideoRenderer.

A wall-clock based implementation is also provided for media pipelines
that do not contain any audio.

BUG=370634

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

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@284122 0039d316-1c4b-4281-b951-d872f2087c98
parent ccf6a5b8
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef MEDIA_BASE_TIME_SOURCE_H_
#define MEDIA_BASE_TIME_SOURCE_H_
#include "base/time/time.h"
#include "media/base/media_export.h"
namespace media {
// A TimeSource is capable of providing the current media time.
class MEDIA_EXPORT TimeSource {
public:
TimeSource() {}
virtual ~TimeSource() {}
// Signal the time source to start ticking. It is expected that values from
// CurrentMediaTime() will start increasing.
virtual void StartTicking() = 0;
// Signal the time source to stop ticking. It is expected that values from
// CurrentMediaTime() will remain constant.
virtual void StopTicking() = 0;
// Updates the current playback rate. It is expected that values from
// CurrentMediaTime() will eventually reflect the new playback rate (e.g., the
// media time will advance at half speed if the rate was set to 0.5f).
virtual void SetPlaybackRate(float playback_rate) = 0;
// Sets the media time to start ticking from. Only valid to call while the
// time source is not ticking.
virtual void SetMediaTime(base::TimeDelta time) = 0;
// Returns the current media time.
virtual base::TimeDelta CurrentMediaTime() = 0;
};
} // namespace media
#endif // MEDIA_BASE_TIME_SOURCE_H_
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "media/base/wall_clock_time_source.h"
#include "base/logging.h"
#include "base/time/default_tick_clock.h"
namespace media {
WallClockTimeSource::WallClockTimeSource()
: tick_clock_(new base::DefaultTickClock()),
ticking_(false),
playback_rate_(1.0f) {
}
WallClockTimeSource::~WallClockTimeSource() {
}
void WallClockTimeSource::StartTicking() {
DCHECK(!ticking_);
ticking_ = true;
reference_wall_ticks_ = tick_clock_->NowTicks();
}
void WallClockTimeSource::StopTicking() {
DCHECK(ticking_);
base_time_ = CurrentMediaTime();
ticking_ = false;
reference_wall_ticks_ = tick_clock_->NowTicks();
}
void WallClockTimeSource::SetPlaybackRate(float playback_rate) {
// Estimate current media time using old rate to use as a new base time for
// the new rate.
if (ticking_) {
base_time_ = CurrentMediaTime();
reference_wall_ticks_ = tick_clock_->NowTicks();
}
playback_rate_ = playback_rate;
}
void WallClockTimeSource::SetMediaTime(base::TimeDelta time) {
CHECK(!ticking_);
base_time_ = time;
}
base::TimeDelta WallClockTimeSource::CurrentMediaTime() {
if (!ticking_)
return base_time_;
base::TimeTicks now = tick_clock_->NowTicks();
return base_time_ +
base::TimeDelta::FromMicroseconds(
(now - reference_wall_ticks_).InMicroseconds() * playback_rate_);
}
void WallClockTimeSource::SetTickClockForTesting(
scoped_ptr<base::TickClock> tick_clock) {
tick_clock_.swap(tick_clock);
}
} // namespace media
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef MEDIA_BASE_WALL_CLOCK_TIME_SOURCE_H_
#define MEDIA_BASE_WALL_CLOCK_TIME_SOURCE_H_
#include "base/memory/scoped_ptr.h"
#include "media/base/media_export.h"
#include "media/base/time_source.h"
namespace base {
class TickClock;
}
namespace media {
// A time source that uses interpolation based on the system clock.
class MEDIA_EXPORT WallClockTimeSource : public TimeSource {
public:
WallClockTimeSource();
virtual ~WallClockTimeSource();
// TimeSource implementation.
virtual void StartTicking() OVERRIDE;
virtual void StopTicking() OVERRIDE;
virtual void SetPlaybackRate(float playback_rate) OVERRIDE;
virtual void SetMediaTime(base::TimeDelta time) OVERRIDE;
virtual base::TimeDelta CurrentMediaTime() OVERRIDE;
void SetTickClockForTesting(scoped_ptr<base::TickClock> tick_clock);
private:
scoped_ptr<base::TickClock> tick_clock_;
bool ticking_;
// While ticking we can interpolate the current media time by measuring the
// delta between our reference ticks and the current system ticks and scaling
// that time by the playback rate.
float playback_rate_;
base::TimeDelta base_time_;
base::TimeTicks reference_wall_ticks_;
DISALLOW_COPY_AND_ASSIGN(WallClockTimeSource);
};
} // namespace media
#endif // MEDIA_BASE_WALL_CLOCK_TIME_SOURCE_H_
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "base/test/simple_test_tick_clock.h"
#include "media/base/wall_clock_time_source.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace media {
class WallClockTimeSourceTest : public testing::Test {
public:
WallClockTimeSourceTest() : tick_clock_(new base::SimpleTestTickClock()) {
time_source_.SetTickClockForTesting(
scoped_ptr<base::TickClock>(tick_clock_));
}
virtual ~WallClockTimeSourceTest() {}
void AdvanceTimeInSeconds(int seconds) {
tick_clock_->Advance(base::TimeDelta::FromSeconds(seconds));
}
int CurrentMediaTimeInSeconds() {
return time_source_.CurrentMediaTime().InSeconds();
}
void SetMediaTimeInSeconds(int seconds) {
return time_source_.SetMediaTime(base::TimeDelta::FromSeconds(seconds));
}
WallClockTimeSource time_source_;
private:
base::SimpleTestTickClock* tick_clock_; // Owned by |time_source_|.
DISALLOW_COPY_AND_ASSIGN(WallClockTimeSourceTest);
};
TEST_F(WallClockTimeSourceTest, InitialTimeIsZero) {
EXPECT_EQ(0, CurrentMediaTimeInSeconds());
}
TEST_F(WallClockTimeSourceTest, InitialTimeIsNotTicking) {
EXPECT_EQ(0, CurrentMediaTimeInSeconds());
AdvanceTimeInSeconds(100);
EXPECT_EQ(0, CurrentMediaTimeInSeconds());
}
TEST_F(WallClockTimeSourceTest, InitialPlaybackRateIsOne) {
time_source_.StartTicking();
EXPECT_EQ(0, CurrentMediaTimeInSeconds());
AdvanceTimeInSeconds(100);
EXPECT_EQ(100, CurrentMediaTimeInSeconds());
}
TEST_F(WallClockTimeSourceTest, SetMediaTime) {
EXPECT_EQ(0, CurrentMediaTimeInSeconds());
SetMediaTimeInSeconds(10);
EXPECT_EQ(10, CurrentMediaTimeInSeconds());
}
TEST_F(WallClockTimeSourceTest, SetPlaybackRate) {
time_source_.StartTicking();
time_source_.SetPlaybackRate(0.5);
EXPECT_EQ(0, CurrentMediaTimeInSeconds());
AdvanceTimeInSeconds(10);
EXPECT_EQ(5, CurrentMediaTimeInSeconds());
time_source_.SetPlaybackRate(2);
EXPECT_EQ(5, CurrentMediaTimeInSeconds());
AdvanceTimeInSeconds(10);
EXPECT_EQ(25, CurrentMediaTimeInSeconds());
}
TEST_F(WallClockTimeSourceTest, StopTicking) {
time_source_.StartTicking();
EXPECT_EQ(0, CurrentMediaTimeInSeconds());
AdvanceTimeInSeconds(10);
EXPECT_EQ(10, CurrentMediaTimeInSeconds());
time_source_.StopTicking();
AdvanceTimeInSeconds(10);
EXPECT_EQ(10, CurrentMediaTimeInSeconds());
}
} // namespace media
......@@ -336,6 +336,7 @@
'base/text_track_config.h',
'base/time_delta_interpolator.cc',
'base/time_delta_interpolator.h',
'base/time_source.h',
'base/user_input_monitor.cc',
'base/user_input_monitor.h',
'base/user_input_monitor_linux.cc',
......@@ -356,6 +357,8 @@
'base/video_util.h',
'base/yuv_convert.cc',
'base/yuv_convert.h',
'base/wall_clock_time_source.cc',
'base/wall_clock_time_source.h',
'cdm/aes_decryptor.cc',
'cdm/aes_decryptor.h',
'cdm/json_web_key.cc',
......@@ -1109,6 +1112,7 @@
'base/video_frame_unittest.cc',
'base/video_frame_pool_unittest.cc',
'base/video_util_unittest.cc',
'base/wall_clock_time_source_unittest.cc',
'base/yuv_convert_unittest.cc',
'cdm/aes_decryptor_unittest.cc',
'cdm/json_web_key_unittest.cc',
......
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