[M108 Migration][VD] Avoid pending frame counter becoming negative
[platform/framework/web/chromium-efl.git] / cc / metrics / video_playback_roughness_reporter.h
1 // Copyright 2020 The Chromium Authors
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 CC_METRICS_VIDEO_PLAYBACK_ROUGHNESS_REPORTER_H_
6 #define CC_METRICS_VIDEO_PLAYBACK_ROUGHNESS_REPORTER_H_
7
8 #include "base/callback.h"
9 #include "base/containers/circular_deque.h"
10 #include "base/containers/flat_set.h"
11 #include "base/time/time.h"
12 #include "cc/cc_export.h"
13 #include "media/base/video_frame.h"
14 #include "media/base/video_types.h"
15 #include "third_party/abseil-cpp/absl/types/optional.h"
16 #include "ui/gfx/geometry/size.h"
17
18 namespace cc {
19
20 // This class tracks moments when each frame was submitted
21 // and when it was displayed. Then series of frames split into groups
22 // of consecutive frames, where each group takes about one second of playback.
23 // Such groups also called 'frame windows'. Each windows is assigned a roughness
24 // score that measures how far playback smoothness was from the ideal playback.
25 //
26 // Information about several windows and their roughness score is aggregated
27 // for a couple of playback minutes ("measurement interval") and then a window
28 // with 95-percentile-max-roughness is reported via the provided callback.
29 //
30 // This sufficiently bad roughness window is deemed to represent overall
31 // playback quality.
32 class CC_EXPORT VideoPlaybackRoughnessReporter {
33  public:
34   struct Measurement {
35     // 95%-worst window measurements ========
36     // These are taken from the |kPercentileToSubmit| worst window in a
37     // measurement interval.
38
39     // |frames| - number of video frames in the window
40     int frames = 0;
41
42     // |duration| - intended wallclock duration of the window (~1s)
43     base::TimeDelta duration;
44
45     // |roughness| - roughness of the window
46     double roughness = 0;
47
48     // Per-measurement interval measurements ========
49     // These are measured over all windows in the measurement interval, without
50     // regard to which window was chosen above.
51
52     // |frame_size| - size of the video frames in the window
53     gfx::Size frame_size;
54
55     // |freezing| maximum amount of time that any VideoFrame in measurement
56     // interval was on-screen beyond the amount of time it should have been.
57     //
58     // TODO(liberato): Should this be expressed in terms of the playback rate?
59     // As in, "twice as long as it should have been"?
60     base::TimeDelta freezing;
61
62     // |refresh_rate_hz| - display refresh rate, usually 60Hz
63     int refresh_rate_hz = 0;
64   };
65
66   // Callback to report video playback roughness on a particularly bumpy
67   // interval.
68   using ReportingCallback = base::RepeatingCallback<void(const Measurement&)>;
69
70   using TokenType = uint32_t;
71   explicit VideoPlaybackRoughnessReporter(ReportingCallback reporting_cb);
72   VideoPlaybackRoughnessReporter(const VideoPlaybackRoughnessReporter&) =
73       delete;
74   VideoPlaybackRoughnessReporter& operator=(
75       const VideoPlaybackRoughnessReporter&) = delete;
76   ~VideoPlaybackRoughnessReporter();
77   void FrameSubmitted(TokenType token,
78                       const media::VideoFrame& frame,
79                       base::TimeDelta render_interval);
80   void FramePresented(TokenType token,
81                       base::TimeTicks timestamp,
82                       bool reliable_timestamp);
83   void ProcessFrameWindow();
84   void Reset();
85
86   // A lower bund on how many frames can be in ConsecutiveFramesWindow
87   static constexpr int kMinWindowSize = 6;
88
89   // An upper bund on how many frames can be in ConsecutiveFramesWindow
90   static constexpr int kMaxWindowSize = 60;
91
92   // How many frame windows should be observed before reporting smoothness
93   // due to playback time.
94   // 1 second per window, 100 windows. It means smoothness will be reported
95   // for every 100 seconds of playback.
96   static constexpr int kMaxWindowsBeforeSubmit = 100;
97
98   // How many frame windows should be observed to report soothness on last
99   // time before the destruction of the reporter.
100   static constexpr int kMinWindowsBeforeSubmit = kMaxWindowsBeforeSubmit / 5;
101
102   // A frame window with this percentile of playback roughness gets reported.
103   // Lower value means more tolerance to rough playback stretches.
104   static constexpr int kPercentileToSubmit = 95;
105   static_assert(kPercentileToSubmit > 0 && kPercentileToSubmit < 100,
106                 "invalid percentile value");
107
108  private:
109   friend class VideoPlaybackRoughnessReporterTest;
110   struct FrameInfo {
111     FrameInfo();
112     FrameInfo(const FrameInfo&);
113     TokenType token = 0;
114     absl::optional<base::TimeTicks> decode_time;
115     absl::optional<base::TimeTicks> presentation_time;
116     absl::optional<base::TimeDelta> actual_duration;
117     absl::optional<base::TimeDelta> intended_duration;
118     int refresh_rate_hz = 60;
119     gfx::Size size;
120   };
121
122   struct ConsecutiveFramesWindow {
123     int size;
124     base::TimeTicks first_frame_time;
125     base::TimeDelta intended_duration;
126     int refresh_rate_hz = 60;
127     gfx::Size frame_size;
128
129     // Root-mean-square error of the differences between the intended
130     // duration and the actual duration, calculated for all subwindows
131     // starting at the beginning of the smoothness window
132     // [1-2][1-3][1-4] ... [1-N].
133     base::TimeDelta root_mean_square_error;
134
135     double roughness() const;
136
137     bool operator<(const ConsecutiveFramesWindow& rhs) const {
138       double r1 = roughness();
139       double r2 = rhs.roughness();
140       if (r1 == r2) {
141         // If roughnesses are equal use window start time as a tie breaker.
142         // We don't want |flat_set worst_windows_| to dedup windows with
143         // the same roughness.
144         return first_frame_time > rhs.first_frame_time;
145       }
146
147       // Reverse sorting order to make sure that better windows go at the
148       // end of |worst_windows_| set. This way it's cheaper to remove them.
149       return r1 > r2;
150     }
151   };
152
153   void ReportWindow(const ConsecutiveFramesWindow& win);
154   void SubmitPlaybackRoughness();
155
156   base::circular_deque<FrameInfo> frames_;
157   base::flat_set<ConsecutiveFramesWindow> worst_windows_;
158   ReportingCallback reporting_cb_;
159   int windows_seen_ = 0;
160   int frames_window_size_ = kMinWindowSize;
161
162   // Worst case difference between a frame's intended duration and
163   // actual duration, calculated for all frames in the reporting interval.
164   base::TimeDelta max_single_frame_error_;
165 };
166
167 }  // namespace cc
168
169 #endif  // CC_METRICS_VIDEO_PLAYBACK_ROUGHNESS_REPORTER_H_