blob: 03ee87e676b3617b4b25438f5aa461205137e9c3 [file] [log] [blame]
Sebastian Janssond4c5d632018-07-10 12:57:37 +02001/*
2 * Copyright 2018 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#ifndef VIDEO_VIDEO_ANALYZER_H_
11#define VIDEO_VIDEO_ANALYZER_H_
12
13#include <deque>
14#include <map>
15#include <memory>
16#include <string>
17#include <vector>
18
Niels Möller1c931c42018-12-18 16:08:11 +010019#include "api/video/video_source_interface.h"
Yves Gerey79e9f4b2019-04-13 18:59:53 +020020#include "rtc_base/numerics/running_statistics.h"
Bjorn Terelius5c2f1f02019-01-16 17:45:05 +010021#include "rtc_base/time_utils.h"
Sebastian Janssond4c5d632018-07-10 12:57:37 +020022#include "test/layer_filtering_transport.h"
23#include "test/rtp_file_writer.h"
Artem Titov82ce3842019-09-23 17:55:52 +020024#include "test/testsupport/perf_test.h"
Sebastian Janssond4c5d632018-07-10 12:57:37 +020025
26namespace webrtc {
27
28class VideoAnalyzer : public PacketReceiver,
29 public Transport,
Niels Möller88be9722018-10-10 10:58:52 +020030 public rtc::VideoSinkInterface<VideoFrame> {
Sebastian Janssond4c5d632018-07-10 12:57:37 +020031 public:
Yves Gerey79e9f4b2019-04-13 18:59:53 +020032 using Statistics = RunningStatistics<double>;
33
Sebastian Janssond4c5d632018-07-10 12:57:37 +020034 VideoAnalyzer(test::LayerFilteringTransport* transport,
35 const std::string& test_label,
36 double avg_psnr_threshold,
37 double avg_ssim_threshold,
38 int duration_frames,
39 FILE* graph_data_output_file,
40 const std::string& graph_title,
41 uint32_t ssrc_to_analyze,
42 uint32_t rtx_ssrc_to_analyze,
43 size_t selected_stream,
44 int selected_sl,
45 int selected_tl,
46 bool is_quick_test_enabled,
47 Clock* clock,
Artem Titovff7730d2019-04-02 13:46:53 +020048 std::string rtp_dump_name,
Yves Gerey6516f762019-08-29 11:50:23 +020049 test::DEPRECATED_SingleThreadedTaskQueueForTesting* task_queue);
Sebastian Janssond4c5d632018-07-10 12:57:37 +020050 ~VideoAnalyzer();
51
52 virtual void SetReceiver(PacketReceiver* receiver);
Niels Möller1c931c42018-12-18 16:08:11 +010053 void SetSource(rtc::VideoSourceInterface<VideoFrame>* video_source,
Sebastian Janssonf1f363f2018-08-13 14:24:58 +020054 bool respect_sink_wants);
Sebastian Janssond4c5d632018-07-10 12:57:37 +020055 void SetCall(Call* call);
56 void SetSendStream(VideoSendStream* stream);
57 void SetReceiveStream(VideoReceiveStream* stream);
Christoffer Rodbroc2a02882018-08-07 14:10:56 +020058 void SetAudioReceiveStream(AudioReceiveStream* recv_stream);
59
Sebastian Janssond4c5d632018-07-10 12:57:37 +020060 rtc::VideoSinkInterface<VideoFrame>* InputInterface();
61 rtc::VideoSourceInterface<VideoFrame>* OutputInterface();
62
63 DeliveryStatus DeliverPacket(MediaType media_type,
64 rtc::CopyOnWriteBuffer packet,
Niels Möller70082872018-08-07 11:03:12 +020065 int64_t packet_time_us) override;
Sebastian Janssond4c5d632018-07-10 12:57:37 +020066
67 void PreEncodeOnFrame(const VideoFrame& video_frame);
Niels Möller88be9722018-10-10 10:58:52 +020068 void PostEncodeOnFrame(size_t stream_id, uint32_t timestamp);
Sebastian Janssond4c5d632018-07-10 12:57:37 +020069
70 bool SendRtp(const uint8_t* packet,
71 size_t length,
72 const PacketOptions& options) override;
73
74 bool SendRtcp(const uint8_t* packet, size_t length) override;
75 void OnFrame(const VideoFrame& video_frame) override;
76 void Wait();
77
Sebastian Janssond4c5d632018-07-10 12:57:37 +020078 void StartMeasuringCpuProcessTime();
79 void StopMeasuringCpuProcessTime();
80 void StartExcludingCpuThreadTime();
81 void StopExcludingCpuThreadTime();
82 double GetCpuUsagePercent();
83
84 test::LayerFilteringTransport* const transport_;
85 PacketReceiver* receiver_;
86
87 private:
88 struct FrameComparison {
89 FrameComparison();
90 FrameComparison(const VideoFrame& reference,
91 const VideoFrame& render,
92 bool dropped,
93 int64_t input_time_ms,
94 int64_t send_time_ms,
95 int64_t recv_time_ms,
96 int64_t render_time_ms,
97 size_t encoded_frame_size);
98 FrameComparison(bool dropped,
99 int64_t input_time_ms,
100 int64_t send_time_ms,
101 int64_t recv_time_ms,
102 int64_t render_time_ms,
103 size_t encoded_frame_size);
104
105 absl::optional<VideoFrame> reference;
106 absl::optional<VideoFrame> render;
107 bool dropped;
108 int64_t input_time_ms;
109 int64_t send_time_ms;
110 int64_t recv_time_ms;
111 int64_t render_time_ms;
112 size_t encoded_frame_size;
113 };
114
115 struct Sample {
116 Sample(int dropped,
117 int64_t input_time_ms,
118 int64_t send_time_ms,
119 int64_t recv_time_ms,
120 int64_t render_time_ms,
121 size_t encoded_frame_size,
122 double psnr,
123 double ssim);
124
125 int dropped;
126 int64_t input_time_ms;
127 int64_t send_time_ms;
128 int64_t recv_time_ms;
129 int64_t render_time_ms;
130 size_t encoded_frame_size;
131 double psnr;
132 double ssim;
133 };
134
Sebastian Janssond4c5d632018-07-10 12:57:37 +0200135 // Implements VideoSinkInterface to receive captured frames from a
136 // FrameGeneratorCapturer. Implements VideoSourceInterface to be able to act
137 // as a source to VideoSendStream.
138 // It forwards all input frames to the VideoAnalyzer for later comparison and
139 // forwards the captured frames to the VideoSendStream.
140 class CapturedFrameForwarder : public rtc::VideoSinkInterface<VideoFrame>,
141 public rtc::VideoSourceInterface<VideoFrame> {
142 public:
Ilya Nikolaevskiy6957abe2019-01-29 16:33:04 +0100143 CapturedFrameForwarder(VideoAnalyzer* analyzer,
144 Clock* clock,
Ilya Nikolaevskiy85fc3252019-02-11 10:41:50 +0100145 int frames_to_process);
Niels Möller1c931c42018-12-18 16:08:11 +0100146 void SetSource(rtc::VideoSourceInterface<VideoFrame>* video_source);
Sebastian Janssond4c5d632018-07-10 12:57:37 +0200147
148 private:
149 void OnFrame(const VideoFrame& video_frame) override;
150
151 // Called when |send_stream_.SetSource()| is called.
152 void AddOrUpdateSink(rtc::VideoSinkInterface<VideoFrame>* sink,
153 const rtc::VideoSinkWants& wants) override;
154
155 // Called by |send_stream_| when |send_stream_.SetSource()| is called.
156 void RemoveSink(rtc::VideoSinkInterface<VideoFrame>* sink) override;
157
158 VideoAnalyzer* const analyzer_;
159 rtc::CriticalSection crit_;
160 rtc::VideoSinkInterface<VideoFrame>* send_stream_input_
161 RTC_GUARDED_BY(crit_);
Niels Möller1c931c42018-12-18 16:08:11 +0100162 VideoSourceInterface<VideoFrame>* video_source_;
Sebastian Janssond4c5d632018-07-10 12:57:37 +0200163 Clock* clock_;
Ilya Nikolaevskiy6957abe2019-01-29 16:33:04 +0100164 int captured_frames_ RTC_GUARDED_BY(crit_);
Yves Gerey0c67c802019-08-01 17:45:54 +0200165 const int frames_to_process_;
Sebastian Janssond4c5d632018-07-10 12:57:37 +0200166 };
167
168 struct FrameWithPsnr {
169 double psnr;
170 VideoFrame frame;
171 };
172
173 bool IsInSelectedSpatialAndTemporalLayer(const uint8_t* packet,
174 size_t length,
175 const RTPHeader& header);
176
177 void AddFrameComparison(const VideoFrame& reference,
178 const VideoFrame& render,
179 bool dropped,
180 int64_t render_time_ms)
181 RTC_EXCLUSIVE_LOCKS_REQUIRED(crit_);
182
Sebastian Janssond4c5d632018-07-10 12:57:37 +0200183 void PollStats();
Niels Möller4731f002019-05-03 09:34:24 +0200184 static void FrameComparisonThread(void* obj);
Sebastian Janssond4c5d632018-07-10 12:57:37 +0200185 bool CompareFrames();
186 bool PopComparison(FrameComparison* comparison);
187 // Increment counter for number of frames received for comparison.
188 void FrameRecorded();
189 // Returns true if all frames to be compared have been taken from the queue.
190 bool AllFramesRecorded();
191 // Increase count of number of frames processed. Returns true if this was the
192 // last frame to be processed.
193 bool FrameProcessed();
194 void PrintResults();
195 void PerformFrameComparison(const FrameComparison& comparison);
Artem Titov82ce3842019-09-23 17:55:52 +0200196 void PrintResult(const char* result_type,
197 Statistics stats,
198 const char* unit,
199 webrtc::test::ImproveDirection improve_direction);
200 void PrintResultWithExternalMean(
201 const char* result_type,
202 double mean,
203 Statistics stats,
204 const char* unit,
205 webrtc::test::ImproveDirection improve_direction);
Sebastian Janssond4c5d632018-07-10 12:57:37 +0200206 void PrintSamplesToFile(void);
Sebastian Janssond4c5d632018-07-10 12:57:37 +0200207 void AddCapturedFrameForComparison(const VideoFrame& video_frame);
208
209 Call* call_;
210 VideoSendStream* send_stream_;
211 VideoReceiveStream* receive_stream_;
Christoffer Rodbroc2a02882018-08-07 14:10:56 +0200212 AudioReceiveStream* audio_receive_stream_;
Sebastian Janssond4c5d632018-07-10 12:57:37 +0200213 CapturedFrameForwarder captured_frame_forwarder_;
214 const std::string test_label_;
215 FILE* const graph_data_output_file_;
216 const std::string graph_title_;
217 const uint32_t ssrc_to_analyze_;
218 const uint32_t rtx_ssrc_to_analyze_;
219 const size_t selected_stream_;
220 const int selected_sl_;
221 const int selected_tl_;
Sebastian Janssond4c5d632018-07-10 12:57:37 +0200222
223 rtc::CriticalSection comparison_lock_;
224 std::vector<Sample> samples_ RTC_GUARDED_BY(comparison_lock_);
Yves Gerey79e9f4b2019-04-13 18:59:53 +0200225 Statistics sender_time_ RTC_GUARDED_BY(comparison_lock_);
226 Statistics receiver_time_ RTC_GUARDED_BY(comparison_lock_);
227 Statistics network_time_ RTC_GUARDED_BY(comparison_lock_);
228 Statistics psnr_ RTC_GUARDED_BY(comparison_lock_);
229 Statistics ssim_ RTC_GUARDED_BY(comparison_lock_);
230 Statistics end_to_end_ RTC_GUARDED_BY(comparison_lock_);
231 Statistics rendered_delta_ RTC_GUARDED_BY(comparison_lock_);
232 Statistics encoded_frame_size_ RTC_GUARDED_BY(comparison_lock_);
233 Statistics encode_frame_rate_ RTC_GUARDED_BY(comparison_lock_);
234 Statistics encode_time_ms_ RTC_GUARDED_BY(comparison_lock_);
235 Statistics encode_usage_percent_ RTC_GUARDED_BY(comparison_lock_);
Johannes Krona1b99b32019-07-30 15:08:16 +0200236 double mean_decode_time_ms_ RTC_GUARDED_BY(comparison_lock_);
Yves Gerey79e9f4b2019-04-13 18:59:53 +0200237 Statistics decode_time_ms_ RTC_GUARDED_BY(comparison_lock_);
238 Statistics decode_time_max_ms_ RTC_GUARDED_BY(comparison_lock_);
239 Statistics media_bitrate_bps_ RTC_GUARDED_BY(comparison_lock_);
240 Statistics fec_bitrate_bps_ RTC_GUARDED_BY(comparison_lock_);
241 Statistics send_bandwidth_bps_ RTC_GUARDED_BY(comparison_lock_);
242 Statistics memory_usage_ RTC_GUARDED_BY(comparison_lock_);
Yves Gerey79e9f4b2019-04-13 18:59:53 +0200243 Statistics audio_expand_rate_ RTC_GUARDED_BY(comparison_lock_);
244 Statistics audio_accelerate_rate_ RTC_GUARDED_BY(comparison_lock_);
245 Statistics audio_jitter_buffer_ms_ RTC_GUARDED_BY(comparison_lock_);
246 Statistics pixels_ RTC_GUARDED_BY(comparison_lock_);
Sebastian Janssond4c5d632018-07-10 12:57:37 +0200247 // Rendered frame with worst PSNR is saved for further analysis.
248 absl::optional<FrameWithPsnr> worst_frame_ RTC_GUARDED_BY(comparison_lock_);
Elad Alon8c513c72019-05-07 21:22:24 +0200249 // Freeze metrics.
250 Statistics time_between_freezes_ RTC_GUARDED_BY(comparison_lock_);
251 uint32_t freeze_count_ RTC_GUARDED_BY(comparison_lock_);
252 uint32_t total_freezes_duration_ms_ RTC_GUARDED_BY(comparison_lock_);
253 uint32_t total_frames_duration_ms_ RTC_GUARDED_BY(comparison_lock_);
254 double sum_squared_frame_durations_ RTC_GUARDED_BY(comparison_lock_);
Sebastian Janssond4c5d632018-07-10 12:57:37 +0200255
Elad Alon58e06572019-05-08 15:34:24 +0200256 double decode_frame_rate_ RTC_GUARDED_BY(comparison_lock_);
257 double render_frame_rate_ RTC_GUARDED_BY(comparison_lock_);
258
Sebastian Janssond4c5d632018-07-10 12:57:37 +0200259 size_t last_fec_bytes_;
260
Yves Gerey0c67c802019-08-01 17:45:54 +0200261 rtc::CriticalSection crit_;
Sebastian Janssond4c5d632018-07-10 12:57:37 +0200262 const int frames_to_process_;
Yves Gerey0c67c802019-08-01 17:45:54 +0200263 int frames_recorded_ RTC_GUARDED_BY(comparison_lock_);
264 int frames_processed_ RTC_GUARDED_BY(comparison_lock_);
265 int captured_frames_ RTC_GUARDED_BY(comparison_lock_);
266 int dropped_frames_ RTC_GUARDED_BY(comparison_lock_);
267 int dropped_frames_before_first_encode_ RTC_GUARDED_BY(crit_);
268 int dropped_frames_before_rendering_ RTC_GUARDED_BY(crit_);
269 int64_t last_render_time_ RTC_GUARDED_BY(comparison_lock_);
270 int64_t last_render_delta_ms_ RTC_GUARDED_BY(comparison_lock_);
271 int64_t last_unfreeze_time_ms_ RTC_GUARDED_BY(comparison_lock_);
272 uint32_t rtp_timestamp_delta_ RTC_GUARDED_BY(crit_);
Sebastian Janssond4c5d632018-07-10 12:57:37 +0200273
274 rtc::CriticalSection cpu_measurement_lock_;
275 int64_t cpu_time_ RTC_GUARDED_BY(cpu_measurement_lock_);
276 int64_t wallclock_time_ RTC_GUARDED_BY(cpu_measurement_lock_);
277
Sebastian Janssond4c5d632018-07-10 12:57:37 +0200278 std::deque<VideoFrame> frames_ RTC_GUARDED_BY(crit_);
279 absl::optional<VideoFrame> last_rendered_frame_ RTC_GUARDED_BY(crit_);
280 rtc::TimestampWrapAroundHandler wrap_handler_ RTC_GUARDED_BY(crit_);
281 std::map<int64_t, int64_t> send_times_ RTC_GUARDED_BY(crit_);
282 std::map<int64_t, int64_t> recv_times_ RTC_GUARDED_BY(crit_);
283 std::map<int64_t, size_t> encoded_frame_sizes_ RTC_GUARDED_BY(crit_);
284 absl::optional<uint32_t> first_encoded_timestamp_ RTC_GUARDED_BY(crit_);
285 absl::optional<uint32_t> first_sent_timestamp_ RTC_GUARDED_BY(crit_);
286 const double avg_psnr_threshold_;
287 const double avg_ssim_threshold_;
288 bool is_quick_test_enabled_;
289
290 std::vector<rtc::PlatformThread*> comparison_thread_pool_;
Sebastian Janssond4c5d632018-07-10 12:57:37 +0200291 rtc::Event comparison_available_event_;
292 std::deque<FrameComparison> comparisons_ RTC_GUARDED_BY(comparison_lock_);
Niels Möller4731f002019-05-03 09:34:24 +0200293 bool quit_ RTC_GUARDED_BY(comparison_lock_);
Sebastian Janssond4c5d632018-07-10 12:57:37 +0200294 rtc::Event done_;
Yves Gerey6516f762019-08-29 11:50:23 +0200295 test::DEPRECATED_SingleThreadedTaskQueueForTesting::TaskId
296 stats_polling_task_id_ RTC_GUARDED_BY(comparison_lock_);
Artem Titovff7730d2019-04-02 13:46:53 +0200297 bool stop_stats_poller_ RTC_GUARDED_BY(comparison_lock_);
Sebastian Janssond4c5d632018-07-10 12:57:37 +0200298
299 std::unique_ptr<test::RtpFileWriter> rtp_file_writer_;
300 Clock* const clock_;
301 const int64_t start_ms_;
Yves Gerey6516f762019-08-29 11:50:23 +0200302 test::DEPRECATED_SingleThreadedTaskQueueForTesting* task_queue_;
Sebastian Janssond4c5d632018-07-10 12:57:37 +0200303};
304
305} // namespace webrtc
306#endif // VIDEO_VIDEO_ANALYZER_H_