Commit 40b18bec authored by scherkus@chromium.org's avatar scherkus@chromium.org

Rename media::Clock to media::TimeDeltaInterpolator and update API.

Mostly cosmetic API changes. The guts of TimeDeltaInterpolator were
spruced up a bit.

BUG=370634

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

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@282186 0039d316-1c4b-4281-b951-d872f2087c98
parent 8c8685ff
...@@ -38,7 +38,7 @@ MediaSourcePlayer::MediaSourcePlayer( ...@@ -38,7 +38,7 @@ MediaSourcePlayer::MediaSourcePlayer(
demuxer_(demuxer.Pass()), demuxer_(demuxer.Pass()),
pending_event_(NO_EVENT_PENDING), pending_event_(NO_EVENT_PENDING),
playing_(false), playing_(false),
clock_(&default_tick_clock_), interpolator_(&default_tick_clock_),
doing_browser_seek_(false), doing_browser_seek_(false),
pending_seek_(false), pending_seek_(false),
drm_bridge_(NULL), drm_bridge_(NULL),
...@@ -62,7 +62,7 @@ MediaSourcePlayer::MediaSourcePlayer( ...@@ -62,7 +62,7 @@ MediaSourcePlayer::MediaSourcePlayer(
base::Bind(&MediaSourcePlayer::OnDemuxerConfigsChanged, base::Bind(&MediaSourcePlayer::OnDemuxerConfigsChanged,
weak_factory_.GetWeakPtr()))); weak_factory_.GetWeakPtr())));
demuxer_->Initialize(this); demuxer_->Initialize(this);
clock_.SetMaxTime(base::TimeDelta()); interpolator_.SetUpperBound(base::TimeDelta());
weak_this_ = weak_factory_.GetWeakPtr(); weak_this_ = weak_factory_.GetWeakPtr();
} }
...@@ -90,7 +90,7 @@ void MediaSourcePlayer::ScheduleSeekEventAndStopDecoding( ...@@ -90,7 +90,7 @@ void MediaSourcePlayer::ScheduleSeekEventAndStopDecoding(
pending_seek_ = false; pending_seek_ = false;
clock_.SetTime(seek_time, seek_time); interpolator_.SetBounds(seek_time, seek_time);
if (audio_decoder_job_->is_decoding()) if (audio_decoder_job_->is_decoding())
audio_decoder_job_->StopDecode(); audio_decoder_job_->StopDecode();
...@@ -173,7 +173,7 @@ void MediaSourcePlayer::SeekTo(base::TimeDelta timestamp) { ...@@ -173,7 +173,7 @@ void MediaSourcePlayer::SeekTo(base::TimeDelta timestamp) {
} }
base::TimeDelta MediaSourcePlayer::GetCurrentTime() { base::TimeDelta MediaSourcePlayer::GetCurrentTime() {
return std::min(clock_.Elapsed(), duration_); return std::min(interpolator_.GetInterpolatedTime(), duration_);
} }
base::TimeDelta MediaSourcePlayer::GetDuration() { base::TimeDelta MediaSourcePlayer::GetDuration() {
...@@ -328,7 +328,7 @@ void MediaSourcePlayer::OnDemuxerSeekDone( ...@@ -328,7 +328,7 @@ void MediaSourcePlayer::OnDemuxerSeekDone(
DCHECK(seek_time >= GetCurrentTime()); DCHECK(seek_time >= GetCurrentTime());
DVLOG(1) << __FUNCTION__ << " : setting clock to actual browser seek time: " DVLOG(1) << __FUNCTION__ << " : setting clock to actual browser seek time: "
<< seek_time.InSecondsF(); << seek_time.InSecondsF();
clock_.SetTime(seek_time, seek_time); interpolator_.SetBounds(seek_time, seek_time);
audio_decoder_job_->SetBaseTimestamp(seek_time); audio_decoder_job_->SetBaseTimestamp(seek_time);
} else { } else {
DCHECK(actual_browser_seek_time == kNoTimestamp()); DCHECK(actual_browser_seek_time == kNoTimestamp());
...@@ -354,7 +354,8 @@ void MediaSourcePlayer::OnDemuxerSeekDone( ...@@ -354,7 +354,8 @@ void MediaSourcePlayer::OnDemuxerSeekDone(
void MediaSourcePlayer::UpdateTimestamps( void MediaSourcePlayer::UpdateTimestamps(
base::TimeDelta current_presentation_timestamp, base::TimeDelta current_presentation_timestamp,
base::TimeDelta max_presentation_timestamp) { base::TimeDelta max_presentation_timestamp) {
clock_.SetTime(current_presentation_timestamp, max_presentation_timestamp); interpolator_.SetBounds(current_presentation_timestamp,
max_presentation_timestamp);
manager()->OnTimeUpdate(player_id(), GetCurrentTime()); manager()->OnTimeUpdate(player_id(), GetCurrentTime());
} }
...@@ -489,7 +490,7 @@ void MediaSourcePlayer::MediaDecoderCallback( ...@@ -489,7 +490,7 @@ void MediaSourcePlayer::MediaDecoderCallback(
if (!playing_) { if (!playing_) {
if (is_clock_manager) if (is_clock_manager)
clock_.Pause(); interpolator_.StopInterpolating();
return; return;
} }
...@@ -571,7 +572,7 @@ void MediaSourcePlayer::PlaybackCompleted(bool is_audio) { ...@@ -571,7 +572,7 @@ void MediaSourcePlayer::PlaybackCompleted(bool is_audio) {
if (AudioFinished() && VideoFinished()) { if (AudioFinished() && VideoFinished()) {
playing_ = false; playing_ = false;
clock_.Pause(); interpolator_.StopInterpolating();
start_time_ticks_ = base::TimeTicks(); start_time_ticks_ = base::TimeTicks();
manager()->OnPlaybackComplete(player_id()); manager()->OnPlaybackComplete(player_id());
} }
...@@ -670,8 +671,8 @@ void MediaSourcePlayer::OnPrefetchDone() { ...@@ -670,8 +671,8 @@ void MediaSourcePlayer::OnPrefetchDone() {
start_time_ticks_ = base::TimeTicks::Now(); start_time_ticks_ = base::TimeTicks::Now();
start_presentation_timestamp_ = GetCurrentTime(); start_presentation_timestamp_ = GetCurrentTime();
if (!clock_.IsPlaying()) if (!interpolator_.interpolating())
clock_.Play(); interpolator_.StartInterpolating();
if (!AudioFinished()) if (!AudioFinished())
DecodeMoreAudio(); DecodeMoreAudio();
......
...@@ -23,8 +23,8 @@ ...@@ -23,8 +23,8 @@
#include "media/base/android/media_decoder_job.h" #include "media/base/android/media_decoder_job.h"
#include "media/base/android/media_drm_bridge.h" #include "media/base/android/media_drm_bridge.h"
#include "media/base/android/media_player_android.h" #include "media/base/android/media_player_android.h"
#include "media/base/clock.h"
#include "media/base/media_export.h" #include "media/base/media_export.h"
#include "media/base/time_delta_interpolator.h"
namespace media { namespace media {
...@@ -200,11 +200,12 @@ class MEDIA_EXPORT MediaSourcePlayer : public MediaPlayerAndroid, ...@@ -200,11 +200,12 @@ class MEDIA_EXPORT MediaSourcePlayer : public MediaPlayerAndroid,
base::TimeDelta duration_; base::TimeDelta duration_;
bool playing_; bool playing_;
// base::TickClock used by |clock_|. // base::TickClock used by |interpolator_|.
base::DefaultTickClock default_tick_clock_; base::DefaultTickClock default_tick_clock_;
// Reference clock. Keeps track of current playback time. // Tracks the most recent media time update and provides interpolated values
Clock clock_; // as playback progresses.
TimeDeltaInterpolator interpolator_;
// Timestamps for providing simple A/V sync. When start decoding an audio // Timestamps for providing simple A/V sync. When start decoding an audio
// chunk, we record its presentation timestamp and the current system time. // chunk, we record its presentation timestamp and the current system time.
......
// Copyright (c) 2012 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/clock.h"
#include <algorithm>
#include "base/logging.h"
#include "base/time/tick_clock.h"
#include "media/base/buffers.h"
namespace media {
Clock::Clock(base::TickClock* clock)
: clock_(clock),
playing_(false),
underflow_(false),
playback_rate_(1.0f),
max_time_(kNoTimestamp()) {
DCHECK(clock_);
}
Clock::~Clock() {}
bool Clock::IsPlaying() const {
return playing_;
}
base::TimeDelta Clock::Play() {
DCHECK(!playing_);
UpdateReferencePoints();
playing_ = true;
return media_time_;
}
base::TimeDelta Clock::Pause() {
DCHECK(playing_);
UpdateReferencePoints();
playing_ = false;
return media_time_;
}
void Clock::SetPlaybackRate(float playback_rate) {
UpdateReferencePoints();
playback_rate_ = playback_rate;
}
void Clock::SetTime(base::TimeDelta current_time, base::TimeDelta max_time) {
DCHECK(current_time <= max_time);
DCHECK(current_time != kNoTimestamp());
UpdateReferencePoints(current_time);
max_time_ = ClampToValidTimeRange(max_time);
underflow_ = false;
}
base::TimeDelta Clock::Elapsed() {
// The clock is not advancing, so return the last recorded time.
if (!playing_ || underflow_)
return media_time_;
base::TimeDelta elapsed = EstimatedElapsedTime();
if (max_time_ != kNoTimestamp() && elapsed > max_time_) {
UpdateReferencePoints(max_time_);
underflow_ = true;
elapsed = max_time_;
}
return elapsed;
}
void Clock::SetMaxTime(base::TimeDelta max_time) {
DCHECK(max_time != kNoTimestamp());
UpdateReferencePoints();
max_time_ = ClampToValidTimeRange(max_time);
underflow_ = media_time_ > max_time_;
if (underflow_)
media_time_ = max_time_;
}
base::TimeDelta Clock::ElapsedViaProvidedTime(
const base::TimeTicks& time) const {
// TODO(scherkus): floating point badness scaling time by playback rate.
int64 now_us = (time - reference_).InMicroseconds();
now_us = static_cast<int64>(now_us * playback_rate_);
return media_time_ + base::TimeDelta::FromMicroseconds(now_us);
}
base::TimeDelta Clock::ClampToValidTimeRange(base::TimeDelta time) const {
return std::max(base::TimeDelta(), time);
}
void Clock::UpdateReferencePoints() {
UpdateReferencePoints(Elapsed());
}
void Clock::UpdateReferencePoints(base::TimeDelta current_time) {
media_time_ = ClampToValidTimeRange(current_time);
reference_ = clock_->NowTicks();
}
base::TimeDelta Clock::EstimatedElapsedTime() {
return ClampToValidTimeRange(ElapsedViaProvidedTime(clock_->NowTicks()));
}
} // namespace media
// Copyright (c) 2012 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_CLOCK_H_
#define MEDIA_BASE_CLOCK_H_
#include "base/basictypes.h"
#include "base/time/time.h"
#include "media/base/media_export.h"
namespace base {
class TickClock;
} // namespace base
namespace media {
// A clock represents a single source of time to allow audio and video streams
// to synchronize with each other. Clock essentially tracks the media time with
// respect to some other source of time, whether that may be the monotonic
// system clock or updates via SetTime(). Clock uses linear interpolation to
// calculate the current media time since the last time SetTime() was called.
//
// Clocks start off paused with a playback rate of 1.0f and a media time of 0.
//
// Clock is not thread-safe and must be externally locked.
//
// TODO(scherkus): Clock will some day be responsible for executing callbacks
// given a media time. This will be used primarily by video renderers. For now
// we'll keep using a poll-and-sleep solution.
//
// TODO(miu): Rename media::Clock to avoid confusion (and tripping up the media
// PRESUBMIT script on future changes).
class MEDIA_EXPORT Clock {
public:
explicit Clock(base::TickClock* clock);
~Clock();
// Returns true if the clock is running.
bool IsPlaying() const;
// Starts the clock and returns the current media time, which will increase
// with respect to the current playback rate.
base::TimeDelta Play();
// Stops the clock and returns the current media time, which will remain
// constant until Play() is called.
base::TimeDelta Pause();
// Sets a new playback rate. The rate at which the media time will increase
// will now change.
void SetPlaybackRate(float playback_rate);
// 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.
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.
base::TimeDelta Elapsed();
private:
// Updates the reference points based on the current calculated time.
void UpdateReferencePoints();
// Updates the reference points based on the given |current_time|.
void UpdateReferencePoints(base::TimeDelta current_time);
// Returns the time elapsed based on the current reference points, ignoring
// the |max_time_| cap.
base::TimeDelta EstimatedElapsedTime();
// Translates |time| into the current media time, based on the perspective of
// the monotonically-increasing system clock.
base::TimeDelta ElapsedViaProvidedTime(const base::TimeTicks& time) const;
base::TimeDelta ClampToValidTimeRange(base::TimeDelta time) const;
base::TickClock* const clock_;
// Whether the clock is running.
bool playing_;
// Whether the clock is stalled because it has reached the |max_time_|
// allowed.
bool underflow_;
// The monotonic system clock time when this Clock last started playing or had
// its time set via SetTime().
base::TimeTicks reference_;
// Current accumulated amount of media time. The remaining portion must be
// calculated by comparing the system time to the reference time.
base::TimeDelta media_time_;
// Current playback rate.
float playback_rate_;
// The maximum time that can be returned by calls to Elapsed().
base::TimeDelta max_time_;
DISALLOW_COPY_AND_ASSIGN(Clock);
};
} // namespace media
#endif // MEDIA_BASE_CLOCK_H_
...@@ -19,11 +19,11 @@ ...@@ -19,11 +19,11 @@
#include "base/synchronization/condition_variable.h" #include "base/synchronization/condition_variable.h"
#include "media/base/audio_decoder.h" #include "media/base/audio_decoder.h"
#include "media/base/audio_renderer.h" #include "media/base/audio_renderer.h"
#include "media/base/clock.h"
#include "media/base/filter_collection.h" #include "media/base/filter_collection.h"
#include "media/base/media_log.h" #include "media/base/media_log.h"
#include "media/base/text_renderer.h" #include "media/base/text_renderer.h"
#include "media/base/text_track_config.h" #include "media/base/text_track_config.h"
#include "media/base/time_delta_interpolator.h"
#include "media/base/video_decoder.h" #include "media/base/video_decoder.h"
#include "media/base/video_decoder_config.h" #include "media/base/video_decoder_config.h"
#include "media/base/video_renderer.h" #include "media/base/video_renderer.h"
...@@ -41,8 +41,8 @@ Pipeline::Pipeline( ...@@ -41,8 +41,8 @@ Pipeline::Pipeline(
did_loading_progress_(false), did_loading_progress_(false),
volume_(1.0f), volume_(1.0f),
playback_rate_(0.0f), playback_rate_(0.0f),
clock_(new Clock(&default_tick_clock_)), interpolator_(new TimeDeltaInterpolator(&default_tick_clock_)),
clock_state_(CLOCK_PAUSED), interpolation_state_(INTERPOLATION_STOPPED),
status_(PIPELINE_OK), status_(PIPELINE_OK),
state_(kCreated), state_(kCreated),
audio_ended_(false), audio_ended_(false),
...@@ -55,7 +55,7 @@ Pipeline::Pipeline( ...@@ -55,7 +55,7 @@ Pipeline::Pipeline(
media_log_->AddEvent(media_log_->CreatePipelineStateChangedEvent(kCreated)); media_log_->AddEvent(media_log_->CreatePipelineStateChangedEvent(kCreated));
media_log_->AddEvent( media_log_->AddEvent(
media_log_->CreateEvent(MediaLogEvent::PIPELINE_CREATED)); media_log_->CreateEvent(MediaLogEvent::PIPELINE_CREATED));
clock_->SetTime(base::TimeDelta(), base::TimeDelta()); interpolator_->SetBounds(base::TimeDelta(), base::TimeDelta());
} }
Pipeline::~Pipeline() { Pipeline::~Pipeline() {
...@@ -157,7 +157,7 @@ void Pipeline::SetVolume(float volume) { ...@@ -157,7 +157,7 @@ void Pipeline::SetVolume(float volume) {
TimeDelta Pipeline::GetMediaTime() const { TimeDelta Pipeline::GetMediaTime() const {
base::AutoLock auto_lock(lock_); base::AutoLock auto_lock(lock_);
return std::min(clock_->Elapsed(), duration_); return std::min(interpolator_->GetInterpolatedTime(), duration_);
} }
Ranges<TimeDelta> Pipeline::GetBufferedTimeRanges() const { Ranges<TimeDelta> Pipeline::GetBufferedTimeRanges() const {
...@@ -182,8 +182,9 @@ PipelineStatistics Pipeline::GetStatistics() const { ...@@ -182,8 +182,9 @@ PipelineStatistics Pipeline::GetStatistics() const {
return statistics_; return statistics_;
} }
void Pipeline::SetClockForTesting(Clock* clock) { void Pipeline::SetTimeDeltaInterpolatorForTesting(
clock_.reset(clock); TimeDeltaInterpolator* interpolator) {
interpolator_.reset(interpolator);
} }
void Pipeline::SetErrorForTesting(PipelineStatus status) { void Pipeline::SetErrorForTesting(PipelineStatus status) {
...@@ -287,15 +288,15 @@ void Pipeline::OnAudioTimeUpdate(TimeDelta time, TimeDelta max_time) { ...@@ -287,15 +288,15 @@ void Pipeline::OnAudioTimeUpdate(TimeDelta time, TimeDelta max_time) {
DCHECK_LE(time.InMicroseconds(), max_time.InMicroseconds()); DCHECK_LE(time.InMicroseconds(), max_time.InMicroseconds());
base::AutoLock auto_lock(lock_); base::AutoLock auto_lock(lock_);
if (clock_state_ == CLOCK_WAITING_FOR_AUDIO_TIME_UPDATE && if (interpolation_state_ == INTERPOLATION_WAITING_FOR_AUDIO_TIME_UPDATE &&
time < clock_->Elapsed()) { time < interpolator_->GetInterpolatedTime()) {
return; return;
} }
if (state_ == kSeeking) if (state_ == kSeeking)
return; return;
clock_->SetTime(time, max_time); interpolator_->SetBounds(time, max_time);
StartClockIfWaitingForTimeUpdate_Locked(); StartClockIfWaitingForTimeUpdate_Locked();
} }
...@@ -309,8 +310,8 @@ void Pipeline::OnVideoTimeUpdate(TimeDelta max_time) { ...@@ -309,8 +310,8 @@ void Pipeline::OnVideoTimeUpdate(TimeDelta max_time) {
return; return;
base::AutoLock auto_lock(lock_); base::AutoLock auto_lock(lock_);
DCHECK_NE(clock_state_, CLOCK_WAITING_FOR_AUDIO_TIME_UPDATE); DCHECK_NE(interpolation_state_, INTERPOLATION_WAITING_FOR_AUDIO_TIME_UPDATE);
clock_->SetMaxTime(max_time); interpolator_->SetUpperBound(max_time);
} }
void Pipeline::SetDuration(TimeDelta duration) { void Pipeline::SetDuration(TimeDelta duration) {
...@@ -397,7 +398,7 @@ void Pipeline::StateTransitionTask(PipelineStatus status) { ...@@ -397,7 +398,7 @@ void Pipeline::StateTransitionTask(PipelineStatus status) {
{ {
base::AutoLock auto_lock(lock_); base::AutoLock auto_lock(lock_);
clock_->SetTime(start_timestamp_, start_timestamp_); interpolator_->SetBounds(start_timestamp_, start_timestamp_);
} }
if (audio_renderer_) if (audio_renderer_)
...@@ -642,7 +643,7 @@ void Pipeline::PlaybackRateChangedTask(float playback_rate) { ...@@ -642,7 +643,7 @@ void Pipeline::PlaybackRateChangedTask(float playback_rate) {
{ {
base::AutoLock auto_lock(lock_); base::AutoLock auto_lock(lock_);
clock_->SetPlaybackRate(playback_rate); interpolator_->SetPlaybackRate(playback_rate);
} }
if (audio_renderer_) if (audio_renderer_)
...@@ -703,7 +704,7 @@ void Pipeline::DoAudioRendererEnded() { ...@@ -703,7 +704,7 @@ void Pipeline::DoAudioRendererEnded() {
// Start clock since there is no more audio to trigger clock updates. // Start clock since there is no more audio to trigger clock updates.
{ {
base::AutoLock auto_lock(lock_); base::AutoLock auto_lock(lock_);
clock_->SetMaxTime(duration_); interpolator_->SetUpperBound(duration_);
StartClockIfWaitingForTimeUpdate_Locked(); StartClockIfWaitingForTimeUpdate_Locked();
} }
...@@ -749,7 +750,7 @@ void Pipeline::RunEndedCallbackIfNeeded() { ...@@ -749,7 +750,7 @@ void Pipeline::RunEndedCallbackIfNeeded() {
{ {
base::AutoLock auto_lock(lock_); base::AutoLock auto_lock(lock_);
PauseClockAndStopRendering_Locked(); PauseClockAndStopRendering_Locked();
clock_->SetTime(duration_, duration_); interpolator_->SetBounds(duration_, duration_);
} }
DCHECK_EQ(status_, PIPELINE_OK); DCHECK_EQ(status_, PIPELINE_OK);
...@@ -822,7 +823,7 @@ void Pipeline::BufferingStateChanged(BufferingState* buffering_state, ...@@ -822,7 +823,7 @@ void Pipeline::BufferingStateChanged(BufferingState* buffering_state,
// Disable underflow by ignoring updates that renderers have ran out of data // Disable underflow by ignoring updates that renderers have ran out of data
// after we have started the clock. // after we have started the clock.
if (state_ == kPlaying && underflow_disabled_for_testing_ && if (state_ == kPlaying && underflow_disabled_for_testing_ &&
clock_state_ != CLOCK_PAUSED) { interpolation_state_ != INTERPOLATION_STOPPED) {
return; return;
} }
...@@ -867,7 +868,7 @@ void Pipeline::PausePlayback() { ...@@ -867,7 +868,7 @@ void Pipeline::PausePlayback() {
void Pipeline::StartPlayback() { void Pipeline::StartPlayback() {
DVLOG(1) << __FUNCTION__; DVLOG(1) << __FUNCTION__;
DCHECK_EQ(state_, kPlaying); DCHECK_EQ(state_, kPlaying);
DCHECK_EQ(clock_state_, CLOCK_PAUSED); DCHECK_EQ(interpolation_state_, INTERPOLATION_STOPPED);
DCHECK(!WaitingForEnoughData()); DCHECK(!WaitingForEnoughData());
DCHECK(task_runner_->BelongsToCurrentThread()); DCHECK(task_runner_->BelongsToCurrentThread());
...@@ -875,43 +876,43 @@ void Pipeline::StartPlayback() { ...@@ -875,43 +876,43 @@ void Pipeline::StartPlayback() {
// We use audio stream to update the clock. So if there is such a // We use audio stream to update the clock. So if there is such a
// stream, we pause the clock until we receive a valid timestamp. // stream, we pause the clock until we receive a valid timestamp.
base::AutoLock auto_lock(lock_); base::AutoLock auto_lock(lock_);
clock_state_ = CLOCK_WAITING_FOR_AUDIO_TIME_UPDATE; interpolation_state_ = INTERPOLATION_WAITING_FOR_AUDIO_TIME_UPDATE;
audio_renderer_->StartRendering(); audio_renderer_->StartRendering();
} else { } else {
base::AutoLock auto_lock(lock_); base::AutoLock auto_lock(lock_);
clock_state_ = CLOCK_PLAYING; interpolation_state_ = INTERPOLATION_STARTED;
clock_->SetMaxTime(duration_); interpolator_->SetUpperBound(duration_);
clock_->Play(); interpolator_->StartInterpolating();
} }
} }
void Pipeline::PauseClockAndStopRendering_Locked() { void Pipeline::PauseClockAndStopRendering_Locked() {
lock_.AssertAcquired(); lock_.AssertAcquired();
switch (clock_state_) { switch (interpolation_state_) {
case CLOCK_PAUSED: case INTERPOLATION_STOPPED:
return; return;
case CLOCK_WAITING_FOR_AUDIO_TIME_UPDATE: case INTERPOLATION_WAITING_FOR_AUDIO_TIME_UPDATE:
audio_renderer_->StopRendering(); audio_renderer_->StopRendering();
break; break;
case CLOCK_PLAYING: case INTERPOLATION_STARTED:
if (audio_renderer_) if (audio_renderer_)
audio_renderer_->StopRendering(); audio_renderer_->StopRendering();
clock_->Pause(); interpolator_->StopInterpolating();
break; break;
} }
clock_state_ = CLOCK_PAUSED; interpolation_state_ = INTERPOLATION_STOPPED;
} }
void Pipeline::StartClockIfWaitingForTimeUpdate_Locked() { void Pipeline::StartClockIfWaitingForTimeUpdate_Locked() {
lock_.AssertAcquired(); lock_.AssertAcquired();
if (clock_state_ != CLOCK_WAITING_FOR_AUDIO_TIME_UPDATE) if (interpolation_state_ != INTERPOLATION_WAITING_FOR_AUDIO_TIME_UPDATE)
return; return;
clock_state_ = CLOCK_PLAYING; interpolation_state_ = INTERPOLATION_STARTED;
clock_->Play(); interpolator_->StartInterpolating();
} }
} // namespace media } // namespace media
...@@ -28,11 +28,11 @@ class TimeDelta; ...@@ -28,11 +28,11 @@ class TimeDelta;
namespace media { namespace media {
class Clock;
class FilterCollection; class FilterCollection;
class MediaLog; class MediaLog;
class TextRenderer; class TextRenderer;
class TextTrackConfig; class TextTrackConfig;
class TimeDeltaInterpolator;
class VideoRenderer; class VideoRenderer;
// Metadata describing a pipeline once it has been initialized. // Metadata describing a pipeline once it has been initialized.
...@@ -176,7 +176,7 @@ class MEDIA_EXPORT Pipeline : public DemuxerHost { ...@@ -176,7 +176,7 @@ class MEDIA_EXPORT Pipeline : public DemuxerHost {
void set_underflow_disabled_for_testing(bool disabled) { void set_underflow_disabled_for_testing(bool disabled) {
underflow_disabled_for_testing_ = disabled; underflow_disabled_for_testing_ = disabled;
} }
void SetClockForTesting(Clock* clock); void SetTimeDeltaInterpolatorForTesting(TimeDeltaInterpolator* interpolator);
void SetErrorForTesting(PipelineStatus status); void SetErrorForTesting(PipelineStatus status);
private: private:
...@@ -349,26 +349,25 @@ class MEDIA_EXPORT Pipeline : public DemuxerHost { ...@@ -349,26 +349,25 @@ class MEDIA_EXPORT Pipeline : public DemuxerHost {
// Current duration as reported by |demuxer_|. // Current duration as reported by |demuxer_|.
base::TimeDelta duration_; base::TimeDelta duration_;
// base::TickClock used by |clock_|. // base::TickClock used by |interpolator_|.
base::DefaultTickClock default_tick_clock_; base::DefaultTickClock default_tick_clock_;
// Reference clock. Keeps track of current playback time. Uses system // Tracks the most recent media time update and provides interpolated values
// clock and linear interpolation, but can have its time manually set // as playback progresses.
// by filters. scoped_ptr<TimeDeltaInterpolator> interpolator_;
scoped_ptr<Clock> clock_;
enum ClockState { enum InterpolationState {
// Audio (if present) is not rendering. Clock isn't playing. // Audio (if present) is not rendering. Time isn't being interpolated.
CLOCK_PAUSED, INTERPOLATION_STOPPED,
// Audio (if present) is rendering. Clock isn't playing. // Audio (if present) is rendering. Time isn't being interpolated.
CLOCK_WAITING_FOR_AUDIO_TIME_UPDATE, INTERPOLATION_WAITING_FOR_AUDIO_TIME_UPDATE,
// Audio (if present) is rendering. Clock is playing. // Audio (if present) is rendering. Time is being interpolated.
CLOCK_PLAYING, INTERPOLATION_STARTED,
}; };
ClockState clock_state_; InterpolationState interpolation_state_;
// Status of the pipeline. Initialized to PIPELINE_OK which indicates that // Status of the pipeline. Initialized to PIPELINE_OK which indicates that
// the pipeline is operating correctly. Any other value indicates that the // the pipeline is operating correctly. Any other value indicates that the
......
...@@ -10,7 +10,6 @@ ...@@ -10,7 +10,6 @@
#include "base/test/simple_test_tick_clock.h" #include "base/test/simple_test_tick_clock.h"
#include "base/threading/simple_thread.h" #include "base/threading/simple_thread.h"
#include "base/time/clock.h" #include "base/time/clock.h"
#include "media/base/clock.h"
#include "media/base/fake_text_track_stream.h" #include "media/base/fake_text_track_stream.h"
#include "media/base/gmock_callback_support.h" #include "media/base/gmock_callback_support.h"
#include "media/base/media_log.h" #include "media/base/media_log.h"
...@@ -19,6 +18,7 @@ ...@@ -19,6 +18,7 @@
#include "media/base/test_helpers.h" #include "media/base/test_helpers.h"
#include "media/base/text_renderer.h" #include "media/base/text_renderer.h"
#include "media/base/text_track_config.h" #include "media/base/text_track_config.h"
#include "media/base/time_delta_interpolator.h"
#include "testing/gtest/include/gtest/gtest.h" #include "testing/gtest/include/gtest/gtest.h"
#include "ui/gfx/size.h" #include "ui/gfx/size.h"
...@@ -619,9 +619,9 @@ TEST_F(PipelineTest, AudioStreamShorterThanVideo) { ...@@ -619,9 +619,9 @@ TEST_F(PipelineTest, AudioStreamShorterThanVideo) {
streams.push_back(audio_stream()); streams.push_back(audio_stream());
streams.push_back(video_stream()); streams.push_back(video_stream());
// Replace the clock so we can simulate wall clock time advancing w/o using // Replace what's used for interpolating to simulate wall clock time.
// Sleep(). pipeline_->SetTimeDeltaInterpolatorForTesting(
pipeline_->SetClockForTesting(new Clock(&test_tick_clock_)); new TimeDeltaInterpolator(&test_tick_clock_));
InitializeDemuxer(&streams, duration); InitializeDemuxer(&streams, duration);
InitializeAudioRenderer(audio_stream()); InitializeAudioRenderer(audio_stream());
......
// 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/time_delta_interpolator.h"
#include <algorithm>
#include "base/logging.h"
#include "base/time/tick_clock.h"
#include "media/base/buffers.h"
namespace media {
TimeDeltaInterpolator::TimeDeltaInterpolator(base::TickClock* tick_clock)
: tick_clock_(tick_clock),
interpolating_(false),
upper_bound_(kNoTimestamp()),
playback_rate_(1.0f) {
DCHECK(tick_clock_);
}
TimeDeltaInterpolator::~TimeDeltaInterpolator() {
}
base::TimeDelta TimeDeltaInterpolator::StartInterpolating() {
DCHECK(!interpolating_);
reference_ = tick_clock_->NowTicks();
interpolating_ = true;
return lower_bound_;
}
base::TimeDelta TimeDeltaInterpolator::StopInterpolating() {
DCHECK(interpolating_);
lower_bound_ = GetInterpolatedTime();
interpolating_ = false;
return lower_bound_;
}
void TimeDeltaInterpolator::SetPlaybackRate(float playback_rate) {
lower_bound_ = GetInterpolatedTime();
reference_ = tick_clock_->NowTicks();
playback_rate_ = playback_rate;
}
void TimeDeltaInterpolator::SetBounds(base::TimeDelta lower_bound,
base::TimeDelta upper_bound) {
DCHECK(lower_bound <= upper_bound);
DCHECK(lower_bound != kNoTimestamp());
lower_bound_ = std::max(base::TimeDelta(), lower_bound);
upper_bound_ = std::max(base::TimeDelta(), upper_bound);
reference_ = tick_clock_->NowTicks();
}
void TimeDeltaInterpolator::SetUpperBound(base::TimeDelta upper_bound) {
DCHECK(upper_bound != kNoTimestamp());
lower_bound_ = GetInterpolatedTime();
reference_ = tick_clock_->NowTicks();
upper_bound_ = upper_bound;
}
base::TimeDelta TimeDeltaInterpolator::GetInterpolatedTime() {
if (!interpolating_)
return lower_bound_;
int64 now_us = (tick_clock_->NowTicks() - reference_).InMicroseconds();
now_us = static_cast<int64>(now_us * playback_rate_);
base::TimeDelta interpolated_time =
lower_bound_ + base::TimeDelta::FromMicroseconds(now_us);
if (upper_bound_ == kNoTimestamp())
return interpolated_time;
return std::min(interpolated_time, upper_bound_);
}
} // 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_TIME_DELTA_INTERPOLATOR_H_
#define MEDIA_BASE_TIME_DELTA_INTERPOLATOR_H_
#include "base/basictypes.h"
#include "base/time/time.h"
#include "media/base/media_export.h"
namespace base {
class TickClock;
} // namespace base
namespace media {
// Interpolates between two TimeDeltas based on the passage of wall clock time
// and the current playback rate.
//
// TimeDeltaInterpolator is not thread-safe and must be externally locked.
class MEDIA_EXPORT TimeDeltaInterpolator {
public:
// Constructs an interpolator initialized to zero with a rate of 1.0.
//
// |tick_clock| is used for sampling wall clock time for interpolating.
explicit TimeDeltaInterpolator(base::TickClock* tick_clock);
~TimeDeltaInterpolator();
bool interpolating() { return interpolating_; }
// Starts returning interpolated TimeDelta values.
//
// |tick_clock| will be queried for a new reference time value.
base::TimeDelta StartInterpolating();
// Stops returning interpolated TimeDelta values.
//
// |tick_clock| will be queried for a new reference time value.
base::TimeDelta StopInterpolating();
// Sets a new rate at which to interpolate.
//
// |tick_clock| will be queried for a new reference time value.
void SetPlaybackRate(float playback_rate);
// Sets the two timestamps to interpolate between at |playback_rate_|.
// |upper_bound| must be greater or equal to |lower_bound|.
//
// |upper_bound| is typically the media timestamp of the last audio frame
// buffered by the audio hardware.
void SetBounds(base::TimeDelta lower_bound, base::TimeDelta upper_bound);
// Sets the upper bound used for interpolation. Note that if |upper_bound| is
// less than what was previously set via SetTime(), then all future calls
// to GetInterpolatedTime() will return |upper_bound|.
void SetUpperBound(base::TimeDelta upper_bound);
// Computes an interpolated time based on SetTime().
base::TimeDelta GetInterpolatedTime();
private:
base::TickClock* const tick_clock_;
bool interpolating_;
// The range of time to interpolate between.
base::TimeDelta lower_bound_;
base::TimeDelta upper_bound_;
// The monotonic system clock time used for interpolating between
// |lower_bound_| and |upper_bound_|.
base::TimeTicks reference_;
float playback_rate_;
DISALLOW_COPY_AND_ASSIGN(TimeDeltaInterpolator);
};
} // namespace media
#endif // MEDIA_BASE_TIME_DELTA_INTERPOLATOR_H_
// Copyright (c) 2012 The Chromium Authors. All rights reserved. // Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
#include "base/logging.h" #include "base/logging.h"
#include "base/test/simple_test_tick_clock.h" #include "base/test/simple_test_tick_clock.h"
#include "media/base/clock.h" #include "media/base/time_delta_interpolator.h"
#include "testing/gtest/include/gtest/gtest.h" #include "testing/gtest/include/gtest/gtest.h"
namespace media { namespace media {
class ClockTest : public ::testing::Test { class TimeDeltaInterpolatorTest : public ::testing::Test {
public: public:
ClockTest() : clock_(&test_tick_clock_) {} TimeDeltaInterpolatorTest() : interpolator_(&test_tick_clock_) {}
protected: protected:
void AdvanceSystemTime(base::TimeDelta delta) { void AdvanceSystemTime(base::TimeDelta delta) {
...@@ -19,45 +19,44 @@ class ClockTest : public ::testing::Test { ...@@ -19,45 +19,44 @@ class ClockTest : public ::testing::Test {
} }
base::SimpleTestTickClock test_tick_clock_; base::SimpleTestTickClock test_tick_clock_;
Clock clock_; TimeDeltaInterpolator interpolator_;
base::TimeDelta time_elapsed_;
}; };
TEST_F(ClockTest, Created) { TEST_F(TimeDeltaInterpolatorTest, Created) {
const base::TimeDelta kExpected = base::TimeDelta::FromSeconds(0); const base::TimeDelta kExpected = base::TimeDelta::FromSeconds(0);
EXPECT_EQ(kExpected, clock_.Elapsed()); EXPECT_EQ(kExpected, interpolator_.GetInterpolatedTime());
} }
TEST_F(ClockTest, Play_NormalSpeed) { TEST_F(TimeDeltaInterpolatorTest, StartInterpolating_NormalSpeed) {
const base::TimeDelta kZero; const base::TimeDelta kZero;
const base::TimeDelta kTimeToAdvance = base::TimeDelta::FromSeconds(2); const base::TimeDelta kTimeToAdvance = base::TimeDelta::FromSeconds(2);
EXPECT_EQ(kZero, clock_.Play()); EXPECT_EQ(kZero, interpolator_.StartInterpolating());
AdvanceSystemTime(kTimeToAdvance); AdvanceSystemTime(kTimeToAdvance);
EXPECT_EQ(kTimeToAdvance, clock_.Elapsed()); EXPECT_EQ(kTimeToAdvance, interpolator_.GetInterpolatedTime());
} }
TEST_F(ClockTest, Play_DoubleSpeed) { TEST_F(TimeDeltaInterpolatorTest, StartInterpolating_DoubleSpeed) {
const base::TimeDelta kZero; const base::TimeDelta kZero;
const base::TimeDelta kTimeToAdvance = base::TimeDelta::FromSeconds(5); const base::TimeDelta kTimeToAdvance = base::TimeDelta::FromSeconds(5);
clock_.SetPlaybackRate(2.0f); interpolator_.SetPlaybackRate(2.0f);
EXPECT_EQ(kZero, clock_.Play()); EXPECT_EQ(kZero, interpolator_.StartInterpolating());
AdvanceSystemTime(kTimeToAdvance); AdvanceSystemTime(kTimeToAdvance);
EXPECT_EQ(2 * kTimeToAdvance, clock_.Elapsed()); EXPECT_EQ(2 * kTimeToAdvance, interpolator_.GetInterpolatedTime());
} }
TEST_F(ClockTest, Play_HalfSpeed) { TEST_F(TimeDeltaInterpolatorTest, StartInterpolating_HalfSpeed) {
const base::TimeDelta kZero; const base::TimeDelta kZero;
const base::TimeDelta kTimeToAdvance = base::TimeDelta::FromSeconds(4); const base::TimeDelta kTimeToAdvance = base::TimeDelta::FromSeconds(4);
clock_.SetPlaybackRate(0.5f); interpolator_.SetPlaybackRate(0.5f);
EXPECT_EQ(kZero, clock_.Play()); EXPECT_EQ(kZero, interpolator_.StartInterpolating());
AdvanceSystemTime(kTimeToAdvance); AdvanceSystemTime(kTimeToAdvance);
EXPECT_EQ(kTimeToAdvance / 2, clock_.Elapsed()); EXPECT_EQ(kTimeToAdvance / 2, interpolator_.GetInterpolatedTime());
} }
TEST_F(ClockTest, Play_ZeroSpeed) { TEST_F(TimeDeltaInterpolatorTest, StartInterpolating_ZeroSpeed) {
// We'll play for 2 seconds at normal speed, 4 seconds at zero speed, and 8 // We'll play for 2 seconds at normal speed, 4 seconds at zero speed, and 8
// seconds at normal speed. // seconds at normal speed.
const base::TimeDelta kZero; const base::TimeDelta kZero;
...@@ -66,18 +65,18 @@ TEST_F(ClockTest, Play_ZeroSpeed) { ...@@ -66,18 +65,18 @@ TEST_F(ClockTest, Play_ZeroSpeed) {
const base::TimeDelta kPlayDuration3 = base::TimeDelta::FromSeconds(8); const base::TimeDelta kPlayDuration3 = base::TimeDelta::FromSeconds(8);
const base::TimeDelta kExpected = kPlayDuration1 + kPlayDuration3; const base::TimeDelta kExpected = kPlayDuration1 + kPlayDuration3;
EXPECT_EQ(kZero, clock_.Play()); EXPECT_EQ(kZero, interpolator_.StartInterpolating());
AdvanceSystemTime(kPlayDuration1); AdvanceSystemTime(kPlayDuration1);
clock_.SetPlaybackRate(0.0f); interpolator_.SetPlaybackRate(0.0f);
AdvanceSystemTime(kPlayDuration2); AdvanceSystemTime(kPlayDuration2);
clock_.SetPlaybackRate(1.0f); interpolator_.SetPlaybackRate(1.0f);
AdvanceSystemTime(kPlayDuration3); AdvanceSystemTime(kPlayDuration3);
EXPECT_EQ(kExpected, clock_.Elapsed()); EXPECT_EQ(kExpected, interpolator_.GetInterpolatedTime());
} }
TEST_F(ClockTest, Play_MultiSpeed) { TEST_F(TimeDeltaInterpolatorTest, StartInterpolating_MultiSpeed) {
// We'll play for 2 seconds at half speed, 4 seconds at normal speed, and 8 // We'll play for 2 seconds at half speed, 4 seconds at normal speed, and 8
// seconds at double speed. // seconds at double speed.
const base::TimeDelta kZero; const base::TimeDelta kZero;
...@@ -87,19 +86,19 @@ TEST_F(ClockTest, Play_MultiSpeed) { ...@@ -87,19 +86,19 @@ TEST_F(ClockTest, Play_MultiSpeed) {
const base::TimeDelta kExpected = const base::TimeDelta kExpected =
kPlayDuration1 / 2 + kPlayDuration2 + 2 * kPlayDuration3; kPlayDuration1 / 2 + kPlayDuration2 + 2 * kPlayDuration3;
clock_.SetPlaybackRate(0.5f); interpolator_.SetPlaybackRate(0.5f);
EXPECT_EQ(kZero, clock_.Play()); EXPECT_EQ(kZero, interpolator_.StartInterpolating());
AdvanceSystemTime(kPlayDuration1); AdvanceSystemTime(kPlayDuration1);
clock_.SetPlaybackRate(1.0f); interpolator_.SetPlaybackRate(1.0f);
AdvanceSystemTime(kPlayDuration2); AdvanceSystemTime(kPlayDuration2);
clock_.SetPlaybackRate(2.0f); interpolator_.SetPlaybackRate(2.0f);
AdvanceSystemTime(kPlayDuration3); AdvanceSystemTime(kPlayDuration3);
EXPECT_EQ(kExpected, clock_.Elapsed()); EXPECT_EQ(kExpected, interpolator_.GetInterpolatedTime());
} }
TEST_F(ClockTest, Pause) { TEST_F(TimeDeltaInterpolatorTest, StopInterpolating) {
const base::TimeDelta kZero; const base::TimeDelta kZero;
const base::TimeDelta kPlayDuration = base::TimeDelta::FromSeconds(4); const base::TimeDelta kPlayDuration = base::TimeDelta::FromSeconds(4);
const base::TimeDelta kPauseDuration = base::TimeDelta::FromSeconds(20); const base::TimeDelta kPauseDuration = base::TimeDelta::FromSeconds(20);
...@@ -107,34 +106,34 @@ TEST_F(ClockTest, Pause) { ...@@ -107,34 +106,34 @@ TEST_F(ClockTest, Pause) {
const base::TimeDelta kExpectedSecondPause = 2 * kPlayDuration; const base::TimeDelta kExpectedSecondPause = 2 * kPlayDuration;
// Play for 4 seconds. // Play for 4 seconds.
EXPECT_EQ(kZero, clock_.Play()); EXPECT_EQ(kZero, interpolator_.StartInterpolating());
AdvanceSystemTime(kPlayDuration); AdvanceSystemTime(kPlayDuration);
// Pause for 20 seconds. // Pause for 20 seconds.
EXPECT_EQ(kExpectedFirstPause, clock_.Pause()); EXPECT_EQ(kExpectedFirstPause, interpolator_.StopInterpolating());
EXPECT_EQ(kExpectedFirstPause, clock_.Elapsed()); EXPECT_EQ(kExpectedFirstPause, interpolator_.GetInterpolatedTime());
AdvanceSystemTime(kPauseDuration); AdvanceSystemTime(kPauseDuration);
EXPECT_EQ(kExpectedFirstPause, clock_.Elapsed()); EXPECT_EQ(kExpectedFirstPause, interpolator_.GetInterpolatedTime());
// Play again for 4 more seconds. // Play again for 4 more seconds.
EXPECT_EQ(kExpectedFirstPause, clock_.Play()); EXPECT_EQ(kExpectedFirstPause, interpolator_.StartInterpolating());
AdvanceSystemTime(kPlayDuration); AdvanceSystemTime(kPlayDuration);
EXPECT_EQ(kExpectedSecondPause, clock_.Pause()); EXPECT_EQ(kExpectedSecondPause, interpolator_.StopInterpolating());
EXPECT_EQ(kExpectedSecondPause, clock_.Elapsed()); EXPECT_EQ(kExpectedSecondPause, interpolator_.GetInterpolatedTime());
} }
TEST_F(ClockTest, SetTime_Paused) { TEST_F(TimeDeltaInterpolatorTest, SetBounds_Stopped) {
const base::TimeDelta kFirstTime = base::TimeDelta::FromSeconds(4); const base::TimeDelta kFirstTime = base::TimeDelta::FromSeconds(4);
const base::TimeDelta kSecondTime = base::TimeDelta::FromSeconds(16); const base::TimeDelta kSecondTime = base::TimeDelta::FromSeconds(16);
const base::TimeDelta kArbitraryMaxTime = base::TimeDelta::FromSeconds(100); const base::TimeDelta kArbitraryMaxTime = base::TimeDelta::FromSeconds(100);
clock_.SetTime(kFirstTime, kArbitraryMaxTime); interpolator_.SetBounds(kFirstTime, kArbitraryMaxTime);
EXPECT_EQ(kFirstTime, clock_.Elapsed()); EXPECT_EQ(kFirstTime, interpolator_.GetInterpolatedTime());
clock_.SetTime(kSecondTime, kArbitraryMaxTime); interpolator_.SetBounds(kSecondTime, kArbitraryMaxTime);
EXPECT_EQ(kSecondTime, clock_.Elapsed()); EXPECT_EQ(kSecondTime, interpolator_.GetInterpolatedTime());
} }
TEST_F(ClockTest, SetTime_Playing) { TEST_F(TimeDeltaInterpolatorTest, SetBounds_Started) {
// We'll play for 4 seconds, then set the time to 12, then play for 4 more // We'll play for 4 seconds, then set the time to 12, then play for 4 more
// seconds. // seconds.
const base::TimeDelta kZero; const base::TimeDelta kZero;
...@@ -143,58 +142,58 @@ TEST_F(ClockTest, SetTime_Playing) { ...@@ -143,58 +142,58 @@ TEST_F(ClockTest, SetTime_Playing) {
const base::TimeDelta kArbitraryMaxTime = base::TimeDelta::FromSeconds(100); const base::TimeDelta kArbitraryMaxTime = base::TimeDelta::FromSeconds(100);
const base::TimeDelta kExpected = kUpdatedTime + kPlayDuration; const base::TimeDelta kExpected = kUpdatedTime + kPlayDuration;
EXPECT_EQ(kZero, clock_.Play()); EXPECT_EQ(kZero, interpolator_.StartInterpolating());
AdvanceSystemTime(kPlayDuration); AdvanceSystemTime(kPlayDuration);
clock_.SetTime(kUpdatedTime, kArbitraryMaxTime); interpolator_.SetBounds(kUpdatedTime, kArbitraryMaxTime);
AdvanceSystemTime(kPlayDuration); AdvanceSystemTime(kPlayDuration);
EXPECT_EQ(kExpected, clock_.Elapsed()); EXPECT_EQ(kExpected, interpolator_.GetInterpolatedTime());
} }
TEST_F(ClockTest, SetMaxTime) { TEST_F(TimeDeltaInterpolatorTest, SetUpperBound) {
const base::TimeDelta kZero; const base::TimeDelta kZero;
const base::TimeDelta kTimeInterval = base::TimeDelta::FromSeconds(4); const base::TimeDelta kTimeInterval = base::TimeDelta::FromSeconds(4);
const base::TimeDelta kMaxTime = base::TimeDelta::FromSeconds(6); const base::TimeDelta kMaxTime = base::TimeDelta::FromSeconds(6);
EXPECT_EQ(kZero, clock_.Play()); EXPECT_EQ(kZero, interpolator_.StartInterpolating());
clock_.SetMaxTime(kMaxTime); interpolator_.SetUpperBound(kMaxTime);
AdvanceSystemTime(kTimeInterval); AdvanceSystemTime(kTimeInterval);
EXPECT_EQ(kTimeInterval, clock_.Elapsed()); EXPECT_EQ(kTimeInterval, interpolator_.GetInterpolatedTime());
AdvanceSystemTime(kTimeInterval); AdvanceSystemTime(kTimeInterval);
EXPECT_EQ(kMaxTime, clock_.Elapsed()); EXPECT_EQ(kMaxTime, interpolator_.GetInterpolatedTime());
AdvanceSystemTime(kTimeInterval); AdvanceSystemTime(kTimeInterval);
EXPECT_EQ(kMaxTime, clock_.Elapsed()); EXPECT_EQ(kMaxTime, interpolator_.GetInterpolatedTime());
} }
TEST_F(ClockTest, SetMaxTime_MultipleTimes) { TEST_F(TimeDeltaInterpolatorTest, SetUpperBound_MultipleTimes) {
const base::TimeDelta kZero; const base::TimeDelta kZero;
const base::TimeDelta kTimeInterval = base::TimeDelta::FromSeconds(4); const base::TimeDelta kTimeInterval = base::TimeDelta::FromSeconds(4);
const base::TimeDelta kMaxTime0 = base::TimeDelta::FromSeconds(120); const base::TimeDelta kMaxTime0 = base::TimeDelta::FromSeconds(120);
const base::TimeDelta kMaxTime1 = base::TimeDelta::FromSeconds(6); const base::TimeDelta kMaxTime1 = base::TimeDelta::FromSeconds(6);
const base::TimeDelta kMaxTime2 = base::TimeDelta::FromSeconds(12); const base::TimeDelta kMaxTime2 = base::TimeDelta::FromSeconds(12);
EXPECT_EQ(kZero, clock_.Play()); EXPECT_EQ(kZero, interpolator_.StartInterpolating());
clock_.SetMaxTime(kMaxTime0); interpolator_.SetUpperBound(kMaxTime0);
AdvanceSystemTime(kTimeInterval); AdvanceSystemTime(kTimeInterval);
EXPECT_EQ(kTimeInterval, clock_.Elapsed()); EXPECT_EQ(kTimeInterval, interpolator_.GetInterpolatedTime());
clock_.SetMaxTime(kMaxTime1); interpolator_.SetUpperBound(kMaxTime1);
AdvanceSystemTime(kTimeInterval); AdvanceSystemTime(kTimeInterval);
EXPECT_EQ(kMaxTime1, clock_.Elapsed()); EXPECT_EQ(kMaxTime1, interpolator_.GetInterpolatedTime());
AdvanceSystemTime(kTimeInterval); AdvanceSystemTime(kTimeInterval);
EXPECT_EQ(kMaxTime1, clock_.Elapsed()); EXPECT_EQ(kMaxTime1, interpolator_.GetInterpolatedTime());
clock_.SetMaxTime(kMaxTime2); interpolator_.SetUpperBound(kMaxTime2);
EXPECT_EQ(kMaxTime1, clock_.Elapsed()); EXPECT_EQ(kMaxTime1, interpolator_.GetInterpolatedTime());
AdvanceSystemTime(kTimeInterval); AdvanceSystemTime(kTimeInterval);
EXPECT_EQ(kMaxTime1 + kTimeInterval, clock_.Elapsed()); EXPECT_EQ(kMaxTime1 + kTimeInterval, interpolator_.GetInterpolatedTime());
AdvanceSystemTime(kTimeInterval); AdvanceSystemTime(kTimeInterval);
EXPECT_EQ(kMaxTime2, clock_.Elapsed()); EXPECT_EQ(kMaxTime2, interpolator_.GetInterpolatedTime());
} }
} // namespace media } // namespace media
...@@ -6,8 +6,8 @@ ...@@ -6,8 +6,8 @@
#include "base/bind.h" #include "base/bind.h"
#include "base/memory/scoped_vector.h" #include "base/memory/scoped_vector.h"
#include "media/base/clock.h"
#include "media/base/media_log.h" #include "media/base/media_log.h"
#include "media/base/time_delta_interpolator.h"
#include "media/filters/audio_renderer_impl.h" #include "media/filters/audio_renderer_impl.h"
#include "media/filters/chunk_demuxer.h" #include "media/filters/chunk_demuxer.h"
#include "media/filters/ffmpeg_audio_decoder.h" #include "media/filters/ffmpeg_audio_decoder.h"
...@@ -132,8 +132,10 @@ bool PipelineIntegrationTestBase::Start(const base::FilePath& file_path, ...@@ -132,8 +132,10 @@ bool PipelineIntegrationTestBase::Start(const base::FilePath& file_path,
kTestType test_type) { kTestType test_type) {
hashing_enabled_ = test_type == kHashed; hashing_enabled_ = test_type == kHashed;
clockless_playback_ = test_type == kClockless; clockless_playback_ = test_type == kClockless;
if (clockless_playback_) if (clockless_playback_) {
pipeline_->SetClockForTesting(new Clock(&dummy_clock_)); pipeline_->SetTimeDeltaInterpolatorForTesting(
new TimeDeltaInterpolator(&dummy_clock_));
}
return Start(file_path, expected_status); return Start(file_path, expected_status);
} }
......
...@@ -256,8 +256,6 @@ ...@@ -256,8 +256,6 @@
'base/cdm_promise.h', 'base/cdm_promise.h',
'base/channel_mixer.cc', 'base/channel_mixer.cc',
'base/channel_mixer.h', 'base/channel_mixer.h',
'base/clock.cc',
'base/clock.h',
'base/container_names.cc', 'base/container_names.cc',
'base/container_names.h', 'base/container_names.h',
'base/data_buffer.cc', 'base/data_buffer.cc',
...@@ -334,6 +332,8 @@ ...@@ -334,6 +332,8 @@
'base/text_track.h', 'base/text_track.h',
'base/text_track_config.cc', 'base/text_track_config.cc',
'base/text_track_config.h', 'base/text_track_config.h',
'base/time_delta_interpolator.cc',
'base/time_delta_interpolator.h',
'base/user_input_monitor.cc', 'base/user_input_monitor.cc',
'base/user_input_monitor.h', 'base/user_input_monitor.h',
'base/user_input_monitor_linux.cc', 'base/user_input_monitor_linux.cc',
...@@ -1077,7 +1077,6 @@ ...@@ -1077,7 +1077,6 @@
'base/callback_holder.h', 'base/callback_holder.h',
'base/callback_holder_unittest.cc', 'base/callback_holder_unittest.cc',
'base/channel_mixer_unittest.cc', 'base/channel_mixer_unittest.cc',
'base/clock_unittest.cc',
'base/container_names_unittest.cc', 'base/container_names_unittest.cc',
'base/data_buffer_unittest.cc', 'base/data_buffer_unittest.cc',
'base/decoder_buffer_queue_unittest.cc', 'base/decoder_buffer_queue_unittest.cc',
...@@ -1096,6 +1095,7 @@ ...@@ -1096,6 +1095,7 @@
'base/stream_parser_unittest.cc', 'base/stream_parser_unittest.cc',
'base/text_ranges_unittest.cc', 'base/text_ranges_unittest.cc',
'base/text_renderer_unittest.cc', 'base/text_renderer_unittest.cc',
'base/time_delta_interpolator_unittest.cc',
'base/user_input_monitor_unittest.cc', 'base/user_input_monitor_unittest.cc',
'base/vector_math_testing.h', 'base/vector_math_testing.h',
'base/vector_math_unittest.cc', 'base/vector_math_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