OLD | NEW |
1 /* | 1 /* |
2 * Copyright (c) 2015 The WebRTC project authors. All Rights Reserved. | 2 * Copyright (c) 2015 The WebRTC project authors. All Rights Reserved. |
3 * | 3 * |
4 * Use of this source code is governed by a BSD-style license | 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 | 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 | 6 * tree. An additional intellectual property rights grant can be found |
7 * in the file PATENTS. All contributing project authors may | 7 * in the file PATENTS. All contributing project authors may |
8 * be found in the AUTHORS file in the root of the source tree. | 8 * be found in the AUTHORS file in the root of the source tree. |
9 */ | 9 */ |
10 #include <stdio.h> | 10 #include <stdio.h> |
(...skipping 24 matching lines...) Expand all Loading... |
35 static const int kTransportSeqExtensionId = | 35 static const int kTransportSeqExtensionId = |
36 VideoQualityTest::kAbsSendTimeExtensionId + 1; | 36 VideoQualityTest::kAbsSendTimeExtensionId + 1; |
37 static const int kSendStatsPollingIntervalMs = 1000; | 37 static const int kSendStatsPollingIntervalMs = 1000; |
38 static const int kPayloadTypeVP8 = 123; | 38 static const int kPayloadTypeVP8 = 123; |
39 static const int kPayloadTypeVP9 = 124; | 39 static const int kPayloadTypeVP9 = 124; |
40 | 40 |
41 class VideoAnalyzer : public PacketReceiver, | 41 class VideoAnalyzer : public PacketReceiver, |
42 public Transport, | 42 public Transport, |
43 public VideoRenderer, | 43 public VideoRenderer, |
44 public VideoCaptureInput, | 44 public VideoCaptureInput, |
45 public EncodedFrameObserver, | 45 public EncodedFrameObserver { |
46 public EncodingTimeObserver { | |
47 public: | 46 public: |
48 VideoAnalyzer(Transport* transport, | 47 VideoAnalyzer(VideoCaptureInput* input, |
| 48 Transport* transport, |
49 const std::string& test_label, | 49 const std::string& test_label, |
50 double avg_psnr_threshold, | 50 double avg_psnr_threshold, |
51 double avg_ssim_threshold, | 51 double avg_ssim_threshold, |
52 int duration_frames, | 52 int duration_frames, |
53 FILE* graph_data_output_file) | 53 FILE* graph_data_output_file) |
54 : input_(nullptr), | 54 : input_(input), |
55 transport_(transport), | 55 transport_(transport), |
56 receiver_(nullptr), | 56 receiver_(nullptr), |
57 send_stream_(nullptr), | 57 send_stream_(nullptr), |
58 test_label_(test_label), | 58 test_label_(test_label), |
59 graph_data_output_file_(graph_data_output_file), | 59 graph_data_output_file_(graph_data_output_file), |
60 frames_to_process_(duration_frames), | 60 frames_to_process_(duration_frames), |
61 frames_recorded_(0), | 61 frames_recorded_(0), |
62 frames_processed_(0), | 62 frames_processed_(0), |
63 dropped_frames_(0), | 63 dropped_frames_(0), |
64 last_render_time_(0), | 64 last_render_time_(0), |
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
116 parser->Parse(packet, length, &header); | 116 parser->Parse(packet, length, &header); |
117 { | 117 { |
118 rtc::CritScope lock(&crit_); | 118 rtc::CritScope lock(&crit_); |
119 recv_times_[header.timestamp - rtp_timestamp_delta_] = | 119 recv_times_[header.timestamp - rtp_timestamp_delta_] = |
120 Clock::GetRealTimeClock()->CurrentNtpInMilliseconds(); | 120 Clock::GetRealTimeClock()->CurrentNtpInMilliseconds(); |
121 } | 121 } |
122 | 122 |
123 return receiver_->DeliverPacket(media_type, packet, length, packet_time); | 123 return receiver_->DeliverPacket(media_type, packet, length, packet_time); |
124 } | 124 } |
125 | 125 |
126 // EncodingTimeObserver. | |
127 void OnReportEncodedTime(int64_t ntp_time_ms, int encode_time_ms) override { | |
128 rtc::CritScope crit(&comparison_lock_); | |
129 samples_encode_time_ms_[ntp_time_ms] = encode_time_ms; | |
130 } | |
131 | |
132 void IncomingCapturedFrame(const VideoFrame& video_frame) override { | 126 void IncomingCapturedFrame(const VideoFrame& video_frame) override { |
133 VideoFrame copy = video_frame; | 127 VideoFrame copy = video_frame; |
134 copy.set_timestamp(copy.ntp_time_ms() * 90); | 128 copy.set_timestamp(copy.ntp_time_ms() * 90); |
135 | 129 |
136 { | 130 { |
137 rtc::CritScope lock(&crit_); | 131 rtc::CritScope lock(&crit_); |
138 if (first_send_frame_.IsZeroSize() && rtp_timestamp_delta_ == 0) | 132 if (first_send_frame_.IsZeroSize() && rtp_timestamp_delta_ == 0) |
139 first_send_frame_ = copy; | 133 first_send_frame_ = copy; |
140 | 134 |
141 frames_.push_back(copy); | 135 frames_.push_back(copy); |
(...skipping 136 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
278 VideoFrame reference; | 272 VideoFrame reference; |
279 VideoFrame render; | 273 VideoFrame render; |
280 bool dropped; | 274 bool dropped; |
281 int64_t send_time_ms; | 275 int64_t send_time_ms; |
282 int64_t recv_time_ms; | 276 int64_t recv_time_ms; |
283 int64_t render_time_ms; | 277 int64_t render_time_ms; |
284 size_t encoded_frame_size; | 278 size_t encoded_frame_size; |
285 }; | 279 }; |
286 | 280 |
287 struct Sample { | 281 struct Sample { |
288 Sample(int dropped, | 282 Sample(double dropped, |
289 int64_t input_time_ms, | 283 double input_time_ms, |
290 int64_t send_time_ms, | 284 double send_time_ms, |
291 int64_t recv_time_ms, | 285 double recv_time_ms, |
292 int64_t render_time_ms, | 286 double encoded_frame_size, |
293 size_t encoded_frame_size, | |
294 double psnr, | 287 double psnr, |
295 double ssim) | 288 double ssim, |
| 289 double render_time_ms) |
296 : dropped(dropped), | 290 : dropped(dropped), |
297 input_time_ms(input_time_ms), | 291 input_time_ms(input_time_ms), |
298 send_time_ms(send_time_ms), | 292 send_time_ms(send_time_ms), |
299 recv_time_ms(recv_time_ms), | 293 recv_time_ms(recv_time_ms), |
300 render_time_ms(render_time_ms), | |
301 encoded_frame_size(encoded_frame_size), | 294 encoded_frame_size(encoded_frame_size), |
302 psnr(psnr), | 295 psnr(psnr), |
303 ssim(ssim) {} | 296 ssim(ssim), |
| 297 render_time_ms(render_time_ms) {} |
304 | 298 |
305 int dropped; | 299 double dropped; |
306 int64_t input_time_ms; | 300 double input_time_ms; |
307 int64_t send_time_ms; | 301 double send_time_ms; |
308 int64_t recv_time_ms; | 302 double recv_time_ms; |
309 int64_t render_time_ms; | 303 double encoded_frame_size; |
310 size_t encoded_frame_size; | |
311 double psnr; | 304 double psnr; |
312 double ssim; | 305 double ssim; |
| 306 double render_time_ms; |
313 }; | 307 }; |
314 | 308 |
315 void AddFrameComparison(const VideoFrame& reference, | 309 void AddFrameComparison(const VideoFrame& reference, |
316 const VideoFrame& render, | 310 const VideoFrame& render, |
317 bool dropped, | 311 bool dropped, |
318 int64_t render_time_ms) | 312 int64_t render_time_ms) |
319 EXCLUSIVE_LOCKS_REQUIRED(crit_) { | 313 EXCLUSIVE_LOCKS_REQUIRED(crit_) { |
320 int64_t send_time_ms = send_times_[reference.timestamp()]; | 314 int64_t send_time_ms = send_times_[reference.timestamp()]; |
321 send_times_.erase(reference.timestamp()); | 315 send_times_.erase(reference.timestamp()); |
322 int64_t recv_time_ms = recv_times_[reference.timestamp()]; | 316 int64_t recv_time_ms = recv_times_[reference.timestamp()]; |
(...skipping 141 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
464 // Perform expensive psnr and ssim calculations while not holding lock. | 458 // Perform expensive psnr and ssim calculations while not holding lock. |
465 double psnr = I420PSNR(&comparison.reference, &comparison.render); | 459 double psnr = I420PSNR(&comparison.reference, &comparison.render); |
466 double ssim = I420SSIM(&comparison.reference, &comparison.render); | 460 double ssim = I420SSIM(&comparison.reference, &comparison.render); |
467 | 461 |
468 int64_t input_time_ms = comparison.reference.ntp_time_ms(); | 462 int64_t input_time_ms = comparison.reference.ntp_time_ms(); |
469 | 463 |
470 rtc::CritScope crit(&comparison_lock_); | 464 rtc::CritScope crit(&comparison_lock_); |
471 if (graph_data_output_file_) { | 465 if (graph_data_output_file_) { |
472 samples_.push_back( | 466 samples_.push_back( |
473 Sample(comparison.dropped, input_time_ms, comparison.send_time_ms, | 467 Sample(comparison.dropped, input_time_ms, comparison.send_time_ms, |
474 comparison.recv_time_ms, comparison.render_time_ms, | 468 comparison.recv_time_ms, comparison.encoded_frame_size, psnr, |
475 comparison.encoded_frame_size, psnr, ssim)); | 469 ssim, comparison.render_time_ms)); |
476 } | 470 } |
477 psnr_.AddSample(psnr); | 471 psnr_.AddSample(psnr); |
478 ssim_.AddSample(ssim); | 472 ssim_.AddSample(ssim); |
479 | 473 |
480 if (comparison.dropped) { | 474 if (comparison.dropped) { |
481 ++dropped_frames_; | 475 ++dropped_frames_; |
482 return; | 476 return; |
483 } | 477 } |
484 if (last_render_time_ != 0) | 478 if (last_render_time_ != 0) |
485 rendered_delta_.AddSample(comparison.render_time_ms - last_render_time_); | 479 rendered_delta_.AddSample(comparison.render_time_ms - last_render_time_); |
(...skipping 25 matching lines...) Expand all Loading... |
511 return A.input_time_ms < B.input_time_ms; | 505 return A.input_time_ms < B.input_time_ms; |
512 }); | 506 }); |
513 | 507 |
514 fprintf(out, "%s\n", test_label_.c_str()); | 508 fprintf(out, "%s\n", test_label_.c_str()); |
515 fprintf(out, "%" PRIuS "\n", samples_.size()); | 509 fprintf(out, "%" PRIuS "\n", samples_.size()); |
516 fprintf(out, | 510 fprintf(out, |
517 "dropped " | 511 "dropped " |
518 "input_time_ms " | 512 "input_time_ms " |
519 "send_time_ms " | 513 "send_time_ms " |
520 "recv_time_ms " | 514 "recv_time_ms " |
521 "render_time_ms " | |
522 "encoded_frame_size " | 515 "encoded_frame_size " |
523 "psnr " | 516 "psnr " |
524 "ssim " | 517 "ssim " |
525 "encode_time_ms\n"); | 518 "render_time_ms\n"); |
526 int missing_encode_time_samples = 0; | |
527 for (const Sample& sample : samples_) { | 519 for (const Sample& sample : samples_) { |
528 auto it = samples_encode_time_ms_.find(sample.input_time_ms); | 520 fprintf(out, "%lf %lf %lf %lf %lf %lf %lf %lf\n", sample.dropped, |
529 int encode_time_ms; | 521 sample.input_time_ms, sample.send_time_ms, sample.recv_time_ms, |
530 if (it != samples_encode_time_ms_.end()) { | |
531 encode_time_ms = it->second; | |
532 } else { | |
533 ++missing_encode_time_samples; | |
534 encode_time_ms = -1; | |
535 } | |
536 fprintf(out, "%d %" PRId64 " %" PRId64 " %" PRId64 " %" PRId64 " %" PRIuS | |
537 " %lf %lf %d\n", | |
538 sample.dropped, sample.input_time_ms, sample.send_time_ms, | |
539 sample.recv_time_ms, sample.render_time_ms, | |
540 sample.encoded_frame_size, sample.psnr, sample.ssim, | 522 sample.encoded_frame_size, sample.psnr, sample.ssim, |
541 encode_time_ms); | 523 sample.render_time_ms); |
542 } | |
543 if (missing_encode_time_samples) { | |
544 fprintf(stderr, | |
545 "Warning: Missing encode_time_ms samples for %d frame(s).\n", | |
546 missing_encode_time_samples); | |
547 } | 524 } |
548 } | 525 } |
549 | 526 |
550 const std::string test_label_; | 527 const std::string test_label_; |
551 FILE* const graph_data_output_file_; | 528 FILE* const graph_data_output_file_; |
552 std::vector<Sample> samples_ GUARDED_BY(comparison_lock_); | 529 std::vector<Sample> samples_ GUARDED_BY(comparison_lock_); |
553 std::map<int64_t, int> samples_encode_time_ms_ GUARDED_BY(comparison_lock_); | |
554 test::Statistics sender_time_ GUARDED_BY(comparison_lock_); | 530 test::Statistics sender_time_ GUARDED_BY(comparison_lock_); |
555 test::Statistics receiver_time_ GUARDED_BY(comparison_lock_); | 531 test::Statistics receiver_time_ GUARDED_BY(comparison_lock_); |
556 test::Statistics psnr_ GUARDED_BY(comparison_lock_); | 532 test::Statistics psnr_ GUARDED_BY(comparison_lock_); |
557 test::Statistics ssim_ GUARDED_BY(comparison_lock_); | 533 test::Statistics ssim_ GUARDED_BY(comparison_lock_); |
558 test::Statistics end_to_end_ GUARDED_BY(comparison_lock_); | 534 test::Statistics end_to_end_ GUARDED_BY(comparison_lock_); |
559 test::Statistics rendered_delta_ GUARDED_BY(comparison_lock_); | 535 test::Statistics rendered_delta_ GUARDED_BY(comparison_lock_); |
560 test::Statistics encoded_frame_size_ GUARDED_BY(comparison_lock_); | 536 test::Statistics encoded_frame_size_ GUARDED_BY(comparison_lock_); |
561 test::Statistics encode_frame_rate_ GUARDED_BY(comparison_lock_); | 537 test::Statistics encode_frame_rate_ GUARDED_BY(comparison_lock_); |
562 test::Statistics encode_time_ms GUARDED_BY(comparison_lock_); | 538 test::Statistics encode_time_ms GUARDED_BY(comparison_lock_); |
563 test::Statistics encode_usage_percent GUARDED_BY(comparison_lock_); | 539 test::Statistics encode_usage_percent GUARDED_BY(comparison_lock_); |
(...skipping 190 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
754 RTC_CHECK(graph_data_output_file != nullptr) | 730 RTC_CHECK(graph_data_output_file != nullptr) |
755 << "Can't open the file " | 731 << "Can't open the file " |
756 << params.analyzer.graph_data_output_filename << "!"; | 732 << params.analyzer.graph_data_output_filename << "!"; |
757 } | 733 } |
758 | 734 |
759 test::LayerFilteringTransport send_transport( | 735 test::LayerFilteringTransport send_transport( |
760 params.pipe, kPayloadTypeVP8, kPayloadTypeVP9, | 736 params.pipe, kPayloadTypeVP8, kPayloadTypeVP9, |
761 static_cast<uint8_t>(params.common.tl_discard_threshold), 0); | 737 static_cast<uint8_t>(params.common.tl_discard_threshold), 0); |
762 test::DirectTransport recv_transport(params.pipe); | 738 test::DirectTransport recv_transport(params.pipe); |
763 VideoAnalyzer analyzer( | 739 VideoAnalyzer analyzer( |
764 &send_transport, params.analyzer.test_label, | 740 nullptr, &send_transport, params.analyzer.test_label, |
765 params.analyzer.avg_psnr_threshold, params.analyzer.avg_ssim_threshold, | 741 params.analyzer.avg_psnr_threshold, params.analyzer.avg_ssim_threshold, |
766 params.analyzer.test_durations_secs * params.common.fps, | 742 params.analyzer.test_durations_secs * params.common.fps, |
767 graph_data_output_file); | 743 graph_data_output_file); |
768 | 744 |
769 Call::Config call_config; | 745 Call::Config call_config; |
770 call_config.bitrate_config = params.common.call_bitrate_config; | 746 call_config.bitrate_config = params.common.call_bitrate_config; |
771 CreateCalls(call_config, call_config); | 747 CreateCalls(call_config, call_config); |
772 | 748 |
773 analyzer.SetReceiver(receiver_call_->Receiver()); | 749 analyzer.SetReceiver(receiver_call_->Receiver()); |
774 send_transport.SetReceiver(&analyzer); | 750 send_transport.SetReceiver(&analyzer); |
775 recv_transport.SetReceiver(sender_call_->Receiver()); | 751 recv_transport.SetReceiver(sender_call_->Receiver()); |
776 | 752 |
777 SetupFullStack(params, &analyzer, &recv_transport); | 753 SetupFullStack(params, &analyzer, &recv_transport); |
778 send_config_.encoding_time_observer = &analyzer; | |
779 receive_configs_[0].renderer = &analyzer; | 754 receive_configs_[0].renderer = &analyzer; |
780 for (auto& config : receive_configs_) | 755 for (auto& config : receive_configs_) |
781 config.pre_decode_callback = &analyzer; | 756 config.pre_decode_callback = &analyzer; |
782 | 757 |
783 if (params.screenshare.enabled) | 758 if (params.screenshare.enabled) |
784 SetupScreenshare(params); | 759 SetupScreenshare(params); |
785 | 760 |
786 CreateCapturer(params, &analyzer); | 761 CreateCapturer(params, &analyzer); |
787 | 762 |
788 CreateStreams(); | 763 CreateStreams(); |
(...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
857 send_stream_->Stop(); | 832 send_stream_->Stop(); |
858 receive_stream->Stop(); | 833 receive_stream->Stop(); |
859 | 834 |
860 call->DestroyVideoReceiveStream(receive_stream); | 835 call->DestroyVideoReceiveStream(receive_stream); |
861 call->DestroyVideoSendStream(send_stream_); | 836 call->DestroyVideoSendStream(send_stream_); |
862 | 837 |
863 transport.StopSending(); | 838 transport.StopSending(); |
864 } | 839 } |
865 | 840 |
866 } // namespace webrtc | 841 } // namespace webrtc |
OLD | NEW |