Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(131)

Unified Diff: webrtc/video/vie_encoder_unittest.cc

Issue 2304363002: Let ViEEncoder express resolution requests as Sinkwants (Closed)
Patch Set: Rebased. Created 4 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « webrtc/video/vie_encoder.cc ('k') | webrtc/video_send_stream.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: webrtc/video/vie_encoder_unittest.cc
diff --git a/webrtc/video/vie_encoder_unittest.cc b/webrtc/video/vie_encoder_unittest.cc
index 78eb62f99fc44f535871378b5614657f1946704b..895109773f16a0837742c6730e2523143f3d1afb 100644
--- a/webrtc/video/vie_encoder_unittest.cc
+++ b/webrtc/video/vie_encoder_unittest.cc
@@ -8,9 +8,11 @@
* be found in the AUTHORS file in the root of the source tree.
*/
+#include <limits>
#include <utility>
#include "webrtc/base/logging.h"
+#include "webrtc/system_wrappers/include/metrics_default.h"
#include "webrtc/test/encoder_settings.h"
#include "webrtc/test/fake_encoder.h"
#include "webrtc/test/frame_generator.h"
@@ -20,6 +22,53 @@
namespace webrtc {
+namespace {
+class TestBuffer : public webrtc::I420Buffer {
+ public:
+ TestBuffer(rtc::Event* event, int width, int height)
+ : I420Buffer(width, height), event_(event) {}
+
+ private:
+ friend class rtc::RefCountedObject<TestBuffer>;
+ ~TestBuffer() override {
+ if (event_)
+ event_->Set();
+ }
+ rtc::Event* const event_;
+};
+
+class ViEEncoderUnderTest : public ViEEncoder {
+ public:
+ ViEEncoderUnderTest(
+ SendStatisticsProxy* stats_proxy,
+ const webrtc::VideoSendStream::Config::EncoderSettings& settings)
+ : ViEEncoder(1 /* number_of_cores */,
+ stats_proxy,
+ settings,
+ nullptr /* pre_encode_callback */,
+ nullptr /* encoder_timing */) {}
+
+ void TriggerCpuOveruse() {
+ rtc::Event event(false, false);
+ encoder_queue()->PostTask([this, &event] {
+ OveruseDetected();
+ event.Set();
+ });
+ event.Wait(rtc::Event::kForever);
+ }
+
+ void TriggerCpuNormalUsage() {
+ rtc::Event event(false, false);
+ encoder_queue()->PostTask([this, &event] {
+ NormalUsage();
+ event.Set();
+ });
+ event.Wait(rtc::Event::kForever);
+ }
+};
+
+} // namespace
+
class ViEEncoderTest : public ::testing::Test {
public:
static const int kDefaultTimeoutMs = 30 * 1000;
@@ -29,12 +78,14 @@ class ViEEncoderTest : public ::testing::Test {
codec_width_(320),
codec_height_(240),
fake_encoder_(),
- stats_proxy_(Clock::GetRealTimeClock(),
- video_send_config_,
- webrtc::VideoEncoderConfig::ContentType::kRealtimeVideo),
+ stats_proxy_(new SendStatisticsProxy(
+ Clock::GetRealTimeClock(),
+ video_send_config_,
+ webrtc::VideoEncoderConfig::ContentType::kRealtimeVideo)),
sink_(&fake_encoder_) {}
void SetUp() override {
+ metrics::Reset();
video_send_config_ = VideoSendStream::Config(nullptr);
video_send_config_.encoder_settings.encoder = &fake_encoder_;
video_send_config_.encoder_settings.payload_name = "FAKE";
@@ -42,31 +93,16 @@ class ViEEncoderTest : public ::testing::Test {
VideoEncoderConfig video_encoder_config;
test::FillEncoderConfiguration(1, &video_encoder_config);
- vie_encoder_.reset(new ViEEncoder(
- 1 /* number_of_cores */, &stats_proxy_,
- video_send_config_.encoder_settings, nullptr /* pre_encode_callback */,
- nullptr /* overuse_callback */, nullptr /* encoder_timing */));
- vie_encoder_->SetSink(&sink_);
- vie_encoder_->SetSource(&video_source_);
+ vie_encoder_.reset(new ViEEncoderUnderTest(
+ stats_proxy_.get(), video_send_config_.encoder_settings));
+ vie_encoder_->SetSink(&sink_, false /* rotation_applied */);
+ vie_encoder_->SetSource(&video_source_,
+ VideoSendStream::DegradationPreference::kBalanced);
vie_encoder_->SetStartBitrate(10000);
vie_encoder_->ConfigureEncoder(std::move(video_encoder_config), 1440);
}
VideoFrame CreateFrame(int64_t ntp_ts, rtc::Event* destruction_event) const {
- class TestBuffer : public webrtc::I420Buffer {
- public:
- TestBuffer(rtc::Event* event, int width, int height)
- : I420Buffer(width, height), event_(event) {}
-
- private:
- friend class rtc::RefCountedObject<TestBuffer>;
- ~TestBuffer() override {
- if (event_)
- event_->Set();
- }
- rtc::Event* const event_;
- };
-
VideoFrame frame(new rtc::RefCountedObject<TestBuffer>(
destruction_event, codec_width_, codec_height_),
99, 99, kVideoRotation_0);
@@ -74,6 +110,14 @@ class ViEEncoderTest : public ::testing::Test {
return frame;
}
+ VideoFrame CreateFrame(int64_t ntp_ts, int width, int height) const {
+ VideoFrame frame(
+ new rtc::RefCountedObject<TestBuffer>(nullptr, width, height), 99, 99,
+ kVideoRotation_0);
+ frame.set_ntp_time_ms(ntp_ts);
+ return frame;
+ }
+
class TestEncoder : public test::FakeEncoder {
public:
TestEncoder()
@@ -112,6 +156,8 @@ class ViEEncoderTest : public ::testing::Test {
timestamp_ = input_image.timestamp();
ntp_time_ms_ = input_image.ntp_time_ms();
+ last_input_width_ = input_image.width();
+ last_input_height_ = input_image.height();
block_encode = block_next_encode_;
block_next_encode_ = false;
}
@@ -122,13 +168,13 @@ class ViEEncoderTest : public ::testing::Test {
return result;
}
-
-
rtc::CriticalSection crit_;
bool block_next_encode_ = false;
rtc::Event continue_encode_event_;
uint32_t timestamp_ = 0;
int64_t ntp_time_ms_ = 0;
+ int last_input_width_ = 0;
+ int last_input_height_ = 0;
};
class TestSink : public ViEEncoder::EncoderSink {
@@ -192,10 +238,10 @@ class ViEEncoderTest : public ::testing::Test {
int codec_width_;
int codec_height_;
TestEncoder fake_encoder_;
- SendStatisticsProxy stats_proxy_;
+ std::unique_ptr<SendStatisticsProxy> stats_proxy_;
TestSink sink_;
test::FrameForwarder video_source_;
- std::unique_ptr<ViEEncoder> vie_encoder_;
+ std::unique_ptr<ViEEncoderUnderTest> vie_encoder_;
};
TEST_F(ViEEncoderTest, EncodeOneFrame) {
@@ -334,4 +380,249 @@ TEST_F(ViEEncoderTest, FrameResolutionChangeReconfigureEncoder) {
vie_encoder_->Stop();
}
+TEST_F(ViEEncoderTest, SwitchSourceDeregisterEncoderAsSink) {
+ EXPECT_TRUE(video_source_.has_sinks());
+ test::FrameForwarder new_video_source;
+ vie_encoder_->SetSource(&new_video_source,
+ VideoSendStream::DegradationPreference::kBalanced);
+ EXPECT_FALSE(video_source_.has_sinks());
+ EXPECT_TRUE(new_video_source.has_sinks());
+
+ vie_encoder_->Stop();
+}
+
+TEST_F(ViEEncoderTest, SinkWantsRotationApplied) {
+ EXPECT_FALSE(video_source_.sink_wants().rotation_applied);
+ vie_encoder_->SetSink(&sink_, true /*rotation_applied*/);
+ EXPECT_TRUE(video_source_.sink_wants().rotation_applied);
+ vie_encoder_->Stop();
+}
+
+TEST_F(ViEEncoderTest, SinkWantsFromOveruseDetector) {
+ const int kTargetBitrateBps = 100000;
+ vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
+
+ EXPECT_FALSE(video_source_.sink_wants().max_pixel_count);
+ EXPECT_FALSE(video_source_.sink_wants().max_pixel_count_step_up);
+
+ int frame_width = 1280;
+ int frame_height = 720;
+
+ // Trigger CPU overuse kMaxCpuDowngrades times. Every time, ViEEncoder should
+ // request lower resolution.
+ for (int i = 1; i <= ViEEncoder::kMaxCpuDowngrades; ++i) {
+ video_source_.IncomingCapturedFrame(
+ CreateFrame(i, frame_width, frame_height));
+ sink_.WaitForEncodedFrame(i);
+
+ vie_encoder_->TriggerCpuOveruse();
+
+ EXPECT_LT(video_source_.sink_wants().max_pixel_count.value_or(
+ std::numeric_limits<int>::max()),
+ frame_width * frame_height);
+ EXPECT_FALSE(video_source_.sink_wants().max_pixel_count_step_up);
+
+ frame_width /= 2;
+ frame_height /= 2;
+ }
+
+ // Trigger CPU overuse a one more time. This should not trigger request for
+ // lower resolution.
+ rtc::VideoSinkWants current_wants = video_source_.sink_wants();
+ video_source_.IncomingCapturedFrame(CreateFrame(
+ ViEEncoder::kMaxCpuDowngrades + 1, frame_width, frame_height));
+ sink_.WaitForEncodedFrame(ViEEncoder::kMaxCpuDowngrades + 1);
+ vie_encoder_->TriggerCpuOveruse();
+ EXPECT_EQ(video_source_.sink_wants().max_pixel_count,
+ current_wants.max_pixel_count);
+ EXPECT_EQ(video_source_.sink_wants().max_pixel_count_step_up,
+ current_wants.max_pixel_count_step_up);
+
+ // Trigger CPU normal use.
+ vie_encoder_->TriggerCpuNormalUsage();
+ EXPECT_FALSE(video_source_.sink_wants().max_pixel_count);
+ EXPECT_EQ(video_source_.sink_wants().max_pixel_count_step_up.value_or(0),
+ frame_width * frame_height);
+
+ vie_encoder_->Stop();
+}
+
+TEST_F(ViEEncoderTest,
+ ResolutionSinkWantsResetOnSetSourceWithDisabledResolutionScaling) {
+ const int kTargetBitrateBps = 100000;
+ vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
+
+ EXPECT_FALSE(video_source_.sink_wants().max_pixel_count);
+ EXPECT_FALSE(video_source_.sink_wants().max_pixel_count_step_up);
+
+ int frame_width = 1280;
+ int frame_height = 720;
+
+ // Trigger CPU overuse.
+ vie_encoder_->TriggerCpuOveruse();
+
+ video_source_.IncomingCapturedFrame(
+ CreateFrame(1, frame_width, frame_height));
+ sink_.WaitForEncodedFrame(1);
+ EXPECT_LT(video_source_.sink_wants().max_pixel_count.value_or(
+ std::numeric_limits<int>::max()),
+ frame_width * frame_height);
+ EXPECT_FALSE(video_source_.sink_wants().max_pixel_count_step_up);
+
+ // Set new source.
+ test::FrameForwarder new_video_source;
+ vie_encoder_->SetSource(
+ &new_video_source,
+ VideoSendStream::DegradationPreference::kMaintainResolution);
+
+ EXPECT_FALSE(new_video_source.sink_wants().max_pixel_count);
+ EXPECT_FALSE(new_video_source.sink_wants().max_pixel_count_step_up);
+
+ new_video_source.IncomingCapturedFrame(
+ CreateFrame(2, frame_width, frame_height));
+ sink_.WaitForEncodedFrame(2);
+ EXPECT_FALSE(new_video_source.sink_wants().max_pixel_count);
+ EXPECT_FALSE(new_video_source.sink_wants().max_pixel_count_step_up);
+
+ // Calling SetSource with resolution scaling enabled apply the old SinkWants.
+ vie_encoder_->SetSource(&new_video_source,
+ VideoSendStream::DegradationPreference::kBalanced);
+ EXPECT_LT(new_video_source.sink_wants().max_pixel_count.value_or(
+ std::numeric_limits<int>::max()),
+ frame_width * frame_height);
+ EXPECT_FALSE(new_video_source.sink_wants().max_pixel_count_step_up);
+
+ vie_encoder_->Stop();
+}
+
+TEST_F(ViEEncoderTest, StatsTracksAdaptationStats) {
+ const int kTargetBitrateBps = 100000;
+ vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
+
+ int frame_width = 1280;
+ int frame_height = 720;
+
+ video_source_.IncomingCapturedFrame(
+ CreateFrame(1, frame_width, frame_height));
+ sink_.WaitForEncodedFrame(1);
+ VideoSendStream::Stats stats = stats_proxy_->GetStats();
+ EXPECT_FALSE(stats.cpu_limited_resolution);
+ EXPECT_EQ(0, stats.number_of_cpu_adapt_changes);
+
+ // Trigger CPU overuse.
+ vie_encoder_->TriggerCpuOveruse();
+ video_source_.IncomingCapturedFrame(
+ CreateFrame(2, frame_width, frame_height));
+ sink_.WaitForEncodedFrame(2);
+
+ stats = stats_proxy_->GetStats();
+ EXPECT_TRUE(stats.cpu_limited_resolution);
+ EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
+
+ // Trigger CPU normal use.
+ vie_encoder_->TriggerCpuNormalUsage();
+ video_source_.IncomingCapturedFrame(
+ CreateFrame(3, frame_width, frame_height));
+ sink_.WaitForEncodedFrame(3);
+
+ stats = stats_proxy_->GetStats();
+ EXPECT_FALSE(stats.cpu_limited_resolution);
+ EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
+
+ vie_encoder_->Stop();
+}
+
+TEST_F(ViEEncoderTest, StatsTracksAdaptationStatsWhenSwitchingSource) {
+ const int kTargetBitrateBps = 100000;
+ vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
+
+ // Trigger CPU overuse.
+ vie_encoder_->TriggerCpuOveruse();
+ int frame_width = 1280;
+ int frame_height = 720;
+
+ video_source_.IncomingCapturedFrame(
+ CreateFrame(1, frame_width, frame_height));
+ sink_.WaitForEncodedFrame(1);
+
+ VideoSendStream::Stats stats = stats_proxy_->GetStats();
+ EXPECT_TRUE(stats.cpu_limited_resolution);
+ EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
+
+ // Set new source with adaptation still enabled.
+ test::FrameForwarder new_video_source;
+ vie_encoder_->SetSource(&new_video_source,
+ VideoSendStream::DegradationPreference::kBalanced);
+
+ new_video_source.IncomingCapturedFrame(
+ CreateFrame(2, frame_width, frame_height));
+ sink_.WaitForEncodedFrame(2);
+ stats = stats_proxy_->GetStats();
+ EXPECT_TRUE(stats.cpu_limited_resolution);
+ EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
+
+ // Set adaptation disabled.
+ vie_encoder_->SetSource(
+ &new_video_source,
+ VideoSendStream::DegradationPreference::kMaintainResolution);
+ new_video_source.IncomingCapturedFrame(
+ CreateFrame(3, frame_width, frame_height));
+ sink_.WaitForEncodedFrame(3);
+ stats = stats_proxy_->GetStats();
+ EXPECT_FALSE(stats.cpu_limited_resolution);
+ EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
+
+ // Switch back the source with adaptation enabled.
+ vie_encoder_->SetSource(&video_source_,
+ VideoSendStream::DegradationPreference::kBalanced);
+ video_source_.IncomingCapturedFrame(
+ CreateFrame(4, frame_width, frame_height));
+ sink_.WaitForEncodedFrame(4);
+ stats = stats_proxy_->GetStats();
+ EXPECT_TRUE(stats.cpu_limited_resolution);
+ EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
+
+ // Trigger CPU normal usage.
+ vie_encoder_->TriggerCpuNormalUsage();
+ video_source_.IncomingCapturedFrame(
+ CreateFrame(5, frame_width, frame_height));
+ sink_.WaitForEncodedFrame(5);
+ stats = stats_proxy_->GetStats();
+ EXPECT_FALSE(stats.cpu_limited_resolution);
+ EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
+
+ vie_encoder_->Stop();
+}
+
+TEST_F(ViEEncoderTest, UMACpuLimitedResolutionInPercent) {
+ const int kTargetBitrateBps = 100000;
+ vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
+
+ int frame_width = 640;
+ int frame_height = 360;
+
+ for (int i = 1; i <= SendStatisticsProxy::kMinRequiredMetricsSamples; ++i) {
+ video_source_.IncomingCapturedFrame(
+ CreateFrame(i, frame_width, frame_height));
+ sink_.WaitForEncodedFrame(i);
+ }
+
+ vie_encoder_->TriggerCpuOveruse();
+ for (int i = 1; i <= SendStatisticsProxy::kMinRequiredMetricsSamples; ++i) {
+ video_source_.IncomingCapturedFrame(
+ CreateFrame(SendStatisticsProxy::kMinRequiredMetricsSamples + i,
+ frame_width, frame_height));
+ sink_.WaitForEncodedFrame(SendStatisticsProxy::kMinRequiredMetricsSamples +
+ i);
+ }
+
+ vie_encoder_->Stop();
+
+ stats_proxy_.reset();
+ EXPECT_EQ(1,
+ metrics::NumSamples("WebRTC.Video.CpuLimitedResolutionInPercent"));
+ EXPECT_EQ(
+ 1, metrics::NumEvents("WebRTC.Video.CpuLimitedResolutionInPercent", 50));
+}
+
} // namespace webrtc
« no previous file with comments | « webrtc/video/vie_encoder.cc ('k') | webrtc/video_send_stream.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698