blob: 759b4e92f5bb6d1da5931fda0014eccea68d0b7f [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"
Bjorn Terelius5c2f1f02019-01-16 17:45:05 +010020#include "rtc_base/time_utils.h"
Ilya Nikolaevskiy1f0a84a2019-02-05 14:35:33 +010021#include "test/frame_change_extractor.h"
Sebastian Janssond4c5d632018-07-10 12:57:37 +020022#include "test/layer_filtering_transport.h"
23#include "test/rtp_file_writer.h"
24#include "test/statistics.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:
32 VideoAnalyzer(test::LayerFilteringTransport* transport,
33 const std::string& test_label,
34 double avg_psnr_threshold,
35 double avg_ssim_threshold,
36 int duration_frames,
37 FILE* graph_data_output_file,
38 const std::string& graph_title,
39 uint32_t ssrc_to_analyze,
40 uint32_t rtx_ssrc_to_analyze,
41 size_t selected_stream,
42 int selected_sl,
43 int selected_tl,
44 bool is_quick_test_enabled,
45 Clock* clock,
Ilya Nikolaevskiy1f0a84a2019-02-05 14:35:33 +010046 std::string rtp_dump_name,
47 bool partial_updates);
Sebastian Janssond4c5d632018-07-10 12:57:37 +020048 ~VideoAnalyzer();
49
50 virtual void SetReceiver(PacketReceiver* receiver);
Niels Möller1c931c42018-12-18 16:08:11 +010051 void SetSource(rtc::VideoSourceInterface<VideoFrame>* video_source,
Sebastian Janssonf1f363f2018-08-13 14:24:58 +020052 bool respect_sink_wants);
Sebastian Janssond4c5d632018-07-10 12:57:37 +020053 void SetCall(Call* call);
54 void SetSendStream(VideoSendStream* stream);
55 void SetReceiveStream(VideoReceiveStream* stream);
Christoffer Rodbroc2a02882018-08-07 14:10:56 +020056 void SetAudioReceiveStream(AudioReceiveStream* recv_stream);
57
Sebastian Janssond4c5d632018-07-10 12:57:37 +020058 rtc::VideoSinkInterface<VideoFrame>* InputInterface();
59 rtc::VideoSourceInterface<VideoFrame>* OutputInterface();
60
61 DeliveryStatus DeliverPacket(MediaType media_type,
62 rtc::CopyOnWriteBuffer packet,
Niels Möller70082872018-08-07 11:03:12 +020063 int64_t packet_time_us) override;
Sebastian Janssond4c5d632018-07-10 12:57:37 +020064
65 void PreEncodeOnFrame(const VideoFrame& video_frame);
Niels Möller88be9722018-10-10 10:58:52 +020066 void PostEncodeOnFrame(size_t stream_id, uint32_t timestamp);
Sebastian Janssond4c5d632018-07-10 12:57:37 +020067
68 bool SendRtp(const uint8_t* packet,
69 size_t length,
70 const PacketOptions& options) override;
71
72 bool SendRtcp(const uint8_t* packet, size_t length) override;
73 void OnFrame(const VideoFrame& video_frame) override;
74 void Wait();
75
Sebastian Janssond4c5d632018-07-10 12:57:37 +020076 void StartMeasuringCpuProcessTime();
77 void StopMeasuringCpuProcessTime();
78 void StartExcludingCpuThreadTime();
79 void StopExcludingCpuThreadTime();
80 double GetCpuUsagePercent();
81
82 test::LayerFilteringTransport* const transport_;
83 PacketReceiver* receiver_;
84
85 private:
86 struct FrameComparison {
87 FrameComparison();
88 FrameComparison(const VideoFrame& reference,
89 const VideoFrame& render,
90 bool dropped,
91 int64_t input_time_ms,
92 int64_t send_time_ms,
93 int64_t recv_time_ms,
94 int64_t render_time_ms,
95 size_t encoded_frame_size);
96 FrameComparison(bool dropped,
97 int64_t input_time_ms,
98 int64_t send_time_ms,
99 int64_t recv_time_ms,
100 int64_t render_time_ms,
101 size_t encoded_frame_size);
102
103 absl::optional<VideoFrame> reference;
104 absl::optional<VideoFrame> render;
105 bool dropped;
106 int64_t input_time_ms;
107 int64_t send_time_ms;
108 int64_t recv_time_ms;
109 int64_t render_time_ms;
110 size_t encoded_frame_size;
111 };
112
113 struct Sample {
114 Sample(int dropped,
115 int64_t input_time_ms,
116 int64_t send_time_ms,
117 int64_t recv_time_ms,
118 int64_t render_time_ms,
119 size_t encoded_frame_size,
120 double psnr,
121 double ssim);
122
123 int dropped;
124 int64_t input_time_ms;
125 int64_t send_time_ms;
126 int64_t recv_time_ms;
127 int64_t render_time_ms;
128 size_t encoded_frame_size;
129 double psnr;
130 double ssim;
131 };
132
Sebastian Janssond4c5d632018-07-10 12:57:37 +0200133 // Implements VideoSinkInterface to receive captured frames from a
134 // FrameGeneratorCapturer. Implements VideoSourceInterface to be able to act
135 // as a source to VideoSendStream.
136 // It forwards all input frames to the VideoAnalyzer for later comparison and
137 // forwards the captured frames to the VideoSendStream.
138 class CapturedFrameForwarder : public rtc::VideoSinkInterface<VideoFrame>,
139 public rtc::VideoSourceInterface<VideoFrame> {
140 public:
Ilya Nikolaevskiy6957abe2019-01-29 16:33:04 +0100141 CapturedFrameForwarder(VideoAnalyzer* analyzer,
142 Clock* clock,
Ilya Nikolaevskiy1f0a84a2019-02-05 14:35:33 +0100143 int frames_to_process,
144 bool partial_updates);
Niels Möller1c931c42018-12-18 16:08:11 +0100145 void SetSource(rtc::VideoSourceInterface<VideoFrame>* video_source);
Sebastian Janssond4c5d632018-07-10 12:57:37 +0200146
147 private:
148 void OnFrame(const VideoFrame& video_frame) override;
149
150 // Called when |send_stream_.SetSource()| is called.
151 void AddOrUpdateSink(rtc::VideoSinkInterface<VideoFrame>* sink,
152 const rtc::VideoSinkWants& wants) override;
153
154 // Called by |send_stream_| when |send_stream_.SetSource()| is called.
155 void RemoveSink(rtc::VideoSinkInterface<VideoFrame>* sink) override;
156
157 VideoAnalyzer* const analyzer_;
158 rtc::CriticalSection crit_;
159 rtc::VideoSinkInterface<VideoFrame>* send_stream_input_
160 RTC_GUARDED_BY(crit_);
Niels Möller1c931c42018-12-18 16:08:11 +0100161 VideoSourceInterface<VideoFrame>* video_source_;
Sebastian Janssond4c5d632018-07-10 12:57:37 +0200162 Clock* clock_;
Ilya Nikolaevskiy6957abe2019-01-29 16:33:04 +0100163 int captured_frames_ RTC_GUARDED_BY(crit_);
164 int frames_to_process_ RTC_GUARDED_BY(crit_);
Ilya Nikolaevskiy1f0a84a2019-02-05 14:35:33 +0100165 std::unique_ptr<FrameChangeExtractor> frame_change_extractor_;
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
183 static void PollStatsThread(void* obj);
184 void PollStats();
185 static bool FrameComparisonThread(void* obj);
186 bool CompareFrames();
187 bool PopComparison(FrameComparison* comparison);
188 // Increment counter for number of frames received for comparison.
189 void FrameRecorded();
190 // Returns true if all frames to be compared have been taken from the queue.
191 bool AllFramesRecorded();
192 // Increase count of number of frames processed. Returns true if this was the
193 // last frame to be processed.
194 bool FrameProcessed();
195 void PrintResults();
196 void PerformFrameComparison(const FrameComparison& comparison);
197 void PrintResult(const char* result_type,
198 test::Statistics stats,
199 const char* unit);
200 void PrintSamplesToFile(void);
201 double GetAverageMediaBitrateBps();
202 void AddCapturedFrameForComparison(const VideoFrame& video_frame);
203
204 Call* call_;
205 VideoSendStream* send_stream_;
206 VideoReceiveStream* receive_stream_;
Christoffer Rodbroc2a02882018-08-07 14:10:56 +0200207 AudioReceiveStream* audio_receive_stream_;
Sebastian Janssond4c5d632018-07-10 12:57:37 +0200208 CapturedFrameForwarder captured_frame_forwarder_;
209 const std::string test_label_;
210 FILE* const graph_data_output_file_;
211 const std::string graph_title_;
212 const uint32_t ssrc_to_analyze_;
213 const uint32_t rtx_ssrc_to_analyze_;
214 const size_t selected_stream_;
215 const int selected_sl_;
216 const int selected_tl_;
Sebastian Janssond4c5d632018-07-10 12:57:37 +0200217
218 rtc::CriticalSection comparison_lock_;
219 std::vector<Sample> samples_ RTC_GUARDED_BY(comparison_lock_);
220 test::Statistics sender_time_ RTC_GUARDED_BY(comparison_lock_);
221 test::Statistics receiver_time_ RTC_GUARDED_BY(comparison_lock_);
222 test::Statistics network_time_ RTC_GUARDED_BY(comparison_lock_);
223 test::Statistics psnr_ RTC_GUARDED_BY(comparison_lock_);
224 test::Statistics ssim_ RTC_GUARDED_BY(comparison_lock_);
225 test::Statistics end_to_end_ RTC_GUARDED_BY(comparison_lock_);
226 test::Statistics rendered_delta_ RTC_GUARDED_BY(comparison_lock_);
227 test::Statistics encoded_frame_size_ RTC_GUARDED_BY(comparison_lock_);
228 test::Statistics encode_frame_rate_ RTC_GUARDED_BY(comparison_lock_);
229 test::Statistics encode_time_ms_ RTC_GUARDED_BY(comparison_lock_);
230 test::Statistics encode_usage_percent_ RTC_GUARDED_BY(comparison_lock_);
231 test::Statistics decode_time_ms_ RTC_GUARDED_BY(comparison_lock_);
232 test::Statistics decode_time_max_ms_ RTC_GUARDED_BY(comparison_lock_);
233 test::Statistics media_bitrate_bps_ RTC_GUARDED_BY(comparison_lock_);
234 test::Statistics fec_bitrate_bps_ RTC_GUARDED_BY(comparison_lock_);
235 test::Statistics send_bandwidth_bps_ RTC_GUARDED_BY(comparison_lock_);
236 test::Statistics memory_usage_ RTC_GUARDED_BY(comparison_lock_);
237 test::Statistics time_between_freezes_ RTC_GUARDED_BY(comparison_lock_);
Christoffer Rodbroc2a02882018-08-07 14:10:56 +0200238 test::Statistics audio_expand_rate_ RTC_GUARDED_BY(comparison_lock_);
239 test::Statistics audio_accelerate_rate_ RTC_GUARDED_BY(comparison_lock_);
240 test::Statistics audio_jitter_buffer_ms_ RTC_GUARDED_BY(comparison_lock_);
Ilya Nikolaevskiyd47d3eb2019-01-21 16:27:17 +0100241 test::Statistics pixels_ RTC_GUARDED_BY(comparison_lock_);
Sebastian Janssond4c5d632018-07-10 12:57:37 +0200242 // Rendered frame with worst PSNR is saved for further analysis.
243 absl::optional<FrameWithPsnr> worst_frame_ RTC_GUARDED_BY(comparison_lock_);
244
245 size_t last_fec_bytes_;
246
247 const int frames_to_process_;
248 int frames_recorded_;
249 int frames_processed_;
250 int dropped_frames_;
Ilya Nikolaevskiy6957abe2019-01-29 16:33:04 +0100251 int captured_frames_;
Sebastian Janssond4c5d632018-07-10 12:57:37 +0200252 int dropped_frames_before_first_encode_;
253 int dropped_frames_before_rendering_;
254 int64_t last_render_time_;
255 int64_t last_render_delta_ms_;
256 int64_t last_unfreeze_time_ms_;
257 uint32_t rtp_timestamp_delta_;
258 int64_t total_media_bytes_;
259 int64_t first_sending_time_;
260 int64_t last_sending_time_;
261
262 rtc::CriticalSection cpu_measurement_lock_;
263 int64_t cpu_time_ RTC_GUARDED_BY(cpu_measurement_lock_);
264 int64_t wallclock_time_ RTC_GUARDED_BY(cpu_measurement_lock_);
265
266 rtc::CriticalSection crit_;
267 std::deque<VideoFrame> frames_ RTC_GUARDED_BY(crit_);
268 absl::optional<VideoFrame> last_rendered_frame_ RTC_GUARDED_BY(crit_);
269 rtc::TimestampWrapAroundHandler wrap_handler_ RTC_GUARDED_BY(crit_);
270 std::map<int64_t, int64_t> send_times_ RTC_GUARDED_BY(crit_);
271 std::map<int64_t, int64_t> recv_times_ RTC_GUARDED_BY(crit_);
272 std::map<int64_t, size_t> encoded_frame_sizes_ RTC_GUARDED_BY(crit_);
273 absl::optional<uint32_t> first_encoded_timestamp_ RTC_GUARDED_BY(crit_);
274 absl::optional<uint32_t> first_sent_timestamp_ RTC_GUARDED_BY(crit_);
275 const double avg_psnr_threshold_;
276 const double avg_ssim_threshold_;
277 bool is_quick_test_enabled_;
278
279 std::vector<rtc::PlatformThread*> comparison_thread_pool_;
280 rtc::PlatformThread stats_polling_thread_;
281 rtc::Event comparison_available_event_;
282 std::deque<FrameComparison> comparisons_ RTC_GUARDED_BY(comparison_lock_);
283 rtc::Event done_;
284
285 std::unique_ptr<test::RtpFileWriter> rtp_file_writer_;
286 Clock* const clock_;
287 const int64_t start_ms_;
288};
289
290} // namespace webrtc
291#endif // VIDEO_VIDEO_ANALYZER_H_