blob: fffc784cf210b4eacdc7219410b4cd6142195961 [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"
Sebastian Janssond4c5d632018-07-10 12:57:37 +020020#include "test/layer_filtering_transport.h"
21#include "test/rtp_file_writer.h"
22#include "test/statistics.h"
Sebastian Janssond4c5d632018-07-10 12:57:37 +020023
24namespace webrtc {
25
26class VideoAnalyzer : public PacketReceiver,
27 public Transport,
Niels Möller88be9722018-10-10 10:58:52 +020028 public rtc::VideoSinkInterface<VideoFrame> {
Sebastian Janssond4c5d632018-07-10 12:57:37 +020029 public:
30 VideoAnalyzer(test::LayerFilteringTransport* transport,
31 const std::string& test_label,
32 double avg_psnr_threshold,
33 double avg_ssim_threshold,
34 int duration_frames,
35 FILE* graph_data_output_file,
36 const std::string& graph_title,
37 uint32_t ssrc_to_analyze,
38 uint32_t rtx_ssrc_to_analyze,
39 size_t selected_stream,
40 int selected_sl,
41 int selected_tl,
42 bool is_quick_test_enabled,
43 Clock* clock,
44 std::string rtp_dump_name);
45 ~VideoAnalyzer();
46
47 virtual void SetReceiver(PacketReceiver* receiver);
Niels Möller1c931c42018-12-18 16:08:11 +010048 void SetSource(rtc::VideoSourceInterface<VideoFrame>* video_source,
Sebastian Janssonf1f363f2018-08-13 14:24:58 +020049 bool respect_sink_wants);
Sebastian Janssond4c5d632018-07-10 12:57:37 +020050 void SetCall(Call* call);
51 void SetSendStream(VideoSendStream* stream);
52 void SetReceiveStream(VideoReceiveStream* stream);
Christoffer Rodbroc2a02882018-08-07 14:10:56 +020053 void SetAudioReceiveStream(AudioReceiveStream* recv_stream);
54
Sebastian Janssond4c5d632018-07-10 12:57:37 +020055 rtc::VideoSinkInterface<VideoFrame>* InputInterface();
56 rtc::VideoSourceInterface<VideoFrame>* OutputInterface();
57
58 DeliveryStatus DeliverPacket(MediaType media_type,
59 rtc::CopyOnWriteBuffer packet,
Niels Möller70082872018-08-07 11:03:12 +020060 int64_t packet_time_us) override;
Sebastian Janssond4c5d632018-07-10 12:57:37 +020061
62 void PreEncodeOnFrame(const VideoFrame& video_frame);
Niels Möller88be9722018-10-10 10:58:52 +020063 void PostEncodeOnFrame(size_t stream_id, uint32_t timestamp);
Sebastian Janssond4c5d632018-07-10 12:57:37 +020064
65 bool SendRtp(const uint8_t* packet,
66 size_t length,
67 const PacketOptions& options) override;
68
69 bool SendRtcp(const uint8_t* packet, size_t length) override;
70 void OnFrame(const VideoFrame& video_frame) override;
71 void Wait();
72
Sebastian Janssond4c5d632018-07-10 12:57:37 +020073 void StartMeasuringCpuProcessTime();
74 void StopMeasuringCpuProcessTime();
75 void StartExcludingCpuThreadTime();
76 void StopExcludingCpuThreadTime();
77 double GetCpuUsagePercent();
78
79 test::LayerFilteringTransport* const transport_;
80 PacketReceiver* receiver_;
81
82 private:
83 struct FrameComparison {
84 FrameComparison();
85 FrameComparison(const VideoFrame& reference,
86 const VideoFrame& render,
87 bool dropped,
88 int64_t input_time_ms,
89 int64_t send_time_ms,
90 int64_t recv_time_ms,
91 int64_t render_time_ms,
92 size_t encoded_frame_size);
93 FrameComparison(bool dropped,
94 int64_t input_time_ms,
95 int64_t send_time_ms,
96 int64_t recv_time_ms,
97 int64_t render_time_ms,
98 size_t encoded_frame_size);
99
100 absl::optional<VideoFrame> reference;
101 absl::optional<VideoFrame> render;
102 bool dropped;
103 int64_t input_time_ms;
104 int64_t send_time_ms;
105 int64_t recv_time_ms;
106 int64_t render_time_ms;
107 size_t encoded_frame_size;
108 };
109
110 struct Sample {
111 Sample(int dropped,
112 int64_t input_time_ms,
113 int64_t send_time_ms,
114 int64_t recv_time_ms,
115 int64_t render_time_ms,
116 size_t encoded_frame_size,
117 double psnr,
118 double ssim);
119
120 int dropped;
121 int64_t input_time_ms;
122 int64_t send_time_ms;
123 int64_t recv_time_ms;
124 int64_t render_time_ms;
125 size_t encoded_frame_size;
126 double psnr;
127 double ssim;
128 };
129
Sebastian Janssond4c5d632018-07-10 12:57:37 +0200130 // Implements VideoSinkInterface to receive captured frames from a
131 // FrameGeneratorCapturer. Implements VideoSourceInterface to be able to act
132 // as a source to VideoSendStream.
133 // It forwards all input frames to the VideoAnalyzer for later comparison and
134 // forwards the captured frames to the VideoSendStream.
135 class CapturedFrameForwarder : public rtc::VideoSinkInterface<VideoFrame>,
136 public rtc::VideoSourceInterface<VideoFrame> {
137 public:
138 explicit CapturedFrameForwarder(VideoAnalyzer* analyzer, Clock* clock);
Niels Möller1c931c42018-12-18 16:08:11 +0100139 void SetSource(rtc::VideoSourceInterface<VideoFrame>* video_source);
Sebastian Janssond4c5d632018-07-10 12:57:37 +0200140
141 private:
142 void OnFrame(const VideoFrame& video_frame) override;
143
144 // Called when |send_stream_.SetSource()| is called.
145 void AddOrUpdateSink(rtc::VideoSinkInterface<VideoFrame>* sink,
146 const rtc::VideoSinkWants& wants) override;
147
148 // Called by |send_stream_| when |send_stream_.SetSource()| is called.
149 void RemoveSink(rtc::VideoSinkInterface<VideoFrame>* sink) override;
150
151 VideoAnalyzer* const analyzer_;
152 rtc::CriticalSection crit_;
153 rtc::VideoSinkInterface<VideoFrame>* send_stream_input_
154 RTC_GUARDED_BY(crit_);
Niels Möller1c931c42018-12-18 16:08:11 +0100155 VideoSourceInterface<VideoFrame>* video_source_;
Sebastian Janssond4c5d632018-07-10 12:57:37 +0200156 Clock* clock_;
157 };
158
159 struct FrameWithPsnr {
160 double psnr;
161 VideoFrame frame;
162 };
163
164 bool IsInSelectedSpatialAndTemporalLayer(const uint8_t* packet,
165 size_t length,
166 const RTPHeader& header);
167
168 void AddFrameComparison(const VideoFrame& reference,
169 const VideoFrame& render,
170 bool dropped,
171 int64_t render_time_ms)
172 RTC_EXCLUSIVE_LOCKS_REQUIRED(crit_);
173
174 static void PollStatsThread(void* obj);
175 void PollStats();
176 static bool FrameComparisonThread(void* obj);
177 bool CompareFrames();
178 bool PopComparison(FrameComparison* comparison);
179 // Increment counter for number of frames received for comparison.
180 void FrameRecorded();
181 // Returns true if all frames to be compared have been taken from the queue.
182 bool AllFramesRecorded();
183 // Increase count of number of frames processed. Returns true if this was the
184 // last frame to be processed.
185 bool FrameProcessed();
186 void PrintResults();
187 void PerformFrameComparison(const FrameComparison& comparison);
188 void PrintResult(const char* result_type,
189 test::Statistics stats,
190 const char* unit);
191 void PrintSamplesToFile(void);
192 double GetAverageMediaBitrateBps();
193 void AddCapturedFrameForComparison(const VideoFrame& video_frame);
194
195 Call* call_;
196 VideoSendStream* send_stream_;
197 VideoReceiveStream* receive_stream_;
Christoffer Rodbroc2a02882018-08-07 14:10:56 +0200198 AudioReceiveStream* audio_receive_stream_;
Sebastian Janssond4c5d632018-07-10 12:57:37 +0200199 CapturedFrameForwarder captured_frame_forwarder_;
200 const std::string test_label_;
201 FILE* const graph_data_output_file_;
202 const std::string graph_title_;
203 const uint32_t ssrc_to_analyze_;
204 const uint32_t rtx_ssrc_to_analyze_;
205 const size_t selected_stream_;
206 const int selected_sl_;
207 const int selected_tl_;
Sebastian Janssond4c5d632018-07-10 12:57:37 +0200208
209 rtc::CriticalSection comparison_lock_;
210 std::vector<Sample> samples_ RTC_GUARDED_BY(comparison_lock_);
211 test::Statistics sender_time_ RTC_GUARDED_BY(comparison_lock_);
212 test::Statistics receiver_time_ RTC_GUARDED_BY(comparison_lock_);
213 test::Statistics network_time_ RTC_GUARDED_BY(comparison_lock_);
214 test::Statistics psnr_ RTC_GUARDED_BY(comparison_lock_);
215 test::Statistics ssim_ RTC_GUARDED_BY(comparison_lock_);
216 test::Statistics end_to_end_ RTC_GUARDED_BY(comparison_lock_);
217 test::Statistics rendered_delta_ RTC_GUARDED_BY(comparison_lock_);
218 test::Statistics encoded_frame_size_ RTC_GUARDED_BY(comparison_lock_);
219 test::Statistics encode_frame_rate_ RTC_GUARDED_BY(comparison_lock_);
220 test::Statistics encode_time_ms_ RTC_GUARDED_BY(comparison_lock_);
221 test::Statistics encode_usage_percent_ RTC_GUARDED_BY(comparison_lock_);
222 test::Statistics decode_time_ms_ RTC_GUARDED_BY(comparison_lock_);
223 test::Statistics decode_time_max_ms_ RTC_GUARDED_BY(comparison_lock_);
224 test::Statistics media_bitrate_bps_ RTC_GUARDED_BY(comparison_lock_);
225 test::Statistics fec_bitrate_bps_ RTC_GUARDED_BY(comparison_lock_);
226 test::Statistics send_bandwidth_bps_ RTC_GUARDED_BY(comparison_lock_);
227 test::Statistics memory_usage_ RTC_GUARDED_BY(comparison_lock_);
228 test::Statistics time_between_freezes_ RTC_GUARDED_BY(comparison_lock_);
Christoffer Rodbroc2a02882018-08-07 14:10:56 +0200229 test::Statistics audio_expand_rate_ RTC_GUARDED_BY(comparison_lock_);
230 test::Statistics audio_accelerate_rate_ RTC_GUARDED_BY(comparison_lock_);
231 test::Statistics audio_jitter_buffer_ms_ RTC_GUARDED_BY(comparison_lock_);
Sebastian Janssond4c5d632018-07-10 12:57:37 +0200232 // Rendered frame with worst PSNR is saved for further analysis.
233 absl::optional<FrameWithPsnr> worst_frame_ RTC_GUARDED_BY(comparison_lock_);
234
235 size_t last_fec_bytes_;
236
237 const int frames_to_process_;
238 int frames_recorded_;
239 int frames_processed_;
240 int dropped_frames_;
241 int dropped_frames_before_first_encode_;
242 int dropped_frames_before_rendering_;
243 int64_t last_render_time_;
244 int64_t last_render_delta_ms_;
245 int64_t last_unfreeze_time_ms_;
246 uint32_t rtp_timestamp_delta_;
247 int64_t total_media_bytes_;
248 int64_t first_sending_time_;
249 int64_t last_sending_time_;
250
251 rtc::CriticalSection cpu_measurement_lock_;
252 int64_t cpu_time_ RTC_GUARDED_BY(cpu_measurement_lock_);
253 int64_t wallclock_time_ RTC_GUARDED_BY(cpu_measurement_lock_);
254
255 rtc::CriticalSection crit_;
256 std::deque<VideoFrame> frames_ RTC_GUARDED_BY(crit_);
257 absl::optional<VideoFrame> last_rendered_frame_ RTC_GUARDED_BY(crit_);
258 rtc::TimestampWrapAroundHandler wrap_handler_ RTC_GUARDED_BY(crit_);
259 std::map<int64_t, int64_t> send_times_ RTC_GUARDED_BY(crit_);
260 std::map<int64_t, int64_t> recv_times_ RTC_GUARDED_BY(crit_);
261 std::map<int64_t, size_t> encoded_frame_sizes_ RTC_GUARDED_BY(crit_);
262 absl::optional<uint32_t> first_encoded_timestamp_ RTC_GUARDED_BY(crit_);
263 absl::optional<uint32_t> first_sent_timestamp_ RTC_GUARDED_BY(crit_);
264 const double avg_psnr_threshold_;
265 const double avg_ssim_threshold_;
266 bool is_quick_test_enabled_;
267
268 std::vector<rtc::PlatformThread*> comparison_thread_pool_;
269 rtc::PlatformThread stats_polling_thread_;
270 rtc::Event comparison_available_event_;
271 std::deque<FrameComparison> comparisons_ RTC_GUARDED_BY(comparison_lock_);
272 rtc::Event done_;
273
274 std::unique_ptr<test::RtpFileWriter> rtp_file_writer_;
275 Clock* const clock_;
276 const int64_t start_ms_;
277};
278
279} // namespace webrtc
280#endif // VIDEO_VIDEO_ANALYZER_H_