Return linux_android_rel_ng to the CQ.
[chromium-blink-merge.git] / media / filters / video_renderer_algorithm.h
blob71d251f416a667e9515afb779d776bdbbffba12d
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.
5 #ifndef MEDIA_FILTERS_VIDEO_RENDERER_ALGORITHM_H_
6 #define MEDIA_FILTERS_VIDEO_RENDERER_ALGORITHM_H_
8 #include <deque>
10 #include "base/callback.h"
11 #include "base/memory/ref_counted.h"
12 #include "base/time/time.h"
13 #include "media/base/media_export.h"
14 #include "media/base/moving_average.h"
15 #include "media/base/video_frame.h"
16 #include "media/base/video_renderer.h"
17 #include "media/filters/video_cadence_estimator.h"
19 namespace media {
21 // VideoRendererAlgorithm manages a queue of VideoFrames from which it chooses
22 // frames with the goal of providing a smooth playback experience. I.e., the
23 // selection process results in the best possible uniformity for displayed frame
24 // durations over time.
26 // Clients will provide frames to VRA via EnqueueFrame() and then VRA will yield
27 // one of those frames in response to a future Render() call. Each Render()
28 // call takes a render interval which is used to compute the best frame for
29 // display during that interval.
31 // Render() calls are expected to happen on a regular basis. Failure to do so
32 // will result in suboptimal rendering experiences. If a client knows that
33 // Render() callbacks are stalled for any reason, it should tell VRA to expire
34 // frames which are unusable via RemoveExpiredFrames(); this prevents useless
35 // accumulation of stale VideoFrame objects (which are frequently quite large).
37 // The primary means of smooth frame selection is via forced integer cadence,
38 // see VideoCadenceEstimator for details on this process. In cases of non-
39 // integer cadence, the algorithm will fall back to choosing the frame which
40 // covers the most of the current render interval. If no frame covers the
41 // current interval, the least bad frame will be chosen based on its drift from
42 // the start of the interval.
44 // Combined these three approaches enforce optimal smoothness in many cases.
45 class MEDIA_EXPORT VideoRendererAlgorithm {
46 public:
47 explicit VideoRendererAlgorithm(
48 const TimeSource::WallClockTimeCB& wall_clock_time_cb);
49 ~VideoRendererAlgorithm();
51 // Chooses the best frame for the interval [deadline_min, deadline_max] based
52 // on available and previously rendered frames.
54 // Under ideal circumstances the deadline interval provided to a Render() call
55 // should be directly adjacent to the deadline given to the previous Render()
56 // call with no overlap or gaps. In practice, |deadline_max| is an estimated
57 // value, which means the next |deadline_min| may overlap it slightly or have
58 // a slight gap. Gaps which exceed the length of the deadline interval are
59 // assumed to be repeated frames for the purposes of cadence detection.
61 // If provided, |frames_dropped| will be set to the number of frames which
62 // were removed from |frame_queue_|, during this call, which were never
63 // returned during a previous Render() call and are no longer suitable for
64 // rendering since their wall clock time is too far in the past.
65 scoped_refptr<VideoFrame> Render(base::TimeTicks deadline_min,
66 base::TimeTicks deadline_max,
67 size_t* frames_dropped);
69 // Removes all video frames which are unusable since their ideal render
70 // interval [timestamp, timestamp + duration] is too far away from
71 // |deadline_min| than is allowed by drift constraints.
73 // At least one frame will always remain after this call so that subsequent
74 // Render() calls have a frame to return if no new frames are enqueued before
75 // then. Returns the number of frames removed.
77 // Note: In cases where there is no known frame duration (i.e. perhaps a video
78 // with only a single frame), the last frame can not be expired, regardless of
79 // the given deadline. Clients must handle this case externally.
80 size_t RemoveExpiredFrames(base::TimeTicks deadline);
82 // Clients should call this if the last frame provided by Render() was never
83 // rendered; it ensures the presented cadence matches internal models. This
84 // must be called before the next Render() call.
85 void OnLastFrameDropped();
87 // Adds a frame to |frame_queue_| for consideration by Render(). Out of order
88 // timestamps will be sorted into appropriate order. Do not enqueue end of
89 // stream frames. Frames inserted prior to the last rendered frame will not
90 // be used. They will be discarded on the next call to Render(), counting as
91 // dropped frames, or by RemoveExpiredFrames(), counting as expired frames.
93 // Attempting to enqueue a frame with the same timestamp as a previous frame
94 // will result in the previous frame being replaced if it has not been
95 // rendered yet. If it has been rendered, the new frame will be dropped.
96 void EnqueueFrame(const scoped_refptr<VideoFrame>& frame);
98 // Removes all frames from the |frame_queue_| and clears predictors. The
99 // algorithm will be as if freshly constructed after this call.
100 void Reset();
102 // Returns the number of frames currently buffered which could be rendered
103 // assuming current Render() interval trends. Before Render() is called, this
104 // will be the same as the number of frames given to EnqueueFrame(). After
105 // Render() has been called, one of two things will be returned:
107 // If a cadence has been identified, this will return the number of frames
108 // which have a non-zero ideal render count.
110 // If cadence has not been identified, this will return the number of frames
111 // which have a frame end time greater than the end of the last render
112 // interval passed to Render(). Note: If Render() callbacks become suspended
113 // and the duration is unknown the last frame may never be stop counting as
114 // effective. Clients must handle this case externally.
116 // In either case, frames enqueued before the last displayed frame will not
117 // be counted as effective.
118 size_t EffectiveFramesQueued() const;
120 // Tells the algorithm that Render() callbacks have been suspended for a known
121 // reason and such stoppage shouldn't be counted against future frames.
122 void set_time_stopped() { was_time_moving_ = false; }
124 size_t frames_queued() const { return frame_queue_.size(); }
126 // Returns the average of the duration of all frames in |frame_queue_|
127 // as measured in wall clock (not media) time.
128 base::TimeDelta average_frame_duration() const {
129 return average_frame_duration_;
132 // Method used for testing which disables frame dropping, in this mode the
133 // algorithm will never drop frames and instead always return every frame
134 // for display at least once.
135 void disable_frame_dropping() { frame_dropping_disabled_ = true; }
137 private:
138 friend class VideoRendererAlgorithmTest;
140 // The determination of whether to clamp to a given cadence is based on the
141 // number of seconds before a frame would have to be dropped or repeated to
142 // compensate for reaching the maximum acceptable drift.
144 // We've chosen 8 seconds based on practical observations and the fact that it
145 // allows 29.9fps and 59.94fps in 60Hz and vice versa.
147 // Most users will not be able to see a single frame repeated or dropped every
148 // 8 seconds and certainly should notice it less than the randomly variable
149 // frame durations.
150 static const int kMinimumAcceptableTimeBetweenGlitchesSecs = 8;
152 // Metadata container for enqueued frames. See |frame_queue_| below.
153 struct ReadyFrame {
154 ReadyFrame(const scoped_refptr<VideoFrame>& frame);
155 ~ReadyFrame();
157 // For use with std::lower_bound.
158 bool operator<(const ReadyFrame& other) const;
160 scoped_refptr<VideoFrame> frame;
162 // |start_time| is only available after UpdateFrameStatistics() has been
163 // called and |end_time| only after we have more than one frame.
164 base::TimeTicks start_time;
165 base::TimeTicks end_time;
167 // True if this frame's end time is based on the average frame duration and
168 // not the time of the next frame.
169 bool has_estimated_end_time;
171 int ideal_render_count;
172 int render_count;
173 int drop_count;
176 // Updates the render count for the last rendered frame based on the number
177 // of missing intervals between Render() calls.
178 void AccountForMissedIntervals(base::TimeTicks deadline_min,
179 base::TimeTicks deadline_max);
181 // Updates the render count and wall clock timestamps for all frames in
182 // |frame_queue_|. Updates |was_time_stopped_|, |cadence_estimator_| and
183 // |frame_duration_calculator_|.
185 // Note: Wall clock time is recomputed each Render() call because it's
186 // expected that the TimeSource powering TimeSource::WallClockTimeCB will skew
187 // slightly based on the audio clock.
189 // TODO(dalecurtis): Investigate how accurate we need the wall clock times to
190 // be, so we can avoid recomputing every time (we would need to recompute when
191 // playback rate changes occur though).
192 void UpdateFrameStatistics();
194 // Updates the ideal render count for all frames in |frame_queue_| based on
195 // the cadence returned by |cadence_estimator_|. Cadence is assigned based
196 // on |frame_counter_|.
197 void UpdateCadenceForFrames();
199 // If |cadence_estimator_| has detected a valid cadence, attempts to find the
200 // next frame which should be rendered. Returns -1 if not enough frames are
201 // available for cadence selection or there is no cadence.
203 // Returns the number of times a prior frame was over displayed and ate into
204 // the returned frames ideal render count via |remaining_overage|.
206 // For example, if we have 2 frames and each has an ideal display count of 3,
207 // but the first was displayed 4 times, the best frame is the second one, but
208 // it should only be displayed twice instead of thrice, so it's overage is 1.
209 int FindBestFrameByCadence(int* remaining_overage) const;
211 // Iterates over |frame_queue_| and finds the frame which covers the most of
212 // the deadline interval. If multiple frames have coverage of the interval,
213 // |second_best| will be set to the index of the frame with the next highest
214 // coverage. Returns -1 if no frame has any coverage of the current interval.
216 // Prefers the earliest frame if multiple frames have similar coverage (within
217 // a few percent of each other).
218 int FindBestFrameByCoverage(base::TimeTicks deadline_min,
219 base::TimeTicks deadline_max,
220 int* second_best) const;
222 // Iterates over |frame_queue_| and find the frame which drifts the least from
223 // |deadline_min|. There's always a best frame by drift, so the return value
224 // is always a valid frame index. |selected_frame_drift| will be set to the
225 // drift of the chosen frame.
227 // Note: Drift calculations assume contiguous frames in the time domain, so
228 // it's not possible to have a case where a frame is -10ms from |deadline_min|
229 // and another frame which is at some time after |deadline_min|. The second
230 // frame would be considered to start at -10ms before |deadline_min| and would
231 // overlap |deadline_min|, so its drift would be zero.
232 int FindBestFrameByDrift(base::TimeTicks deadline_min,
233 base::TimeDelta* selected_frame_drift) const;
235 // Calculates the drift from |deadline_min| for the given |frame_index|. If
236 // the [start_time, end_time] lies before |deadline_min| the drift is
237 // the delta between |deadline_min| and |end_time|. If the frame
238 // overlaps |deadline_min| the drift is zero. If the frame lies after
239 // |deadline_min| the drift is the delta between |deadline_min| and
240 // |start_time|.
241 base::TimeDelta CalculateAbsoluteDriftForFrame(base::TimeTicks deadline_min,
242 int frame_index) const;
244 // Queue of incoming frames waiting for rendering.
245 using VideoFrameQueue = std::deque<ReadyFrame>;
246 VideoFrameQueue frame_queue_;
248 // The index of the last frame rendered; presumed to be the first frame if no
249 // frame has been rendered yet. Updated by Render() and EnqueueFrame() if any
250 // frames are added or removed.
252 // In most cases this value is zero, but when out of order timestamps are
253 // present, the last rendered frame may be moved.
254 size_t last_frame_index_;
256 // Handles cadence detection and frame cadence assignments.
257 VideoCadenceEstimator cadence_estimator_;
259 // Indicates if any calls to Render() have successfully yielded a frame yet.
260 bool have_rendered_frames_;
262 // Callback used to convert media timestamps into wall clock timestamps.
263 const TimeSource::WallClockTimeCB wall_clock_time_cb_;
265 // The last |deadline_max| provided to Render(), used to predict whether
266 // frames were rendered over cadence between Render() calls.
267 base::TimeTicks last_deadline_max_;
269 // The average of the duration of all frames in |frame_queue_| as measured in
270 // wall clock (not media) time at the time of the last Render().
271 MovingAverage frame_duration_calculator_;
272 base::TimeDelta average_frame_duration_;
274 // The length of the last deadline interval given to Render(), updated at the
275 // start of Render().
276 base::TimeDelta render_interval_;
278 // The maximum acceptable drift before a frame can no longer be considered for
279 // rendering within a given interval.
280 base::TimeDelta max_acceptable_drift_;
282 // Indicates that the last call to Render() experienced a rendering glitch; it
283 // may have: under-rendered a frame, over-rendered a frame, dropped one or
284 // more frames, or chosen a frame which exceeded acceptable drift.
285 bool last_render_had_glitch_;
287 // For testing functionality which enables clockless playback of all frames,
288 // does not prevent frame dropping due to equivalent timestamps.
289 bool frame_dropping_disabled_;
291 // Tracks frames dropped during enqueue when identical timestamps are added
292 // to the queue. Callers are told about these frames during Render().
293 size_t frames_dropped_during_enqueue_;
295 // When cadence is present, we don't want to start counting against cadence
296 // until the first frame has reached its presentation time.
297 bool first_frame_;
299 // The frame number of the last rendered frame; incremented for every frame
300 // rendered and every frame dropped or expired since the last rendered frame.
302 // Given to |cadence_estimator_| when assigning cadence values to the
303 // ReadyFrameQueue. Cleared when a new cadence is detected.
304 uint64_t cadence_frame_counter_;
306 // Tracks whether the last call to Render() choose to ignore the frame chosen
307 // by cadence in favor of one by drift or coverage.
308 bool last_render_ignored_cadence_frame_;
310 // Indicates if time was moving, set to the return value from
311 // UpdateFrameStatistics() during Render() or externally by
312 // set_time_stopped().
313 bool was_time_moving_;
315 DISALLOW_COPY_AND_ASSIGN(VideoRendererAlgorithm);
318 } // namespace media
320 #endif // MEDIA_FILTERS_VIDEO_RENDERER_ALGORITHM_H_