blob: c40018885f5510f40ae49e38693be767b0ec3053 [file] [log] [blame]
Sebastian Janssond4c5d632018-07-10 10:57:371/*
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 15:08:1119#include "api/video/video_source_interface.h"
Bjorn Terelius5c2f1f02019-01-16 16:45:0520#include "rtc_base/time_utils.h"
Sebastian Janssond4c5d632018-07-10 10:57:3721#include "test/layer_filtering_transport.h"
22#include "test/rtp_file_writer.h"
23#include "test/statistics.h"
Sebastian Janssond4c5d632018-07-10 10:57:3724
25namespace webrtc {
26
27class VideoAnalyzer : public PacketReceiver,
28 public Transport,
Niels Möller88be9722018-10-10 08:58:5229 public rtc::VideoSinkInterface<VideoFrame> {
Sebastian Janssond4c5d632018-07-10 10:57:3730 public:
31 VideoAnalyzer(test::LayerFilteringTransport* transport,
32 const std::string& test_label,
33 double avg_psnr_threshold,
34 double avg_ssim_threshold,
35 int duration_frames,
36 FILE* graph_data_output_file,
37 const std::string& graph_title,
38 uint32_t ssrc_to_analyze,
39 uint32_t rtx_ssrc_to_analyze,
40 size_t selected_stream,
41 int selected_sl,
42 int selected_tl,
43 bool is_quick_test_enabled,
44 Clock* clock,
Artem Titovf537da62019-04-02 11:46:5345 std::string rtp_dump_name,
46 test::SingleThreadedTaskQueueForTesting* task_queue);
Sebastian Janssond4c5d632018-07-10 10:57:3747 ~VideoAnalyzer();
48
49 virtual void SetReceiver(PacketReceiver* receiver);
Niels Möller1c931c42018-12-18 15:08:1150 void SetSource(rtc::VideoSourceInterface<VideoFrame>* video_source,
Sebastian Janssonf1f363f2018-08-13 12:24:5851 bool respect_sink_wants);
Sebastian Janssond4c5d632018-07-10 10:57:3752 void SetCall(Call* call);
53 void SetSendStream(VideoSendStream* stream);
54 void SetReceiveStream(VideoReceiveStream* stream);
Christoffer Rodbroc2a02882018-08-07 12:10:5655 void SetAudioReceiveStream(AudioReceiveStream* recv_stream);
56
Sebastian Janssond4c5d632018-07-10 10:57:3757 rtc::VideoSinkInterface<VideoFrame>* InputInterface();
58 rtc::VideoSourceInterface<VideoFrame>* OutputInterface();
59
60 DeliveryStatus DeliverPacket(MediaType media_type,
61 rtc::CopyOnWriteBuffer packet,
Niels Möller70082872018-08-07 09:03:1262 int64_t packet_time_us) override;
Sebastian Janssond4c5d632018-07-10 10:57:3763
64 void PreEncodeOnFrame(const VideoFrame& video_frame);
Niels Möller88be9722018-10-10 08:58:5265 void PostEncodeOnFrame(size_t stream_id, uint32_t timestamp);
Sebastian Janssond4c5d632018-07-10 10:57:3766
67 bool SendRtp(const uint8_t* packet,
68 size_t length,
69 const PacketOptions& options) override;
70
71 bool SendRtcp(const uint8_t* packet, size_t length) override;
72 void OnFrame(const VideoFrame& video_frame) override;
73 void Wait();
74
Sebastian Janssond4c5d632018-07-10 10:57:3775 void StartMeasuringCpuProcessTime();
76 void StopMeasuringCpuProcessTime();
77 void StartExcludingCpuThreadTime();
78 void StopExcludingCpuThreadTime();
79 double GetCpuUsagePercent();
80
81 test::LayerFilteringTransport* const transport_;
82 PacketReceiver* receiver_;
83
84 private:
85 struct FrameComparison {
86 FrameComparison();
87 FrameComparison(const VideoFrame& reference,
88 const VideoFrame& render,
89 bool dropped,
90 int64_t input_time_ms,
91 int64_t send_time_ms,
92 int64_t recv_time_ms,
93 int64_t render_time_ms,
94 size_t encoded_frame_size);
95 FrameComparison(bool dropped,
96 int64_t input_time_ms,
97 int64_t send_time_ms,
98 int64_t recv_time_ms,
99 int64_t render_time_ms,
100 size_t encoded_frame_size);
101
102 absl::optional<VideoFrame> reference;
103 absl::optional<VideoFrame> render;
104 bool dropped;
105 int64_t input_time_ms;
106 int64_t send_time_ms;
107 int64_t recv_time_ms;
108 int64_t render_time_ms;
109 size_t encoded_frame_size;
110 };
111
112 struct Sample {
113 Sample(int dropped,
114 int64_t input_time_ms,
115 int64_t send_time_ms,
116 int64_t recv_time_ms,
117 int64_t render_time_ms,
118 size_t encoded_frame_size,
119 double psnr,
120 double ssim);
121
122 int dropped;
123 int64_t input_time_ms;
124 int64_t send_time_ms;
125 int64_t recv_time_ms;
126 int64_t render_time_ms;
127 size_t encoded_frame_size;
128 double psnr;
129 double ssim;
130 };
131
Sebastian Janssond4c5d632018-07-10 10:57:37132 // Implements VideoSinkInterface to receive captured frames from a
133 // FrameGeneratorCapturer. Implements VideoSourceInterface to be able to act
134 // as a source to VideoSendStream.
135 // It forwards all input frames to the VideoAnalyzer for later comparison and
136 // forwards the captured frames to the VideoSendStream.
137 class CapturedFrameForwarder : public rtc::VideoSinkInterface<VideoFrame>,
138 public rtc::VideoSourceInterface<VideoFrame> {
139 public:
Ilya Nikolaevskiy6957abe2019-01-29 15:33:04140 CapturedFrameForwarder(VideoAnalyzer* analyzer,
141 Clock* clock,
Ilya Nikolaevskiy85fc3252019-02-11 09:41:50142 int frames_to_process);
Niels Möller1c931c42018-12-18 15:08:11143 void SetSource(rtc::VideoSourceInterface<VideoFrame>* video_source);
Sebastian Janssond4c5d632018-07-10 10:57:37144
145 private:
146 void OnFrame(const VideoFrame& video_frame) override;
147
148 // Called when |send_stream_.SetSource()| is called.
149 void AddOrUpdateSink(rtc::VideoSinkInterface<VideoFrame>* sink,
150 const rtc::VideoSinkWants& wants) override;
151
152 // Called by |send_stream_| when |send_stream_.SetSource()| is called.
153 void RemoveSink(rtc::VideoSinkInterface<VideoFrame>* sink) override;
154
155 VideoAnalyzer* const analyzer_;
156 rtc::CriticalSection crit_;
157 rtc::VideoSinkInterface<VideoFrame>* send_stream_input_
158 RTC_GUARDED_BY(crit_);
Niels Möller1c931c42018-12-18 15:08:11159 VideoSourceInterface<VideoFrame>* video_source_;
Sebastian Janssond4c5d632018-07-10 10:57:37160 Clock* clock_;
Ilya Nikolaevskiy6957abe2019-01-29 15:33:04161 int captured_frames_ RTC_GUARDED_BY(crit_);
162 int frames_to_process_ RTC_GUARDED_BY(crit_);
Sebastian Janssond4c5d632018-07-10 10:57:37163 };
164
165 struct FrameWithPsnr {
166 double psnr;
167 VideoFrame frame;
168 };
169
170 bool IsInSelectedSpatialAndTemporalLayer(const uint8_t* packet,
171 size_t length,
172 const RTPHeader& header);
173
174 void AddFrameComparison(const VideoFrame& reference,
175 const VideoFrame& render,
176 bool dropped,
177 int64_t render_time_ms)
178 RTC_EXCLUSIVE_LOCKS_REQUIRED(crit_);
179
Sebastian Janssond4c5d632018-07-10 10:57:37180 void PollStats();
181 static bool FrameComparisonThread(void* obj);
182 bool CompareFrames();
183 bool PopComparison(FrameComparison* comparison);
184 // Increment counter for number of frames received for comparison.
185 void FrameRecorded();
186 // Returns true if all frames to be compared have been taken from the queue.
187 bool AllFramesRecorded();
188 // Increase count of number of frames processed. Returns true if this was the
189 // last frame to be processed.
190 bool FrameProcessed();
191 void PrintResults();
192 void PerformFrameComparison(const FrameComparison& comparison);
193 void PrintResult(const char* result_type,
194 test::Statistics stats,
195 const char* unit);
196 void PrintSamplesToFile(void);
197 double GetAverageMediaBitrateBps();
198 void AddCapturedFrameForComparison(const VideoFrame& video_frame);
199
200 Call* call_;
201 VideoSendStream* send_stream_;
202 VideoReceiveStream* receive_stream_;
Christoffer Rodbroc2a02882018-08-07 12:10:56203 AudioReceiveStream* audio_receive_stream_;
Sebastian Janssond4c5d632018-07-10 10:57:37204 CapturedFrameForwarder captured_frame_forwarder_;
205 const std::string test_label_;
206 FILE* const graph_data_output_file_;
207 const std::string graph_title_;
208 const uint32_t ssrc_to_analyze_;
209 const uint32_t rtx_ssrc_to_analyze_;
210 const size_t selected_stream_;
211 const int selected_sl_;
212 const int selected_tl_;
Sebastian Janssond4c5d632018-07-10 10:57:37213
214 rtc::CriticalSection comparison_lock_;
215 std::vector<Sample> samples_ RTC_GUARDED_BY(comparison_lock_);
216 test::Statistics sender_time_ RTC_GUARDED_BY(comparison_lock_);
217 test::Statistics receiver_time_ RTC_GUARDED_BY(comparison_lock_);
218 test::Statistics network_time_ RTC_GUARDED_BY(comparison_lock_);
219 test::Statistics psnr_ RTC_GUARDED_BY(comparison_lock_);
220 test::Statistics ssim_ RTC_GUARDED_BY(comparison_lock_);
221 test::Statistics end_to_end_ RTC_GUARDED_BY(comparison_lock_);
222 test::Statistics rendered_delta_ RTC_GUARDED_BY(comparison_lock_);
223 test::Statistics encoded_frame_size_ RTC_GUARDED_BY(comparison_lock_);
224 test::Statistics encode_frame_rate_ RTC_GUARDED_BY(comparison_lock_);
225 test::Statistics encode_time_ms_ RTC_GUARDED_BY(comparison_lock_);
226 test::Statistics encode_usage_percent_ RTC_GUARDED_BY(comparison_lock_);
227 test::Statistics decode_time_ms_ RTC_GUARDED_BY(comparison_lock_);
228 test::Statistics decode_time_max_ms_ RTC_GUARDED_BY(comparison_lock_);
229 test::Statistics media_bitrate_bps_ RTC_GUARDED_BY(comparison_lock_);
230 test::Statistics fec_bitrate_bps_ RTC_GUARDED_BY(comparison_lock_);
231 test::Statistics send_bandwidth_bps_ RTC_GUARDED_BY(comparison_lock_);
232 test::Statistics memory_usage_ RTC_GUARDED_BY(comparison_lock_);
233 test::Statistics time_between_freezes_ RTC_GUARDED_BY(comparison_lock_);
Christoffer Rodbroc2a02882018-08-07 12:10:56234 test::Statistics audio_expand_rate_ RTC_GUARDED_BY(comparison_lock_);
235 test::Statistics audio_accelerate_rate_ RTC_GUARDED_BY(comparison_lock_);
236 test::Statistics audio_jitter_buffer_ms_ RTC_GUARDED_BY(comparison_lock_);
Ilya Nikolaevskiyd47d3eb2019-01-21 15:27:17237 test::Statistics pixels_ RTC_GUARDED_BY(comparison_lock_);
Sebastian Janssond4c5d632018-07-10 10:57:37238 // Rendered frame with worst PSNR is saved for further analysis.
239 absl::optional<FrameWithPsnr> worst_frame_ RTC_GUARDED_BY(comparison_lock_);
240
241 size_t last_fec_bytes_;
242
243 const int frames_to_process_;
244 int frames_recorded_;
245 int frames_processed_;
246 int dropped_frames_;
Ilya Nikolaevskiy6957abe2019-01-29 15:33:04247 int captured_frames_;
Sebastian Janssond4c5d632018-07-10 10:57:37248 int dropped_frames_before_first_encode_;
249 int dropped_frames_before_rendering_;
250 int64_t last_render_time_;
251 int64_t last_render_delta_ms_;
252 int64_t last_unfreeze_time_ms_;
253 uint32_t rtp_timestamp_delta_;
254 int64_t total_media_bytes_;
255 int64_t first_sending_time_;
256 int64_t last_sending_time_;
257
258 rtc::CriticalSection cpu_measurement_lock_;
259 int64_t cpu_time_ RTC_GUARDED_BY(cpu_measurement_lock_);
260 int64_t wallclock_time_ RTC_GUARDED_BY(cpu_measurement_lock_);
261
262 rtc::CriticalSection crit_;
263 std::deque<VideoFrame> frames_ RTC_GUARDED_BY(crit_);
264 absl::optional<VideoFrame> last_rendered_frame_ RTC_GUARDED_BY(crit_);
265 rtc::TimestampWrapAroundHandler wrap_handler_ RTC_GUARDED_BY(crit_);
266 std::map<int64_t, int64_t> send_times_ RTC_GUARDED_BY(crit_);
267 std::map<int64_t, int64_t> recv_times_ RTC_GUARDED_BY(crit_);
268 std::map<int64_t, size_t> encoded_frame_sizes_ RTC_GUARDED_BY(crit_);
269 absl::optional<uint32_t> first_encoded_timestamp_ RTC_GUARDED_BY(crit_);
270 absl::optional<uint32_t> first_sent_timestamp_ RTC_GUARDED_BY(crit_);
271 const double avg_psnr_threshold_;
272 const double avg_ssim_threshold_;
273 bool is_quick_test_enabled_;
274
275 std::vector<rtc::PlatformThread*> comparison_thread_pool_;
Sebastian Janssond4c5d632018-07-10 10:57:37276 rtc::Event comparison_available_event_;
277 std::deque<FrameComparison> comparisons_ RTC_GUARDED_BY(comparison_lock_);
278 rtc::Event done_;
Artem Titovf537da62019-04-02 11:46:53279 test::SingleThreadedTaskQueueForTesting::TaskId stats_polling_task_id_
280 RTC_GUARDED_BY(comparison_lock_);
281 bool stop_stats_poller_ RTC_GUARDED_BY(comparison_lock_);
Sebastian Janssond4c5d632018-07-10 10:57:37282
283 std::unique_ptr<test::RtpFileWriter> rtp_file_writer_;
284 Clock* const clock_;
285 const int64_t start_ms_;
Artem Titovf537da62019-04-02 11:46:53286 test::SingleThreadedTaskQueueForTesting* task_queue_;
Sebastian Janssond4c5d632018-07-10 10:57:37287};
288
289} // namespace webrtc
290#endif // VIDEO_VIDEO_ANALYZER_H_