blob: 7d60e7c8facef6c32cd266cb2ab42928619367d7 [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
Danil Chapovalov9cd53b42019-10-21 13:36:59 +020019#include "api/task_queue/task_queue_base.h"
Niels Möller1c931c42018-12-18 16:08:11 +010020#include "api/video/video_source_interface.h"
Danil Chapovalovb57fe172019-12-11 09:38:44 +010021#include "modules/rtp_rtcp/source/rtp_packet.h"
22#include "modules/rtp_rtcp/source/video_rtp_depacketizer.h"
Danil Chapovalov85a10002019-10-21 15:00:53 +020023#include "rtc_base/event.h"
Yves Gerey79e9f4b2019-04-13 18:59:53 +020024#include "rtc_base/numerics/running_statistics.h"
Danil Chapovalov85a10002019-10-21 15:00:53 +020025#include "rtc_base/platform_thread.h"
Bjorn Terelius5c2f1f02019-01-16 17:45:05 +010026#include "rtc_base/time_utils.h"
Sebastian Janssond4c5d632018-07-10 12:57:37 +020027#include "test/layer_filtering_transport.h"
28#include "test/rtp_file_writer.h"
Artem Titov82ce3842019-09-23 17:55:52 +020029#include "test/testsupport/perf_test.h"
Sebastian Janssond4c5d632018-07-10 12:57:37 +020030
31namespace webrtc {
32
33class VideoAnalyzer : public PacketReceiver,
34 public Transport,
Niels Möller88be9722018-10-10 10:58:52 +020035 public rtc::VideoSinkInterface<VideoFrame> {
Sebastian Janssond4c5d632018-07-10 12:57:37 +020036 public:
Yves Gerey79e9f4b2019-04-13 18:59:53 +020037 using Statistics = RunningStatistics<double>;
38
Sebastian Janssond4c5d632018-07-10 12:57:37 +020039 VideoAnalyzer(test::LayerFilteringTransport* transport,
40 const std::string& test_label,
41 double avg_psnr_threshold,
42 double avg_ssim_threshold,
43 int duration_frames,
44 FILE* graph_data_output_file,
45 const std::string& graph_title,
46 uint32_t ssrc_to_analyze,
47 uint32_t rtx_ssrc_to_analyze,
48 size_t selected_stream,
49 int selected_sl,
50 int selected_tl,
51 bool is_quick_test_enabled,
52 Clock* clock,
Artem Titovff7730d2019-04-02 13:46:53 +020053 std::string rtp_dump_name,
Danil Chapovalov9cd53b42019-10-21 13:36:59 +020054 TaskQueueBase* task_queue);
Sebastian Janssond4c5d632018-07-10 12:57:37 +020055 ~VideoAnalyzer();
56
57 virtual void SetReceiver(PacketReceiver* receiver);
Niels Möller1c931c42018-12-18 16:08:11 +010058 void SetSource(rtc::VideoSourceInterface<VideoFrame>* video_source,
Sebastian Janssonf1f363f2018-08-13 14:24:58 +020059 bool respect_sink_wants);
Sebastian Janssond4c5d632018-07-10 12:57:37 +020060 void SetCall(Call* call);
61 void SetSendStream(VideoSendStream* stream);
62 void SetReceiveStream(VideoReceiveStream* stream);
Christoffer Rodbroc2a02882018-08-07 14:10:56 +020063 void SetAudioReceiveStream(AudioReceiveStream* recv_stream);
64
Sebastian Janssond4c5d632018-07-10 12:57:37 +020065 rtc::VideoSinkInterface<VideoFrame>* InputInterface();
66 rtc::VideoSourceInterface<VideoFrame>* OutputInterface();
67
68 DeliveryStatus DeliverPacket(MediaType media_type,
69 rtc::CopyOnWriteBuffer packet,
Niels Möller70082872018-08-07 11:03:12 +020070 int64_t packet_time_us) override;
Sebastian Janssond4c5d632018-07-10 12:57:37 +020071
72 void PreEncodeOnFrame(const VideoFrame& video_frame);
Niels Möller88be9722018-10-10 10:58:52 +020073 void PostEncodeOnFrame(size_t stream_id, uint32_t timestamp);
Sebastian Janssond4c5d632018-07-10 12:57:37 +020074
75 bool SendRtp(const uint8_t* packet,
76 size_t length,
77 const PacketOptions& options) override;
78
79 bool SendRtcp(const uint8_t* packet, size_t length) override;
80 void OnFrame(const VideoFrame& video_frame) override;
81 void Wait();
82
Sebastian Janssond4c5d632018-07-10 12:57:37 +020083 void StartMeasuringCpuProcessTime();
84 void StopMeasuringCpuProcessTime();
85 void StartExcludingCpuThreadTime();
86 void StopExcludingCpuThreadTime();
87 double GetCpuUsagePercent();
88
89 test::LayerFilteringTransport* const transport_;
90 PacketReceiver* receiver_;
91
92 private:
93 struct FrameComparison {
94 FrameComparison();
95 FrameComparison(const VideoFrame& reference,
96 const VideoFrame& render,
97 bool dropped,
98 int64_t input_time_ms,
99 int64_t send_time_ms,
100 int64_t recv_time_ms,
101 int64_t render_time_ms,
102 size_t encoded_frame_size);
103 FrameComparison(bool dropped,
104 int64_t input_time_ms,
105 int64_t send_time_ms,
106 int64_t recv_time_ms,
107 int64_t render_time_ms,
108 size_t encoded_frame_size);
109
110 absl::optional<VideoFrame> reference;
111 absl::optional<VideoFrame> render;
112 bool dropped;
113 int64_t input_time_ms;
114 int64_t send_time_ms;
115 int64_t recv_time_ms;
116 int64_t render_time_ms;
117 size_t encoded_frame_size;
118 };
119
120 struct Sample {
121 Sample(int dropped,
122 int64_t input_time_ms,
123 int64_t send_time_ms,
124 int64_t recv_time_ms,
125 int64_t render_time_ms,
126 size_t encoded_frame_size,
127 double psnr,
128 double ssim);
129
130 int dropped;
131 int64_t input_time_ms;
132 int64_t send_time_ms;
133 int64_t recv_time_ms;
134 int64_t render_time_ms;
135 size_t encoded_frame_size;
136 double psnr;
137 double ssim;
138 };
139
Sebastian Janssond4c5d632018-07-10 12:57:37 +0200140 // Implements VideoSinkInterface to receive captured frames from a
141 // FrameGeneratorCapturer. Implements VideoSourceInterface to be able to act
142 // as a source to VideoSendStream.
143 // It forwards all input frames to the VideoAnalyzer for later comparison and
144 // forwards the captured frames to the VideoSendStream.
145 class CapturedFrameForwarder : public rtc::VideoSinkInterface<VideoFrame>,
146 public rtc::VideoSourceInterface<VideoFrame> {
147 public:
Ilya Nikolaevskiy6957abe2019-01-29 16:33:04 +0100148 CapturedFrameForwarder(VideoAnalyzer* analyzer,
149 Clock* clock,
Ilya Nikolaevskiy85fc3252019-02-11 10:41:50 +0100150 int frames_to_process);
Niels Möller1c931c42018-12-18 16:08:11 +0100151 void SetSource(rtc::VideoSourceInterface<VideoFrame>* video_source);
Sebastian Janssond4c5d632018-07-10 12:57:37 +0200152
153 private:
154 void OnFrame(const VideoFrame& video_frame) override;
155
156 // Called when |send_stream_.SetSource()| is called.
157 void AddOrUpdateSink(rtc::VideoSinkInterface<VideoFrame>* sink,
158 const rtc::VideoSinkWants& wants) override;
159
160 // Called by |send_stream_| when |send_stream_.SetSource()| is called.
161 void RemoveSink(rtc::VideoSinkInterface<VideoFrame>* sink) override;
162
163 VideoAnalyzer* const analyzer_;
164 rtc::CriticalSection crit_;
165 rtc::VideoSinkInterface<VideoFrame>* send_stream_input_
166 RTC_GUARDED_BY(crit_);
Niels Möller1c931c42018-12-18 16:08:11 +0100167 VideoSourceInterface<VideoFrame>* video_source_;
Sebastian Janssond4c5d632018-07-10 12:57:37 +0200168 Clock* clock_;
Ilya Nikolaevskiy6957abe2019-01-29 16:33:04 +0100169 int captured_frames_ RTC_GUARDED_BY(crit_);
Yves Gerey0c67c802019-08-01 17:45:54 +0200170 const int frames_to_process_;
Sebastian Janssond4c5d632018-07-10 12:57:37 +0200171 };
172
173 struct FrameWithPsnr {
174 double psnr;
175 VideoFrame frame;
176 };
177
Danil Chapovalovb57fe172019-12-11 09:38:44 +0100178 bool IsInSelectedSpatialAndTemporalLayer(const RtpPacket& rtp_packet);
Sebastian Janssond4c5d632018-07-10 12:57:37 +0200179
180 void AddFrameComparison(const VideoFrame& reference,
181 const VideoFrame& render,
182 bool dropped,
183 int64_t render_time_ms)
184 RTC_EXCLUSIVE_LOCKS_REQUIRED(crit_);
185
Sebastian Janssond4c5d632018-07-10 12:57:37 +0200186 void PollStats();
Niels Möller4731f002019-05-03 09:34:24 +0200187 static void FrameComparisonThread(void* obj);
Sebastian Janssond4c5d632018-07-10 12:57:37 +0200188 bool CompareFrames();
189 bool PopComparison(FrameComparison* comparison);
190 // Increment counter for number of frames received for comparison.
191 void FrameRecorded();
192 // Returns true if all frames to be compared have been taken from the queue.
193 bool AllFramesRecorded();
194 // Increase count of number of frames processed. Returns true if this was the
195 // last frame to be processed.
196 bool FrameProcessed();
197 void PrintResults();
198 void PerformFrameComparison(const FrameComparison& comparison);
Artem Titov82ce3842019-09-23 17:55:52 +0200199 void PrintResult(const char* result_type,
200 Statistics stats,
201 const char* unit,
202 webrtc::test::ImproveDirection improve_direction);
203 void PrintResultWithExternalMean(
204 const char* result_type,
205 double mean,
206 Statistics stats,
207 const char* unit,
208 webrtc::test::ImproveDirection improve_direction);
Sebastian Janssond4c5d632018-07-10 12:57:37 +0200209 void PrintSamplesToFile(void);
Sebastian Janssond4c5d632018-07-10 12:57:37 +0200210 void AddCapturedFrameForComparison(const VideoFrame& video_frame);
211
212 Call* call_;
213 VideoSendStream* send_stream_;
214 VideoReceiveStream* receive_stream_;
Christoffer Rodbroc2a02882018-08-07 14:10:56 +0200215 AudioReceiveStream* audio_receive_stream_;
Sebastian Janssond4c5d632018-07-10 12:57:37 +0200216 CapturedFrameForwarder captured_frame_forwarder_;
217 const std::string test_label_;
218 FILE* const graph_data_output_file_;
219 const std::string graph_title_;
220 const uint32_t ssrc_to_analyze_;
221 const uint32_t rtx_ssrc_to_analyze_;
222 const size_t selected_stream_;
223 const int selected_sl_;
224 const int selected_tl_;
Sebastian Janssond4c5d632018-07-10 12:57:37 +0200225
226 rtc::CriticalSection comparison_lock_;
227 std::vector<Sample> samples_ RTC_GUARDED_BY(comparison_lock_);
Yves Gerey79e9f4b2019-04-13 18:59:53 +0200228 Statistics sender_time_ RTC_GUARDED_BY(comparison_lock_);
229 Statistics receiver_time_ RTC_GUARDED_BY(comparison_lock_);
230 Statistics network_time_ RTC_GUARDED_BY(comparison_lock_);
231 Statistics psnr_ RTC_GUARDED_BY(comparison_lock_);
232 Statistics ssim_ RTC_GUARDED_BY(comparison_lock_);
233 Statistics end_to_end_ RTC_GUARDED_BY(comparison_lock_);
234 Statistics rendered_delta_ RTC_GUARDED_BY(comparison_lock_);
235 Statistics encoded_frame_size_ RTC_GUARDED_BY(comparison_lock_);
236 Statistics encode_frame_rate_ RTC_GUARDED_BY(comparison_lock_);
237 Statistics encode_time_ms_ RTC_GUARDED_BY(comparison_lock_);
238 Statistics encode_usage_percent_ RTC_GUARDED_BY(comparison_lock_);
Johannes Krona1b99b32019-07-30 15:08:16 +0200239 double mean_decode_time_ms_ RTC_GUARDED_BY(comparison_lock_);
Yves Gerey79e9f4b2019-04-13 18:59:53 +0200240 Statistics decode_time_ms_ RTC_GUARDED_BY(comparison_lock_);
241 Statistics decode_time_max_ms_ RTC_GUARDED_BY(comparison_lock_);
242 Statistics media_bitrate_bps_ RTC_GUARDED_BY(comparison_lock_);
243 Statistics fec_bitrate_bps_ RTC_GUARDED_BY(comparison_lock_);
244 Statistics send_bandwidth_bps_ RTC_GUARDED_BY(comparison_lock_);
245 Statistics memory_usage_ RTC_GUARDED_BY(comparison_lock_);
Yves Gerey79e9f4b2019-04-13 18:59:53 +0200246 Statistics audio_expand_rate_ RTC_GUARDED_BY(comparison_lock_);
247 Statistics audio_accelerate_rate_ RTC_GUARDED_BY(comparison_lock_);
248 Statistics audio_jitter_buffer_ms_ RTC_GUARDED_BY(comparison_lock_);
249 Statistics pixels_ RTC_GUARDED_BY(comparison_lock_);
Sebastian Janssond4c5d632018-07-10 12:57:37 +0200250 // Rendered frame with worst PSNR is saved for further analysis.
251 absl::optional<FrameWithPsnr> worst_frame_ RTC_GUARDED_BY(comparison_lock_);
Elad Alon8c513c72019-05-07 21:22:24 +0200252 // Freeze metrics.
253 Statistics time_between_freezes_ RTC_GUARDED_BY(comparison_lock_);
254 uint32_t freeze_count_ RTC_GUARDED_BY(comparison_lock_);
255 uint32_t total_freezes_duration_ms_ RTC_GUARDED_BY(comparison_lock_);
256 uint32_t total_frames_duration_ms_ RTC_GUARDED_BY(comparison_lock_);
257 double sum_squared_frame_durations_ RTC_GUARDED_BY(comparison_lock_);
Sebastian Janssond4c5d632018-07-10 12:57:37 +0200258
Elad Alon58e06572019-05-08 15:34:24 +0200259 double decode_frame_rate_ RTC_GUARDED_BY(comparison_lock_);
260 double render_frame_rate_ RTC_GUARDED_BY(comparison_lock_);
261
Sebastian Janssond4c5d632018-07-10 12:57:37 +0200262 size_t last_fec_bytes_;
263
Yves Gerey0c67c802019-08-01 17:45:54 +0200264 rtc::CriticalSection crit_;
Sebastian Janssond4c5d632018-07-10 12:57:37 +0200265 const int frames_to_process_;
Yves Gerey0c67c802019-08-01 17:45:54 +0200266 int frames_recorded_ RTC_GUARDED_BY(comparison_lock_);
267 int frames_processed_ RTC_GUARDED_BY(comparison_lock_);
268 int captured_frames_ RTC_GUARDED_BY(comparison_lock_);
269 int dropped_frames_ RTC_GUARDED_BY(comparison_lock_);
270 int dropped_frames_before_first_encode_ RTC_GUARDED_BY(crit_);
271 int dropped_frames_before_rendering_ RTC_GUARDED_BY(crit_);
272 int64_t last_render_time_ RTC_GUARDED_BY(comparison_lock_);
273 int64_t last_render_delta_ms_ RTC_GUARDED_BY(comparison_lock_);
274 int64_t last_unfreeze_time_ms_ RTC_GUARDED_BY(comparison_lock_);
275 uint32_t rtp_timestamp_delta_ RTC_GUARDED_BY(crit_);
Sebastian Janssond4c5d632018-07-10 12:57:37 +0200276
277 rtc::CriticalSection cpu_measurement_lock_;
278 int64_t cpu_time_ RTC_GUARDED_BY(cpu_measurement_lock_);
279 int64_t wallclock_time_ RTC_GUARDED_BY(cpu_measurement_lock_);
280
Sebastian Janssond4c5d632018-07-10 12:57:37 +0200281 std::deque<VideoFrame> frames_ RTC_GUARDED_BY(crit_);
282 absl::optional<VideoFrame> last_rendered_frame_ RTC_GUARDED_BY(crit_);
283 rtc::TimestampWrapAroundHandler wrap_handler_ RTC_GUARDED_BY(crit_);
284 std::map<int64_t, int64_t> send_times_ RTC_GUARDED_BY(crit_);
285 std::map<int64_t, int64_t> recv_times_ RTC_GUARDED_BY(crit_);
286 std::map<int64_t, size_t> encoded_frame_sizes_ RTC_GUARDED_BY(crit_);
287 absl::optional<uint32_t> first_encoded_timestamp_ RTC_GUARDED_BY(crit_);
288 absl::optional<uint32_t> first_sent_timestamp_ RTC_GUARDED_BY(crit_);
289 const double avg_psnr_threshold_;
290 const double avg_ssim_threshold_;
291 bool is_quick_test_enabled_;
292
293 std::vector<rtc::PlatformThread*> comparison_thread_pool_;
Sebastian Janssond4c5d632018-07-10 12:57:37 +0200294 rtc::Event comparison_available_event_;
295 std::deque<FrameComparison> comparisons_ RTC_GUARDED_BY(comparison_lock_);
Niels Möller4731f002019-05-03 09:34:24 +0200296 bool quit_ RTC_GUARDED_BY(comparison_lock_);
Sebastian Janssond4c5d632018-07-10 12:57:37 +0200297 rtc::Event done_;
298
Danil Chapovalovb57fe172019-12-11 09:38:44 +0100299 std::unique_ptr<VideoRtpDepacketizer> vp8_depacketizer_;
300 std::unique_ptr<VideoRtpDepacketizer> vp9_depacketizer_;
Sebastian Janssond4c5d632018-07-10 12:57:37 +0200301 std::unique_ptr<test::RtpFileWriter> rtp_file_writer_;
302 Clock* const clock_;
303 const int64_t start_ms_;
Danil Chapovalov9cd53b42019-10-21 13:36:59 +0200304 TaskQueueBase* task_queue_;
Sebastian Janssond4c5d632018-07-10 12:57:37 +0200305};
306
307} // namespace webrtc
308#endif // VIDEO_VIDEO_ANALYZER_H_