Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 1 // Copyright 2015 The Chromium Authors. All rights reserved. | |
| 2 // Use of this source code is governed by a BSD-style license that can be | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 #ifndef MEDIA_FILTERS_VIDEO_CADENCE_ESTIMATOR_H_ | |
| 6 #define MEDIA_FILTERS_VIDEO_CADENCE_ESTIMATOR_H_ | |
| 7 | |
| 8 #include "base/time/time.h" | |
| 9 #include "media/base/media_export.h" | |
| 10 | |
| 11 namespace media { | |
| 12 | |
| 13 // Estimates whether a given frame duration and render interval length have a | |
| 14 // render cadence which would allow for optimal uniformity of displayed frame | |
| 15 // durations over time. | |
| 16 // | |
| 17 // Cadence is the ratio of the frame duration to render interval length. I.e. | |
| 18 // for 30fps in 60Hz the cadence would be (1/30) / (1/60) = 60 / 30 = 2. It's | |
| 19 // common that this is not an exact integer, e.g., 29.974fps in 60Hz which | |
| 20 // would have a cadence of (1/29.974) / (1/60) = ~2.0029. | |
| 21 // | |
| 22 // Forced integer cadence means we round the actual cadence (~2.0029 in the | |
|
xhwang
2015/04/28 16:01:08
nit: s/Forced/Clamped?
DaleCurtis
2015/04/28 21:45:24
Done.
| |
| 23 // previous example) to the nearest integer value (2 in this case). If the | |
| 24 // delta between those values is small, we can choose to render frames for the | |
| 25 // integer number of render intervals; shortening or lengthening the actual | |
| 26 // rendered frame duration. Doing so ensures each frame gets an optimal amount | |
| 27 // of display time. | |
| 28 // | |
| 29 // Obviously forcing cadence like that leads to drift over time of the actual | |
|
xhwang
2015/04/28 16:01:08
nit: s/forcing/clamping
DaleCurtis
2015/04/28 21:45:24
Done.
| |
| 30 // VideoFrame timestamp relative to its rendered time, so we perform some | |
| 31 // calculations to ensure we only force cadence when it will take some time to | |
| 32 // drift an undesirable amount; see CalculateCadence() for details on how this | |
| 33 // calculation is made. | |
| 34 // | |
| 35 // Notably, this concept can be extended to include fractional cadence when the | |
| 36 // frame duration is shorter than the render interval; e.g. 120fps in 60Hz. In | |
| 37 // this case, the first frame in each group of N frames is displayed once, while | |
| 38 // the next N - 1 frames are dropped; where N is the fractional cadence of the | |
| 39 // frame group. Using the previous example N = 120/60 = 2. See implementations | |
| 40 // of CalculateCadence() and UpdateCadenceEstimate() for more details. | |
| 41 // | |
| 42 // In practice this works out to the following for common setups if we use | |
| 43 // cadence based selection: | |
| 44 // | |
| 45 // 29.5fps in 60Hz, ~17ms max drift => exhausted in ~1 second. | |
| 46 // 29.9fps in 60Hz, ~17ms max drift => exhausted in ~16.4 seconds. | |
| 47 // 24fps in 60Hz, ~21ms max drift => exhausted in ~0.15 seconds. | |
| 48 // 25fps in 60Hz, 20ms max drift => exhausted in ~4.0 seconds. | |
| 49 // 59.9fps in 60Hz, ~8.3ms max drift => exhausted in ~8.2 seconds. | |
| 50 // 24.9fps in 50Hz, ~20ms max drift => exhausted in ~20.5 seconds. | |
| 51 // 120fps in 59.9Hz, ~8.3ms max drift => exhausted in ~8.2 seconds. | |
| 52 // | |
| 53 class MEDIA_EXPORT VideoCadenceEstimator { | |
| 54 public: | |
| 55 // As mentioned in the introduction, the determination of whether to clamp to | |
| 56 // a given cadence is based on how long it takes before a frame would have to | |
| 57 // be dropped or repeated to compensate for reaching the maximum acceptable | |
| 58 // drift; this time length is controlled by |minimum_time_until_glitch|. | |
| 59 explicit VideoCadenceEstimator(base::TimeDelta minimum_time_until_glitch); | |
| 60 ~VideoCadenceEstimator(); | |
| 61 | |
| 62 // Clears stored cadence information. | |
| 63 void Reset(); | |
| 64 | |
| 65 // Updates the estimates for |cadence_| and |fractional_cadence_| based on the | |
| 66 // given values as described in the introduction above. | |
| 67 // | |
| 68 // Clients should call this and then update the cadence for all frames via the | |
| 69 // GetCadenceForFrame() method. | |
| 70 // | |
| 71 // Cadence changes will not take affect until enough render intervals have | |
| 72 // elapsed. For the purposes of hysteresis, each UpdateCadenceEstimate() call | |
| 73 // is assumed to elapse one |render_interval| worth of time. | |
| 74 // | |
| 75 // Returns true if the cadence has changed since the last call. | |
| 76 bool UpdateCadenceEstimate(base::TimeDelta render_interval, | |
| 77 base::TimeDelta frame_duration, | |
| 78 base::TimeDelta max_acceptable_drift); | |
| 79 | |
| 80 // Returns true if a useful cadence was found. | |
| 81 bool has_cadence() const { return cadence_ > 0; } | |
| 82 | |
| 83 // Given a frame |index|, where zero is the most recently rendered frame, | |
| 84 // returns the ideal cadence for that frame. | |
| 85 int GetCadenceForFrame(int index) const; | |
| 86 | |
| 87 void disable_cadence_hysteresis_for_testing() { | |
| 88 cadence_hysteresis_enabled_ = false; | |
| 89 } | |
| 90 | |
| 91 int get_cadence_for_testing() const { | |
|
xhwang
2015/04/28 16:01:08
When you get something like "2", how do you know w
DaleCurtis
2015/04/28 21:45:24
Tests can figure this out by calling GetCadenceFor
| |
| 92 return cadence_ && fractional_cadence_ ? fractional_cadence_ : cadence_; | |
| 93 } | |
| 94 | |
| 95 private: | |
| 96 // To prevent oscillation in and out of cadence or between cadence values, we | |
| 97 // require some time to elapse before a cadence switch is accepted. | |
| 98 static const int kMinimumCadenceDurationMs = 100; | |
| 99 | |
| 100 // Determines an ideal integer cadence for the given |render_interval| and | |
| 101 // |frame_duration|, then calculates how long that cadence can be used before | |
| 102 // exhausting |max_acceptable_drift|. If the time until exhaustion is greater | |
| 103 // than |minimum_time_until_glitch_|, returns true and sets |cadence| to the | |
| 104 // ideal integer cadence. | |
| 105 // | |
| 106 // If |fractional| is true, GetCadence() will calculate using the ratio of the | |
| 107 // |render_interval| to |frame_duration| instead of the other way around. | |
| 108 // | |
| 109 // Sets |time_until_glitch| to the computed glitch time. | |
| 110 bool CalculateCadence(base::TimeDelta render_interval, | |
| 111 base::TimeDelta frame_duration, | |
| 112 base::TimeDelta max_acceptable_drift, | |
| 113 bool fractional, | |
| 114 int* cadence, | |
| 115 base::TimeDelta* time_until_glitch); | |
| 116 | |
| 117 // The idealized cadence for all frames seen thus far; updated based upon the | |
| 118 // ratio of |frame_duration| to |render_interval|, or vice versa, as given to | |
| 119 // UpdateCadenceEstimate(). Zero if no integer cadence could be detected. | |
| 120 // | |
| 121 // Fractional cadences are handled by strongly preferring the first frame in | |
| 122 // a series if it fits within acceptable drift. E.g., with 120fps content on | |
| 123 // a 60Hz monitor we'll strongly prefer the first frame of every 2 frames. | |
| 124 // | |
| 125 // |fractional_cadence_| is the number of frames per render interval; the | |
| 126 // first of which would be rendered and the rest dropped. | |
| 127 int cadence_; | |
| 128 int fractional_cadence_; | |
| 129 | |
| 130 // Used as hysteresis to prevent oscillation between cadence and coverage | |
| 131 // based rendering methods. Previous values are updated upon each new cadence | |
| 132 // detected by UpdateCadenceEstimate(). |render_intervals_cadence_held_| is | |
| 133 // incremented for each UpdateCadenceEstimate() where the cadence remains the | |
| 134 // same. Once |kMinimumCadenceDurationMs| is exceeded in render intervals, | |
| 135 // the detected cadence is set in |cadence_| and |fractional_cadence_|. | |
| 136 int previous_cadence_; | |
| 137 int previous_fractional_cadence_; | |
| 138 int render_intervals_cadence_held_; | |
| 139 bool cadence_hysteresis_enabled_; | |
| 140 | |
| 141 // The minimum amount of time allowed before a glitch occurs before confirming | |
| 142 // cadence for a given render interval and frame duration. | |
| 143 const base::TimeDelta minimum_time_until_glitch_; | |
| 144 | |
| 145 DISALLOW_COPY_AND_ASSIGN(VideoCadenceEstimator); | |
| 146 }; | |
| 147 | |
| 148 } // namespace media | |
| 149 | |
| 150 #endif // MEDIA_FILTERS_VIDEO_CADENCE_ESTIMATOR_H_ | |
| OLD | NEW |