OLD | NEW |
1 /* | 1 /* |
2 * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. | 2 * Copyright (c) 2016 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 | 10 |
11 #include <limits> | 11 #include <limits> |
12 #include <utility> | 12 #include <utility> |
13 | 13 |
14 #include "webrtc/base/logging.h" | 14 #include "webrtc/base/logging.h" |
15 #include "webrtc/system_wrappers/include/metrics_default.h" | 15 #include "webrtc/system_wrappers/include/metrics_default.h" |
16 #include "webrtc/test/encoder_settings.h" | 16 #include "webrtc/test/encoder_settings.h" |
17 #include "webrtc/test/fake_encoder.h" | 17 #include "webrtc/test/fake_encoder.h" |
18 #include "webrtc/test/frame_generator.h" | 18 #include "webrtc/test/frame_generator.h" |
19 #include "webrtc/test/gtest.h" | 19 #include "webrtc/test/gtest.h" |
20 #include "webrtc/video/send_statistics_proxy.h" | 20 #include "webrtc/video/send_statistics_proxy.h" |
21 #include "webrtc/video/vie_encoder.h" | 21 #include "webrtc/video/vie_encoder.h" |
22 | 22 |
23 namespace webrtc { | 23 namespace webrtc { |
24 | 24 |
| 25 using DegredationPreference = VideoSendStream::DegradationPreference; |
| 26 |
25 namespace { | 27 namespace { |
| 28 // Copied from vie_encoder.cc. Must be kept in sync. |
| 29 static const int kMaxCpuDowngrades = 2; |
| 30 |
26 class TestBuffer : public webrtc::I420Buffer { | 31 class TestBuffer : public webrtc::I420Buffer { |
27 public: | 32 public: |
28 TestBuffer(rtc::Event* event, int width, int height) | 33 TestBuffer(rtc::Event* event, int width, int height) |
29 : I420Buffer(width, height), event_(event) {} | 34 : I420Buffer(width, height), event_(event) {} |
30 | 35 |
31 private: | 36 private: |
32 friend class rtc::RefCountedObject<TestBuffer>; | 37 friend class rtc::RefCountedObject<TestBuffer>; |
33 ~TestBuffer() override { | 38 ~TestBuffer() override { |
34 if (event_) | 39 if (event_) |
35 event_->Set(); | 40 event_->Set(); |
36 } | 41 } |
37 rtc::Event* const event_; | 42 rtc::Event* const event_; |
38 }; | 43 }; |
39 | 44 |
40 class ViEEncoderUnderTest : public ViEEncoder { | 45 class ViEEncoderUnderTest : public ViEEncoder { |
41 public: | 46 public: |
42 ViEEncoderUnderTest( | 47 using ScalingObserverInterface::ScaleReason; |
43 SendStatisticsProxy* stats_proxy, | 48 ViEEncoderUnderTest(SendStatisticsProxy* stats_proxy, |
44 const webrtc::VideoSendStream::Config::EncoderSettings& settings) | 49 const VideoSendStream::Config::EncoderSettings& settings) |
45 : ViEEncoder(1 /* number_of_cores */, | 50 : ViEEncoder(1 /* number_of_cores */, |
46 stats_proxy, | 51 stats_proxy, |
47 settings, | 52 settings, |
48 nullptr /* pre_encode_callback */, | 53 nullptr /* pre_encode_callback */, |
49 nullptr /* encoder_timing */) {} | 54 nullptr /* encoder_timing */) {} |
50 | 55 |
51 void TriggerCpuOveruse() { | 56 void PostTaskAndWait(bool down, ScaleReason reason) { |
52 rtc::Event event(false, false); | 57 rtc::Event event(false, false); |
53 encoder_queue()->PostTask([this, &event] { | 58 encoder_queue()->PostTask([this, &event, reason, down] { |
54 OveruseDetected(); | 59 down ? ScaleDown(reason) : ScaleUp(reason); |
55 event.Set(); | 60 event.Set(); |
56 }); | 61 }); |
57 event.Wait(rtc::Event::kForever); | 62 RTC_DCHECK(event.Wait(5000)); |
58 } | 63 } |
59 | 64 |
60 void TriggerCpuNormalUsage() { | 65 void TriggerCpuOveruse() { PostTaskAndWait(true, kCpu); } |
61 rtc::Event event(false, false); | 66 |
62 encoder_queue()->PostTask([this, &event] { | 67 void TriggerCpuNormalUsage() { PostTaskAndWait(false, kCpu); } |
63 NormalUsage(); | 68 |
64 event.Set(); | 69 void TriggerQualityLow() { PostTaskAndWait(true, kQuality); } |
65 }); | 70 |
66 event.Wait(rtc::Event::kForever); | 71 void TriggerQualityHigh() { PostTaskAndWait(false, kQuality); } |
67 } | |
68 }; | 72 }; |
69 | 73 |
70 } // namespace | 74 } // namespace |
71 | 75 |
72 class ViEEncoderTest : public ::testing::Test { | 76 class ViEEncoderTest : public ::testing::Test { |
73 public: | 77 public: |
74 static const int kDefaultTimeoutMs = 30 * 1000; | 78 static const int kDefaultTimeoutMs = 30 * 1000; |
75 | 79 |
76 ViEEncoderTest() | 80 ViEEncoderTest() |
77 : video_send_config_(VideoSendStream::Config(nullptr)), | 81 : video_send_config_(VideoSendStream::Config(nullptr)), |
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
127 VideoCodec codec_config() { | 131 VideoCodec codec_config() { |
128 rtc::CritScope lock(&crit_); | 132 rtc::CritScope lock(&crit_); |
129 return config_; | 133 return config_; |
130 } | 134 } |
131 | 135 |
132 void BlockNextEncode() { | 136 void BlockNextEncode() { |
133 rtc::CritScope lock(&crit_); | 137 rtc::CritScope lock(&crit_); |
134 block_next_encode_ = true; | 138 block_next_encode_ = true; |
135 } | 139 } |
136 | 140 |
| 141 QualityScaler::Settings GetQPThresholds() const override { |
| 142 return QualityScaler::Settings(true, 1, 2); |
| 143 } |
| 144 |
137 void ContinueEncode() { continue_encode_event_.Set(); } | 145 void ContinueEncode() { continue_encode_event_.Set(); } |
138 | 146 |
139 void CheckLastTimeStampsMatch(int64_t ntp_time_ms, | 147 void CheckLastTimeStampsMatch(int64_t ntp_time_ms, |
140 uint32_t timestamp) const { | 148 uint32_t timestamp) const { |
141 rtc::CritScope lock(&crit_); | 149 rtc::CritScope lock(&crit_); |
142 EXPECT_EQ(timestamp_, timestamp); | 150 EXPECT_EQ(timestamp_, timestamp); |
143 EXPECT_EQ(ntp_time_ms_, ntp_time_ms); | 151 EXPECT_EQ(ntp_time_ms_, ntp_time_ms); |
144 } | 152 } |
145 | 153 |
146 private: | 154 private: |
(...skipping 257 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
404 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0); | 412 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0); |
405 | 413 |
406 EXPECT_FALSE(video_source_.sink_wants().max_pixel_count); | 414 EXPECT_FALSE(video_source_.sink_wants().max_pixel_count); |
407 EXPECT_FALSE(video_source_.sink_wants().max_pixel_count_step_up); | 415 EXPECT_FALSE(video_source_.sink_wants().max_pixel_count_step_up); |
408 | 416 |
409 int frame_width = 1280; | 417 int frame_width = 1280; |
410 int frame_height = 720; | 418 int frame_height = 720; |
411 | 419 |
412 // Trigger CPU overuse kMaxCpuDowngrades times. Every time, ViEEncoder should | 420 // Trigger CPU overuse kMaxCpuDowngrades times. Every time, ViEEncoder should |
413 // request lower resolution. | 421 // request lower resolution. |
414 for (int i = 1; i <= ViEEncoder::kMaxCpuDowngrades; ++i) { | 422 for (int i = 1; i <= kMaxCpuDowngrades; ++i) { |
415 video_source_.IncomingCapturedFrame( | 423 video_source_.IncomingCapturedFrame( |
416 CreateFrame(i, frame_width, frame_height)); | 424 CreateFrame(i, frame_width, frame_height)); |
417 sink_.WaitForEncodedFrame(i); | 425 sink_.WaitForEncodedFrame(i); |
418 | 426 |
419 vie_encoder_->TriggerCpuOveruse(); | 427 vie_encoder_->TriggerCpuOveruse(); |
420 | 428 |
421 EXPECT_LT(video_source_.sink_wants().max_pixel_count.value_or( | 429 EXPECT_LT(video_source_.sink_wants().max_pixel_count.value_or( |
422 std::numeric_limits<int>::max()), | 430 std::numeric_limits<int>::max()), |
423 frame_width * frame_height); | 431 frame_width * frame_height); |
424 EXPECT_FALSE(video_source_.sink_wants().max_pixel_count_step_up); | 432 EXPECT_FALSE(video_source_.sink_wants().max_pixel_count_step_up); |
425 | 433 |
426 frame_width /= 2; | 434 frame_width /= 2; |
427 frame_height /= 2; | 435 frame_height /= 2; |
428 } | 436 } |
429 | 437 |
430 // Trigger CPU overuse a one more time. This should not trigger request for | 438 // Trigger CPU overuse one more time. This should not trigger a request for |
431 // lower resolution. | 439 // lower resolution. |
432 rtc::VideoSinkWants current_wants = video_source_.sink_wants(); | 440 rtc::VideoSinkWants current_wants = video_source_.sink_wants(); |
433 video_source_.IncomingCapturedFrame(CreateFrame( | 441 video_source_.IncomingCapturedFrame( |
434 ViEEncoder::kMaxCpuDowngrades + 1, frame_width, frame_height)); | 442 CreateFrame(kMaxCpuDowngrades + 1, frame_width, frame_height)); |
435 sink_.WaitForEncodedFrame(ViEEncoder::kMaxCpuDowngrades + 1); | 443 sink_.WaitForEncodedFrame(kMaxCpuDowngrades + 1); |
436 vie_encoder_->TriggerCpuOveruse(); | 444 vie_encoder_->TriggerCpuOveruse(); |
437 EXPECT_EQ(video_source_.sink_wants().max_pixel_count, | 445 EXPECT_EQ(video_source_.sink_wants().max_pixel_count, |
438 current_wants.max_pixel_count); | 446 current_wants.max_pixel_count); |
439 EXPECT_EQ(video_source_.sink_wants().max_pixel_count_step_up, | 447 EXPECT_EQ(video_source_.sink_wants().max_pixel_count_step_up, |
440 current_wants.max_pixel_count_step_up); | 448 current_wants.max_pixel_count_step_up); |
441 | 449 |
442 // Trigger CPU normal use. | 450 // Trigger CPU normal use. |
443 vie_encoder_->TriggerCpuNormalUsage(); | 451 vie_encoder_->TriggerCpuNormalUsage(); |
444 EXPECT_FALSE(video_source_.sink_wants().max_pixel_count); | 452 EXPECT_FALSE(video_source_.sink_wants().max_pixel_count); |
445 EXPECT_EQ(video_source_.sink_wants().max_pixel_count_step_up.value_or(0), | 453 EXPECT_EQ(video_source_.sink_wants().max_pixel_count_step_up.value_or(0), |
(...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
526 CreateFrame(3, frame_width, frame_height)); | 534 CreateFrame(3, frame_width, frame_height)); |
527 sink_.WaitForEncodedFrame(3); | 535 sink_.WaitForEncodedFrame(3); |
528 | 536 |
529 stats = stats_proxy_->GetStats(); | 537 stats = stats_proxy_->GetStats(); |
530 EXPECT_FALSE(stats.cpu_limited_resolution); | 538 EXPECT_FALSE(stats.cpu_limited_resolution); |
531 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes); | 539 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes); |
532 | 540 |
533 vie_encoder_->Stop(); | 541 vie_encoder_->Stop(); |
534 } | 542 } |
535 | 543 |
| 544 TEST_F(ViEEncoderTest, SwitchingSourceKeepsAdaptation) { |
| 545 const int kTargetBitrateBps = 100000; |
| 546 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0); |
| 547 |
| 548 int frame_width = 1280; |
| 549 int frame_height = 720; |
| 550 video_source_.IncomingCapturedFrame( |
| 551 CreateFrame(1, frame_width, frame_height)); |
| 552 sink_.WaitForEncodedFrame(1); |
| 553 |
| 554 VideoSendStream::Stats stats = stats_proxy_->GetStats(); |
| 555 EXPECT_FALSE(stats.cpu_limited_resolution); |
| 556 EXPECT_FALSE(stats.bw_limited_resolution); |
| 557 EXPECT_EQ(0, stats.number_of_cpu_adapt_changes); |
| 558 |
| 559 // Set new source with adaptation still enabled. |
| 560 test::FrameForwarder new_video_source; |
| 561 vie_encoder_->SetSource(&new_video_source, |
| 562 VideoSendStream::DegradationPreference::kBalanced); |
| 563 |
| 564 new_video_source.IncomingCapturedFrame( |
| 565 CreateFrame(2, frame_width, frame_height)); |
| 566 sink_.WaitForEncodedFrame(2); |
| 567 stats = stats_proxy_->GetStats(); |
| 568 EXPECT_FALSE(stats.cpu_limited_resolution); |
| 569 EXPECT_FALSE(stats.bw_limited_resolution); |
| 570 EXPECT_EQ(0, stats.number_of_cpu_adapt_changes); |
| 571 |
| 572 vie_encoder_->TriggerQualityLow(); |
| 573 |
| 574 new_video_source.IncomingCapturedFrame( |
| 575 CreateFrame(3, frame_width, frame_height)); |
| 576 sink_.WaitForEncodedFrame(3); |
| 577 stats = stats_proxy_->GetStats(); |
| 578 EXPECT_FALSE(stats.cpu_limited_resolution); |
| 579 EXPECT_TRUE(stats.bw_limited_resolution); |
| 580 |
| 581 vie_encoder_->SetSource(&new_video_source, |
| 582 VideoSendStream::DegradationPreference::kBalanced); |
| 583 |
| 584 new_video_source.IncomingCapturedFrame( |
| 585 CreateFrame(4, frame_width, frame_height)); |
| 586 sink_.WaitForEncodedFrame(4); |
| 587 stats = stats_proxy_->GetStats(); |
| 588 EXPECT_FALSE(stats.cpu_limited_resolution); |
| 589 EXPECT_TRUE(stats.bw_limited_resolution); |
| 590 |
| 591 // Set adaptation disabled. |
| 592 vie_encoder_->SetSource( |
| 593 &new_video_source, |
| 594 VideoSendStream::DegradationPreference::kMaintainResolution); |
| 595 |
| 596 new_video_source.IncomingCapturedFrame( |
| 597 CreateFrame(5, frame_width, frame_height)); |
| 598 sink_.WaitForEncodedFrame(5); |
| 599 stats = stats_proxy_->GetStats(); |
| 600 EXPECT_FALSE(stats.cpu_limited_resolution); |
| 601 EXPECT_FALSE(stats.bw_limited_resolution); |
| 602 |
| 603 vie_encoder_->Stop(); |
| 604 } |
| 605 |
536 TEST_F(ViEEncoderTest, StatsTracksAdaptationStatsWhenSwitchingSource) { | 606 TEST_F(ViEEncoderTest, StatsTracksAdaptationStatsWhenSwitchingSource) { |
537 const int kTargetBitrateBps = 100000; | 607 const int kTargetBitrateBps = 100000; |
538 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0); | 608 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0); |
539 | 609 |
540 // Trigger CPU overuse. | 610 // Trigger CPU overuse. |
541 vie_encoder_->TriggerCpuOveruse(); | 611 vie_encoder_->TriggerCpuOveruse(); |
542 int frame_width = 1280; | 612 int frame_width = 1280; |
543 int frame_height = 720; | 613 int frame_height = 720; |
544 | 614 |
545 video_source_.IncomingCapturedFrame( | 615 video_source_.IncomingCapturedFrame( |
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
588 video_source_.IncomingCapturedFrame( | 658 video_source_.IncomingCapturedFrame( |
589 CreateFrame(5, frame_width, frame_height)); | 659 CreateFrame(5, frame_width, frame_height)); |
590 sink_.WaitForEncodedFrame(5); | 660 sink_.WaitForEncodedFrame(5); |
591 stats = stats_proxy_->GetStats(); | 661 stats = stats_proxy_->GetStats(); |
592 EXPECT_FALSE(stats.cpu_limited_resolution); | 662 EXPECT_FALSE(stats.cpu_limited_resolution); |
593 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes); | 663 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes); |
594 | 664 |
595 vie_encoder_->Stop(); | 665 vie_encoder_->Stop(); |
596 } | 666 } |
597 | 667 |
| 668 TEST_F(ViEEncoderTest, StatsTracksQualityAdaptationStatsWhenSwitchingSource) { |
| 669 const int kTargetBitrateBps = 100000; |
| 670 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0); |
| 671 |
| 672 // Trigger CPU overuse. |
| 673 vie_encoder_->TriggerQualityLow(); |
| 674 int frame_width = 1280; |
| 675 int frame_height = 720; |
| 676 |
| 677 video_source_.IncomingCapturedFrame( |
| 678 CreateFrame(1, frame_width, frame_height)); |
| 679 sink_.WaitForEncodedFrame(1); |
| 680 |
| 681 VideoSendStream::Stats stats = stats_proxy_->GetStats(); |
| 682 EXPECT_TRUE(stats.bw_limited_resolution); |
| 683 |
| 684 // Set new source with adaptation still enabled. |
| 685 test::FrameForwarder new_video_source; |
| 686 vie_encoder_->SetSource(&new_video_source, |
| 687 VideoSendStream::DegradationPreference::kBalanced); |
| 688 |
| 689 new_video_source.IncomingCapturedFrame( |
| 690 CreateFrame(2, frame_width, frame_height)); |
| 691 sink_.WaitForEncodedFrame(2); |
| 692 stats = stats_proxy_->GetStats(); |
| 693 EXPECT_TRUE(stats.bw_limited_resolution); |
| 694 |
| 695 // Set adaptation disabled. |
| 696 vie_encoder_->SetSource( |
| 697 &new_video_source, |
| 698 VideoSendStream::DegradationPreference::kMaintainResolution); |
| 699 |
| 700 new_video_source.IncomingCapturedFrame( |
| 701 CreateFrame(3, frame_width, frame_height)); |
| 702 sink_.WaitForEncodedFrame(3); |
| 703 stats = stats_proxy_->GetStats(); |
| 704 EXPECT_FALSE(stats.bw_limited_resolution); |
| 705 |
| 706 // Switch back the source with adaptation enabled. |
| 707 vie_encoder_->SetSource(&video_source_, |
| 708 VideoSendStream::DegradationPreference::kBalanced); |
| 709 video_source_.IncomingCapturedFrame( |
| 710 CreateFrame(4, frame_width, frame_height)); |
| 711 sink_.WaitForEncodedFrame(4); |
| 712 stats = stats_proxy_->GetStats(); |
| 713 EXPECT_TRUE(stats.bw_limited_resolution); |
| 714 |
| 715 // Trigger CPU normal usage. |
| 716 vie_encoder_->TriggerQualityHigh(); |
| 717 video_source_.IncomingCapturedFrame( |
| 718 CreateFrame(5, frame_width, frame_height)); |
| 719 sink_.WaitForEncodedFrame(5); |
| 720 stats = stats_proxy_->GetStats(); |
| 721 EXPECT_FALSE(stats.bw_limited_resolution); |
| 722 |
| 723 vie_encoder_->Stop(); |
| 724 } |
| 725 |
598 TEST_F(ViEEncoderTest, UMACpuLimitedResolutionInPercent) { | 726 TEST_F(ViEEncoderTest, UMACpuLimitedResolutionInPercent) { |
599 const int kTargetBitrateBps = 100000; | 727 const int kTargetBitrateBps = 100000; |
600 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0); | 728 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0); |
601 | 729 |
602 int frame_width = 640; | 730 int frame_width = 640; |
603 int frame_height = 360; | 731 int frame_height = 360; |
604 | 732 |
605 for (int i = 1; i <= SendStatisticsProxy::kMinRequiredMetricsSamples; ++i) { | 733 for (int i = 1; i <= SendStatisticsProxy::kMinRequiredMetricsSamples; ++i) { |
606 video_source_.IncomingCapturedFrame( | 734 video_source_.IncomingCapturedFrame( |
607 CreateFrame(i, frame_width, frame_height)); | 735 CreateFrame(i, frame_width, frame_height)); |
(...skipping 12 matching lines...) Expand all Loading... |
620 vie_encoder_->Stop(); | 748 vie_encoder_->Stop(); |
621 | 749 |
622 stats_proxy_.reset(); | 750 stats_proxy_.reset(); |
623 EXPECT_EQ(1, | 751 EXPECT_EQ(1, |
624 metrics::NumSamples("WebRTC.Video.CpuLimitedResolutionInPercent")); | 752 metrics::NumSamples("WebRTC.Video.CpuLimitedResolutionInPercent")); |
625 EXPECT_EQ( | 753 EXPECT_EQ( |
626 1, metrics::NumEvents("WebRTC.Video.CpuLimitedResolutionInPercent", 50)); | 754 1, metrics::NumEvents("WebRTC.Video.CpuLimitedResolutionInPercent", 50)); |
627 } | 755 } |
628 | 756 |
629 } // namespace webrtc | 757 } // namespace webrtc |
OLD | NEW |