Index: services/media/common/rate_control_base.cc |
diff --git a/services/media/common/rate_control_base.cc b/services/media/common/rate_control_base.cc |
deleted file mode 100644 |
index c72d26548bf4eab0ddf179c48fc47a2f2a7d414a..0000000000000000000000000000000000000000 |
--- a/services/media/common/rate_control_base.cc |
+++ /dev/null |
@@ -1,299 +0,0 @@ |
-// Copyright 2015 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/debug/stack_trace.h" |
-#include "base/logging.h" |
-#include "mojo/services/media/common/cpp/local_time.h" |
-#include "services/media/common/rate_control_base.h" |
- |
-namespace mojo { |
-namespace media { |
- |
-static inline int64_t LocalTimeNow() { |
- return LocalClock::now().time_since_epoch().count(); |
-} |
- |
-RateControlBase::RateControlBase() |
- : binding_(this) |
- , current_transform_(0, 1) { |
-} |
- |
-RateControlBase::~RateControlBase() { |
- Reset(); |
-} |
- |
-bool RateControlBase::Bind(InterfaceRequest<RateControl> request) { |
- Reset(); |
- |
- binding_.Bind(request.Pass()); |
- binding_.set_connection_error_handler([this]() -> void { |
- Reset(); |
- }); |
- |
- return true; |
-} |
- |
-void RateControlBase::SnapshotCurrentTransform(LinearTransform* out, |
- uint32_t* generation) { |
- DCHECK(out); |
- base::AutoLock lock(transform_lock_); |
- ApplyPendingChangesLocked(LocalTimeNow()); |
- *out = current_transform_; |
- if (generation) { |
- *generation = generation_; |
- } |
-} |
- |
-void RateControlBase::GetCurrentTransform( |
- const GetCurrentTransformCallback& cbk) { |
- TimelineTransformPtr ret(TimelineTransform::New()); |
- ret->quad = TimelineQuad::New(); |
- |
- LinearTransform trans; |
- SnapshotCurrentTransform(&trans); |
- ret->quad->target_offset = trans.a_zero; |
- ret->quad->reference_offset = trans.b_zero; |
- ret->quad->target_delta = trans.scale.denominator; |
- ret->quad->reference_delta = trans.scale.numerator; |
- ret->reference_timeline_id = TimelineTransform::kContextual; |
- ret->target_timeline_id = TimelineTransform::kLocalTimeID; |
- |
- cbk.Run(ret.Pass()); |
-} |
- |
-// TODO(johngro): implement or remove. Until we have the ability to query the |
-// clock in the target timeline (or at least, transform local time to the target |
-// timeline), we have no way to apply scheduled changes. |
-void RateControlBase::SetTargetTimelineID(uint32_t id) { |
- if (id != TimelineTransform::kLocalTimeID) { |
- LOG(ERROR) << "Unsupported target timeline id (" |
- << id << ") during SetTargetTimelineID"; |
- Reset(); |
- } |
-} |
- |
-void RateControlBase::SetCurrentQuad(TimelineQuadPtr quad) { |
- // A target delta of zero means that the transformation from the target |
- // timeline to the media timeline is singular. This is not permitted, log an |
- // error and close the connection if someone attempts to do this. |
- if (!quad->target_delta) { |
- OnIllegalRateChange(quad->reference_delta, quad->target_delta); |
- return; |
- } else { |
- base::AutoLock lock(transform_lock_); |
- |
- reference_pending_changes_.clear(); |
- target_pending_changes_.clear(); |
- |
- current_transform_.a_zero = quad->target_offset; |
- current_transform_.b_zero = quad->reference_offset; |
- |
- if (quad->reference_delta) { |
- current_transform_.scale = |
- LinearTransform::Ratio(quad->reference_delta, quad->target_delta); |
- } else { |
- current_transform_.scale.numerator = 0; |
- current_transform_.scale.denominator = 1; |
- } |
- |
- AdvanceGenerationLocked(); |
- } |
-} |
- |
-void RateControlBase::SetRate(uint32_t reference_delta, uint32_t target_delta) { |
- // Only rate changes with a non-zero target_delta are permitted. See comment |
- // in SetCurrentQuad. |
- if (!target_delta) { |
- OnIllegalRateChange(reference_delta, target_delta); |
- return; |
- } else { |
- base::AutoLock lock(transform_lock_); |
- |
- // Make sure we are up to date. |
- int64_t target_now = LocalTimeNow(); |
- ApplyPendingChangesLocked(target_now); |
- |
- DCHECK(current_transform_.scale.denominator); |
- int64_t reference_now; |
- if (!current_transform_.DoForwardTransform(target_now, &reference_now)) { |
- // TODO(johngro): we cannot apply this transformation because of |
- // overflow, so we are forced to skip it. Should we introduce a callback |
- // to allow the user to know that their transformation was skipped? |
- // Alternatively, should we log something about how the transformation was |
- // skipped? |
- return; |
- } |
- |
- current_transform_.a_zero = target_now; |
- current_transform_.b_zero = reference_now; |
- current_transform_.scale.numerator = reference_delta; |
- current_transform_.scale.denominator = target_delta; |
- |
- AdvanceGenerationLocked(); |
- } |
-} |
- |
-void RateControlBase::SetRateAtReferenceTime(uint32_t reference_delta, |
- uint32_t target_delta, |
- int64_t reference_time) { |
- // Only rate changes with a non-zero target_delta are permitted. See comment |
- // in SetCurrentQuad. |
- if (!target_delta) { |
- OnIllegalRateChange(reference_delta, target_delta); |
- return; |
- } else { |
- base::AutoLock lock(transform_lock_); |
- |
- // If the user tries to schedule a change which takes place before any |
- // already scheduled change, ignore it. |
- if (reference_pending_changes_.size() && |
- reference_pending_changes_.back().b_zero >= reference_time) { |
- return; |
- } |
- |
- reference_pending_changes_.emplace_back(0, |
- reference_delta, |
- target_delta, |
- reference_time); |
- } |
-} |
- |
-void RateControlBase::SetRateAtTargetTime(uint32_t reference_delta, |
- uint32_t target_delta, |
- int64_t target_time) { |
- // Only rate changes with a non-zero target_delta are permitted. See comment |
- // in SetCurrentQuad. |
- if (!target_delta) { |
- OnIllegalRateChange(reference_delta, target_delta); |
- return; |
- } else { |
- base::AutoLock lock(transform_lock_); |
- |
- // If the user tries to schedule a change which takes place before any |
- // already scheduled change, ignore it. |
- if (target_pending_changes_.size() && |
- target_pending_changes_.back().a_zero >= target_time) { |
- return; |
- } |
- |
- target_pending_changes_.emplace_back(target_time, |
- reference_delta, |
- target_delta, |
- 0); |
- } |
-} |
- |
-void RateControlBase::CancelPendingChanges() { |
- base::AutoLock lock(transform_lock_); |
- |
- reference_pending_changes_.clear(); |
- target_pending_changes_.clear(); |
-} |
- |
-void RateControlBase::ApplyPendingChangesLocked(int64_t target_now) { |
- bool advance_generation = false; |
- |
- do { |
- // Grab a pointer to the next pending target scheduled transform which is |
- // not in the future, if any. |
- int64_t target_age; |
- const LinearTransform* target_trans = nullptr; |
- if (target_pending_changes_.size() && |
- (target_now >= target_pending_changes_.front().a_zero)) { |
- target_trans = &target_pending_changes_.front(); |
- target_age = target_now - target_trans->a_zero; |
- } |
- |
- // Grab a pointer to the next pending reference scheduled transform which is |
- // not in the future, if any. |
- // |
- // TODO(johngro): Optimize this. When we have pending reference scheduled |
- // transformations, we don't have to compute this each and every time. We |
- // could just keep the time of the next reference scheduled change |
- // (expressed in target time) pre-computed, and only update it when the |
- // current transformation actually changes. |
- int64_t reference_age; |
- int64_t next_reference_change_target_time; |
- const LinearTransform* reference_trans = nullptr; |
- if (reference_pending_changes_.size()) { |
- if (current_transform_.DoReverseTransform( |
- reference_pending_changes_.front().b_zero, |
- &next_reference_change_target_time)) { |
- if (target_now >= next_reference_change_target_time) { |
- reference_age = target_now - next_reference_change_target_time; |
- reference_trans = &reference_pending_changes_.front(); |
- } |
- } |
- } |
- |
- if (target_trans && (!reference_trans || (reference_age <= target_age))) { |
- // If we have a target scheduled transform which should be applied, and we |
- // either have no reference scheduled transform which should be applied, |
- // or we have a reference scheduled transform which should be applied |
- // after the pending target scheduled transform, go ahead and apply the |
- // target transform. |
- // |
- // Note: if we cannot apply this transformation due to overflow, we have a |
- // serious problem. For now, we just purge the scheduled transformation |
- // and move on, but this is something which should never happen. We |
- // should probably signal an error up to the user somehow. |
- int64_t next_target_change_reference_time; |
- |
- if (current_transform_.DoForwardTransform( |
- target_trans->a_zero, |
- &next_target_change_reference_time)) { |
- current_transform_.a_zero = target_trans->a_zero; |
- current_transform_.b_zero = next_target_change_reference_time; |
- current_transform_.scale.numerator = target_trans->scale.numerator; |
- current_transform_.scale.denominator = target_trans->scale.denominator; |
- DCHECK(current_transform_.scale.denominator); |
- } |
- |
- advance_generation = true; |
- target_pending_changes_.pop_front(); |
- } else if (reference_trans) { |
- // We have a reference scheduled transformation which should be applied |
- // before any pending target scheduled transformation. Do so now. No |
- // need to compute the splice point for the function, we have already done |
- // so when determining if we should apply this transformation or not. |
- current_transform_.a_zero = next_reference_change_target_time; |
- current_transform_.b_zero = reference_trans->a_zero; |
- current_transform_.scale.numerator = reference_trans->scale.numerator; |
- current_transform_.scale.denominator = reference_trans->scale.denominator; |
- DCHECK(current_transform_.scale.denominator); |
- |
- advance_generation = true; |
- reference_pending_changes_.pop_front(); |
- } else { |
- // We have no transformations which need to be applied at the moment. We |
- // are done for now. |
- break; |
- } |
- } while (true); |
- |
- // If we have applied any changes, advance the transformation generation |
- if (advance_generation) { |
- AdvanceGenerationLocked(); |
- } |
-} |
- |
-void RateControlBase::OnIllegalRateChange(uint32_t numerator, |
- uint32_t denominator) { |
- LOG(ERROR) << "Illegal rate change requested (" |
- << numerator << "/" << denominator << ")"; |
- Reset(); |
-} |
- |
-void RateControlBase::Reset() { |
- CancelPendingChanges(); |
- SetRate(0, 1); |
- |
- if (binding_.is_bound()) { |
- binding_.set_connection_error_handler(mojo::Closure()); |
- binding_.Close(); |
- } |
-} |
- |
-} // namespace media |
-} // namespace mojo |