Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1157)

Unified Diff: media/filters/video_cadence_estimator.cc

Issue 1125893002: Implement support for 2-pattern cadence. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Fix comments. Created 5 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « media/filters/video_cadence_estimator.h ('k') | media/filters/video_cadence_estimator_unittest.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: media/filters/video_cadence_estimator.cc
diff --git a/media/filters/video_cadence_estimator.cc b/media/filters/video_cadence_estimator.cc
index 54146598459b196dd63f3a89d633bdad0747c43d..a328abd491a634d9b0d79efa462e8ac68758e670 100644
--- a/media/filters/video_cadence_estimator.cc
+++ b/media/filters/video_cadence_estimator.cc
@@ -5,7 +5,9 @@
#include "media/filters/video_cadence_estimator.h"
#include <algorithm>
+#include <iterator>
#include <limits>
+#include <string>
#include "base/metrics/histogram_macros.h"
@@ -24,10 +26,10 @@ static void HistogramCadenceChangeCount(int cadence_changes) {
}
VideoCadenceEstimator::VideoCadenceEstimator(
- base::TimeDelta minimum_time_until_glitch)
+ base::TimeDelta minimum_time_until_max_drift)
: cadence_hysteresis_threshold_(
base::TimeDelta::FromMilliseconds(kMinimumCadenceDurationMs)),
- minimum_time_until_glitch_(minimum_time_until_glitch) {
+ minimum_time_until_max_drift_(minimum_time_until_max_drift) {
Reset();
}
@@ -35,8 +37,8 @@ VideoCadenceEstimator::~VideoCadenceEstimator() {
}
void VideoCadenceEstimator::Reset() {
- cadence_ = fractional_cadence_ = 0;
- pending_cadence_ = pending_fractional_cadence_ = 0;
+ cadence_.clear();
+ pending_cadence_.clear();
cadence_changes_ = render_intervals_cadence_held_ = 0;
first_update_call_ = true;
}
@@ -48,21 +50,12 @@ bool VideoCadenceEstimator::UpdateCadenceEstimate(
DCHECK_GT(render_interval, base::TimeDelta());
DCHECK_GT(frame_duration, base::TimeDelta());
- base::TimeDelta time_until_cadence_glitch;
- base::TimeDelta time_until_fractional_cadence_glitch;
-
- // See if the clamped cadence fits acceptable thresholds for exhausting drift.
- int new_cadence = 0, new_fractional_cadence = 0;
- if (CalculateCadence(render_interval, frame_duration, max_acceptable_drift,
- false, &new_cadence, &time_until_cadence_glitch)) {
- DCHECK(new_cadence);
- } else if (CalculateCadence(render_interval, frame_duration,
- max_acceptable_drift, true,
- &new_fractional_cadence,
- &time_until_fractional_cadence_glitch)) {
- new_cadence = 1;
- DCHECK(new_fractional_cadence);
- }
+ base::TimeDelta time_until_max_drift;
+
+ // See if we can find a cadence which fits the data.
+ Cadence new_cadence =
+ CalculateCadence(render_interval, frame_duration, max_acceptable_drift,
+ &time_until_max_drift);
// If this is the first time UpdateCadenceEstimate() has been called,
// initialize the histogram with a zero count for cadence changes; this
@@ -73,9 +66,8 @@ bool VideoCadenceEstimator::UpdateCadenceEstimate(
HistogramCadenceChangeCount(0);
}
- // Nothing changed, so do nothing.
- if (new_cadence == cadence_ &&
- new_fractional_cadence == fractional_cadence_) {
+ // If nothing changed, do nothing.
+ if (new_cadence == cadence_) {
// Clear cadence hold to pending values from accumulating incorrectly.
render_intervals_cadence_held_ = 0;
return false;
@@ -84,18 +76,14 @@ bool VideoCadenceEstimator::UpdateCadenceEstimate(
// Wait until enough render intervals have elapsed before accepting the
// cadence change. Prevents oscillation of the cadence selection.
bool update_pending_cadence = true;
- if ((new_cadence == pending_cadence_ &&
- new_fractional_cadence == pending_fractional_cadence_) ||
+ if (new_cadence == pending_cadence_ ||
cadence_hysteresis_threshold_ <= render_interval) {
if (++render_intervals_cadence_held_ * render_interval >=
cadence_hysteresis_threshold_) {
- DVLOG(1) << "Cadence switch: (" << cadence_ << ", " << fractional_cadence_
- << ") -> (" << new_cadence << ", " << new_fractional_cadence
- << ") :: (" << time_until_cadence_glitch << ", "
- << time_until_fractional_cadence_glitch << ")";
-
- cadence_ = new_cadence;
- fractional_cadence_ = new_fractional_cadence;
+ DVLOG(1) << "Cadence switch: " << CadenceToString(cadence_) << " -> "
+ << CadenceToString(new_cadence)
+ << " :: Time until drift exceeded: " << time_until_max_drift;
+ cadence_.swap(new_cadence);
// Note: Because this class is transitively owned by a garbage collected
// object, WebMediaPlayer, we log cadence changes as they are encountered.
@@ -106,86 +94,161 @@ bool VideoCadenceEstimator::UpdateCadenceEstimate(
update_pending_cadence = false;
}
- DVLOG(2) << "Hysteresis prevented cadence switch: (" << cadence_ << ", "
- << fractional_cadence_ << ") -> (" << new_cadence << ", "
- << new_fractional_cadence << ") :: (" << time_until_cadence_glitch
- << ", " << time_until_fractional_cadence_glitch << ")";
+ DVLOG(2) << "Hysteresis prevented cadence switch: "
+ << CadenceToString(cadence_) << " -> "
+ << CadenceToString(new_cadence);
if (update_pending_cadence) {
- pending_cadence_ = new_cadence;
- pending_fractional_cadence_ = new_fractional_cadence;
+ pending_cadence_.swap(new_cadence);
render_intervals_cadence_held_ = 1;
}
return false;
}
-bool VideoCadenceEstimator::CalculateCadence(
+int VideoCadenceEstimator::GetCadenceForFrame(uint64_t frame_number) const {
+ DCHECK(has_cadence());
+ return cadence_[frame_number % cadence_.size()];
+}
+
+VideoCadenceEstimator::Cadence VideoCadenceEstimator::CalculateCadence(
+ base::TimeDelta render_interval,
+ base::TimeDelta frame_duration,
+ base::TimeDelta max_acceptable_drift,
+ base::TimeDelta* time_until_max_drift) const {
+ // See if we can find a cadence which fits the data.
+ Cadence result;
+ if (CalculateOneFrameCadence(render_interval, frame_duration,
+ max_acceptable_drift, &result,
+ time_until_max_drift)) {
+ DCHECK_EQ(1u, result.size());
+ } else if (CalculateFractionalCadence(render_interval, frame_duration,
+ max_acceptable_drift, &result,
+ time_until_max_drift)) {
+ DCHECK(!result.empty());
+ } else if (CalculateOneFrameCadence(render_interval, frame_duration * 2,
+ max_acceptable_drift, &result,
+ time_until_max_drift)) {
+ // By finding cadence for double the frame duration, we're saying there
+ // exist two integers a and b, where a > b and a + b = |result|; this
+ // matches all patterns which regularly have half a frame per render
+ // interval; i.e. 24fps in 60hz.
+ DCHECK_EQ(1u, result.size());
+
+ // Two pattern cadence is always an odd number.
+ DCHECK(result[0] & 1);
+
+ result[0] = std::ceil(result[0] / 2.0);
+ result.push_back(result[0] - 1);
+ }
+ return result;
+}
+
+bool VideoCadenceEstimator::CalculateOneFrameCadence(
base::TimeDelta render_interval,
base::TimeDelta frame_duration,
base::TimeDelta max_acceptable_drift,
- bool fractional,
- int* cadence,
- base::TimeDelta* time_until_glitch) {
+ Cadence* cadence,
+ base::TimeDelta* time_until_max_drift) const {
+ DCHECK(cadence->empty());
+
// The perfect cadence is the number of render intervals per frame, while the
- // clamped cadence is the nearest matching integer cadence.
- //
- // Fractional cadence is checked to see if we have a cadence which would look
- // best if we consistently drop the same frames.
+ // clamped cadence is the nearest matching integer value.
//
// As mentioned in the introduction, |perfect_cadence| is the ratio of the
// frame duration to render interval length; while |clamped_cadence| is the
- // nearest integer value to |perfect_cadence|. When computing a fractional
- // cadence (1/|perfect_cadence|), |fractional| must be set to true to ensure
- // the rendered and actual frame durations are computed correctly.
+ // nearest integer value to |perfect_cadence|.
const double perfect_cadence =
- fractional ? render_interval.InSecondsF() / frame_duration.InSecondsF()
- : frame_duration.InSecondsF() / render_interval.InSecondsF();
+ frame_duration.InSecondsF() / render_interval.InSecondsF();
const int clamped_cadence = perfect_cadence + 0.5;
if (!clamped_cadence)
return false;
- // Calculate the drift in microseconds for each frame we render at cadence
- // instead of for its real duration.
+ // For cadence based rendering the actual frame duration is just the frame
+ // duration, while the |rendered_frame_duration| is how long the frame would
+ // be displayed for if we rendered it |clamped_cadence| times.
const base::TimeDelta rendered_frame_duration =
- fractional ? render_interval : clamped_cadence * render_interval;
+ clamped_cadence * render_interval;
+ if (!IsAcceptableCadence(rendered_frame_duration, frame_duration,
+ max_acceptable_drift, time_until_max_drift)) {
+ return false;
+ }
+
+ cadence->push_back(clamped_cadence);
+ return true;
+}
+
+bool VideoCadenceEstimator::CalculateFractionalCadence(
+ base::TimeDelta render_interval,
+ base::TimeDelta frame_duration,
+ base::TimeDelta max_acceptable_drift,
+ Cadence* cadence,
+ base::TimeDelta* time_until_max_drift) const {
+ DCHECK(cadence->empty());
+
+ // Fractional cadence allows us to see if we have a cadence which would look
+ // best if we consistently drop the same frames.
+ //
+ // In this case, the perfect cadence is the number of frames per render
+ // interval, while the clamped cadence is the nearest integer value.
+ const double perfect_cadence =
+ render_interval.InSecondsF() / frame_duration.InSecondsF();
+ const int clamped_cadence = perfect_cadence + 0.5;
+ if (!clamped_cadence)
+ return false;
- // When computing a fractional drift, we render the first of |clamped_cadence|
- // frames and drop |clamped_cadence| - 1 frames. To make the calculations
- // below work we need to project out the timestamp of the frame which would be
- // rendered after accounting for those |clamped_cadence| frames.
+ // For fractional cadence, the rendered duration of each frame is just the
+ // render interval. While the actual frame duration is the total duration of
+ // all the frames we would end up dropping during that time.
const base::TimeDelta actual_frame_duration =
- fractional ? clamped_cadence * frame_duration : frame_duration;
- if (rendered_frame_duration == actual_frame_duration) {
- *cadence = clamped_cadence;
- return true;
+ clamped_cadence * frame_duration;
+ if (!IsAcceptableCadence(render_interval, actual_frame_duration,
+ max_acceptable_drift, time_until_max_drift)) {
+ return false;
}
- // Compute how long it'll take to exhaust the drift using |clamped_cadence|.
+ // Fractional cadence means we render the first of |clamped_cadence| frames
+ // and drop |clamped_cadence| - 1 frames.
+ cadence->insert(cadence->begin(), clamped_cadence, 0);
+ (*cadence)[0] = 1;
+ return true;
+}
+
+std::string VideoCadenceEstimator::CadenceToString(
+ const Cadence& cadence) const {
+ if (cadence.empty())
+ return std::string("[]");
+
+ std::ostringstream os;
+ os << "[";
+ std::copy(cadence.begin(), cadence.end() - 1,
+ std::ostream_iterator<int>(os, ":"));
+ os << cadence.back() << "]";
+ return os.str();
+}
+
+bool VideoCadenceEstimator::IsAcceptableCadence(
+ base::TimeDelta rendered_frame_duration,
+ base::TimeDelta actual_frame_duration,
+ base::TimeDelta max_acceptable_drift,
+ base::TimeDelta* time_until_max_drift) const {
+ if (rendered_frame_duration == actual_frame_duration)
+ return true;
+
+ // Compute how long it'll take to exhaust the drift if frames are rendered for
+ // |rendered_frame_duration| instead of |actual_frame_duration|.
const double duration_delta =
(rendered_frame_duration - actual_frame_duration)
.magnitude()
.InMicroseconds();
const int64 frames_until_drift_exhausted =
std::ceil(max_acceptable_drift.InMicroseconds() / duration_delta);
- *time_until_glitch = rendered_frame_duration * frames_until_drift_exhausted;
-
- if (*time_until_glitch >= minimum_time_until_glitch_) {
- *cadence = clamped_cadence;
- return true;
- }
-
- return false;
-}
-
-int VideoCadenceEstimator::GetCadenceForFrame(int index) const {
- DCHECK(has_cadence());
- DCHECK_GE(index, 0);
-
- if (fractional_cadence_)
- return index % fractional_cadence_ == 0 ? 1 : 0;
- return cadence_;
+ // If the time until a frame would be repeated or dropped is greater than our
+ // limit of acceptability, the cadence is acceptable.
+ *time_until_max_drift =
+ rendered_frame_duration * frames_until_drift_exhausted;
+ return *time_until_max_drift >= minimum_time_until_max_drift_;
}
} // namespace media
« no previous file with comments | « media/filters/video_cadence_estimator.h ('k') | media/filters/video_cadence_estimator_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698