blob: b4d31dbaea14b19eb3886f60ae6aaaa59af2cf7b [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
19#include "test/layer_filtering_transport.h"
20#include "test/rtp_file_writer.h"
21#include "test/statistics.h"
22#include "test/vcm_capturer.h"
23
24namespace webrtc {
25
26class VideoAnalyzer : public PacketReceiver,
27 public Transport,
28 public rtc::VideoSinkInterface<VideoFrame>,
29 public EncodedFrameObserver {
30 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,
45 std::string rtp_dump_name);
46 ~VideoAnalyzer();
47
48 virtual void SetReceiver(PacketReceiver* receiver);
49 void SetSource(test::VideoCapturer* video_capturer, bool respect_sink_wants);
50 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);
63
64 // EncodedFrameObserver implementation, wired to post_encode_callback.
65 void EncodedFrameCallback(const EncodedFrame& encoded_frame) override;
66
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
75 rtc::VideoSinkInterface<VideoFrame>* pre_encode_proxy();
76
77 void StartMeasuringCpuProcessTime();
78 void StopMeasuringCpuProcessTime();
79 void StartExcludingCpuThreadTime();
80 void StopExcludingCpuThreadTime();
81 double GetCpuUsagePercent();
82
83 test::LayerFilteringTransport* const transport_;
84 PacketReceiver* receiver_;
85
86 private:
87 struct FrameComparison {
88 FrameComparison();
89 FrameComparison(const VideoFrame& reference,
90 const VideoFrame& render,
91 bool dropped,
92 int64_t input_time_ms,
93 int64_t send_time_ms,
94 int64_t recv_time_ms,
95 int64_t render_time_ms,
96 size_t encoded_frame_size);
97 FrameComparison(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
104 absl::optional<VideoFrame> reference;
105 absl::optional<VideoFrame> render;
106 bool dropped;
107 int64_t input_time_ms;
108 int64_t send_time_ms;
109 int64_t recv_time_ms;
110 int64_t render_time_ms;
111 size_t encoded_frame_size;
112 };
113
114 struct Sample {
115 Sample(int dropped,
116 int64_t input_time_ms,
117 int64_t send_time_ms,
118 int64_t recv_time_ms,
119 int64_t render_time_ms,
120 size_t encoded_frame_size,
121 double psnr,
122 double ssim);
123
124 int dropped;
125 int64_t input_time_ms;
126 int64_t send_time_ms;
127 int64_t recv_time_ms;
128 int64_t render_time_ms;
129 size_t encoded_frame_size;
130 double psnr;
131 double ssim;
132 };
133
134 // This class receives the send-side OnFrame callback and is provided to not
135 // conflict with the receiver-side renderer callback.
136 class PreEncodeProxy : public rtc::VideoSinkInterface<VideoFrame> {
137 public:
138 explicit PreEncodeProxy(VideoAnalyzer* parent);
139 void OnFrame(const VideoFrame& video_frame) override;
140
141 private:
142 VideoAnalyzer* const parent_;
143 };
144
145 // Implements VideoSinkInterface to receive captured frames from a
146 // FrameGeneratorCapturer. Implements VideoSourceInterface to be able to act
147 // as a source to VideoSendStream.
148 // It forwards all input frames to the VideoAnalyzer for later comparison and
149 // forwards the captured frames to the VideoSendStream.
150 class CapturedFrameForwarder : public rtc::VideoSinkInterface<VideoFrame>,
151 public rtc::VideoSourceInterface<VideoFrame> {
152 public:
153 explicit CapturedFrameForwarder(VideoAnalyzer* analyzer, Clock* clock);
154 void SetSource(test::VideoCapturer* video_capturer);
155
156 private:
157 void OnFrame(const VideoFrame& video_frame) override;
158
159 // Called when |send_stream_.SetSource()| is called.
160 void AddOrUpdateSink(rtc::VideoSinkInterface<VideoFrame>* sink,
161 const rtc::VideoSinkWants& wants) override;
162
163 // Called by |send_stream_| when |send_stream_.SetSource()| is called.
164 void RemoveSink(rtc::VideoSinkInterface<VideoFrame>* sink) override;
165
166 VideoAnalyzer* const analyzer_;
167 rtc::CriticalSection crit_;
168 rtc::VideoSinkInterface<VideoFrame>* send_stream_input_
169 RTC_GUARDED_BY(crit_);
170 test::VideoCapturer* video_capturer_;
171 Clock* clock_;
172 };
173
174 struct FrameWithPsnr {
175 double psnr;
176 VideoFrame frame;
177 };
178
179 bool IsInSelectedSpatialAndTemporalLayer(const uint8_t* packet,
180 size_t length,
181 const RTPHeader& header);
182
183 void AddFrameComparison(const VideoFrame& reference,
184 const VideoFrame& render,
185 bool dropped,
186 int64_t render_time_ms)
187 RTC_EXCLUSIVE_LOCKS_REQUIRED(crit_);
188
189 static void PollStatsThread(void* obj);
190 void PollStats();
191 static bool FrameComparisonThread(void* obj);
192 bool CompareFrames();
193 bool PopComparison(FrameComparison* comparison);
194 // Increment counter for number of frames received for comparison.
195 void FrameRecorded();
196 // Returns true if all frames to be compared have been taken from the queue.
197 bool AllFramesRecorded();
198 // Increase count of number of frames processed. Returns true if this was the
199 // last frame to be processed.
200 bool FrameProcessed();
201 void PrintResults();
202 void PerformFrameComparison(const FrameComparison& comparison);
203 void PrintResult(const char* result_type,
204 test::Statistics stats,
205 const char* unit);
206 void PrintSamplesToFile(void);
207 double GetAverageMediaBitrateBps();
208 void AddCapturedFrameForComparison(const VideoFrame& video_frame);
209
210 Call* call_;
211 VideoSendStream* send_stream_;
212 VideoReceiveStream* receive_stream_;
Christoffer Rodbroc2a02882018-08-07 14:10:56 +0200213 AudioReceiveStream* audio_receive_stream_;
Sebastian Janssond4c5d632018-07-10 12:57:37 +0200214 CapturedFrameForwarder captured_frame_forwarder_;
215 const std::string test_label_;
216 FILE* const graph_data_output_file_;
217 const std::string graph_title_;
218 const uint32_t ssrc_to_analyze_;
219 const uint32_t rtx_ssrc_to_analyze_;
220 const size_t selected_stream_;
221 const int selected_sl_;
222 const int selected_tl_;
223 PreEncodeProxy pre_encode_proxy_;
224
225 rtc::CriticalSection comparison_lock_;
226 std::vector<Sample> samples_ RTC_GUARDED_BY(comparison_lock_);
227 test::Statistics sender_time_ RTC_GUARDED_BY(comparison_lock_);
228 test::Statistics receiver_time_ RTC_GUARDED_BY(comparison_lock_);
229 test::Statistics network_time_ RTC_GUARDED_BY(comparison_lock_);
230 test::Statistics psnr_ RTC_GUARDED_BY(comparison_lock_);
231 test::Statistics ssim_ RTC_GUARDED_BY(comparison_lock_);
232 test::Statistics end_to_end_ RTC_GUARDED_BY(comparison_lock_);
233 test::Statistics rendered_delta_ RTC_GUARDED_BY(comparison_lock_);
234 test::Statistics encoded_frame_size_ RTC_GUARDED_BY(comparison_lock_);
235 test::Statistics encode_frame_rate_ RTC_GUARDED_BY(comparison_lock_);
236 test::Statistics encode_time_ms_ RTC_GUARDED_BY(comparison_lock_);
237 test::Statistics encode_usage_percent_ RTC_GUARDED_BY(comparison_lock_);
238 test::Statistics decode_time_ms_ RTC_GUARDED_BY(comparison_lock_);
239 test::Statistics decode_time_max_ms_ RTC_GUARDED_BY(comparison_lock_);
240 test::Statistics media_bitrate_bps_ RTC_GUARDED_BY(comparison_lock_);
241 test::Statistics fec_bitrate_bps_ RTC_GUARDED_BY(comparison_lock_);
242 test::Statistics send_bandwidth_bps_ RTC_GUARDED_BY(comparison_lock_);
243 test::Statistics memory_usage_ RTC_GUARDED_BY(comparison_lock_);
244 test::Statistics time_between_freezes_ RTC_GUARDED_BY(comparison_lock_);
Christoffer Rodbroc2a02882018-08-07 14:10:56 +0200245 test::Statistics audio_expand_rate_ RTC_GUARDED_BY(comparison_lock_);
246 test::Statistics audio_accelerate_rate_ RTC_GUARDED_BY(comparison_lock_);
247 test::Statistics audio_jitter_buffer_ms_ RTC_GUARDED_BY(comparison_lock_);
Sebastian Janssond4c5d632018-07-10 12:57:37 +0200248 // Rendered frame with worst PSNR is saved for further analysis.
249 absl::optional<FrameWithPsnr> worst_frame_ RTC_GUARDED_BY(comparison_lock_);
250
251 size_t last_fec_bytes_;
252
253 const int frames_to_process_;
254 int frames_recorded_;
255 int frames_processed_;
256 int dropped_frames_;
257 int dropped_frames_before_first_encode_;
258 int dropped_frames_before_rendering_;
259 int64_t last_render_time_;
260 int64_t last_render_delta_ms_;
261 int64_t last_unfreeze_time_ms_;
262 uint32_t rtp_timestamp_delta_;
263 int64_t total_media_bytes_;
264 int64_t first_sending_time_;
265 int64_t last_sending_time_;
266
267 rtc::CriticalSection cpu_measurement_lock_;
268 int64_t cpu_time_ RTC_GUARDED_BY(cpu_measurement_lock_);
269 int64_t wallclock_time_ RTC_GUARDED_BY(cpu_measurement_lock_);
270
271 rtc::CriticalSection crit_;
272 std::deque<VideoFrame> frames_ RTC_GUARDED_BY(crit_);
273 absl::optional<VideoFrame> last_rendered_frame_ RTC_GUARDED_BY(crit_);
274 rtc::TimestampWrapAroundHandler wrap_handler_ RTC_GUARDED_BY(crit_);
275 std::map<int64_t, int64_t> send_times_ RTC_GUARDED_BY(crit_);
276 std::map<int64_t, int64_t> recv_times_ RTC_GUARDED_BY(crit_);
277 std::map<int64_t, size_t> encoded_frame_sizes_ RTC_GUARDED_BY(crit_);
278 absl::optional<uint32_t> first_encoded_timestamp_ RTC_GUARDED_BY(crit_);
279 absl::optional<uint32_t> first_sent_timestamp_ RTC_GUARDED_BY(crit_);
280 const double avg_psnr_threshold_;
281 const double avg_ssim_threshold_;
282 bool is_quick_test_enabled_;
283
284 std::vector<rtc::PlatformThread*> comparison_thread_pool_;
285 rtc::PlatformThread stats_polling_thread_;
286 rtc::Event comparison_available_event_;
287 std::deque<FrameComparison> comparisons_ RTC_GUARDED_BY(comparison_lock_);
288 rtc::Event done_;
289
290 std::unique_ptr<test::RtpFileWriter> rtp_file_writer_;
291 Clock* const clock_;
292 const int64_t start_ms_;
293};
294
295} // namespace webrtc
296#endif // VIDEO_VIDEO_ANALYZER_H_