1 /*
2  *  Copyright (c) 2021 The WebRTC project authors. All Rights Reserved.
3  *
4  *  Use of this source code is governed by a BSD-style license
5  *  that can be found in the LICENSE file in the root of the source
6  *  tree. An additional intellectual property rights grant can be found
7  *  in the file PATENTS.  All contributing project authors may
8  *  be found in the AUTHORS file in the root of the source tree.
9  */
10 
11 #ifndef TEST_PC_E2E_ANALYZER_VIDEO_DEFAULT_VIDEO_QUALITY_ANALYZER_SHARED_OBJECTS_H_
12 #define TEST_PC_E2E_ANALYZER_VIDEO_DEFAULT_VIDEO_QUALITY_ANALYZER_SHARED_OBJECTS_H_
13 
14 #include <cstdint>
15 #include <map>
16 #include <memory>
17 #include <ostream>
18 #include <set>
19 #include <string>
20 #include <utility>
21 #include <vector>
22 
23 #include "absl/types/optional.h"
24 #include "api/numerics/samples_stats_counter.h"
25 #include "api/units/timestamp.h"
26 #include "rtc_base/strings/string_builder.h"
27 
28 namespace webrtc {
29 
30 // WebRTC will request a key frame after 3 seconds if no frames were received.
31 // We assume max frame rate ~60 fps, so 270 frames will cover max freeze without
32 // key frame request.
33 constexpr size_t kDefaultMaxFramesInFlightPerStream = 270;
34 
35 class SamplesRateCounter {
36  public:
37   void AddEvent(Timestamp event_time);
38 
IsEmpty()39   bool IsEmpty() const { return event_first_time_ == event_last_time_; }
40 
41   double GetEventsPerSecond() const;
42 
43  private:
44   Timestamp event_first_time_ = Timestamp::MinusInfinity();
45   Timestamp event_last_time_ = Timestamp::MinusInfinity();
46   int64_t events_count_ = 0;
47 };
48 
49 struct FrameCounters {
50   // Count of frames, that were passed into WebRTC pipeline by video stream
51   // source.
52   int64_t captured = 0;
53   // Count of frames that reached video encoder.
54   int64_t pre_encoded = 0;
55   // Count of encoded images that were produced by encoder for all requested
56   // spatial layers and simulcast streams.
57   int64_t encoded = 0;
58   // Count of encoded images received in decoder for all requested spatial
59   // layers and simulcast streams.
60   int64_t received = 0;
61   // Count of frames that were produced by decoder.
62   int64_t decoded = 0;
63   // Count of frames that went out from WebRTC pipeline to video sink.
64   int64_t rendered = 0;
65   // Count of frames that were dropped in any point between capturing and
66   // rendering.
67   int64_t dropped = 0;
68   // Count of frames for which decoder returned error when they were sent for
69   // decoding.
70   int64_t failed_to_decode = 0;
71 };
72 
73 // Contains information about the codec that was used for encoding or decoding
74 // the stream.
75 struct StreamCodecInfo {
76   // Codec implementation name.
77   std::string codec_name;
78   // Id of the first frame for which this codec was used.
79   uint16_t first_frame_id;
80   // Id of the last frame for which this codec was used.
81   uint16_t last_frame_id;
82   // Timestamp when the first frame was handled by the encode/decoder.
83   Timestamp switched_on_at = Timestamp::PlusInfinity();
84   // Timestamp when this codec was used last time.
85   Timestamp switched_from_at = Timestamp::PlusInfinity();
86 
87   std::string ToString() const;
88 };
89 
90 std::ostream& operator<<(std::ostream& os, const StreamCodecInfo& state);
91 rtc::StringBuilder& operator<<(rtc::StringBuilder& sb,
92                                const StreamCodecInfo& state);
93 bool operator==(const StreamCodecInfo& a, const StreamCodecInfo& b);
94 
95 // Represents phases where video frame can be dropped and such drop will be
96 // detected by analyzer.
97 enum class FrameDropPhase : int {
98   kBeforeEncoder,
99   kByEncoder,
100   kTransport,
101   kByDecoder,
102   kAfterDecoder,
103   // kLastValue must be the last value in this enumeration.
104   kLastValue
105 };
106 
107 std::string ToString(FrameDropPhase phase);
108 std::ostream& operator<<(std::ostream& os, FrameDropPhase phase);
109 rtc::StringBuilder& operator<<(rtc::StringBuilder& sb, FrameDropPhase phase);
110 
111 struct StreamStats {
112   explicit StreamStats(Timestamp stream_started_time);
113 
114   // The time when the first frame of this stream was captured.
115   Timestamp stream_started_time;
116 
117   // Spatial quality metrics.
118   SamplesStatsCounter psnr;
119   SamplesStatsCounter ssim;
120 
121   // Time from frame encoded (time point on exit from encoder) to the
122   // encoded image received in decoder (time point on entrance to decoder).
123   SamplesStatsCounter transport_time_ms;
124   // Time from frame was captured on device to time frame was displayed on
125   // device.
126   SamplesStatsCounter total_delay_incl_transport_ms;
127   // Time between frames out from renderer.
128   SamplesStatsCounter time_between_rendered_frames_ms;
129   SamplesRateCounter capture_frame_rate;
130   SamplesRateCounter encode_frame_rate;
131   SamplesStatsCounter encode_time_ms;
132   SamplesStatsCounter decode_time_ms;
133   // Time from last packet of frame is received until it's sent to the renderer.
134   SamplesStatsCounter receive_to_render_time_ms;
135   // Max frames skipped between two nearest.
136   SamplesStatsCounter skipped_between_rendered;
137   // In the next 2 metrics freeze is a pause that is longer, than maximum:
138   //  1. 150ms
139   //  2. 3 * average time between two sequential frames.
140   // Item 1 will cover high fps video and is a duration, that is noticeable by
141   // human eye. Item 2 will cover low fps video like screen sharing.
142   // Freeze duration.
143   SamplesStatsCounter freeze_time_ms;
144   // Mean time between one freeze end and next freeze start.
145   SamplesStatsCounter time_between_freezes_ms;
146   SamplesStatsCounter resolution_of_decoded_frame;
147   SamplesStatsCounter target_encode_bitrate;
148   SamplesStatsCounter qp;
149 
150   int64_t total_encoded_images_payload = 0;
151   // Counters on which phase how many frames were dropped.
152   std::map<FrameDropPhase, int64_t> dropped_by_phase;
153 
154   // Frame count metrics.
155   int64_t num_send_key_frames = 0;
156   int64_t num_recv_key_frames = 0;
157 
158   // Encoded frame size (in bytes) metrics.
159   SamplesStatsCounter recv_key_frame_size_bytes;
160   SamplesStatsCounter recv_delta_frame_size_bytes;
161 
162   // Vector of encoders used for this stream by sending client.
163   std::vector<StreamCodecInfo> encoders;
164   // Vectors of decoders used for this stream by receiving client.
165   std::vector<StreamCodecInfo> decoders;
166 };
167 
168 struct AnalyzerStats {
169   // Size of analyzer internal comparisons queue, measured when new element
170   // id added to the queue.
171   SamplesStatsCounter comparisons_queue_size;
172   // Number of performed comparisons of 2 video frames from captured and
173   // rendered streams.
174   int64_t comparisons_done = 0;
175   // Number of cpu overloaded comparisons. Comparison is cpu overloaded if it is
176   // queued when there are too many not processed comparisons in the queue.
177   // Overloaded comparison doesn't include metrics like SSIM and PSNR that
178   // require heavy computations.
179   int64_t cpu_overloaded_comparisons_done = 0;
180   // Number of memory overloaded comparisons. Comparison is memory overloaded if
181   // it is queued when its captured frame was already removed due to high memory
182   // usage for that video stream.
183   int64_t memory_overloaded_comparisons_done = 0;
184   // Count of frames in flight in analyzer measured when new comparison is added
185   // and after analyzer was stopped.
186   SamplesStatsCounter frames_in_flight_left_count;
187 
188   // Next metrics are collected and reported iff
189   // `DefaultVideoQualityAnalyzerOptions::report_infra_metrics` is true.
190   SamplesStatsCounter on_frame_captured_processing_time_ms;
191   SamplesStatsCounter on_frame_pre_encode_processing_time_ms;
192   SamplesStatsCounter on_frame_encoded_processing_time_ms;
193   SamplesStatsCounter on_frame_pre_decode_processing_time_ms;
194   SamplesStatsCounter on_frame_decoded_processing_time_ms;
195   SamplesStatsCounter on_frame_rendered_processing_time_ms;
196   SamplesStatsCounter on_decoder_error_processing_time_ms;
197 };
198 
199 struct StatsKey {
StatsKeyStatsKey200   StatsKey(std::string stream_label, std::string receiver)
201       : stream_label(std::move(stream_label)), receiver(std::move(receiver)) {}
202 
203   std::string ToString() const;
204 
205   // Label of video stream to which stats belongs to.
206   std::string stream_label;
207   // Name of the peer on which stream was received.
208   std::string receiver;
209 };
210 
211 // Required to use StatsKey as std::map key.
212 bool operator<(const StatsKey& a, const StatsKey& b);
213 bool operator==(const StatsKey& a, const StatsKey& b);
214 
215 // Contains all metadata related to the video streams that were seen by the
216 // video analyzer.
217 class VideoStreamsInfo {
218  public:
219   std::set<StatsKey> GetStatsKeys() const;
220 
221   // Returns all stream labels that are known to the video analyzer.
222   std::set<std::string> GetStreams() const;
223 
224   // Returns set of the stream for specified `sender_name`. If sender didn't
225   // send any streams or `sender_name` isn't known to the video analyzer
226   // empty set will be returned.
227   std::set<std::string> GetStreams(absl::string_view sender_name) const;
228 
229   // Returns sender name for specified `stream_label`. Returns `absl::nullopt`
230   // if provided `stream_label` isn't known to the video analyzer.
231   absl::optional<std::string> GetSender(absl::string_view stream_label) const;
232 
233   // Returns set of the receivers for specified `stream_label`. If stream wasn't
234   // received by any peer or `stream_label` isn't known to the video analyzer
235   // empty set will be returned.
236   std::set<std::string> GetReceivers(absl::string_view stream_label) const;
237 
238  protected:
239   friend class DefaultVideoQualityAnalyzer;
240   VideoStreamsInfo(
241       std::map<std::string, std::string> stream_to_sender,
242       std::map<std::string, std::set<std::string>> sender_to_streams,
243       std::map<std::string, std::set<std::string>> stream_to_receivers);
244 
245  private:
246   std::map<std::string, std::string> stream_to_sender_;
247   std::map<std::string, std::set<std::string>> sender_to_streams_;
248   std::map<std::string, std::set<std::string>> stream_to_receivers_;
249 };
250 
251 struct DefaultVideoQualityAnalyzerOptions {
252   // Tells DefaultVideoQualityAnalyzer if heavy metrics have to be computed.
253   bool compute_psnr = true;
254   bool compute_ssim = true;
255   // If true, weights the luma plane more than the chroma planes in the PSNR.
256   bool use_weighted_psnr = false;
257   // Tells DefaultVideoQualityAnalyzer if detailed frame stats should be
258   // reported.
259   bool report_detailed_frame_stats = false;
260   // Tells DefaultVideoQualityAnalyzer if infra metrics related to the
261   // performance and stability of the analyzer itself should be reported.
262   bool report_infra_metrics = false;
263   // If true DefaultVideoQualityAnalyzer will try to adjust frames before
264   // computing PSNR and SSIM for them. In some cases picture may be shifted by
265   // a few pixels after the encode/decode step. Those difference is invisible
266   // for a human eye, but it affects the metrics. So the adjustment is used to
267   // get metrics that are closer to how human perceive the video. This feature
268   // significantly slows down the comparison, so turn it on only when it is
269   // needed.
270   bool adjust_cropping_before_comparing_frames = false;
271   // Amount of frames that are queued in the DefaultVideoQualityAnalyzer from
272   // the point they were captured to the point they were rendered on all
273   // receivers per stream.
274   size_t max_frames_in_flight_per_stream_count =
275       kDefaultMaxFramesInFlightPerStream;
276   // If true, the analyzer will expect peers to receive their own video streams.
277   bool enable_receive_own_stream = false;
278 };
279 
280 }  // namespace webrtc
281 
282 #endif  // TEST_PC_E2E_ANALYZER_VIDEO_DEFAULT_VIDEO_QUALITY_ANALYZER_SHARED_OBJECTS_H_
283