blob: b18abbe488c883cece9c604dce6dbe3d7d4f9790 [file] [log] [blame]
perkj26091b12016-09-01 01:17:40 -07001/*
2 * Copyright (c) 2016 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
sprangfe627f32017-03-29 08:24:59 -070011#include <algorithm>
perkj803d97f2016-11-01 11:45:46 -070012#include <limits>
Per512ecb32016-09-23 15:52:06 +020013#include <utility>
14
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020015#include "api/video/i420_buffer.h"
16#include "media/base/videoadapter.h"
17#include "modules/video_coding/codecs/vp8/temporal_layers.h"
Sergey Silkin86684962018-03-28 19:32:37 +020018#include "modules/video_coding/codecs/vp9/include/vp9_globals.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020019#include "modules/video_coding/utility/default_video_bitrate_allocator.h"
20#include "rtc_base/fakeclock.h"
21#include "rtc_base/logging.h"
22#include "system_wrappers/include/metrics_default.h"
23#include "system_wrappers/include/sleep.h"
Niels Möller4db138e2018-04-19 09:04:13 +020024#include "test/encoder_proxy_factory.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020025#include "test/encoder_settings.h"
26#include "test/fake_encoder.h"
27#include "test/frame_generator.h"
28#include "test/gmock.h"
29#include "test/gtest.h"
30#include "video/send_statistics_proxy.h"
31#include "video/video_stream_encoder.h"
perkj26091b12016-09-01 01:17:40 -070032
kthelgason33ce8892016-12-09 03:53:59 -080033namespace {
kthelgason33ce8892016-12-09 03:53:59 -080034const int kMinPixelsPerFrame = 320 * 180;
sprangc5d62e22017-04-02 23:53:04 -070035const int kMinFramerateFps = 2;
Jonathan Yubc771b72017-12-08 17:04:29 -080036const int kMinBalancedFramerateFps = 7;
sprangc5d62e22017-04-02 23:53:04 -070037const int64_t kFrameTimeoutMs = 100;
38} // namespace
kthelgason33ce8892016-12-09 03:53:59 -080039
perkj26091b12016-09-01 01:17:40 -070040namespace webrtc {
41
sprangb1ca0732017-02-01 08:38:12 -080042using ScaleReason = AdaptationObserverInterface::AdaptReason;
sprang57c2fff2017-01-16 06:24:02 -080043using ::testing::_;
44using ::testing::Return;
kthelgason876222f2016-11-29 01:44:11 -080045
perkj803d97f2016-11-01 11:45:46 -070046namespace {
asapersson5f7226f2016-11-25 04:37:00 -080047const size_t kMaxPayloadLength = 1440;
kthelgason2bc68642017-02-07 07:02:22 -080048const int kTargetBitrateBps = 1000000;
49const int kLowTargetBitrateBps = kTargetBitrateBps / 10;
50const int kMaxInitialFramedrop = 4;
sprangfda496a2017-06-15 04:21:07 -070051const int kDefaultFramerate = 30;
asapersson5f7226f2016-11-25 04:37:00 -080052
perkj803d97f2016-11-01 11:45:46 -070053class TestBuffer : public webrtc::I420Buffer {
54 public:
55 TestBuffer(rtc::Event* event, int width, int height)
56 : I420Buffer(width, height), event_(event) {}
57
58 private:
59 friend class rtc::RefCountedObject<TestBuffer>;
60 ~TestBuffer() override {
61 if (event_)
62 event_->Set();
63 }
64 rtc::Event* const event_;
65};
66
Niels Möller7dc26b72017-12-06 10:27:48 +010067class CpuOveruseDetectorProxy : public OveruseFrameDetector {
68 public:
Niels Möllerd1f7eb62018-03-28 16:40:58 +020069 explicit CpuOveruseDetectorProxy(CpuOveruseMetricsObserver* metrics_observer)
70 : OveruseFrameDetector(metrics_observer),
Niels Möller7dc26b72017-12-06 10:27:48 +010071 last_target_framerate_fps_(-1) {}
72 virtual ~CpuOveruseDetectorProxy() {}
73
74 void OnTargetFramerateUpdated(int framerate_fps) override {
75 rtc::CritScope cs(&lock_);
76 last_target_framerate_fps_ = framerate_fps;
77 OveruseFrameDetector::OnTargetFramerateUpdated(framerate_fps);
78 }
79
80 int GetLastTargetFramerate() {
81 rtc::CritScope cs(&lock_);
82 return last_target_framerate_fps_;
83 }
84
Niels Möller4db138e2018-04-19 09:04:13 +020085 CpuOveruseOptions GetOptions() { return options_; }
86
Niels Möller7dc26b72017-12-06 10:27:48 +010087 private:
88 rtc::CriticalSection lock_;
89 int last_target_framerate_fps_ RTC_GUARDED_BY(lock_);
90};
91
mflodmancc3d4422017-08-03 08:27:51 -070092class VideoStreamEncoderUnderTest : public VideoStreamEncoder {
perkj803d97f2016-11-01 11:45:46 -070093 public:
Niels Möller7dc26b72017-12-06 10:27:48 +010094 VideoStreamEncoderUnderTest(SendStatisticsProxy* stats_proxy,
95 const VideoSendStream::Config::EncoderSettings& settings)
mflodmancc3d4422017-08-03 08:27:51 -070096 : VideoStreamEncoder(
97 1 /* number_of_cores */,
98 stats_proxy,
99 settings,
100 nullptr /* pre_encode_callback */,
mflodmancc3d4422017-08-03 08:27:51 -0700101 std::unique_ptr<OveruseFrameDetector>(
Niels Möller7dc26b72017-12-06 10:27:48 +0100102 overuse_detector_proxy_ = new CpuOveruseDetectorProxy(
mflodmancc3d4422017-08-03 08:27:51 -0700103 stats_proxy))) {}
perkj803d97f2016-11-01 11:45:46 -0700104
sprangb1ca0732017-02-01 08:38:12 -0800105 void PostTaskAndWait(bool down, AdaptReason reason) {
perkj803d97f2016-11-01 11:45:46 -0700106 rtc::Event event(false, false);
kthelgason876222f2016-11-29 01:44:11 -0800107 encoder_queue()->PostTask([this, &event, reason, down] {
sprangb1ca0732017-02-01 08:38:12 -0800108 down ? AdaptDown(reason) : AdaptUp(reason);
perkj803d97f2016-11-01 11:45:46 -0700109 event.Set();
110 });
perkj070ba852017-02-16 15:46:27 -0800111 ASSERT_TRUE(event.Wait(5000));
perkj803d97f2016-11-01 11:45:46 -0700112 }
113
kthelgason2fc52542017-03-03 00:24:41 -0800114 // This is used as a synchronisation mechanism, to make sure that the
115 // encoder queue is not blocked before we start sending it frames.
116 void WaitUntilTaskQueueIsIdle() {
117 rtc::Event event(false, false);
118 encoder_queue()->PostTask([&event] {
119 event.Set();
120 });
121 ASSERT_TRUE(event.Wait(5000));
122 }
123
sprangb1ca0732017-02-01 08:38:12 -0800124 void TriggerCpuOveruse() { PostTaskAndWait(true, AdaptReason::kCpu); }
kthelgason876222f2016-11-29 01:44:11 -0800125
sprangb1ca0732017-02-01 08:38:12 -0800126 void TriggerCpuNormalUsage() { PostTaskAndWait(false, AdaptReason::kCpu); }
kthelgason876222f2016-11-29 01:44:11 -0800127
sprangb1ca0732017-02-01 08:38:12 -0800128 void TriggerQualityLow() { PostTaskAndWait(true, AdaptReason::kQuality); }
kthelgason876222f2016-11-29 01:44:11 -0800129
sprangb1ca0732017-02-01 08:38:12 -0800130 void TriggerQualityHigh() { PostTaskAndWait(false, AdaptReason::kQuality); }
sprangfda496a2017-06-15 04:21:07 -0700131
Niels Möller7dc26b72017-12-06 10:27:48 +0100132 CpuOveruseDetectorProxy* overuse_detector_proxy_;
perkj803d97f2016-11-01 11:45:46 -0700133};
134
asapersson5f7226f2016-11-25 04:37:00 -0800135class VideoStreamFactory
136 : public VideoEncoderConfig::VideoStreamFactoryInterface {
137 public:
sprangfda496a2017-06-15 04:21:07 -0700138 explicit VideoStreamFactory(size_t num_temporal_layers, int framerate)
139 : num_temporal_layers_(num_temporal_layers), framerate_(framerate) {
asapersson5f7226f2016-11-25 04:37:00 -0800140 EXPECT_GT(num_temporal_layers, 0u);
sprangfda496a2017-06-15 04:21:07 -0700141 EXPECT_GT(framerate, 0);
asapersson5f7226f2016-11-25 04:37:00 -0800142 }
143
144 private:
145 std::vector<VideoStream> CreateEncoderStreams(
146 int width,
147 int height,
148 const VideoEncoderConfig& encoder_config) override {
149 std::vector<VideoStream> streams =
150 test::CreateVideoStreams(width, height, encoder_config);
151 for (VideoStream& stream : streams) {
Sergey Silkina796a7e2018-03-01 15:11:29 +0100152 stream.num_temporal_layers = num_temporal_layers_;
sprangfda496a2017-06-15 04:21:07 -0700153 stream.max_framerate = framerate_;
asapersson5f7226f2016-11-25 04:37:00 -0800154 }
155 return streams;
156 }
sprangfda496a2017-06-15 04:21:07 -0700157
asapersson5f7226f2016-11-25 04:37:00 -0800158 const size_t num_temporal_layers_;
sprangfda496a2017-06-15 04:21:07 -0700159 const int framerate_;
asapersson5f7226f2016-11-25 04:37:00 -0800160};
161
ilnik6b826ef2017-06-16 06:53:48 -0700162
sprangb1ca0732017-02-01 08:38:12 -0800163class AdaptingFrameForwarder : public test::FrameForwarder {
164 public:
165 AdaptingFrameForwarder() : adaptation_enabled_(false) {}
asaperssonfab67072017-04-04 05:51:49 -0700166 ~AdaptingFrameForwarder() override {}
sprangb1ca0732017-02-01 08:38:12 -0800167
168 void set_adaptation_enabled(bool enabled) {
169 rtc::CritScope cs(&crit_);
170 adaptation_enabled_ = enabled;
171 }
172
asaperssonfab67072017-04-04 05:51:49 -0700173 bool adaption_enabled() const {
sprangb1ca0732017-02-01 08:38:12 -0800174 rtc::CritScope cs(&crit_);
175 return adaptation_enabled_;
176 }
177
asapersson09f05612017-05-15 23:40:18 -0700178 rtc::VideoSinkWants last_wants() const {
179 rtc::CritScope cs(&crit_);
180 return last_wants_;
181 }
182
Jonathan Yubc771b72017-12-08 17:04:29 -0800183 rtc::Optional<int> last_sent_width() const { return last_width_; }
184 rtc::Optional<int> last_sent_height() const { return last_height_; }
185
sprangb1ca0732017-02-01 08:38:12 -0800186 void IncomingCapturedFrame(const VideoFrame& video_frame) override {
187 int cropped_width = 0;
188 int cropped_height = 0;
189 int out_width = 0;
190 int out_height = 0;
sprangc5d62e22017-04-02 23:53:04 -0700191 if (adaption_enabled()) {
192 if (adapter_.AdaptFrameResolution(
193 video_frame.width(), video_frame.height(),
194 video_frame.timestamp_us() * 1000, &cropped_width,
195 &cropped_height, &out_width, &out_height)) {
196 VideoFrame adapted_frame(new rtc::RefCountedObject<TestBuffer>(
197 nullptr, out_width, out_height),
198 99, 99, kVideoRotation_0);
199 adapted_frame.set_ntp_time_ms(video_frame.ntp_time_ms());
200 test::FrameForwarder::IncomingCapturedFrame(adapted_frame);
Jonathan Yubc771b72017-12-08 17:04:29 -0800201 last_width_.emplace(adapted_frame.width());
202 last_height_.emplace(adapted_frame.height());
203 } else {
204 last_width_ = rtc::nullopt;
205 last_height_ = rtc::nullopt;
sprangc5d62e22017-04-02 23:53:04 -0700206 }
sprangb1ca0732017-02-01 08:38:12 -0800207 } else {
208 test::FrameForwarder::IncomingCapturedFrame(video_frame);
Jonathan Yubc771b72017-12-08 17:04:29 -0800209 last_width_.emplace(video_frame.width());
210 last_height_.emplace(video_frame.height());
sprangb1ca0732017-02-01 08:38:12 -0800211 }
212 }
213
214 void AddOrUpdateSink(rtc::VideoSinkInterface<VideoFrame>* sink,
215 const rtc::VideoSinkWants& wants) override {
216 rtc::CritScope cs(&crit_);
asapersson09f05612017-05-15 23:40:18 -0700217 last_wants_ = sink_wants();
sprangc5d62e22017-04-02 23:53:04 -0700218 adapter_.OnResolutionFramerateRequest(wants.target_pixel_count,
219 wants.max_pixel_count,
220 wants.max_framerate_fps);
sprangb1ca0732017-02-01 08:38:12 -0800221 test::FrameForwarder::AddOrUpdateSink(sink, wants);
222 }
sprangb1ca0732017-02-01 08:38:12 -0800223 cricket::VideoAdapter adapter_;
danilchapa37de392017-09-09 04:17:22 -0700224 bool adaptation_enabled_ RTC_GUARDED_BY(crit_);
225 rtc::VideoSinkWants last_wants_ RTC_GUARDED_BY(crit_);
Jonathan Yubc771b72017-12-08 17:04:29 -0800226 rtc::Optional<int> last_width_;
227 rtc::Optional<int> last_height_;
sprangb1ca0732017-02-01 08:38:12 -0800228};
sprangc5d62e22017-04-02 23:53:04 -0700229
230class MockableSendStatisticsProxy : public SendStatisticsProxy {
231 public:
232 MockableSendStatisticsProxy(Clock* clock,
233 const VideoSendStream::Config& config,
234 VideoEncoderConfig::ContentType content_type)
235 : SendStatisticsProxy(clock, config, content_type) {}
236
237 VideoSendStream::Stats GetStats() override {
238 rtc::CritScope cs(&lock_);
239 if (mock_stats_)
240 return *mock_stats_;
241 return SendStatisticsProxy::GetStats();
242 }
243
244 void SetMockStats(const VideoSendStream::Stats& stats) {
245 rtc::CritScope cs(&lock_);
246 mock_stats_.emplace(stats);
247 }
248
249 void ResetMockStats() {
250 rtc::CritScope cs(&lock_);
251 mock_stats_.reset();
252 }
253
254 private:
255 rtc::CriticalSection lock_;
danilchapa37de392017-09-09 04:17:22 -0700256 rtc::Optional<VideoSendStream::Stats> mock_stats_ RTC_GUARDED_BY(lock_);
sprangc5d62e22017-04-02 23:53:04 -0700257};
258
sprang4847ae62017-06-27 07:06:52 -0700259class MockBitrateObserver : public VideoBitrateAllocationObserver {
260 public:
Erik Språng566124a2018-04-23 12:32:22 +0200261 MOCK_METHOD1(OnBitrateAllocationUpdated, void(const VideoBitrateAllocation&));
sprang4847ae62017-06-27 07:06:52 -0700262};
263
perkj803d97f2016-11-01 11:45:46 -0700264} // namespace
265
mflodmancc3d4422017-08-03 08:27:51 -0700266class VideoStreamEncoderTest : public ::testing::Test {
perkj26091b12016-09-01 01:17:40 -0700267 public:
268 static const int kDefaultTimeoutMs = 30 * 1000;
269
mflodmancc3d4422017-08-03 08:27:51 -0700270 VideoStreamEncoderTest()
perkj26091b12016-09-01 01:17:40 -0700271 : video_send_config_(VideoSendStream::Config(nullptr)),
perkjfa10b552016-10-02 23:45:26 -0700272 codec_width_(320),
273 codec_height_(240),
sprang4847ae62017-06-27 07:06:52 -0700274 max_framerate_(30),
perkj26091b12016-09-01 01:17:40 -0700275 fake_encoder_(),
Niels Möller4db138e2018-04-19 09:04:13 +0200276 encoder_factory_(&fake_encoder_),
sprangc5d62e22017-04-02 23:53:04 -0700277 stats_proxy_(new MockableSendStatisticsProxy(
perkj803d97f2016-11-01 11:45:46 -0700278 Clock::GetRealTimeClock(),
279 video_send_config_,
280 webrtc::VideoEncoderConfig::ContentType::kRealtimeVideo)),
perkj26091b12016-09-01 01:17:40 -0700281 sink_(&fake_encoder_) {}
282
283 void SetUp() override {
perkj803d97f2016-11-01 11:45:46 -0700284 metrics::Reset();
perkj26091b12016-09-01 01:17:40 -0700285 video_send_config_ = VideoSendStream::Config(nullptr);
Niels Möller4db138e2018-04-19 09:04:13 +0200286 video_send_config_.encoder_settings.encoder_factory = &encoder_factory_;
Niels Möller259a4972018-04-05 15:36:51 +0200287 video_send_config_.rtp.payload_name = "FAKE";
288 video_send_config_.rtp.payload_type = 125;
perkj26091b12016-09-01 01:17:40 -0700289
Per512ecb32016-09-23 15:52:06 +0200290 VideoEncoderConfig video_encoder_config;
Niels Möller259a4972018-04-05 15:36:51 +0200291 test::FillEncoderConfiguration(kVideoCodecVP8, 1, &video_encoder_config);
sprang4847ae62017-06-27 07:06:52 -0700292 video_encoder_config.video_stream_factory =
293 new rtc::RefCountedObject<VideoStreamFactory>(1, max_framerate_);
Erik Språng08127a92016-11-16 16:41:30 +0100294 video_encoder_config_ = video_encoder_config.Copy();
sprang4847ae62017-06-27 07:06:52 -0700295
296 // Framerate limit is specified by the VideoStreamFactory.
297 std::vector<VideoStream> streams =
298 video_encoder_config.video_stream_factory->CreateEncoderStreams(
299 codec_width_, codec_height_, video_encoder_config);
300 max_framerate_ = streams[0].max_framerate;
301 fake_clock_.SetTimeMicros(1234);
302
Niels Möllerf1338562018-04-26 09:51:47 +0200303 ConfigureEncoder(std::move(video_encoder_config));
asapersson5f7226f2016-11-25 04:37:00 -0800304 }
305
Niels Möllerf1338562018-04-26 09:51:47 +0200306 void ConfigureEncoder(VideoEncoderConfig video_encoder_config) {
mflodmancc3d4422017-08-03 08:27:51 -0700307 if (video_stream_encoder_)
308 video_stream_encoder_->Stop();
309 video_stream_encoder_.reset(new VideoStreamEncoderUnderTest(
perkj803d97f2016-11-01 11:45:46 -0700310 stats_proxy_.get(), video_send_config_.encoder_settings));
mflodmancc3d4422017-08-03 08:27:51 -0700311 video_stream_encoder_->SetSink(&sink_, false /* rotation_applied */);
312 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -0700313 &video_source_, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
mflodmancc3d4422017-08-03 08:27:51 -0700314 video_stream_encoder_->SetStartBitrate(kTargetBitrateBps);
315 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
Niels Möllerf1338562018-04-26 09:51:47 +0200316 kMaxPayloadLength);
mflodmancc3d4422017-08-03 08:27:51 -0700317 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
asapersson5f7226f2016-11-25 04:37:00 -0800318 }
319
320 void ResetEncoder(const std::string& payload_name,
321 size_t num_streams,
322 size_t num_temporal_layers,
emircanbbcc3562017-08-18 00:28:40 -0700323 unsigned char num_spatial_layers,
sprang4847ae62017-06-27 07:06:52 -0700324 bool screenshare) {
Niels Möller259a4972018-04-05 15:36:51 +0200325 video_send_config_.rtp.payload_name = payload_name;
asapersson5f7226f2016-11-25 04:37:00 -0800326
327 VideoEncoderConfig video_encoder_config;
Niels Möller259a4972018-04-05 15:36:51 +0200328 video_encoder_config.codec_type = PayloadStringToCodecType(payload_name);
asapersson5f7226f2016-11-25 04:37:00 -0800329 video_encoder_config.number_of_streams = num_streams;
kthelgason2bc68642017-02-07 07:02:22 -0800330 video_encoder_config.max_bitrate_bps = kTargetBitrateBps;
asapersson5f7226f2016-11-25 04:37:00 -0800331 video_encoder_config.video_stream_factory =
sprangfda496a2017-06-15 04:21:07 -0700332 new rtc::RefCountedObject<VideoStreamFactory>(num_temporal_layers,
333 kDefaultFramerate);
sprang4847ae62017-06-27 07:06:52 -0700334 video_encoder_config.content_type =
335 screenshare ? VideoEncoderConfig::ContentType::kScreen
336 : VideoEncoderConfig::ContentType::kRealtimeVideo;
emircanbbcc3562017-08-18 00:28:40 -0700337 if (payload_name == "VP9") {
338 VideoCodecVP9 vp9_settings = VideoEncoder::GetDefaultVp9Settings();
339 vp9_settings.numberOfSpatialLayers = num_spatial_layers;
340 video_encoder_config.encoder_specific_settings =
341 new rtc::RefCountedObject<
342 VideoEncoderConfig::Vp9EncoderSpecificSettings>(vp9_settings);
343 }
Niels Möllerf1338562018-04-26 09:51:47 +0200344 ConfigureEncoder(std::move(video_encoder_config));
perkj26091b12016-09-01 01:17:40 -0700345 }
346
sprang57c2fff2017-01-16 06:24:02 -0800347 VideoFrame CreateFrame(int64_t ntp_time_ms,
348 rtc::Event* destruction_event) const {
Per512ecb32016-09-23 15:52:06 +0200349 VideoFrame frame(new rtc::RefCountedObject<TestBuffer>(
350 destruction_event, codec_width_, codec_height_),
351 99, 99, kVideoRotation_0);
sprang57c2fff2017-01-16 06:24:02 -0800352 frame.set_ntp_time_ms(ntp_time_ms);
perkj26091b12016-09-01 01:17:40 -0700353 return frame;
354 }
355
sprang57c2fff2017-01-16 06:24:02 -0800356 VideoFrame CreateFrame(int64_t ntp_time_ms, int width, int height) const {
perkj803d97f2016-11-01 11:45:46 -0700357 VideoFrame frame(
358 new rtc::RefCountedObject<TestBuffer>(nullptr, width, height), 99, 99,
359 kVideoRotation_0);
sprang57c2fff2017-01-16 06:24:02 -0800360 frame.set_ntp_time_ms(ntp_time_ms);
sprangc5d62e22017-04-02 23:53:04 -0700361 frame.set_timestamp_us(ntp_time_ms * 1000);
perkj803d97f2016-11-01 11:45:46 -0700362 return frame;
363 }
364
asapersson02465b82017-04-10 01:12:52 -0700365 void VerifyNoLimitation(const rtc::VideoSinkWants& wants) {
asapersson02465b82017-04-10 01:12:52 -0700366 EXPECT_EQ(std::numeric_limits<int>::max(), wants.max_framerate_fps);
asapersson09f05612017-05-15 23:40:18 -0700367 EXPECT_EQ(std::numeric_limits<int>::max(), wants.max_pixel_count);
368 EXPECT_FALSE(wants.target_pixel_count);
asapersson02465b82017-04-10 01:12:52 -0700369 }
370
asapersson09f05612017-05-15 23:40:18 -0700371 void VerifyFpsEqResolutionEq(const rtc::VideoSinkWants& wants1,
372 const rtc::VideoSinkWants& wants2) {
373 EXPECT_EQ(wants1.max_framerate_fps, wants2.max_framerate_fps);
374 EXPECT_EQ(wants1.max_pixel_count, wants2.max_pixel_count);
375 }
376
377 void VerifyFpsMaxResolutionLt(const rtc::VideoSinkWants& wants1,
378 const rtc::VideoSinkWants& wants2) {
379 EXPECT_EQ(std::numeric_limits<int>::max(), wants1.max_framerate_fps);
380 EXPECT_LT(wants1.max_pixel_count, wants2.max_pixel_count);
381 EXPECT_GT(wants1.max_pixel_count, 0);
382 }
383
384 void VerifyFpsMaxResolutionGt(const rtc::VideoSinkWants& wants1,
385 const rtc::VideoSinkWants& wants2) {
386 EXPECT_EQ(std::numeric_limits<int>::max(), wants1.max_framerate_fps);
387 EXPECT_GT(wants1.max_pixel_count, wants2.max_pixel_count);
388 }
389
asaperssonf7e294d2017-06-13 23:25:22 -0700390 void VerifyFpsMaxResolutionEq(const rtc::VideoSinkWants& wants1,
391 const rtc::VideoSinkWants& wants2) {
392 EXPECT_EQ(std::numeric_limits<int>::max(), wants1.max_framerate_fps);
393 EXPECT_EQ(wants1.max_pixel_count, wants2.max_pixel_count);
394 }
395
396 void VerifyFpsLtResolutionEq(const rtc::VideoSinkWants& wants1,
397 const rtc::VideoSinkWants& wants2) {
398 EXPECT_LT(wants1.max_framerate_fps, wants2.max_framerate_fps);
399 EXPECT_EQ(wants1.max_pixel_count, wants2.max_pixel_count);
400 }
401
402 void VerifyFpsGtResolutionEq(const rtc::VideoSinkWants& wants1,
403 const rtc::VideoSinkWants& wants2) {
404 EXPECT_GT(wants1.max_framerate_fps, wants2.max_framerate_fps);
405 EXPECT_EQ(wants1.max_pixel_count, wants2.max_pixel_count);
406 }
407
408 void VerifyFpsEqResolutionLt(const rtc::VideoSinkWants& wants1,
409 const rtc::VideoSinkWants& wants2) {
410 EXPECT_EQ(wants1.max_framerate_fps, wants2.max_framerate_fps);
411 EXPECT_LT(wants1.max_pixel_count, wants2.max_pixel_count);
412 EXPECT_GT(wants1.max_pixel_count, 0);
413 }
414
415 void VerifyFpsEqResolutionGt(const rtc::VideoSinkWants& wants1,
416 const rtc::VideoSinkWants& wants2) {
417 EXPECT_EQ(wants1.max_framerate_fps, wants2.max_framerate_fps);
418 EXPECT_GT(wants1.max_pixel_count, wants2.max_pixel_count);
419 }
420
asapersson09f05612017-05-15 23:40:18 -0700421 void VerifyFpsMaxResolutionLt(const rtc::VideoSinkWants& wants,
422 int pixel_count) {
423 EXPECT_EQ(std::numeric_limits<int>::max(), wants.max_framerate_fps);
asapersson02465b82017-04-10 01:12:52 -0700424 EXPECT_LT(wants.max_pixel_count, pixel_count);
425 EXPECT_GT(wants.max_pixel_count, 0);
asapersson09f05612017-05-15 23:40:18 -0700426 }
427
428 void VerifyFpsLtResolutionMax(const rtc::VideoSinkWants& wants, int fps) {
429 EXPECT_LT(wants.max_framerate_fps, fps);
430 EXPECT_EQ(std::numeric_limits<int>::max(), wants.max_pixel_count);
431 EXPECT_FALSE(wants.target_pixel_count);
asapersson02465b82017-04-10 01:12:52 -0700432 }
433
asaperssonf7e294d2017-06-13 23:25:22 -0700434 void VerifyFpsEqResolutionMax(const rtc::VideoSinkWants& wants,
435 int expected_fps) {
436 EXPECT_EQ(expected_fps, wants.max_framerate_fps);
437 EXPECT_EQ(std::numeric_limits<int>::max(), wants.max_pixel_count);
438 EXPECT_FALSE(wants.target_pixel_count);
439 }
440
Jonathan Yubc771b72017-12-08 17:04:29 -0800441 void VerifyBalancedModeFpsRange(const rtc::VideoSinkWants& wants,
442 int last_frame_pixels) {
443 // Balanced mode should always scale FPS to the desired range before
444 // attempting to scale resolution.
445 int fps_limit = wants.max_framerate_fps;
446 if (last_frame_pixels <= 320 * 240) {
447 EXPECT_TRUE(7 <= fps_limit && fps_limit <= 10);
448 } else if (last_frame_pixels <= 480 * 270) {
449 EXPECT_TRUE(10 <= fps_limit && fps_limit <= 15);
450 } else if (last_frame_pixels <= 640 * 480) {
451 EXPECT_LE(15, fps_limit);
452 } else {
453 EXPECT_EQ(std::numeric_limits<int>::max(), fps_limit);
454 }
455 }
456
sprang4847ae62017-06-27 07:06:52 -0700457 void WaitForEncodedFrame(int64_t expected_ntp_time) {
458 sink_.WaitForEncodedFrame(expected_ntp_time);
459 fake_clock_.AdvanceTimeMicros(rtc::kNumMicrosecsPerSec / max_framerate_);
460 }
461
462 bool TimedWaitForEncodedFrame(int64_t expected_ntp_time, int64_t timeout_ms) {
463 bool ok = sink_.TimedWaitForEncodedFrame(expected_ntp_time, timeout_ms);
464 fake_clock_.AdvanceTimeMicros(rtc::kNumMicrosecsPerSec / max_framerate_);
465 return ok;
466 }
467
468 void WaitForEncodedFrame(uint32_t expected_width, uint32_t expected_height) {
469 sink_.WaitForEncodedFrame(expected_width, expected_height);
470 fake_clock_.AdvanceTimeMicros(rtc::kNumMicrosecsPerSec / max_framerate_);
471 }
472
473 void ExpectDroppedFrame() {
474 sink_.ExpectDroppedFrame();
475 fake_clock_.AdvanceTimeMicros(rtc::kNumMicrosecsPerSec / max_framerate_);
476 }
477
478 bool WaitForFrame(int64_t timeout_ms) {
479 bool ok = sink_.WaitForFrame(timeout_ms);
480 fake_clock_.AdvanceTimeMicros(rtc::kNumMicrosecsPerSec / max_framerate_);
481 return ok;
482 }
483
perkj26091b12016-09-01 01:17:40 -0700484 class TestEncoder : public test::FakeEncoder {
485 public:
486 TestEncoder()
487 : FakeEncoder(Clock::GetRealTimeClock()),
488 continue_encode_event_(false, false) {}
489
asaperssonfab67072017-04-04 05:51:49 -0700490 VideoCodec codec_config() const {
brandtre78d2662017-01-16 05:57:16 -0800491 rtc::CritScope lock(&crit_sect_);
perkjfa10b552016-10-02 23:45:26 -0700492 return config_;
493 }
494
495 void BlockNextEncode() {
brandtre78d2662017-01-16 05:57:16 -0800496 rtc::CritScope lock(&local_crit_sect_);
perkjfa10b552016-10-02 23:45:26 -0700497 block_next_encode_ = true;
498 }
499
kthelgason876222f2016-11-29 01:44:11 -0800500 VideoEncoder::ScalingSettings GetScalingSettings() const override {
kthelgason2fc52542017-03-03 00:24:41 -0800501 rtc::CritScope lock(&local_crit_sect_);
kthelgasonad9010c2017-02-14 00:46:51 -0800502 if (quality_scaling_)
Niels Möller225c7872018-02-22 15:03:53 +0100503 return VideoEncoder::ScalingSettings(1, 2, kMinPixelsPerFrame);
504 return VideoEncoder::ScalingSettings::kOff;
kthelgason876222f2016-11-29 01:44:11 -0800505 }
506
perkjfa10b552016-10-02 23:45:26 -0700507 void ContinueEncode() { continue_encode_event_.Set(); }
508
509 void CheckLastTimeStampsMatch(int64_t ntp_time_ms,
510 uint32_t timestamp) const {
brandtre78d2662017-01-16 05:57:16 -0800511 rtc::CritScope lock(&local_crit_sect_);
perkjfa10b552016-10-02 23:45:26 -0700512 EXPECT_EQ(timestamp_, timestamp);
513 EXPECT_EQ(ntp_time_ms_, ntp_time_ms);
514 }
515
kthelgason2fc52542017-03-03 00:24:41 -0800516 void SetQualityScaling(bool b) {
517 rtc::CritScope lock(&local_crit_sect_);
518 quality_scaling_ = b;
519 }
kthelgasonad9010c2017-02-14 00:46:51 -0800520
sprangfe627f32017-03-29 08:24:59 -0700521 void ForceInitEncodeFailure(bool force_failure) {
522 rtc::CritScope lock(&local_crit_sect_);
523 force_init_encode_failed_ = force_failure;
524 }
525
perkjfa10b552016-10-02 23:45:26 -0700526 private:
perkj26091b12016-09-01 01:17:40 -0700527 int32_t Encode(const VideoFrame& input_image,
528 const CodecSpecificInfo* codec_specific_info,
529 const std::vector<FrameType>* frame_types) override {
530 bool block_encode;
531 {
brandtre78d2662017-01-16 05:57:16 -0800532 rtc::CritScope lock(&local_crit_sect_);
perkj26091b12016-09-01 01:17:40 -0700533 EXPECT_GT(input_image.timestamp(), timestamp_);
534 EXPECT_GT(input_image.ntp_time_ms(), ntp_time_ms_);
535 EXPECT_EQ(input_image.timestamp(), input_image.ntp_time_ms() * 90);
536
537 timestamp_ = input_image.timestamp();
538 ntp_time_ms_ = input_image.ntp_time_ms();
perkj803d97f2016-11-01 11:45:46 -0700539 last_input_width_ = input_image.width();
540 last_input_height_ = input_image.height();
perkj26091b12016-09-01 01:17:40 -0700541 block_encode = block_next_encode_;
542 block_next_encode_ = false;
543 }
544 int32_t result =
545 FakeEncoder::Encode(input_image, codec_specific_info, frame_types);
546 if (block_encode)
perkja49cbd32016-09-16 07:53:41 -0700547 EXPECT_TRUE(continue_encode_event_.Wait(kDefaultTimeoutMs));
perkj26091b12016-09-01 01:17:40 -0700548 return result;
549 }
550
sprangfe627f32017-03-29 08:24:59 -0700551 int32_t InitEncode(const VideoCodec* config,
552 int32_t number_of_cores,
553 size_t max_payload_size) override {
554 int res =
555 FakeEncoder::InitEncode(config, number_of_cores, max_payload_size);
556 rtc::CritScope lock(&local_crit_sect_);
Erik Språng82fad3d2018-03-21 09:57:23 +0100557 if (config->codecType == kVideoCodecVP8) {
sprangfe627f32017-03-29 08:24:59 -0700558 // Simulate setting up temporal layers, in order to validate the life
559 // cycle of these objects.
560 int num_streams = std::max<int>(1, config->numberOfSimulcastStreams);
sprangfe627f32017-03-29 08:24:59 -0700561 for (int i = 0; i < num_streams; ++i) {
562 allocated_temporal_layers_.emplace_back(
Niels Möller150dcb02018-03-27 14:16:55 +0200563 TemporalLayers::CreateTemporalLayers(*config, i));
sprangfe627f32017-03-29 08:24:59 -0700564 }
565 }
566 if (force_init_encode_failed_)
567 return -1;
568 return res;
569 }
570
brandtre78d2662017-01-16 05:57:16 -0800571 rtc::CriticalSection local_crit_sect_;
danilchapa37de392017-09-09 04:17:22 -0700572 bool block_next_encode_ RTC_GUARDED_BY(local_crit_sect_) = false;
perkj26091b12016-09-01 01:17:40 -0700573 rtc::Event continue_encode_event_;
danilchapa37de392017-09-09 04:17:22 -0700574 uint32_t timestamp_ RTC_GUARDED_BY(local_crit_sect_) = 0;
575 int64_t ntp_time_ms_ RTC_GUARDED_BY(local_crit_sect_) = 0;
576 int last_input_width_ RTC_GUARDED_BY(local_crit_sect_) = 0;
577 int last_input_height_ RTC_GUARDED_BY(local_crit_sect_) = 0;
578 bool quality_scaling_ RTC_GUARDED_BY(local_crit_sect_) = true;
sprangfe627f32017-03-29 08:24:59 -0700579 std::vector<std::unique_ptr<TemporalLayers>> allocated_temporal_layers_
danilchapa37de392017-09-09 04:17:22 -0700580 RTC_GUARDED_BY(local_crit_sect_);
581 bool force_init_encode_failed_ RTC_GUARDED_BY(local_crit_sect_) = false;
perkj26091b12016-09-01 01:17:40 -0700582 };
583
mflodmancc3d4422017-08-03 08:27:51 -0700584 class TestSink : public VideoStreamEncoder::EncoderSink {
perkj26091b12016-09-01 01:17:40 -0700585 public:
586 explicit TestSink(TestEncoder* test_encoder)
587 : test_encoder_(test_encoder), encoded_frame_event_(false, false) {}
588
perkj26091b12016-09-01 01:17:40 -0700589 void WaitForEncodedFrame(int64_t expected_ntp_time) {
sprang4847ae62017-06-27 07:06:52 -0700590 EXPECT_TRUE(
591 TimedWaitForEncodedFrame(expected_ntp_time, kDefaultTimeoutMs));
592 }
593
594 bool TimedWaitForEncodedFrame(int64_t expected_ntp_time,
595 int64_t timeout_ms) {
perkj26091b12016-09-01 01:17:40 -0700596 uint32_t timestamp = 0;
sprang4847ae62017-06-27 07:06:52 -0700597 if (!encoded_frame_event_.Wait(timeout_ms))
598 return false;
perkj26091b12016-09-01 01:17:40 -0700599 {
600 rtc::CritScope lock(&crit_);
sprangb1ca0732017-02-01 08:38:12 -0800601 timestamp = last_timestamp_;
perkj26091b12016-09-01 01:17:40 -0700602 }
603 test_encoder_->CheckLastTimeStampsMatch(expected_ntp_time, timestamp);
sprang4847ae62017-06-27 07:06:52 -0700604 return true;
perkj26091b12016-09-01 01:17:40 -0700605 }
606
sprangb1ca0732017-02-01 08:38:12 -0800607 void WaitForEncodedFrame(uint32_t expected_width,
608 uint32_t expected_height) {
sprangc5d62e22017-04-02 23:53:04 -0700609 EXPECT_TRUE(encoded_frame_event_.Wait(kDefaultTimeoutMs));
Åsa Perssonc74d8da2017-12-04 14:13:56 +0100610 CheckLastFrameSizeMatches(expected_width, expected_height);
sprangc5d62e22017-04-02 23:53:04 -0700611 }
612
Åsa Perssonc74d8da2017-12-04 14:13:56 +0100613 void CheckLastFrameSizeMatches(uint32_t expected_width,
sprangc5d62e22017-04-02 23:53:04 -0700614 uint32_t expected_height) {
sprangb1ca0732017-02-01 08:38:12 -0800615 uint32_t width = 0;
616 uint32_t height = 0;
sprangb1ca0732017-02-01 08:38:12 -0800617 {
618 rtc::CritScope lock(&crit_);
619 width = last_width_;
620 height = last_height_;
621 }
622 EXPECT_EQ(expected_height, height);
623 EXPECT_EQ(expected_width, width);
624 }
625
kthelgason2fc52542017-03-03 00:24:41 -0800626 void ExpectDroppedFrame() { EXPECT_FALSE(encoded_frame_event_.Wait(100)); }
kthelgason2bc68642017-02-07 07:02:22 -0800627
sprangc5d62e22017-04-02 23:53:04 -0700628 bool WaitForFrame(int64_t timeout_ms) {
629 return encoded_frame_event_.Wait(timeout_ms);
630 }
631
perkj26091b12016-09-01 01:17:40 -0700632 void SetExpectNoFrames() {
633 rtc::CritScope lock(&crit_);
634 expect_frames_ = false;
635 }
636
asaperssonfab67072017-04-04 05:51:49 -0700637 int number_of_reconfigurations() const {
Per512ecb32016-09-23 15:52:06 +0200638 rtc::CritScope lock(&crit_);
639 return number_of_reconfigurations_;
640 }
641
asaperssonfab67072017-04-04 05:51:49 -0700642 int last_min_transmit_bitrate() const {
Per512ecb32016-09-23 15:52:06 +0200643 rtc::CritScope lock(&crit_);
644 return min_transmit_bitrate_bps_;
645 }
646
perkj26091b12016-09-01 01:17:40 -0700647 private:
sergeyu2cb155a2016-11-04 11:39:29 -0700648 Result OnEncodedImage(
649 const EncodedImage& encoded_image,
650 const CodecSpecificInfo* codec_specific_info,
651 const RTPFragmentationHeader* fragmentation) override {
Per512ecb32016-09-23 15:52:06 +0200652 rtc::CritScope lock(&crit_);
653 EXPECT_TRUE(expect_frames_);
sprangb1ca0732017-02-01 08:38:12 -0800654 last_timestamp_ = encoded_image._timeStamp;
655 last_width_ = encoded_image._encodedWidth;
656 last_height_ = encoded_image._encodedHeight;
Per512ecb32016-09-23 15:52:06 +0200657 encoded_frame_event_.Set();
sprangb1ca0732017-02-01 08:38:12 -0800658 return Result(Result::OK, last_timestamp_);
Per512ecb32016-09-23 15:52:06 +0200659 }
660
661 void OnEncoderConfigurationChanged(std::vector<VideoStream> streams,
662 int min_transmit_bitrate_bps) override {
663 rtc::CriticalSection crit_;
664 ++number_of_reconfigurations_;
665 min_transmit_bitrate_bps_ = min_transmit_bitrate_bps;
666 }
667
perkj26091b12016-09-01 01:17:40 -0700668 rtc::CriticalSection crit_;
669 TestEncoder* test_encoder_;
670 rtc::Event encoded_frame_event_;
sprangb1ca0732017-02-01 08:38:12 -0800671 uint32_t last_timestamp_ = 0;
672 uint32_t last_height_ = 0;
673 uint32_t last_width_ = 0;
perkj26091b12016-09-01 01:17:40 -0700674 bool expect_frames_ = true;
Per512ecb32016-09-23 15:52:06 +0200675 int number_of_reconfigurations_ = 0;
676 int min_transmit_bitrate_bps_ = 0;
perkj26091b12016-09-01 01:17:40 -0700677 };
678
679 VideoSendStream::Config video_send_config_;
Erik Språng08127a92016-11-16 16:41:30 +0100680 VideoEncoderConfig video_encoder_config_;
Per512ecb32016-09-23 15:52:06 +0200681 int codec_width_;
682 int codec_height_;
sprang4847ae62017-06-27 07:06:52 -0700683 int max_framerate_;
perkj26091b12016-09-01 01:17:40 -0700684 TestEncoder fake_encoder_;
Niels Möller4db138e2018-04-19 09:04:13 +0200685 test::EncoderProxyFactory encoder_factory_;
sprangc5d62e22017-04-02 23:53:04 -0700686 std::unique_ptr<MockableSendStatisticsProxy> stats_proxy_;
perkj26091b12016-09-01 01:17:40 -0700687 TestSink sink_;
sprangb1ca0732017-02-01 08:38:12 -0800688 AdaptingFrameForwarder video_source_;
mflodmancc3d4422017-08-03 08:27:51 -0700689 std::unique_ptr<VideoStreamEncoderUnderTest> video_stream_encoder_;
sprang4847ae62017-06-27 07:06:52 -0700690 rtc::ScopedFakeClock fake_clock_;
perkj26091b12016-09-01 01:17:40 -0700691};
692
mflodmancc3d4422017-08-03 08:27:51 -0700693TEST_F(VideoStreamEncoderTest, EncodeOneFrame) {
694 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkj26091b12016-09-01 01:17:40 -0700695 rtc::Event frame_destroyed_event(false, false);
perkja49cbd32016-09-16 07:53:41 -0700696 video_source_.IncomingCapturedFrame(CreateFrame(1, &frame_destroyed_event));
sprang4847ae62017-06-27 07:06:52 -0700697 WaitForEncodedFrame(1);
perkja49cbd32016-09-16 07:53:41 -0700698 EXPECT_TRUE(frame_destroyed_event.Wait(kDefaultTimeoutMs));
mflodmancc3d4422017-08-03 08:27:51 -0700699 video_stream_encoder_->Stop();
perkj26091b12016-09-01 01:17:40 -0700700}
701
mflodmancc3d4422017-08-03 08:27:51 -0700702TEST_F(VideoStreamEncoderTest, DropsFramesBeforeFirstOnBitrateUpdated) {
perkj26091b12016-09-01 01:17:40 -0700703 // Dropped since no target bitrate has been set.
704 rtc::Event frame_destroyed_event(false, false);
Sebastian Janssona3177052018-04-10 13:05:49 +0200705 // The encoder will cache up to one frame for a short duration. Adding two
706 // frames means that the first frame will be dropped and the second frame will
707 // be sent when the encoder is enabled.
perkja49cbd32016-09-16 07:53:41 -0700708 video_source_.IncomingCapturedFrame(CreateFrame(1, &frame_destroyed_event));
Sebastian Janssona3177052018-04-10 13:05:49 +0200709 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
perkja49cbd32016-09-16 07:53:41 -0700710 EXPECT_TRUE(frame_destroyed_event.Wait(kDefaultTimeoutMs));
perkj26091b12016-09-01 01:17:40 -0700711
mflodmancc3d4422017-08-03 08:27:51 -0700712 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkj26091b12016-09-01 01:17:40 -0700713
Sebastian Janssona3177052018-04-10 13:05:49 +0200714 // The pending frame should be received.
sprang4847ae62017-06-27 07:06:52 -0700715 WaitForEncodedFrame(2);
Sebastian Janssona3177052018-04-10 13:05:49 +0200716 video_source_.IncomingCapturedFrame(CreateFrame(3, nullptr));
717
718 WaitForEncodedFrame(3);
mflodmancc3d4422017-08-03 08:27:51 -0700719 video_stream_encoder_->Stop();
perkj26091b12016-09-01 01:17:40 -0700720}
721
mflodmancc3d4422017-08-03 08:27:51 -0700722TEST_F(VideoStreamEncoderTest, DropsFramesWhenRateSetToZero) {
723 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkja49cbd32016-09-16 07:53:41 -0700724 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700725 WaitForEncodedFrame(1);
perkj26091b12016-09-01 01:17:40 -0700726
mflodmancc3d4422017-08-03 08:27:51 -0700727 video_stream_encoder_->OnBitrateUpdated(0, 0, 0);
Sebastian Janssona3177052018-04-10 13:05:49 +0200728 // The encoder will cache up to one frame for a short duration. Adding two
729 // frames means that the first frame will be dropped and the second frame will
730 // be sent when the encoder is resumed.
perkja49cbd32016-09-16 07:53:41 -0700731 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
Sebastian Janssona3177052018-04-10 13:05:49 +0200732 video_source_.IncomingCapturedFrame(CreateFrame(3, nullptr));
perkj26091b12016-09-01 01:17:40 -0700733
mflodmancc3d4422017-08-03 08:27:51 -0700734 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
sprang4847ae62017-06-27 07:06:52 -0700735 WaitForEncodedFrame(3);
Sebastian Janssona3177052018-04-10 13:05:49 +0200736 video_source_.IncomingCapturedFrame(CreateFrame(4, nullptr));
737 WaitForEncodedFrame(4);
mflodmancc3d4422017-08-03 08:27:51 -0700738 video_stream_encoder_->Stop();
perkj26091b12016-09-01 01:17:40 -0700739}
740
mflodmancc3d4422017-08-03 08:27:51 -0700741TEST_F(VideoStreamEncoderTest, DropsFramesWithSameOrOldNtpTimestamp) {
742 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkja49cbd32016-09-16 07:53:41 -0700743 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700744 WaitForEncodedFrame(1);
perkj26091b12016-09-01 01:17:40 -0700745
746 // This frame will be dropped since it has the same ntp timestamp.
perkja49cbd32016-09-16 07:53:41 -0700747 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
perkj26091b12016-09-01 01:17:40 -0700748
perkja49cbd32016-09-16 07:53:41 -0700749 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700750 WaitForEncodedFrame(2);
mflodmancc3d4422017-08-03 08:27:51 -0700751 video_stream_encoder_->Stop();
perkj26091b12016-09-01 01:17:40 -0700752}
753
mflodmancc3d4422017-08-03 08:27:51 -0700754TEST_F(VideoStreamEncoderTest, DropsFrameAfterStop) {
755 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkj26091b12016-09-01 01:17:40 -0700756
perkja49cbd32016-09-16 07:53:41 -0700757 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700758 WaitForEncodedFrame(1);
perkj26091b12016-09-01 01:17:40 -0700759
mflodmancc3d4422017-08-03 08:27:51 -0700760 video_stream_encoder_->Stop();
perkj26091b12016-09-01 01:17:40 -0700761 sink_.SetExpectNoFrames();
762 rtc::Event frame_destroyed_event(false, false);
perkja49cbd32016-09-16 07:53:41 -0700763 video_source_.IncomingCapturedFrame(CreateFrame(2, &frame_destroyed_event));
764 EXPECT_TRUE(frame_destroyed_event.Wait(kDefaultTimeoutMs));
perkj26091b12016-09-01 01:17:40 -0700765}
766
mflodmancc3d4422017-08-03 08:27:51 -0700767TEST_F(VideoStreamEncoderTest, DropsPendingFramesOnSlowEncode) {
768 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkj26091b12016-09-01 01:17:40 -0700769
770 fake_encoder_.BlockNextEncode();
perkja49cbd32016-09-16 07:53:41 -0700771 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700772 WaitForEncodedFrame(1);
perkj26091b12016-09-01 01:17:40 -0700773 // Here, the encoder thread will be blocked in the TestEncoder waiting for a
774 // call to ContinueEncode.
perkja49cbd32016-09-16 07:53:41 -0700775 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
776 video_source_.IncomingCapturedFrame(CreateFrame(3, nullptr));
perkj26091b12016-09-01 01:17:40 -0700777 fake_encoder_.ContinueEncode();
sprang4847ae62017-06-27 07:06:52 -0700778 WaitForEncodedFrame(3);
perkj26091b12016-09-01 01:17:40 -0700779
mflodmancc3d4422017-08-03 08:27:51 -0700780 video_stream_encoder_->Stop();
perkj26091b12016-09-01 01:17:40 -0700781}
782
mflodmancc3d4422017-08-03 08:27:51 -0700783TEST_F(VideoStreamEncoderTest,
784 ConfigureEncoderTriggersOnEncoderConfigurationChanged) {
785 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
Per21d45d22016-10-30 21:37:57 +0100786 EXPECT_EQ(0, sink_.number_of_reconfigurations());
Per512ecb32016-09-23 15:52:06 +0200787
788 // Capture a frame and wait for it to synchronize with the encoder thread.
Perf8c5f2b2016-09-23 16:24:55 +0200789 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700790 WaitForEncodedFrame(1);
Per21d45d22016-10-30 21:37:57 +0100791 // The encoder will have been configured once when the first frame is
792 // received.
793 EXPECT_EQ(1, sink_.number_of_reconfigurations());
Per512ecb32016-09-23 15:52:06 +0200794
795 VideoEncoderConfig video_encoder_config;
Niels Möller259a4972018-04-05 15:36:51 +0200796 test::FillEncoderConfiguration(kVideoCodecVP8, 1, &video_encoder_config);
Per512ecb32016-09-23 15:52:06 +0200797 video_encoder_config.min_transmit_bitrate_bps = 9999;
mflodmancc3d4422017-08-03 08:27:51 -0700798 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
Niels Möllerf1338562018-04-26 09:51:47 +0200799 kMaxPayloadLength);
Per512ecb32016-09-23 15:52:06 +0200800
801 // Capture a frame and wait for it to synchronize with the encoder thread.
Perf8c5f2b2016-09-23 16:24:55 +0200802 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700803 WaitForEncodedFrame(2);
Per21d45d22016-10-30 21:37:57 +0100804 EXPECT_EQ(2, sink_.number_of_reconfigurations());
perkj3b703ed2016-09-29 23:25:40 -0700805 EXPECT_EQ(9999, sink_.last_min_transmit_bitrate());
perkj26105b42016-09-29 22:39:10 -0700806
mflodmancc3d4422017-08-03 08:27:51 -0700807 video_stream_encoder_->Stop();
perkj26105b42016-09-29 22:39:10 -0700808}
809
mflodmancc3d4422017-08-03 08:27:51 -0700810TEST_F(VideoStreamEncoderTest, FrameResolutionChangeReconfigureEncoder) {
811 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkjfa10b552016-10-02 23:45:26 -0700812
813 // Capture a frame and wait for it to synchronize with the encoder thread.
814 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700815 WaitForEncodedFrame(1);
Per21d45d22016-10-30 21:37:57 +0100816 // The encoder will have been configured once.
817 EXPECT_EQ(1, sink_.number_of_reconfigurations());
perkjfa10b552016-10-02 23:45:26 -0700818 EXPECT_EQ(codec_width_, fake_encoder_.codec_config().width);
819 EXPECT_EQ(codec_height_, fake_encoder_.codec_config().height);
820
821 codec_width_ *= 2;
822 codec_height_ *= 2;
823 // Capture a frame with a higher resolution and wait for it to synchronize
824 // with the encoder thread.
825 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700826 WaitForEncodedFrame(2);
perkjfa10b552016-10-02 23:45:26 -0700827 EXPECT_EQ(codec_width_, fake_encoder_.codec_config().width);
828 EXPECT_EQ(codec_height_, fake_encoder_.codec_config().height);
Per21d45d22016-10-30 21:37:57 +0100829 EXPECT_EQ(2, sink_.number_of_reconfigurations());
perkjfa10b552016-10-02 23:45:26 -0700830
mflodmancc3d4422017-08-03 08:27:51 -0700831 video_stream_encoder_->Stop();
perkjfa10b552016-10-02 23:45:26 -0700832}
833
mflodmancc3d4422017-08-03 08:27:51 -0700834TEST_F(VideoStreamEncoderTest, SwitchSourceDeregisterEncoderAsSink) {
perkj803d97f2016-11-01 11:45:46 -0700835 EXPECT_TRUE(video_source_.has_sinks());
836 test::FrameForwarder new_video_source;
mflodmancc3d4422017-08-03 08:27:51 -0700837 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -0700838 &new_video_source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
perkj803d97f2016-11-01 11:45:46 -0700839 EXPECT_FALSE(video_source_.has_sinks());
840 EXPECT_TRUE(new_video_source.has_sinks());
841
mflodmancc3d4422017-08-03 08:27:51 -0700842 video_stream_encoder_->Stop();
perkj803d97f2016-11-01 11:45:46 -0700843}
844
mflodmancc3d4422017-08-03 08:27:51 -0700845TEST_F(VideoStreamEncoderTest, SinkWantsRotationApplied) {
perkj803d97f2016-11-01 11:45:46 -0700846 EXPECT_FALSE(video_source_.sink_wants().rotation_applied);
mflodmancc3d4422017-08-03 08:27:51 -0700847 video_stream_encoder_->SetSink(&sink_, true /*rotation_applied*/);
perkj803d97f2016-11-01 11:45:46 -0700848 EXPECT_TRUE(video_source_.sink_wants().rotation_applied);
mflodmancc3d4422017-08-03 08:27:51 -0700849 video_stream_encoder_->Stop();
perkj803d97f2016-11-01 11:45:46 -0700850}
851
Jonathan Yubc771b72017-12-08 17:04:29 -0800852TEST_F(VideoStreamEncoderTest, TestCpuDowngrades_BalancedMode) {
853 const int kFramerateFps = 30;
asaperssonf7e294d2017-06-13 23:25:22 -0700854 const int kWidth = 1280;
855 const int kHeight = 720;
Jonathan Yubc771b72017-12-08 17:04:29 -0800856
857 // We rely on the automatic resolution adaptation, but we handle framerate
858 // adaptation manually by mocking the stats proxy.
859 video_source_.set_adaptation_enabled(true);
asaperssonf7e294d2017-06-13 23:25:22 -0700860
Taylor Brandstetter49fcc102018-05-16 14:20:41 -0700861 // Enable BALANCED preference, no initial limitation.
Jonathan Yubc771b72017-12-08 17:04:29 -0800862 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
Taylor Brandstetter49fcc102018-05-16 14:20:41 -0700863 video_stream_encoder_->SetSource(&video_source_,
864 webrtc::DegradationPreference::BALANCED);
Jonathan Yubc771b72017-12-08 17:04:29 -0800865 VerifyNoLimitation(video_source_.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -0700866 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
Jonathan Yubc771b72017-12-08 17:04:29 -0800867 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
asaperssonf7e294d2017-06-13 23:25:22 -0700868 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
869
Jonathan Yubc771b72017-12-08 17:04:29 -0800870 // Adapt down as far as possible.
871 rtc::VideoSinkWants last_wants;
872 int64_t t = 1;
873 int loop_count = 0;
874 do {
875 ++loop_count;
876 last_wants = video_source_.sink_wants();
877
878 // Simulate the framerate we've been asked to adapt to.
879 const int fps = std::min(kFramerateFps, last_wants.max_framerate_fps);
880 const int frame_interval_ms = rtc::kNumMillisecsPerSec / fps;
881 VideoSendStream::Stats mock_stats = stats_proxy_->GetStats();
882 mock_stats.input_frame_rate = fps;
883 stats_proxy_->SetMockStats(mock_stats);
884
885 video_source_.IncomingCapturedFrame(CreateFrame(t, kWidth, kHeight));
886 sink_.WaitForEncodedFrame(t);
887 t += frame_interval_ms;
888
mflodmancc3d4422017-08-03 08:27:51 -0700889 video_stream_encoder_->TriggerCpuOveruse();
Jonathan Yubc771b72017-12-08 17:04:29 -0800890 VerifyBalancedModeFpsRange(
891 video_source_.sink_wants(),
892 *video_source_.last_sent_width() * *video_source_.last_sent_height());
893 } while (video_source_.sink_wants().max_pixel_count <
894 last_wants.max_pixel_count ||
895 video_source_.sink_wants().max_framerate_fps <
896 last_wants.max_framerate_fps);
asaperssonf7e294d2017-06-13 23:25:22 -0700897
Jonathan Yubc771b72017-12-08 17:04:29 -0800898 // Verify that we've adapted all the way down.
899 stats_proxy_->ResetMockStats();
asaperssonf7e294d2017-06-13 23:25:22 -0700900 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
Jonathan Yubc771b72017-12-08 17:04:29 -0800901 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_framerate);
902 EXPECT_EQ(loop_count - 1,
asaperssonf7e294d2017-06-13 23:25:22 -0700903 stats_proxy_->GetStats().number_of_cpu_adapt_changes);
Jonathan Yubc771b72017-12-08 17:04:29 -0800904 EXPECT_EQ(kMinPixelsPerFrame, *video_source_.last_sent_width() *
905 *video_source_.last_sent_height());
906 EXPECT_EQ(kMinBalancedFramerateFps,
907 video_source_.sink_wants().max_framerate_fps);
asaperssonf7e294d2017-06-13 23:25:22 -0700908
Jonathan Yubc771b72017-12-08 17:04:29 -0800909 // Adapt back up the same number of times we adapted down.
910 for (int i = 0; i < loop_count - 1; ++i) {
911 last_wants = video_source_.sink_wants();
912
913 // Simulate the framerate we've been asked to adapt to.
914 const int fps = std::min(kFramerateFps, last_wants.max_framerate_fps);
915 const int frame_interval_ms = rtc::kNumMillisecsPerSec / fps;
916 VideoSendStream::Stats mock_stats = stats_proxy_->GetStats();
917 mock_stats.input_frame_rate = fps;
918 stats_proxy_->SetMockStats(mock_stats);
919
920 video_source_.IncomingCapturedFrame(CreateFrame(t, kWidth, kHeight));
921 sink_.WaitForEncodedFrame(t);
922 t += frame_interval_ms;
923
mflodmancc3d4422017-08-03 08:27:51 -0700924 video_stream_encoder_->TriggerCpuNormalUsage();
Jonathan Yubc771b72017-12-08 17:04:29 -0800925 VerifyBalancedModeFpsRange(
926 video_source_.sink_wants(),
927 *video_source_.last_sent_width() * *video_source_.last_sent_height());
928 EXPECT_TRUE(video_source_.sink_wants().max_pixel_count >
929 last_wants.max_pixel_count ||
930 video_source_.sink_wants().max_framerate_fps >
931 last_wants.max_framerate_fps);
asaperssonf7e294d2017-06-13 23:25:22 -0700932 }
933
Jonathan Yubc771b72017-12-08 17:04:29 -0800934 VerifyNoLimitation(video_source_.sink_wants());
935 stats_proxy_->ResetMockStats();
asaperssonf7e294d2017-06-13 23:25:22 -0700936 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
Jonathan Yubc771b72017-12-08 17:04:29 -0800937 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
938 EXPECT_EQ((loop_count - 1) * 2,
939 stats_proxy_->GetStats().number_of_cpu_adapt_changes);
asaperssonf7e294d2017-06-13 23:25:22 -0700940
mflodmancc3d4422017-08-03 08:27:51 -0700941 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -0700942}
mflodmancc3d4422017-08-03 08:27:51 -0700943TEST_F(VideoStreamEncoderTest, SinkWantsStoredByDegradationPreference) {
944 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson02465b82017-04-10 01:12:52 -0700945 VerifyNoLimitation(video_source_.sink_wants());
perkj803d97f2016-11-01 11:45:46 -0700946
sprangc5d62e22017-04-02 23:53:04 -0700947 const int kFrameWidth = 1280;
948 const int kFrameHeight = 720;
949 const int kFrameIntervalMs = 1000 / 30;
950
951 int frame_timestamp = 1;
perkj803d97f2016-11-01 11:45:46 -0700952
kthelgason5e13d412016-12-01 03:59:51 -0800953 video_source_.IncomingCapturedFrame(
sprangc5d62e22017-04-02 23:53:04 -0700954 CreateFrame(frame_timestamp, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -0700955 WaitForEncodedFrame(frame_timestamp);
sprangc5d62e22017-04-02 23:53:04 -0700956 frame_timestamp += kFrameIntervalMs;
957
perkj803d97f2016-11-01 11:45:46 -0700958 // Trigger CPU overuse.
mflodmancc3d4422017-08-03 08:27:51 -0700959 video_stream_encoder_->TriggerCpuOveruse();
perkj803d97f2016-11-01 11:45:46 -0700960 video_source_.IncomingCapturedFrame(
sprangc5d62e22017-04-02 23:53:04 -0700961 CreateFrame(frame_timestamp, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -0700962 WaitForEncodedFrame(frame_timestamp);
sprangc5d62e22017-04-02 23:53:04 -0700963 frame_timestamp += kFrameIntervalMs;
sprang3ea3c772017-03-30 07:23:48 -0700964
asapersson0944a802017-04-07 00:57:58 -0700965 // Default degradation preference is maintain-framerate, so will lower max
sprangc5d62e22017-04-02 23:53:04 -0700966 // wanted resolution.
967 EXPECT_FALSE(video_source_.sink_wants().target_pixel_count);
968 EXPECT_LT(video_source_.sink_wants().max_pixel_count,
969 kFrameWidth * kFrameHeight);
970 EXPECT_EQ(std::numeric_limits<int>::max(),
971 video_source_.sink_wants().max_framerate_fps);
972
973 // Set new source, switch to maintain-resolution.
perkj803d97f2016-11-01 11:45:46 -0700974 test::FrameForwarder new_video_source;
mflodmancc3d4422017-08-03 08:27:51 -0700975 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -0700976 &new_video_source, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
perkj803d97f2016-11-01 11:45:46 -0700977
sprangc5d62e22017-04-02 23:53:04 -0700978 // Initially no degradation registered.
asapersson02465b82017-04-10 01:12:52 -0700979 VerifyNoLimitation(new_video_source.sink_wants());
perkj803d97f2016-11-01 11:45:46 -0700980
sprangc5d62e22017-04-02 23:53:04 -0700981 // Force an input frame rate to be available, or the adaptation call won't
982 // know what framerate to adapt form.
asapersson02465b82017-04-10 01:12:52 -0700983 const int kInputFps = 30;
sprangc5d62e22017-04-02 23:53:04 -0700984 VideoSendStream::Stats stats = stats_proxy_->GetStats();
asapersson02465b82017-04-10 01:12:52 -0700985 stats.input_frame_rate = kInputFps;
sprangc5d62e22017-04-02 23:53:04 -0700986 stats_proxy_->SetMockStats(stats);
987
mflodmancc3d4422017-08-03 08:27:51 -0700988 video_stream_encoder_->TriggerCpuOveruse();
perkj803d97f2016-11-01 11:45:46 -0700989 new_video_source.IncomingCapturedFrame(
sprangc5d62e22017-04-02 23:53:04 -0700990 CreateFrame(frame_timestamp, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -0700991 WaitForEncodedFrame(frame_timestamp);
sprangc5d62e22017-04-02 23:53:04 -0700992 frame_timestamp += kFrameIntervalMs;
993
994 // Some framerate constraint should be set.
sprang84a37592017-02-10 07:04:27 -0800995 EXPECT_FALSE(new_video_source.sink_wants().target_pixel_count);
sprangc5d62e22017-04-02 23:53:04 -0700996 EXPECT_EQ(std::numeric_limits<int>::max(),
997 new_video_source.sink_wants().max_pixel_count);
asapersson02465b82017-04-10 01:12:52 -0700998 EXPECT_LT(new_video_source.sink_wants().max_framerate_fps, kInputFps);
sprangc5d62e22017-04-02 23:53:04 -0700999
asapersson02465b82017-04-10 01:12:52 -07001000 // Turn off degradation completely.
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001001 video_stream_encoder_->SetSource(&new_video_source,
1002 webrtc::DegradationPreference::DISABLED);
asapersson02465b82017-04-10 01:12:52 -07001003 VerifyNoLimitation(new_video_source.sink_wants());
sprangc5d62e22017-04-02 23:53:04 -07001004
mflodmancc3d4422017-08-03 08:27:51 -07001005 video_stream_encoder_->TriggerCpuOveruse();
sprangc5d62e22017-04-02 23:53:04 -07001006 new_video_source.IncomingCapturedFrame(
1007 CreateFrame(frame_timestamp, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07001008 WaitForEncodedFrame(frame_timestamp);
sprangc5d62e22017-04-02 23:53:04 -07001009 frame_timestamp += kFrameIntervalMs;
1010
1011 // Still no degradation.
asapersson02465b82017-04-10 01:12:52 -07001012 VerifyNoLimitation(new_video_source.sink_wants());
perkj803d97f2016-11-01 11:45:46 -07001013
1014 // Calling SetSource with resolution scaling enabled apply the old SinkWants.
mflodmancc3d4422017-08-03 08:27:51 -07001015 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001016 &new_video_source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
sprangc5d62e22017-04-02 23:53:04 -07001017 EXPECT_LT(new_video_source.sink_wants().max_pixel_count,
1018 kFrameWidth * kFrameHeight);
sprang84a37592017-02-10 07:04:27 -08001019 EXPECT_FALSE(new_video_source.sink_wants().target_pixel_count);
sprangc5d62e22017-04-02 23:53:04 -07001020 EXPECT_EQ(std::numeric_limits<int>::max(),
1021 new_video_source.sink_wants().max_framerate_fps);
1022
1023 // Calling SetSource with framerate scaling enabled apply the old SinkWants.
mflodmancc3d4422017-08-03 08:27:51 -07001024 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001025 &new_video_source, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
sprangc5d62e22017-04-02 23:53:04 -07001026 EXPECT_FALSE(new_video_source.sink_wants().target_pixel_count);
1027 EXPECT_EQ(std::numeric_limits<int>::max(),
1028 new_video_source.sink_wants().max_pixel_count);
asapersson02465b82017-04-10 01:12:52 -07001029 EXPECT_LT(new_video_source.sink_wants().max_framerate_fps, kInputFps);
perkj803d97f2016-11-01 11:45:46 -07001030
mflodmancc3d4422017-08-03 08:27:51 -07001031 video_stream_encoder_->Stop();
perkj803d97f2016-11-01 11:45:46 -07001032}
1033
mflodmancc3d4422017-08-03 08:27:51 -07001034TEST_F(VideoStreamEncoderTest, StatsTracksQualityAdaptationStats) {
1035 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkj803d97f2016-11-01 11:45:46 -07001036
asaperssonfab67072017-04-04 05:51:49 -07001037 const int kWidth = 1280;
1038 const int kHeight = 720;
asaperssonfab67072017-04-04 05:51:49 -07001039 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001040 WaitForEncodedFrame(1);
asaperssonfab67072017-04-04 05:51:49 -07001041 VideoSendStream::Stats stats = stats_proxy_->GetStats();
1042 EXPECT_FALSE(stats.bw_limited_resolution);
1043 EXPECT_EQ(0, stats.number_of_quality_adapt_changes);
1044
1045 // Trigger adapt down.
mflodmancc3d4422017-08-03 08:27:51 -07001046 video_stream_encoder_->TriggerQualityLow();
asaperssonfab67072017-04-04 05:51:49 -07001047 video_source_.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001048 WaitForEncodedFrame(2);
asaperssonfab67072017-04-04 05:51:49 -07001049
1050 stats = stats_proxy_->GetStats();
1051 EXPECT_TRUE(stats.bw_limited_resolution);
1052 EXPECT_EQ(1, stats.number_of_quality_adapt_changes);
1053
1054 // Trigger adapt up.
mflodmancc3d4422017-08-03 08:27:51 -07001055 video_stream_encoder_->TriggerQualityHigh();
asaperssonfab67072017-04-04 05:51:49 -07001056 video_source_.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001057 WaitForEncodedFrame(3);
asaperssonfab67072017-04-04 05:51:49 -07001058
1059 stats = stats_proxy_->GetStats();
1060 EXPECT_FALSE(stats.bw_limited_resolution);
1061 EXPECT_EQ(2, stats.number_of_quality_adapt_changes);
1062 EXPECT_EQ(0, stats.number_of_cpu_adapt_changes);
1063
mflodmancc3d4422017-08-03 08:27:51 -07001064 video_stream_encoder_->Stop();
asaperssonfab67072017-04-04 05:51:49 -07001065}
1066
mflodmancc3d4422017-08-03 08:27:51 -07001067TEST_F(VideoStreamEncoderTest, StatsTracksCpuAdaptationStats) {
1068 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonfab67072017-04-04 05:51:49 -07001069
1070 const int kWidth = 1280;
1071 const int kHeight = 720;
asaperssonfab67072017-04-04 05:51:49 -07001072 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001073 WaitForEncodedFrame(1);
perkj803d97f2016-11-01 11:45:46 -07001074 VideoSendStream::Stats stats = stats_proxy_->GetStats();
1075 EXPECT_FALSE(stats.cpu_limited_resolution);
1076 EXPECT_EQ(0, stats.number_of_cpu_adapt_changes);
1077
1078 // Trigger CPU overuse.
mflodmancc3d4422017-08-03 08:27:51 -07001079 video_stream_encoder_->TriggerCpuOveruse();
asaperssonfab67072017-04-04 05:51:49 -07001080 video_source_.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001081 WaitForEncodedFrame(2);
perkj803d97f2016-11-01 11:45:46 -07001082
1083 stats = stats_proxy_->GetStats();
1084 EXPECT_TRUE(stats.cpu_limited_resolution);
1085 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1086
1087 // Trigger CPU normal use.
mflodmancc3d4422017-08-03 08:27:51 -07001088 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssonfab67072017-04-04 05:51:49 -07001089 video_source_.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001090 WaitForEncodedFrame(3);
perkj803d97f2016-11-01 11:45:46 -07001091
1092 stats = stats_proxy_->GetStats();
1093 EXPECT_FALSE(stats.cpu_limited_resolution);
1094 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
asaperssonfab67072017-04-04 05:51:49 -07001095 EXPECT_EQ(0, stats.number_of_quality_adapt_changes);
perkj803d97f2016-11-01 11:45:46 -07001096
mflodmancc3d4422017-08-03 08:27:51 -07001097 video_stream_encoder_->Stop();
perkj803d97f2016-11-01 11:45:46 -07001098}
1099
mflodmancc3d4422017-08-03 08:27:51 -07001100TEST_F(VideoStreamEncoderTest, SwitchingSourceKeepsCpuAdaptation) {
1101 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
kthelgason876222f2016-11-29 01:44:11 -08001102
asaperssonfab67072017-04-04 05:51:49 -07001103 const int kWidth = 1280;
1104 const int kHeight = 720;
1105 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001106 WaitForEncodedFrame(1);
kthelgason876222f2016-11-29 01:44:11 -08001107 VideoSendStream::Stats stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001108 EXPECT_FALSE(stats.bw_limited_resolution);
kthelgason876222f2016-11-29 01:44:11 -08001109 EXPECT_FALSE(stats.cpu_limited_resolution);
1110 EXPECT_EQ(0, stats.number_of_cpu_adapt_changes);
1111
asaperssonfab67072017-04-04 05:51:49 -07001112 // Trigger CPU overuse.
mflodmancc3d4422017-08-03 08:27:51 -07001113 video_stream_encoder_->TriggerCpuOveruse();
asaperssonfab67072017-04-04 05:51:49 -07001114 video_source_.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001115 WaitForEncodedFrame(2);
kthelgason876222f2016-11-29 01:44:11 -08001116 stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001117 EXPECT_FALSE(stats.bw_limited_resolution);
kthelgason876222f2016-11-29 01:44:11 -08001118 EXPECT_TRUE(stats.cpu_limited_resolution);
1119 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1120
1121 // Set new source with adaptation still enabled.
1122 test::FrameForwarder new_video_source;
mflodmancc3d4422017-08-03 08:27:51 -07001123 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001124 &new_video_source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
kthelgason876222f2016-11-29 01:44:11 -08001125
asaperssonfab67072017-04-04 05:51:49 -07001126 new_video_source.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001127 WaitForEncodedFrame(3);
kthelgason876222f2016-11-29 01:44:11 -08001128 stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001129 EXPECT_FALSE(stats.bw_limited_resolution);
kthelgason876222f2016-11-29 01:44:11 -08001130 EXPECT_TRUE(stats.cpu_limited_resolution);
1131 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1132
1133 // Set adaptation disabled.
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001134 video_stream_encoder_->SetSource(&new_video_source,
1135 webrtc::DegradationPreference::DISABLED);
kthelgason876222f2016-11-29 01:44:11 -08001136
asaperssonfab67072017-04-04 05:51:49 -07001137 new_video_source.IncomingCapturedFrame(CreateFrame(4, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001138 WaitForEncodedFrame(4);
kthelgason876222f2016-11-29 01:44:11 -08001139 stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001140 EXPECT_FALSE(stats.bw_limited_resolution);
kthelgason876222f2016-11-29 01:44:11 -08001141 EXPECT_FALSE(stats.cpu_limited_resolution);
1142 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1143
1144 // Set adaptation back to enabled.
mflodmancc3d4422017-08-03 08:27:51 -07001145 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001146 &new_video_source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
kthelgason876222f2016-11-29 01:44:11 -08001147
asaperssonfab67072017-04-04 05:51:49 -07001148 new_video_source.IncomingCapturedFrame(CreateFrame(5, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001149 WaitForEncodedFrame(5);
kthelgason876222f2016-11-29 01:44:11 -08001150 stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001151 EXPECT_FALSE(stats.bw_limited_resolution);
kthelgason876222f2016-11-29 01:44:11 -08001152 EXPECT_TRUE(stats.cpu_limited_resolution);
1153 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1154
asaperssonfab67072017-04-04 05:51:49 -07001155 // Trigger CPU normal use.
mflodmancc3d4422017-08-03 08:27:51 -07001156 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssonfab67072017-04-04 05:51:49 -07001157 new_video_source.IncomingCapturedFrame(CreateFrame(6, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001158 WaitForEncodedFrame(6);
kthelgason876222f2016-11-29 01:44:11 -08001159 stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001160 EXPECT_FALSE(stats.bw_limited_resolution);
kthelgason876222f2016-11-29 01:44:11 -08001161 EXPECT_FALSE(stats.cpu_limited_resolution);
1162 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
asapersson02465b82017-04-10 01:12:52 -07001163 EXPECT_EQ(0, stats.number_of_quality_adapt_changes);
kthelgason876222f2016-11-29 01:44:11 -08001164
mflodmancc3d4422017-08-03 08:27:51 -07001165 video_stream_encoder_->Stop();
kthelgason876222f2016-11-29 01:44:11 -08001166}
1167
mflodmancc3d4422017-08-03 08:27:51 -07001168TEST_F(VideoStreamEncoderTest, SwitchingSourceKeepsQualityAdaptation) {
1169 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
kthelgason876222f2016-11-29 01:44:11 -08001170
asaperssonfab67072017-04-04 05:51:49 -07001171 const int kWidth = 1280;
1172 const int kHeight = 720;
1173 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001174 WaitForEncodedFrame(1);
kthelgason876222f2016-11-29 01:44:11 -08001175 VideoSendStream::Stats stats = stats_proxy_->GetStats();
kthelgason876222f2016-11-29 01:44:11 -08001176 EXPECT_FALSE(stats.bw_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001177 EXPECT_FALSE(stats.bw_limited_framerate);
asaperssonfab67072017-04-04 05:51:49 -07001178 EXPECT_EQ(0, stats.number_of_quality_adapt_changes);
kthelgason876222f2016-11-29 01:44:11 -08001179
1180 // Set new source with adaptation still enabled.
1181 test::FrameForwarder new_video_source;
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001182 video_stream_encoder_->SetSource(&new_video_source,
1183 webrtc::DegradationPreference::BALANCED);
kthelgason876222f2016-11-29 01:44:11 -08001184
asaperssonfab67072017-04-04 05:51:49 -07001185 new_video_source.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001186 WaitForEncodedFrame(2);
kthelgason876222f2016-11-29 01:44:11 -08001187 stats = stats_proxy_->GetStats();
kthelgason876222f2016-11-29 01:44:11 -08001188 EXPECT_FALSE(stats.bw_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001189 EXPECT_FALSE(stats.bw_limited_framerate);
asaperssonfab67072017-04-04 05:51:49 -07001190 EXPECT_EQ(0, stats.number_of_quality_adapt_changes);
kthelgason876222f2016-11-29 01:44:11 -08001191
asaperssonfab67072017-04-04 05:51:49 -07001192 // Trigger adapt down.
mflodmancc3d4422017-08-03 08:27:51 -07001193 video_stream_encoder_->TriggerQualityLow();
asaperssonfab67072017-04-04 05:51:49 -07001194 new_video_source.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001195 WaitForEncodedFrame(3);
kthelgason876222f2016-11-29 01:44:11 -08001196 stats = stats_proxy_->GetStats();
kthelgason876222f2016-11-29 01:44:11 -08001197 EXPECT_TRUE(stats.bw_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001198 EXPECT_FALSE(stats.bw_limited_framerate);
asaperssonfab67072017-04-04 05:51:49 -07001199 EXPECT_EQ(1, stats.number_of_quality_adapt_changes);
kthelgason876222f2016-11-29 01:44:11 -08001200
asaperssonfab67072017-04-04 05:51:49 -07001201 // Set new source with adaptation still enabled.
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001202 video_stream_encoder_->SetSource(&new_video_source,
1203 webrtc::DegradationPreference::BALANCED);
kthelgason876222f2016-11-29 01:44:11 -08001204
asaperssonfab67072017-04-04 05:51:49 -07001205 new_video_source.IncomingCapturedFrame(CreateFrame(4, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001206 WaitForEncodedFrame(4);
kthelgason876222f2016-11-29 01:44:11 -08001207 stats = stats_proxy_->GetStats();
kthelgason876222f2016-11-29 01:44:11 -08001208 EXPECT_TRUE(stats.bw_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001209 EXPECT_FALSE(stats.bw_limited_framerate);
asaperssonfab67072017-04-04 05:51:49 -07001210 EXPECT_EQ(1, stats.number_of_quality_adapt_changes);
kthelgason876222f2016-11-29 01:44:11 -08001211
asapersson02465b82017-04-10 01:12:52 -07001212 // Disable resolution scaling.
mflodmancc3d4422017-08-03 08:27:51 -07001213 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001214 &new_video_source, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
kthelgason876222f2016-11-29 01:44:11 -08001215
asaperssonfab67072017-04-04 05:51:49 -07001216 new_video_source.IncomingCapturedFrame(CreateFrame(5, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001217 WaitForEncodedFrame(5);
kthelgason876222f2016-11-29 01:44:11 -08001218 stats = stats_proxy_->GetStats();
kthelgason876222f2016-11-29 01:44:11 -08001219 EXPECT_FALSE(stats.bw_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001220 EXPECT_FALSE(stats.bw_limited_framerate);
asaperssonfab67072017-04-04 05:51:49 -07001221 EXPECT_EQ(1, stats.number_of_quality_adapt_changes);
1222 EXPECT_EQ(0, stats.number_of_cpu_adapt_changes);
kthelgason876222f2016-11-29 01:44:11 -08001223
mflodmancc3d4422017-08-03 08:27:51 -07001224 video_stream_encoder_->Stop();
kthelgason876222f2016-11-29 01:44:11 -08001225}
1226
mflodmancc3d4422017-08-03 08:27:51 -07001227TEST_F(VideoStreamEncoderTest,
1228 QualityAdaptationStatsAreResetWhenScalerIsDisabled) {
1229 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson36e9eb42017-03-31 05:29:12 -07001230
1231 const int kWidth = 1280;
1232 const int kHeight = 720;
1233 video_source_.set_adaptation_enabled(true);
1234 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001235 WaitForEncodedFrame(1);
asapersson36e9eb42017-03-31 05:29:12 -07001236 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1237 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1238 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1239
1240 // Trigger adapt down.
mflodmancc3d4422017-08-03 08:27:51 -07001241 video_stream_encoder_->TriggerQualityLow();
asapersson36e9eb42017-03-31 05:29:12 -07001242 video_source_.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001243 WaitForEncodedFrame(2);
asapersson36e9eb42017-03-31 05:29:12 -07001244 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1245 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1246 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1247
1248 // Trigger overuse.
mflodmancc3d4422017-08-03 08:27:51 -07001249 video_stream_encoder_->TriggerCpuOveruse();
asapersson36e9eb42017-03-31 05:29:12 -07001250 video_source_.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001251 WaitForEncodedFrame(3);
asapersson36e9eb42017-03-31 05:29:12 -07001252 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1253 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1254 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1255
Niels Möller4db138e2018-04-19 09:04:13 +02001256 // Leave source unchanged, but disable quality scaler.
asapersson36e9eb42017-03-31 05:29:12 -07001257 fake_encoder_.SetQualityScaling(false);
Niels Möller4db138e2018-04-19 09:04:13 +02001258
1259 VideoEncoderConfig video_encoder_config;
1260 test::FillEncoderConfiguration(kVideoCodecVP8, 1, &video_encoder_config);
1261 // Make format different, to force recreation of encoder.
1262 video_encoder_config.video_format.parameters["foo"] = "foo";
1263 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
Niels Möllerf1338562018-04-26 09:51:47 +02001264 kMaxPayloadLength);
asapersson36e9eb42017-03-31 05:29:12 -07001265
1266 video_source_.IncomingCapturedFrame(CreateFrame(4, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001267 WaitForEncodedFrame(4);
asapersson36e9eb42017-03-31 05:29:12 -07001268 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1269 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1270 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1271
mflodmancc3d4422017-08-03 08:27:51 -07001272 video_stream_encoder_->Stop();
asapersson36e9eb42017-03-31 05:29:12 -07001273}
1274
mflodmancc3d4422017-08-03 08:27:51 -07001275TEST_F(VideoStreamEncoderTest,
1276 StatsTracksCpuAdaptationStatsWhenSwitchingSource) {
1277 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkj803d97f2016-11-01 11:45:46 -07001278
asapersson0944a802017-04-07 00:57:58 -07001279 const int kWidth = 1280;
1280 const int kHeight = 720;
sprang84a37592017-02-10 07:04:27 -08001281 int sequence = 1;
perkj803d97f2016-11-01 11:45:46 -07001282
asaperssonfab67072017-04-04 05:51:49 -07001283 video_source_.IncomingCapturedFrame(CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001284 WaitForEncodedFrame(sequence++);
perkj803d97f2016-11-01 11:45:46 -07001285 VideoSendStream::Stats stats = stats_proxy_->GetStats();
sprang84a37592017-02-10 07:04:27 -08001286 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001287 EXPECT_FALSE(stats.cpu_limited_framerate);
sprang84a37592017-02-10 07:04:27 -08001288 EXPECT_EQ(0, stats.number_of_cpu_adapt_changes);
1289
asapersson02465b82017-04-10 01:12:52 -07001290 // Trigger CPU overuse, should now adapt down.
mflodmancc3d4422017-08-03 08:27:51 -07001291 video_stream_encoder_->TriggerCpuOveruse();
asaperssonfab67072017-04-04 05:51:49 -07001292 video_source_.IncomingCapturedFrame(CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001293 WaitForEncodedFrame(sequence++);
sprang84a37592017-02-10 07:04:27 -08001294 stats = stats_proxy_->GetStats();
perkj803d97f2016-11-01 11:45:46 -07001295 EXPECT_TRUE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001296 EXPECT_FALSE(stats.cpu_limited_framerate);
perkj803d97f2016-11-01 11:45:46 -07001297 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1298
1299 // Set new source with adaptation still enabled.
1300 test::FrameForwarder new_video_source;
mflodmancc3d4422017-08-03 08:27:51 -07001301 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001302 &new_video_source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
perkj803d97f2016-11-01 11:45:46 -07001303
1304 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001305 CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001306 WaitForEncodedFrame(sequence++);
perkj803d97f2016-11-01 11:45:46 -07001307 stats = stats_proxy_->GetStats();
1308 EXPECT_TRUE(stats.cpu_limited_resolution);
asapersson09f05612017-05-15 23:40:18 -07001309 EXPECT_FALSE(stats.cpu_limited_framerate);
perkj803d97f2016-11-01 11:45:46 -07001310 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1311
sprangc5d62e22017-04-02 23:53:04 -07001312 // Set cpu adaptation by frame dropping.
mflodmancc3d4422017-08-03 08:27:51 -07001313 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001314 &new_video_source, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
perkj803d97f2016-11-01 11:45:46 -07001315 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001316 CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001317 WaitForEncodedFrame(sequence++);
perkj803d97f2016-11-01 11:45:46 -07001318 stats = stats_proxy_->GetStats();
sprangc5d62e22017-04-02 23:53:04 -07001319 // Not adapted at first.
perkj803d97f2016-11-01 11:45:46 -07001320 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson09f05612017-05-15 23:40:18 -07001321 EXPECT_FALSE(stats.cpu_limited_framerate);
perkj803d97f2016-11-01 11:45:46 -07001322 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1323
sprangc5d62e22017-04-02 23:53:04 -07001324 // Force an input frame rate to be available, or the adaptation call won't
asapersson09f05612017-05-15 23:40:18 -07001325 // know what framerate to adapt from.
sprangc5d62e22017-04-02 23:53:04 -07001326 VideoSendStream::Stats mock_stats = stats_proxy_->GetStats();
1327 mock_stats.input_frame_rate = 30;
1328 stats_proxy_->SetMockStats(mock_stats);
mflodmancc3d4422017-08-03 08:27:51 -07001329 video_stream_encoder_->TriggerCpuOveruse();
sprangc5d62e22017-04-02 23:53:04 -07001330 stats_proxy_->ResetMockStats();
1331
1332 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001333 CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001334 WaitForEncodedFrame(sequence++);
sprangc5d62e22017-04-02 23:53:04 -07001335
1336 // Framerate now adapted.
1337 stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001338 EXPECT_FALSE(stats.cpu_limited_resolution);
1339 EXPECT_TRUE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001340 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
1341
1342 // Disable CPU adaptation.
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001343 video_stream_encoder_->SetSource(&new_video_source,
1344 webrtc::DegradationPreference::DISABLED);
sprangc5d62e22017-04-02 23:53:04 -07001345 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001346 CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001347 WaitForEncodedFrame(sequence++);
sprangc5d62e22017-04-02 23:53:04 -07001348
1349 stats = stats_proxy_->GetStats();
1350 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001351 EXPECT_FALSE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001352 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
1353
1354 // Try to trigger overuse. Should not succeed.
1355 stats_proxy_->SetMockStats(mock_stats);
mflodmancc3d4422017-08-03 08:27:51 -07001356 video_stream_encoder_->TriggerCpuOveruse();
sprangc5d62e22017-04-02 23:53:04 -07001357 stats_proxy_->ResetMockStats();
1358
1359 stats = stats_proxy_->GetStats();
1360 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001361 EXPECT_FALSE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001362 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
1363
1364 // Switch back the source with resolution adaptation enabled.
mflodmancc3d4422017-08-03 08:27:51 -07001365 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001366 &video_source_, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
asaperssonfab67072017-04-04 05:51:49 -07001367 video_source_.IncomingCapturedFrame(CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001368 WaitForEncodedFrame(sequence++);
perkj803d97f2016-11-01 11:45:46 -07001369 stats = stats_proxy_->GetStats();
1370 EXPECT_TRUE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001371 EXPECT_FALSE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001372 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
perkj803d97f2016-11-01 11:45:46 -07001373
1374 // Trigger CPU normal usage.
mflodmancc3d4422017-08-03 08:27:51 -07001375 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssonfab67072017-04-04 05:51:49 -07001376 video_source_.IncomingCapturedFrame(CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001377 WaitForEncodedFrame(sequence++);
perkj803d97f2016-11-01 11:45:46 -07001378 stats = stats_proxy_->GetStats();
1379 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001380 EXPECT_FALSE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001381 EXPECT_EQ(3, stats.number_of_cpu_adapt_changes);
1382
1383 // Back to the source with adaptation off, set it back to maintain-resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001384 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001385 &new_video_source, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
sprangc5d62e22017-04-02 23:53:04 -07001386 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001387 CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001388 WaitForEncodedFrame(sequence++);
sprangc5d62e22017-04-02 23:53:04 -07001389 stats = stats_proxy_->GetStats();
asapersson13874762017-06-07 00:01:02 -07001390 // Disabled, since we previously switched the source to disabled.
sprangc5d62e22017-04-02 23:53:04 -07001391 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001392 EXPECT_TRUE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001393 EXPECT_EQ(3, stats.number_of_cpu_adapt_changes);
1394
1395 // Trigger CPU normal usage.
mflodmancc3d4422017-08-03 08:27:51 -07001396 video_stream_encoder_->TriggerCpuNormalUsage();
sprangc5d62e22017-04-02 23:53:04 -07001397 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001398 CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001399 WaitForEncodedFrame(sequence++);
sprangc5d62e22017-04-02 23:53:04 -07001400 stats = stats_proxy_->GetStats();
1401 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001402 EXPECT_FALSE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001403 EXPECT_EQ(4, stats.number_of_cpu_adapt_changes);
asapersson02465b82017-04-10 01:12:52 -07001404 EXPECT_EQ(0, stats.number_of_quality_adapt_changes);
perkj803d97f2016-11-01 11:45:46 -07001405
mflodmancc3d4422017-08-03 08:27:51 -07001406 video_stream_encoder_->Stop();
perkj803d97f2016-11-01 11:45:46 -07001407}
1408
mflodmancc3d4422017-08-03 08:27:51 -07001409TEST_F(VideoStreamEncoderTest, StatsTracksPreferredBitrate) {
1410 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
Erik Språng08127a92016-11-16 16:41:30 +01001411
asaperssonfab67072017-04-04 05:51:49 -07001412 const int kWidth = 1280;
1413 const int kHeight = 720;
1414 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001415 WaitForEncodedFrame(1);
Erik Språng08127a92016-11-16 16:41:30 +01001416
1417 VideoSendStream::Stats stats = stats_proxy_->GetStats();
1418 EXPECT_EQ(video_encoder_config_.max_bitrate_bps,
1419 stats.preferred_media_bitrate_bps);
1420
mflodmancc3d4422017-08-03 08:27:51 -07001421 video_stream_encoder_->Stop();
Erik Språng08127a92016-11-16 16:41:30 +01001422}
1423
mflodmancc3d4422017-08-03 08:27:51 -07001424TEST_F(VideoStreamEncoderTest,
1425 ScalingUpAndDownDoesNothingWithMaintainResolution) {
asaperssonfab67072017-04-04 05:51:49 -07001426 const int kWidth = 1280;
1427 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001428 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
kthelgason876222f2016-11-29 01:44:11 -08001429
asaperssonfab67072017-04-04 05:51:49 -07001430 // Expect no scaling to begin with.
asapersson02465b82017-04-10 01:12:52 -07001431 VerifyNoLimitation(video_source_.sink_wants());
kthelgason876222f2016-11-29 01:44:11 -08001432
asaperssonfab67072017-04-04 05:51:49 -07001433 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001434 WaitForEncodedFrame(1);
kthelgason876222f2016-11-29 01:44:11 -08001435
asaperssonfab67072017-04-04 05:51:49 -07001436 // Trigger scale down.
mflodmancc3d4422017-08-03 08:27:51 -07001437 video_stream_encoder_->TriggerQualityLow();
kthelgason5e13d412016-12-01 03:59:51 -08001438
asaperssonfab67072017-04-04 05:51:49 -07001439 video_source_.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001440 WaitForEncodedFrame(2);
kthelgason5e13d412016-12-01 03:59:51 -08001441
kthelgason876222f2016-11-29 01:44:11 -08001442 // Expect a scale down.
1443 EXPECT_TRUE(video_source_.sink_wants().max_pixel_count);
asaperssonfab67072017-04-04 05:51:49 -07001444 EXPECT_LT(video_source_.sink_wants().max_pixel_count, kWidth * kHeight);
kthelgason876222f2016-11-29 01:44:11 -08001445
asapersson02465b82017-04-10 01:12:52 -07001446 // Set resolution scaling disabled.
kthelgason876222f2016-11-29 01:44:11 -08001447 test::FrameForwarder new_video_source;
mflodmancc3d4422017-08-03 08:27:51 -07001448 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001449 &new_video_source, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
kthelgason876222f2016-11-29 01:44:11 -08001450
asaperssonfab67072017-04-04 05:51:49 -07001451 // Trigger scale down.
mflodmancc3d4422017-08-03 08:27:51 -07001452 video_stream_encoder_->TriggerQualityLow();
asaperssonfab67072017-04-04 05:51:49 -07001453 new_video_source.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001454 WaitForEncodedFrame(3);
kthelgason876222f2016-11-29 01:44:11 -08001455
asaperssonfab67072017-04-04 05:51:49 -07001456 // Expect no scaling.
sprangc5d62e22017-04-02 23:53:04 -07001457 EXPECT_EQ(std::numeric_limits<int>::max(),
1458 new_video_source.sink_wants().max_pixel_count);
kthelgason876222f2016-11-29 01:44:11 -08001459
asaperssonfab67072017-04-04 05:51:49 -07001460 // Trigger scale up.
mflodmancc3d4422017-08-03 08:27:51 -07001461 video_stream_encoder_->TriggerQualityHigh();
asaperssonfab67072017-04-04 05:51:49 -07001462 new_video_source.IncomingCapturedFrame(CreateFrame(4, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001463 WaitForEncodedFrame(4);
kthelgason876222f2016-11-29 01:44:11 -08001464
asapersson02465b82017-04-10 01:12:52 -07001465 // Expect nothing to change, still no scaling.
sprangc5d62e22017-04-02 23:53:04 -07001466 EXPECT_EQ(std::numeric_limits<int>::max(),
1467 new_video_source.sink_wants().max_pixel_count);
kthelgason876222f2016-11-29 01:44:11 -08001468
mflodmancc3d4422017-08-03 08:27:51 -07001469 video_stream_encoder_->Stop();
kthelgason876222f2016-11-29 01:44:11 -08001470}
1471
mflodmancc3d4422017-08-03 08:27:51 -07001472TEST_F(VideoStreamEncoderTest,
1473 SkipsSameAdaptDownRequest_MaintainFramerateMode) {
asapersson02465b82017-04-10 01:12:52 -07001474 const int kWidth = 1280;
1475 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001476 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson02465b82017-04-10 01:12:52 -07001477
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001478 // Enable MAINTAIN_FRAMERATE preference, no initial limitation.
asapersson02465b82017-04-10 01:12:52 -07001479 test::FrameForwarder source;
mflodmancc3d4422017-08-03 08:27:51 -07001480 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001481 &source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
asapersson02465b82017-04-10 01:12:52 -07001482
1483 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001484 WaitForEncodedFrame(1);
asapersson02465b82017-04-10 01:12:52 -07001485 VerifyNoLimitation(source.sink_wants());
1486 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1487 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1488
1489 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001490 video_stream_encoder_->TriggerCpuOveruse();
asapersson09f05612017-05-15 23:40:18 -07001491 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
asapersson02465b82017-04-10 01:12:52 -07001492 const int kLastMaxPixelCount = source.sink_wants().max_pixel_count;
1493 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1494 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1495
1496 // Trigger adapt down for same input resolution, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07001497 video_stream_encoder_->TriggerCpuOveruse();
asapersson02465b82017-04-10 01:12:52 -07001498 EXPECT_EQ(kLastMaxPixelCount, source.sink_wants().max_pixel_count);
1499 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1500 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1501
mflodmancc3d4422017-08-03 08:27:51 -07001502 video_stream_encoder_->Stop();
asapersson02465b82017-04-10 01:12:52 -07001503}
1504
mflodmancc3d4422017-08-03 08:27:51 -07001505TEST_F(VideoStreamEncoderTest, SkipsSameOrLargerAdaptDownRequest_BalancedMode) {
asaperssonf7e294d2017-06-13 23:25:22 -07001506 const int kWidth = 1280;
1507 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001508 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -07001509
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001510 // Enable BALANCED preference, no initial limitation.
asaperssonf7e294d2017-06-13 23:25:22 -07001511 test::FrameForwarder source;
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001512 video_stream_encoder_->SetSource(&source,
1513 webrtc::DegradationPreference::BALANCED);
asaperssonf7e294d2017-06-13 23:25:22 -07001514 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
1515 sink_.WaitForEncodedFrame(1);
1516 VerifyNoLimitation(source.sink_wants());
1517
1518 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001519 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07001520 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
1521 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1522 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1523 const int kLastMaxPixelCount = source.sink_wants().max_pixel_count;
1524
1525 // Trigger adapt down for same input resolution, expect no change.
1526 source.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
1527 sink_.WaitForEncodedFrame(2);
mflodmancc3d4422017-08-03 08:27:51 -07001528 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07001529 EXPECT_EQ(kLastMaxPixelCount, source.sink_wants().max_pixel_count);
1530 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1531 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1532
1533 // Trigger adapt down for larger input resolution, expect no change.
1534 source.IncomingCapturedFrame(CreateFrame(3, kWidth + 1, kHeight + 1));
1535 sink_.WaitForEncodedFrame(3);
mflodmancc3d4422017-08-03 08:27:51 -07001536 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07001537 EXPECT_EQ(kLastMaxPixelCount, source.sink_wants().max_pixel_count);
1538 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1539 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1540
mflodmancc3d4422017-08-03 08:27:51 -07001541 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07001542}
1543
mflodmancc3d4422017-08-03 08:27:51 -07001544TEST_F(VideoStreamEncoderTest,
1545 NoChangeForInitialNormalUsage_MaintainFramerateMode) {
asapersson02465b82017-04-10 01:12:52 -07001546 const int kWidth = 1280;
1547 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001548 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson02465b82017-04-10 01:12:52 -07001549
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001550 // Enable MAINTAIN_FRAMERATE preference, no initial limitation.
asapersson02465b82017-04-10 01:12:52 -07001551 test::FrameForwarder source;
mflodmancc3d4422017-08-03 08:27:51 -07001552 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001553 &source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
asapersson02465b82017-04-10 01:12:52 -07001554
1555 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001556 WaitForEncodedFrame(kWidth, kHeight);
asapersson02465b82017-04-10 01:12:52 -07001557 VerifyNoLimitation(source.sink_wants());
1558 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1559 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1560
1561 // Trigger adapt up, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07001562 video_stream_encoder_->TriggerCpuNormalUsage();
asapersson02465b82017-04-10 01:12:52 -07001563 VerifyNoLimitation(source.sink_wants());
1564 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1565 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1566
mflodmancc3d4422017-08-03 08:27:51 -07001567 video_stream_encoder_->Stop();
asapersson02465b82017-04-10 01:12:52 -07001568}
1569
mflodmancc3d4422017-08-03 08:27:51 -07001570TEST_F(VideoStreamEncoderTest,
1571 NoChangeForInitialNormalUsage_MaintainResolutionMode) {
asapersson02465b82017-04-10 01:12:52 -07001572 const int kWidth = 1280;
1573 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001574 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson02465b82017-04-10 01:12:52 -07001575
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001576 // Enable MAINTAIN_RESOLUTION preference, no initial limitation.
asapersson02465b82017-04-10 01:12:52 -07001577 test::FrameForwarder source;
mflodmancc3d4422017-08-03 08:27:51 -07001578 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001579 &source, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
asapersson02465b82017-04-10 01:12:52 -07001580
1581 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001582 WaitForEncodedFrame(kWidth, kHeight);
asapersson02465b82017-04-10 01:12:52 -07001583 VerifyNoLimitation(source.sink_wants());
asapersson09f05612017-05-15 23:40:18 -07001584 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
asapersson02465b82017-04-10 01:12:52 -07001585 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1586
1587 // Trigger adapt up, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07001588 video_stream_encoder_->TriggerCpuNormalUsage();
asapersson02465b82017-04-10 01:12:52 -07001589 VerifyNoLimitation(source.sink_wants());
asapersson09f05612017-05-15 23:40:18 -07001590 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
asapersson02465b82017-04-10 01:12:52 -07001591 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1592
mflodmancc3d4422017-08-03 08:27:51 -07001593 video_stream_encoder_->Stop();
asapersson02465b82017-04-10 01:12:52 -07001594}
1595
mflodmancc3d4422017-08-03 08:27:51 -07001596TEST_F(VideoStreamEncoderTest, NoChangeForInitialNormalUsage_BalancedMode) {
asaperssonf7e294d2017-06-13 23:25:22 -07001597 const int kWidth = 1280;
1598 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001599 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -07001600
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001601 // Enable BALANCED preference, no initial limitation.
asaperssonf7e294d2017-06-13 23:25:22 -07001602 test::FrameForwarder source;
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001603 video_stream_encoder_->SetSource(&source,
1604 webrtc::DegradationPreference::BALANCED);
asaperssonf7e294d2017-06-13 23:25:22 -07001605
1606 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
1607 sink_.WaitForEncodedFrame(kWidth, kHeight);
1608 VerifyNoLimitation(source.sink_wants());
1609 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1610 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
1611 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1612
1613 // Trigger adapt up, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07001614 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07001615 VerifyNoLimitation(source.sink_wants());
1616 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1617 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
1618 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1619
mflodmancc3d4422017-08-03 08:27:51 -07001620 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07001621}
1622
mflodmancc3d4422017-08-03 08:27:51 -07001623TEST_F(VideoStreamEncoderTest, NoChangeForInitialNormalUsage_DisabledMode) {
asapersson09f05612017-05-15 23:40:18 -07001624 const int kWidth = 1280;
1625 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001626 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson09f05612017-05-15 23:40:18 -07001627
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001628 // Enable DISABLED preference, no initial limitation.
asapersson09f05612017-05-15 23:40:18 -07001629 test::FrameForwarder source;
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001630 video_stream_encoder_->SetSource(&source,
1631 webrtc::DegradationPreference::DISABLED);
asapersson09f05612017-05-15 23:40:18 -07001632
1633 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
1634 sink_.WaitForEncodedFrame(kWidth, kHeight);
1635 VerifyNoLimitation(source.sink_wants());
1636 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1637 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
1638 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1639
1640 // Trigger adapt up, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07001641 video_stream_encoder_->TriggerQualityHigh();
asapersson09f05612017-05-15 23:40:18 -07001642 VerifyNoLimitation(source.sink_wants());
1643 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1644 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
1645 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1646
mflodmancc3d4422017-08-03 08:27:51 -07001647 video_stream_encoder_->Stop();
asapersson09f05612017-05-15 23:40:18 -07001648}
1649
mflodmancc3d4422017-08-03 08:27:51 -07001650TEST_F(VideoStreamEncoderTest,
1651 AdaptsResolutionForLowQuality_MaintainFramerateMode) {
asapersson02465b82017-04-10 01:12:52 -07001652 const int kWidth = 1280;
1653 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001654 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson02465b82017-04-10 01:12:52 -07001655
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001656 // Enable MAINTAIN_FRAMERATE preference, no initial limitation.
asapersson02465b82017-04-10 01:12:52 -07001657 AdaptingFrameForwarder source;
1658 source.set_adaptation_enabled(true);
mflodmancc3d4422017-08-03 08:27:51 -07001659 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001660 &source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
asapersson02465b82017-04-10 01:12:52 -07001661
1662 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001663 WaitForEncodedFrame(1);
asapersson02465b82017-04-10 01:12:52 -07001664 VerifyNoLimitation(source.sink_wants());
1665 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1666 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1667
1668 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001669 video_stream_encoder_->TriggerQualityLow();
asapersson02465b82017-04-10 01:12:52 -07001670 source.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001671 WaitForEncodedFrame(2);
asapersson09f05612017-05-15 23:40:18 -07001672 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
asapersson02465b82017-04-10 01:12:52 -07001673 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1674 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1675
1676 // Trigger adapt up, expect no restriction.
mflodmancc3d4422017-08-03 08:27:51 -07001677 video_stream_encoder_->TriggerQualityHigh();
asapersson02465b82017-04-10 01:12:52 -07001678 VerifyNoLimitation(source.sink_wants());
1679 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1680 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1681 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1682
mflodmancc3d4422017-08-03 08:27:51 -07001683 video_stream_encoder_->Stop();
asapersson02465b82017-04-10 01:12:52 -07001684}
1685
mflodmancc3d4422017-08-03 08:27:51 -07001686TEST_F(VideoStreamEncoderTest,
1687 AdaptsFramerateForLowQuality_MaintainResolutionMode) {
asapersson09f05612017-05-15 23:40:18 -07001688 const int kWidth = 1280;
1689 const int kHeight = 720;
1690 const int kInputFps = 30;
mflodmancc3d4422017-08-03 08:27:51 -07001691 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson09f05612017-05-15 23:40:18 -07001692
1693 VideoSendStream::Stats stats = stats_proxy_->GetStats();
1694 stats.input_frame_rate = kInputFps;
1695 stats_proxy_->SetMockStats(stats);
1696
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001697 // Expect no scaling to begin with (preference: MAINTAIN_FRAMERATE).
asapersson09f05612017-05-15 23:40:18 -07001698 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
1699 sink_.WaitForEncodedFrame(1);
1700 VerifyNoLimitation(video_source_.sink_wants());
1701
1702 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001703 video_stream_encoder_->TriggerQualityLow();
asapersson09f05612017-05-15 23:40:18 -07001704 video_source_.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
1705 sink_.WaitForEncodedFrame(2);
1706 VerifyFpsMaxResolutionLt(video_source_.sink_wants(), kWidth * kHeight);
1707
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001708 // Enable MAINTAIN_RESOLUTION preference.
asapersson09f05612017-05-15 23:40:18 -07001709 test::FrameForwarder new_video_source;
mflodmancc3d4422017-08-03 08:27:51 -07001710 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001711 &new_video_source, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
asapersson09f05612017-05-15 23:40:18 -07001712 VerifyNoLimitation(new_video_source.sink_wants());
1713
1714 // Trigger adapt down, expect reduced framerate.
mflodmancc3d4422017-08-03 08:27:51 -07001715 video_stream_encoder_->TriggerQualityLow();
asapersson09f05612017-05-15 23:40:18 -07001716 new_video_source.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
1717 sink_.WaitForEncodedFrame(3);
1718 VerifyFpsLtResolutionMax(new_video_source.sink_wants(), kInputFps);
1719
1720 // Trigger adapt up, expect no restriction.
mflodmancc3d4422017-08-03 08:27:51 -07001721 video_stream_encoder_->TriggerQualityHigh();
asapersson09f05612017-05-15 23:40:18 -07001722 VerifyNoLimitation(new_video_source.sink_wants());
1723
mflodmancc3d4422017-08-03 08:27:51 -07001724 video_stream_encoder_->Stop();
asapersson09f05612017-05-15 23:40:18 -07001725}
1726
mflodmancc3d4422017-08-03 08:27:51 -07001727TEST_F(VideoStreamEncoderTest, DoesNotScaleBelowSetResolutionLimit) {
asaperssond0de2952017-04-21 01:47:31 -07001728 const int kWidth = 1280;
1729 const int kHeight = 720;
1730 const size_t kNumFrames = 10;
1731
mflodmancc3d4422017-08-03 08:27:51 -07001732 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
kthelgason5e13d412016-12-01 03:59:51 -08001733
asaperssond0de2952017-04-21 01:47:31 -07001734 // Enable adapter, expected input resolutions when downscaling:
asapersson142fcc92017-08-17 08:58:54 -07001735 // 1280x720 -> 960x540 -> 640x360 -> 480x270 -> 320x180 (kMinPixelsPerFrame)
asaperssond0de2952017-04-21 01:47:31 -07001736 video_source_.set_adaptation_enabled(true);
1737
1738 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1739 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1740
1741 int downscales = 0;
1742 for (size_t i = 1; i <= kNumFrames; i++) {
1743 video_source_.IncomingCapturedFrame(CreateFrame(i, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001744 WaitForEncodedFrame(i);
asaperssond0de2952017-04-21 01:47:31 -07001745
asaperssonfab67072017-04-04 05:51:49 -07001746 // Trigger scale down.
asaperssond0de2952017-04-21 01:47:31 -07001747 rtc::VideoSinkWants last_wants = video_source_.sink_wants();
mflodmancc3d4422017-08-03 08:27:51 -07001748 video_stream_encoder_->TriggerQualityLow();
sprangc5d62e22017-04-02 23:53:04 -07001749 EXPECT_GE(video_source_.sink_wants().max_pixel_count, kMinPixelsPerFrame);
asaperssond0de2952017-04-21 01:47:31 -07001750
1751 if (video_source_.sink_wants().max_pixel_count < last_wants.max_pixel_count)
1752 ++downscales;
1753
1754 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1755 EXPECT_EQ(downscales,
1756 stats_proxy_->GetStats().number_of_quality_adapt_changes);
1757 EXPECT_GT(downscales, 0);
kthelgason5e13d412016-12-01 03:59:51 -08001758 }
mflodmancc3d4422017-08-03 08:27:51 -07001759 video_stream_encoder_->Stop();
asaperssond0de2952017-04-21 01:47:31 -07001760}
1761
mflodmancc3d4422017-08-03 08:27:51 -07001762TEST_F(VideoStreamEncoderTest,
asaperssond0de2952017-04-21 01:47:31 -07001763 AdaptsResolutionUpAndDownTwiceOnOveruse_MaintainFramerateMode) {
1764 const int kWidth = 1280;
1765 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001766 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssond0de2952017-04-21 01:47:31 -07001767
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001768 // Enable MAINTAIN_FRAMERATE preference, no initial limitation.
asaperssond0de2952017-04-21 01:47:31 -07001769 AdaptingFrameForwarder source;
1770 source.set_adaptation_enabled(true);
mflodmancc3d4422017-08-03 08:27:51 -07001771 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001772 &source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
asaperssond0de2952017-04-21 01:47:31 -07001773
1774 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001775 WaitForEncodedFrame(kWidth, kHeight);
asaperssond0de2952017-04-21 01:47:31 -07001776 VerifyNoLimitation(source.sink_wants());
1777 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1778 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1779
1780 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001781 video_stream_encoder_->TriggerCpuOveruse();
asaperssond0de2952017-04-21 01:47:31 -07001782 source.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001783 WaitForEncodedFrame(2);
asapersson09f05612017-05-15 23:40:18 -07001784 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
asaperssond0de2952017-04-21 01:47:31 -07001785 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1786 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1787
1788 // Trigger adapt up, expect no restriction.
mflodmancc3d4422017-08-03 08:27:51 -07001789 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssond0de2952017-04-21 01:47:31 -07001790 source.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001791 WaitForEncodedFrame(kWidth, kHeight);
asaperssond0de2952017-04-21 01:47:31 -07001792 VerifyNoLimitation(source.sink_wants());
1793 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1794 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1795
1796 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001797 video_stream_encoder_->TriggerCpuOveruse();
asaperssond0de2952017-04-21 01:47:31 -07001798 source.IncomingCapturedFrame(CreateFrame(4, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001799 WaitForEncodedFrame(4);
asapersson09f05612017-05-15 23:40:18 -07001800 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
asaperssond0de2952017-04-21 01:47:31 -07001801 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1802 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1803
1804 // Trigger adapt up, expect no restriction.
mflodmancc3d4422017-08-03 08:27:51 -07001805 video_stream_encoder_->TriggerCpuNormalUsage();
asapersson09f05612017-05-15 23:40:18 -07001806 source.IncomingCapturedFrame(CreateFrame(5, kWidth, kHeight));
1807 sink_.WaitForEncodedFrame(kWidth, kHeight);
asaperssond0de2952017-04-21 01:47:31 -07001808 VerifyNoLimitation(source.sink_wants());
1809 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1810 EXPECT_EQ(4, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1811
mflodmancc3d4422017-08-03 08:27:51 -07001812 video_stream_encoder_->Stop();
asaperssond0de2952017-04-21 01:47:31 -07001813}
1814
mflodmancc3d4422017-08-03 08:27:51 -07001815TEST_F(VideoStreamEncoderTest,
asaperssonf7e294d2017-06-13 23:25:22 -07001816 AdaptsResolutionUpAndDownTwiceForLowQuality_BalancedMode_NoFpsLimit) {
1817 const int kWidth = 1280;
1818 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001819 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -07001820
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001821 // Enable BALANCED preference, no initial limitation.
asaperssonf7e294d2017-06-13 23:25:22 -07001822 AdaptingFrameForwarder source;
1823 source.set_adaptation_enabled(true);
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001824 video_stream_encoder_->SetSource(&source,
1825 webrtc::DegradationPreference::BALANCED);
asaperssonf7e294d2017-06-13 23:25:22 -07001826
1827 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
1828 sink_.WaitForEncodedFrame(kWidth, kHeight);
1829 VerifyNoLimitation(source.sink_wants());
1830 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1831 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1832
1833 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001834 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07001835 source.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
1836 sink_.WaitForEncodedFrame(2);
1837 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
1838 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1839 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1840
1841 // Trigger adapt up, expect no restriction.
mflodmancc3d4422017-08-03 08:27:51 -07001842 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07001843 source.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
1844 sink_.WaitForEncodedFrame(kWidth, kHeight);
1845 VerifyNoLimitation(source.sink_wants());
1846 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1847 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1848
1849 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001850 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07001851 source.IncomingCapturedFrame(CreateFrame(4, kWidth, kHeight));
1852 sink_.WaitForEncodedFrame(4);
1853 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
1854 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1855 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1856
1857 // Trigger adapt up, expect no restriction.
mflodmancc3d4422017-08-03 08:27:51 -07001858 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07001859 source.IncomingCapturedFrame(CreateFrame(5, kWidth, kHeight));
1860 sink_.WaitForEncodedFrame(kWidth, kHeight);
1861 VerifyNoLimitation(source.sink_wants());
1862 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1863 EXPECT_EQ(4, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1864
mflodmancc3d4422017-08-03 08:27:51 -07001865 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07001866}
1867
mflodmancc3d4422017-08-03 08:27:51 -07001868TEST_F(VideoStreamEncoderTest,
asaperssond0de2952017-04-21 01:47:31 -07001869 AdaptsResolutionOnOveruseAndLowQuality_MaintainFramerateMode) {
1870 const int kWidth = 1280;
1871 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001872 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssond0de2952017-04-21 01:47:31 -07001873
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001874 // Enable MAINTAIN_FRAMERATE preference, no initial limitation.
asaperssond0de2952017-04-21 01:47:31 -07001875 AdaptingFrameForwarder source;
1876 source.set_adaptation_enabled(true);
mflodmancc3d4422017-08-03 08:27:51 -07001877 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001878 &source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
asaperssond0de2952017-04-21 01:47:31 -07001879
1880 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001881 WaitForEncodedFrame(kWidth, kHeight);
asaperssond0de2952017-04-21 01:47:31 -07001882 VerifyNoLimitation(source.sink_wants());
1883 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1884 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1885 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1886 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1887
1888 // Trigger cpu adapt down, expect scaled down resolution (960x540).
mflodmancc3d4422017-08-03 08:27:51 -07001889 video_stream_encoder_->TriggerCpuOveruse();
asaperssond0de2952017-04-21 01:47:31 -07001890 source.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001891 WaitForEncodedFrame(2);
asapersson09f05612017-05-15 23:40:18 -07001892 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
asaperssond0de2952017-04-21 01:47:31 -07001893 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1894 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1895 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1896 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1897
1898 // Trigger cpu adapt down, expect scaled down resolution (640x360).
mflodmancc3d4422017-08-03 08:27:51 -07001899 video_stream_encoder_->TriggerCpuOveruse();
asaperssond0de2952017-04-21 01:47:31 -07001900 source.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001901 WaitForEncodedFrame(3);
asapersson09f05612017-05-15 23:40:18 -07001902 VerifyFpsMaxResolutionLt(source.sink_wants(), source.last_wants());
asaperssond0de2952017-04-21 01:47:31 -07001903 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1904 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1905 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1906 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1907
Jonathan Yubc771b72017-12-08 17:04:29 -08001908 // Trigger cpu adapt down, expect scaled down resolution (480x270).
mflodmancc3d4422017-08-03 08:27:51 -07001909 video_stream_encoder_->TriggerCpuOveruse();
asaperssond0de2952017-04-21 01:47:31 -07001910 source.IncomingCapturedFrame(CreateFrame(4, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001911 WaitForEncodedFrame(4);
Jonathan Yubc771b72017-12-08 17:04:29 -08001912 VerifyFpsMaxResolutionLt(source.sink_wants(), source.last_wants());
asaperssond0de2952017-04-21 01:47:31 -07001913 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1914 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
Jonathan Yubc771b72017-12-08 17:04:29 -08001915 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
asaperssond0de2952017-04-21 01:47:31 -07001916 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1917
Jonathan Yubc771b72017-12-08 17:04:29 -08001918 // Trigger quality adapt down, expect scaled down resolution (320x180).
mflodmancc3d4422017-08-03 08:27:51 -07001919 video_stream_encoder_->TriggerQualityLow();
asaperssond0de2952017-04-21 01:47:31 -07001920 source.IncomingCapturedFrame(CreateFrame(5, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001921 WaitForEncodedFrame(5);
asapersson09f05612017-05-15 23:40:18 -07001922 VerifyFpsMaxResolutionLt(source.sink_wants(), source.last_wants());
Jonathan Yubc771b72017-12-08 17:04:29 -08001923 rtc::VideoSinkWants last_wants = source.sink_wants();
asaperssond0de2952017-04-21 01:47:31 -07001924 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1925 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1926 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1927 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1928
Jonathan Yubc771b72017-12-08 17:04:29 -08001929 // Trigger quality adapt down, expect no change (min resolution reached).
1930 video_stream_encoder_->TriggerQualityLow();
1931 source.IncomingCapturedFrame(CreateFrame(6, kWidth, kHeight));
1932 WaitForEncodedFrame(6);
1933 VerifyFpsMaxResolutionEq(source.sink_wants(), last_wants);
1934 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1935 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1936 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1937 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1938
1939 // Trigger cpu adapt up, expect upscaled resolution (480x270).
mflodmancc3d4422017-08-03 08:27:51 -07001940 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssond0de2952017-04-21 01:47:31 -07001941 source.IncomingCapturedFrame(CreateFrame(7, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001942 WaitForEncodedFrame(7);
asapersson09f05612017-05-15 23:40:18 -07001943 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
Jonathan Yubc771b72017-12-08 17:04:29 -08001944 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1945 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1946 EXPECT_EQ(4, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1947 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1948
1949 // Trigger cpu adapt up, expect upscaled resolution (640x360).
1950 video_stream_encoder_->TriggerCpuNormalUsage();
1951 source.IncomingCapturedFrame(CreateFrame(8, kWidth, kHeight));
1952 WaitForEncodedFrame(8);
1953 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
1954 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1955 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1956 EXPECT_EQ(5, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1957 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1958
1959 // Trigger cpu adapt up, expect upscaled resolution (960x540).
1960 video_stream_encoder_->TriggerCpuNormalUsage();
1961 source.IncomingCapturedFrame(CreateFrame(9, kWidth, kHeight));
1962 WaitForEncodedFrame(9);
1963 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
asaperssond0de2952017-04-21 01:47:31 -07001964 last_wants = source.sink_wants();
1965 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1966 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
Jonathan Yubc771b72017-12-08 17:04:29 -08001967 EXPECT_EQ(6, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
asaperssond0de2952017-04-21 01:47:31 -07001968 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1969
1970 // Trigger cpu adapt up, no cpu downgrades, expect no change (960x540).
mflodmancc3d4422017-08-03 08:27:51 -07001971 video_stream_encoder_->TriggerCpuNormalUsage();
Jonathan Yubc771b72017-12-08 17:04:29 -08001972 source.IncomingCapturedFrame(CreateFrame(10, kWidth, kHeight));
1973 WaitForEncodedFrame(10);
asapersson09f05612017-05-15 23:40:18 -07001974 VerifyFpsEqResolutionEq(source.sink_wants(), last_wants);
asaperssond0de2952017-04-21 01:47:31 -07001975 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1976 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
Jonathan Yubc771b72017-12-08 17:04:29 -08001977 EXPECT_EQ(6, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
asaperssond0de2952017-04-21 01:47:31 -07001978 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1979
1980 // Trigger quality adapt up, expect no restriction (1280x720).
mflodmancc3d4422017-08-03 08:27:51 -07001981 video_stream_encoder_->TriggerQualityHigh();
Jonathan Yubc771b72017-12-08 17:04:29 -08001982 source.IncomingCapturedFrame(CreateFrame(11, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001983 WaitForEncodedFrame(kWidth, kHeight);
asapersson09f05612017-05-15 23:40:18 -07001984 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
asaperssond0de2952017-04-21 01:47:31 -07001985 VerifyNoLimitation(source.sink_wants());
1986 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1987 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
Jonathan Yubc771b72017-12-08 17:04:29 -08001988 EXPECT_EQ(6, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
asaperssond0de2952017-04-21 01:47:31 -07001989 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
kthelgason5e13d412016-12-01 03:59:51 -08001990
mflodmancc3d4422017-08-03 08:27:51 -07001991 video_stream_encoder_->Stop();
kthelgason5e13d412016-12-01 03:59:51 -08001992}
1993
mflodmancc3d4422017-08-03 08:27:51 -07001994TEST_F(VideoStreamEncoderTest, CpuLimitedHistogramIsReported) {
asaperssonfab67072017-04-04 05:51:49 -07001995 const int kWidth = 640;
1996 const int kHeight = 360;
perkj803d97f2016-11-01 11:45:46 -07001997
mflodmancc3d4422017-08-03 08:27:51 -07001998 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
sprang4847ae62017-06-27 07:06:52 -07001999
perkj803d97f2016-11-01 11:45:46 -07002000 for (int i = 1; i <= SendStatisticsProxy::kMinRequiredMetricsSamples; ++i) {
asaperssonfab67072017-04-04 05:51:49 -07002001 video_source_.IncomingCapturedFrame(CreateFrame(i, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002002 WaitForEncodedFrame(i);
perkj803d97f2016-11-01 11:45:46 -07002003 }
2004
mflodmancc3d4422017-08-03 08:27:51 -07002005 video_stream_encoder_->TriggerCpuOveruse();
perkj803d97f2016-11-01 11:45:46 -07002006 for (int i = 1; i <= SendStatisticsProxy::kMinRequiredMetricsSamples; ++i) {
asaperssonfab67072017-04-04 05:51:49 -07002007 video_source_.IncomingCapturedFrame(CreateFrame(
2008 SendStatisticsProxy::kMinRequiredMetricsSamples + i, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002009 WaitForEncodedFrame(SendStatisticsProxy::kMinRequiredMetricsSamples + i);
perkj803d97f2016-11-01 11:45:46 -07002010 }
2011
mflodmancc3d4422017-08-03 08:27:51 -07002012 video_stream_encoder_->Stop();
2013 video_stream_encoder_.reset();
perkj803d97f2016-11-01 11:45:46 -07002014 stats_proxy_.reset();
sprangf8ee65e2017-02-28 08:49:33 -08002015
perkj803d97f2016-11-01 11:45:46 -07002016 EXPECT_EQ(1,
2017 metrics::NumSamples("WebRTC.Video.CpuLimitedResolutionInPercent"));
2018 EXPECT_EQ(
2019 1, metrics::NumEvents("WebRTC.Video.CpuLimitedResolutionInPercent", 50));
2020}
2021
mflodmancc3d4422017-08-03 08:27:51 -07002022TEST_F(VideoStreamEncoderTest,
2023 CpuLimitedHistogramIsNotReportedForDisabledDegradation) {
2024 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonf4e44af2017-04-19 02:01:06 -07002025 const int kWidth = 640;
2026 const int kHeight = 360;
2027
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002028 video_stream_encoder_->SetSource(&video_source_,
2029 webrtc::DegradationPreference::DISABLED);
asaperssonf4e44af2017-04-19 02:01:06 -07002030
2031 for (int i = 1; i <= SendStatisticsProxy::kMinRequiredMetricsSamples; ++i) {
2032 video_source_.IncomingCapturedFrame(CreateFrame(i, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002033 WaitForEncodedFrame(i);
asaperssonf4e44af2017-04-19 02:01:06 -07002034 }
2035
mflodmancc3d4422017-08-03 08:27:51 -07002036 video_stream_encoder_->Stop();
2037 video_stream_encoder_.reset();
asaperssonf4e44af2017-04-19 02:01:06 -07002038 stats_proxy_.reset();
2039
2040 EXPECT_EQ(0,
2041 metrics::NumSamples("WebRTC.Video.CpuLimitedResolutionInPercent"));
2042}
2043
mflodmancc3d4422017-08-03 08:27:51 -07002044TEST_F(VideoStreamEncoderTest, CallsBitrateObserver) {
sprang4847ae62017-06-27 07:06:52 -07002045 MockBitrateObserver bitrate_observer;
mflodmancc3d4422017-08-03 08:27:51 -07002046 video_stream_encoder_->SetBitrateObserver(&bitrate_observer);
sprang57c2fff2017-01-16 06:24:02 -08002047
2048 const int kDefaultFps = 30;
Erik Språng566124a2018-04-23 12:32:22 +02002049 const VideoBitrateAllocation expected_bitrate =
sprang57c2fff2017-01-16 06:24:02 -08002050 DefaultVideoBitrateAllocator(fake_encoder_.codec_config())
kthelgason2bc68642017-02-07 07:02:22 -08002051 .GetAllocation(kLowTargetBitrateBps, kDefaultFps);
sprang57c2fff2017-01-16 06:24:02 -08002052
2053 // First called on bitrate updated, then again on first frame.
2054 EXPECT_CALL(bitrate_observer, OnBitrateAllocationUpdated(expected_bitrate))
2055 .Times(2);
mflodmancc3d4422017-08-03 08:27:51 -07002056 video_stream_encoder_->OnBitrateUpdated(kLowTargetBitrateBps, 0, 0);
sprang57c2fff2017-01-16 06:24:02 -08002057
2058 const int64_t kStartTimeMs = 1;
2059 video_source_.IncomingCapturedFrame(
2060 CreateFrame(kStartTimeMs, codec_width_, codec_height_));
sprang4847ae62017-06-27 07:06:52 -07002061 WaitForEncodedFrame(kStartTimeMs);
sprang57c2fff2017-01-16 06:24:02 -08002062
2063 // Not called on second frame.
2064 EXPECT_CALL(bitrate_observer, OnBitrateAllocationUpdated(expected_bitrate))
2065 .Times(0);
2066 video_source_.IncomingCapturedFrame(
2067 CreateFrame(kStartTimeMs + 1, codec_width_, codec_height_));
sprang4847ae62017-06-27 07:06:52 -07002068 WaitForEncodedFrame(kStartTimeMs + 1);
sprang57c2fff2017-01-16 06:24:02 -08002069
2070 // Called after a process interval.
2071 const int64_t kProcessIntervalMs =
2072 vcm::VCMProcessTimer::kDefaultProcessIntervalMs;
sprang4847ae62017-06-27 07:06:52 -07002073 fake_clock_.AdvanceTimeMicros(rtc::kNumMicrosecsPerMillisec *
2074 (kProcessIntervalMs + (1000 / kDefaultFps)));
sprang57c2fff2017-01-16 06:24:02 -08002075 EXPECT_CALL(bitrate_observer, OnBitrateAllocationUpdated(expected_bitrate))
2076 .Times(1);
2077 video_source_.IncomingCapturedFrame(CreateFrame(
2078 kStartTimeMs + kProcessIntervalMs, codec_width_, codec_height_));
sprang4847ae62017-06-27 07:06:52 -07002079 WaitForEncodedFrame(kStartTimeMs + kProcessIntervalMs);
sprang57c2fff2017-01-16 06:24:02 -08002080
mflodmancc3d4422017-08-03 08:27:51 -07002081 video_stream_encoder_->Stop();
sprang57c2fff2017-01-16 06:24:02 -08002082}
2083
Niels Möller7dc26b72017-12-06 10:27:48 +01002084TEST_F(VideoStreamEncoderTest, OveruseDetectorUpdatedOnReconfigureAndAdaption) {
2085 const int kFrameWidth = 1280;
2086 const int kFrameHeight = 720;
2087 const int kFramerate = 24;
2088
2089 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
2090 test::FrameForwarder source;
2091 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002092 &source, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
Niels Möller7dc26b72017-12-06 10:27:48 +01002093
2094 // Insert a single frame, triggering initial configuration.
2095 source.IncomingCapturedFrame(CreateFrame(1, kFrameWidth, kFrameHeight));
2096 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2097
2098 EXPECT_EQ(
2099 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2100 kDefaultFramerate);
2101
2102 // Trigger reconfigure encoder (without resetting the entire instance).
2103 VideoEncoderConfig video_encoder_config;
Niels Möller259a4972018-04-05 15:36:51 +02002104 video_encoder_config.codec_type = kVideoCodecVP8;
Niels Möller7dc26b72017-12-06 10:27:48 +01002105 video_encoder_config.max_bitrate_bps = kTargetBitrateBps;
2106 video_encoder_config.number_of_streams = 1;
2107 video_encoder_config.video_stream_factory =
2108 new rtc::RefCountedObject<VideoStreamFactory>(1, kFramerate);
2109 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
Niels Möllerf1338562018-04-26 09:51:47 +02002110 kMaxPayloadLength);
Niels Möller7dc26b72017-12-06 10:27:48 +01002111 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2112
2113 // Detector should be updated with fps limit from codec config.
2114 EXPECT_EQ(
2115 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2116 kFramerate);
2117
2118 // Trigger overuse, max framerate should be reduced.
2119 VideoSendStream::Stats stats = stats_proxy_->GetStats();
2120 stats.input_frame_rate = kFramerate;
2121 stats_proxy_->SetMockStats(stats);
2122 video_stream_encoder_->TriggerCpuOveruse();
2123 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2124 int adapted_framerate =
2125 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate();
2126 EXPECT_LT(adapted_framerate, kFramerate);
2127
2128 // Trigger underuse, max framerate should go back to codec configured fps.
2129 // Set extra low fps, to make sure it's actually reset, not just incremented.
2130 stats = stats_proxy_->GetStats();
2131 stats.input_frame_rate = adapted_framerate / 2;
2132 stats_proxy_->SetMockStats(stats);
2133 video_stream_encoder_->TriggerCpuNormalUsage();
2134 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2135 EXPECT_EQ(
2136 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2137 kFramerate);
2138
2139 video_stream_encoder_->Stop();
2140}
2141
2142TEST_F(VideoStreamEncoderTest,
2143 OveruseDetectorUpdatedRespectsFramerateAfterUnderuse) {
2144 const int kFrameWidth = 1280;
2145 const int kFrameHeight = 720;
2146 const int kLowFramerate = 15;
2147 const int kHighFramerate = 25;
2148
2149 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
2150 test::FrameForwarder source;
2151 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002152 &source, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
Niels Möller7dc26b72017-12-06 10:27:48 +01002153
2154 // Trigger initial configuration.
2155 VideoEncoderConfig video_encoder_config;
Niels Möller259a4972018-04-05 15:36:51 +02002156 video_encoder_config.codec_type = kVideoCodecVP8;
Niels Möller7dc26b72017-12-06 10:27:48 +01002157 video_encoder_config.max_bitrate_bps = kTargetBitrateBps;
2158 video_encoder_config.number_of_streams = 1;
2159 video_encoder_config.video_stream_factory =
2160 new rtc::RefCountedObject<VideoStreamFactory>(1, kLowFramerate);
2161 source.IncomingCapturedFrame(CreateFrame(1, kFrameWidth, kFrameHeight));
2162 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
Niels Möllerf1338562018-04-26 09:51:47 +02002163 kMaxPayloadLength);
Niels Möller7dc26b72017-12-06 10:27:48 +01002164 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2165
2166 EXPECT_EQ(
2167 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2168 kLowFramerate);
2169
2170 // Trigger overuse, max framerate should be reduced.
2171 VideoSendStream::Stats stats = stats_proxy_->GetStats();
2172 stats.input_frame_rate = kLowFramerate;
2173 stats_proxy_->SetMockStats(stats);
2174 video_stream_encoder_->TriggerCpuOveruse();
2175 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2176 int adapted_framerate =
2177 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate();
2178 EXPECT_LT(adapted_framerate, kLowFramerate);
2179
2180 // Reconfigure the encoder with a new (higher max framerate), max fps should
2181 // still respect the adaptation.
2182 video_encoder_config.video_stream_factory =
2183 new rtc::RefCountedObject<VideoStreamFactory>(1, kHighFramerate);
2184 source.IncomingCapturedFrame(CreateFrame(1, kFrameWidth, kFrameHeight));
2185 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
Niels Möllerf1338562018-04-26 09:51:47 +02002186 kMaxPayloadLength);
Niels Möller7dc26b72017-12-06 10:27:48 +01002187 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2188
2189 EXPECT_EQ(
2190 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2191 adapted_framerate);
2192
2193 // Trigger underuse, max framerate should go back to codec configured fps.
2194 stats = stats_proxy_->GetStats();
2195 stats.input_frame_rate = adapted_framerate;
2196 stats_proxy_->SetMockStats(stats);
2197 video_stream_encoder_->TriggerCpuNormalUsage();
2198 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2199 EXPECT_EQ(
2200 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2201 kHighFramerate);
2202
2203 video_stream_encoder_->Stop();
2204}
2205
mflodmancc3d4422017-08-03 08:27:51 -07002206TEST_F(VideoStreamEncoderTest,
2207 OveruseDetectorUpdatedOnDegradationPreferenceChange) {
sprangfda496a2017-06-15 04:21:07 -07002208 const int kFrameWidth = 1280;
2209 const int kFrameHeight = 720;
2210 const int kFramerate = 24;
2211
mflodmancc3d4422017-08-03 08:27:51 -07002212 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
sprangfda496a2017-06-15 04:21:07 -07002213 test::FrameForwarder source;
mflodmancc3d4422017-08-03 08:27:51 -07002214 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002215 &source, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
sprangfda496a2017-06-15 04:21:07 -07002216
2217 // Trigger initial configuration.
2218 VideoEncoderConfig video_encoder_config;
Niels Möller259a4972018-04-05 15:36:51 +02002219 video_encoder_config.codec_type = kVideoCodecVP8;
sprangfda496a2017-06-15 04:21:07 -07002220 video_encoder_config.max_bitrate_bps = kTargetBitrateBps;
2221 video_encoder_config.number_of_streams = 1;
2222 video_encoder_config.video_stream_factory =
2223 new rtc::RefCountedObject<VideoStreamFactory>(1, kFramerate);
2224 source.IncomingCapturedFrame(CreateFrame(1, kFrameWidth, kFrameHeight));
mflodmancc3d4422017-08-03 08:27:51 -07002225 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
Niels Möllerf1338562018-04-26 09:51:47 +02002226 kMaxPayloadLength);
mflodmancc3d4422017-08-03 08:27:51 -07002227 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
sprangfda496a2017-06-15 04:21:07 -07002228
Niels Möller7dc26b72017-12-06 10:27:48 +01002229 EXPECT_EQ(
2230 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2231 kFramerate);
sprangfda496a2017-06-15 04:21:07 -07002232
2233 // Trigger overuse, max framerate should be reduced.
2234 VideoSendStream::Stats stats = stats_proxy_->GetStats();
2235 stats.input_frame_rate = kFramerate;
2236 stats_proxy_->SetMockStats(stats);
mflodmancc3d4422017-08-03 08:27:51 -07002237 video_stream_encoder_->TriggerCpuOveruse();
2238 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
Niels Möller7dc26b72017-12-06 10:27:48 +01002239 int adapted_framerate =
2240 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate();
sprangfda496a2017-06-15 04:21:07 -07002241 EXPECT_LT(adapted_framerate, kFramerate);
2242
2243 // Change degradation preference to not enable framerate scaling. Target
2244 // framerate should be changed to codec defined limit.
mflodmancc3d4422017-08-03 08:27:51 -07002245 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002246 &source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
mflodmancc3d4422017-08-03 08:27:51 -07002247 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
Niels Möller7dc26b72017-12-06 10:27:48 +01002248 EXPECT_EQ(
2249 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2250 kFramerate);
sprangfda496a2017-06-15 04:21:07 -07002251
mflodmancc3d4422017-08-03 08:27:51 -07002252 video_stream_encoder_->Stop();
sprangfda496a2017-06-15 04:21:07 -07002253}
2254
mflodmancc3d4422017-08-03 08:27:51 -07002255TEST_F(VideoStreamEncoderTest, DropsFramesAndScalesWhenBitrateIsTooLow) {
asaperssonfab67072017-04-04 05:51:49 -07002256 const int kTooLowBitrateForFrameSizeBps = 10000;
mflodmancc3d4422017-08-03 08:27:51 -07002257 video_stream_encoder_->OnBitrateUpdated(kTooLowBitrateForFrameSizeBps, 0, 0);
asaperssonfab67072017-04-04 05:51:49 -07002258 const int kWidth = 640;
2259 const int kHeight = 360;
kthelgason2bc68642017-02-07 07:02:22 -08002260
asaperssonfab67072017-04-04 05:51:49 -07002261 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
kthelgason2bc68642017-02-07 07:02:22 -08002262
2263 // Expect to drop this frame, the wait should time out.
sprang4847ae62017-06-27 07:06:52 -07002264 ExpectDroppedFrame();
kthelgason2bc68642017-02-07 07:02:22 -08002265
2266 // Expect the sink_wants to specify a scaled frame.
asapersson0944a802017-04-07 00:57:58 -07002267 EXPECT_LT(video_source_.sink_wants().max_pixel_count, kWidth * kHeight);
kthelgason2bc68642017-02-07 07:02:22 -08002268
sprangc5d62e22017-04-02 23:53:04 -07002269 int last_pixel_count = video_source_.sink_wants().max_pixel_count;
kthelgason2bc68642017-02-07 07:02:22 -08002270
asaperssonfab67072017-04-04 05:51:49 -07002271 // Next frame is scaled.
kthelgason2bc68642017-02-07 07:02:22 -08002272 video_source_.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07002273 CreateFrame(2, kWidth * 3 / 4, kHeight * 3 / 4));
kthelgason2bc68642017-02-07 07:02:22 -08002274
2275 // Expect to drop this frame, the wait should time out.
sprang4847ae62017-06-27 07:06:52 -07002276 ExpectDroppedFrame();
kthelgason2bc68642017-02-07 07:02:22 -08002277
sprangc5d62e22017-04-02 23:53:04 -07002278 EXPECT_LT(video_source_.sink_wants().max_pixel_count, last_pixel_count);
kthelgason2bc68642017-02-07 07:02:22 -08002279
mflodmancc3d4422017-08-03 08:27:51 -07002280 video_stream_encoder_->Stop();
kthelgason2bc68642017-02-07 07:02:22 -08002281}
2282
mflodmancc3d4422017-08-03 08:27:51 -07002283TEST_F(VideoStreamEncoderTest,
2284 NumberOfDroppedFramesLimitedWhenBitrateIsTooLow) {
asaperssonfab67072017-04-04 05:51:49 -07002285 const int kTooLowBitrateForFrameSizeBps = 10000;
mflodmancc3d4422017-08-03 08:27:51 -07002286 video_stream_encoder_->OnBitrateUpdated(kTooLowBitrateForFrameSizeBps, 0, 0);
asaperssonfab67072017-04-04 05:51:49 -07002287 const int kWidth = 640;
2288 const int kHeight = 360;
kthelgason2bc68642017-02-07 07:02:22 -08002289
2290 // We expect the n initial frames to get dropped.
2291 int i;
2292 for (i = 1; i <= kMaxInitialFramedrop; ++i) {
asaperssonfab67072017-04-04 05:51:49 -07002293 video_source_.IncomingCapturedFrame(CreateFrame(i, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002294 ExpectDroppedFrame();
kthelgason2bc68642017-02-07 07:02:22 -08002295 }
2296 // The n+1th frame should not be dropped, even though it's size is too large.
asaperssonfab67072017-04-04 05:51:49 -07002297 video_source_.IncomingCapturedFrame(CreateFrame(i, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002298 WaitForEncodedFrame(i);
kthelgason2bc68642017-02-07 07:02:22 -08002299
2300 // Expect the sink_wants to specify a scaled frame.
asaperssonfab67072017-04-04 05:51:49 -07002301 EXPECT_LT(video_source_.sink_wants().max_pixel_count, kWidth * kHeight);
kthelgason2bc68642017-02-07 07:02:22 -08002302
mflodmancc3d4422017-08-03 08:27:51 -07002303 video_stream_encoder_->Stop();
kthelgason2bc68642017-02-07 07:02:22 -08002304}
2305
mflodmancc3d4422017-08-03 08:27:51 -07002306TEST_F(VideoStreamEncoderTest,
2307 InitialFrameDropOffWithMaintainResolutionPreference) {
asaperssonfab67072017-04-04 05:51:49 -07002308 const int kWidth = 640;
2309 const int kHeight = 360;
mflodmancc3d4422017-08-03 08:27:51 -07002310 video_stream_encoder_->OnBitrateUpdated(kLowTargetBitrateBps, 0, 0);
kthelgason2bc68642017-02-07 07:02:22 -08002311
2312 // Set degradation preference.
mflodmancc3d4422017-08-03 08:27:51 -07002313 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002314 &video_source_, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
kthelgason2bc68642017-02-07 07:02:22 -08002315
asaperssonfab67072017-04-04 05:51:49 -07002316 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
kthelgason2bc68642017-02-07 07:02:22 -08002317 // Frame should not be dropped, even if it's too large.
sprang4847ae62017-06-27 07:06:52 -07002318 WaitForEncodedFrame(1);
kthelgason2bc68642017-02-07 07:02:22 -08002319
mflodmancc3d4422017-08-03 08:27:51 -07002320 video_stream_encoder_->Stop();
kthelgason2bc68642017-02-07 07:02:22 -08002321}
2322
mflodmancc3d4422017-08-03 08:27:51 -07002323TEST_F(VideoStreamEncoderTest, InitialFrameDropOffWhenEncoderDisabledScaling) {
asaperssonfab67072017-04-04 05:51:49 -07002324 const int kWidth = 640;
2325 const int kHeight = 360;
kthelgasonad9010c2017-02-14 00:46:51 -08002326 fake_encoder_.SetQualityScaling(false);
Niels Möller4db138e2018-04-19 09:04:13 +02002327
2328 VideoEncoderConfig video_encoder_config;
2329 test::FillEncoderConfiguration(kVideoCodecVP8, 1, &video_encoder_config);
2330 // Make format different, to force recreation of encoder.
2331 video_encoder_config.video_format.parameters["foo"] = "foo";
2332 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
Niels Möllerf1338562018-04-26 09:51:47 +02002333 kMaxPayloadLength);
mflodmancc3d4422017-08-03 08:27:51 -07002334 video_stream_encoder_->OnBitrateUpdated(kLowTargetBitrateBps, 0, 0);
asapersson09f05612017-05-15 23:40:18 -07002335
kthelgasonb83797b2017-02-14 11:57:25 -08002336 // Force quality scaler reconfiguration by resetting the source.
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002337 video_stream_encoder_->SetSource(&video_source_,
2338 webrtc::DegradationPreference::BALANCED);
kthelgasonad9010c2017-02-14 00:46:51 -08002339
asaperssonfab67072017-04-04 05:51:49 -07002340 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
kthelgasonad9010c2017-02-14 00:46:51 -08002341 // Frame should not be dropped, even if it's too large.
sprang4847ae62017-06-27 07:06:52 -07002342 WaitForEncodedFrame(1);
kthelgasonad9010c2017-02-14 00:46:51 -08002343
mflodmancc3d4422017-08-03 08:27:51 -07002344 video_stream_encoder_->Stop();
kthelgasonad9010c2017-02-14 00:46:51 -08002345 fake_encoder_.SetQualityScaling(true);
2346}
2347
mflodmancc3d4422017-08-03 08:27:51 -07002348TEST_F(VideoStreamEncoderTest,
asaperssond0de2952017-04-21 01:47:31 -07002349 ResolutionNotAdaptedForTooSmallFrame_MaintainFramerateMode) {
2350 const int kTooSmallWidth = 10;
2351 const int kTooSmallHeight = 10;
mflodmancc3d4422017-08-03 08:27:51 -07002352 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssond0de2952017-04-21 01:47:31 -07002353
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002354 // Enable MAINTAIN_FRAMERATE preference, no initial limitation.
asaperssond0de2952017-04-21 01:47:31 -07002355 test::FrameForwarder source;
mflodmancc3d4422017-08-03 08:27:51 -07002356 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002357 &source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
asaperssond0de2952017-04-21 01:47:31 -07002358 VerifyNoLimitation(source.sink_wants());
2359 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2360
2361 // Trigger adapt down, too small frame, expect no change.
2362 source.IncomingCapturedFrame(CreateFrame(1, kTooSmallWidth, kTooSmallHeight));
sprang4847ae62017-06-27 07:06:52 -07002363 WaitForEncodedFrame(1);
mflodmancc3d4422017-08-03 08:27:51 -07002364 video_stream_encoder_->TriggerCpuOveruse();
asaperssond0de2952017-04-21 01:47:31 -07002365 VerifyNoLimitation(source.sink_wants());
2366 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2367 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2368
mflodmancc3d4422017-08-03 08:27:51 -07002369 video_stream_encoder_->Stop();
asaperssond0de2952017-04-21 01:47:31 -07002370}
2371
mflodmancc3d4422017-08-03 08:27:51 -07002372TEST_F(VideoStreamEncoderTest,
2373 ResolutionNotAdaptedForTooSmallFrame_BalancedMode) {
asaperssonf7e294d2017-06-13 23:25:22 -07002374 const int kTooSmallWidth = 10;
2375 const int kTooSmallHeight = 10;
2376 const int kFpsLimit = 7;
mflodmancc3d4422017-08-03 08:27:51 -07002377 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -07002378
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002379 // Enable BALANCED preference, no initial limitation.
asaperssonf7e294d2017-06-13 23:25:22 -07002380 test::FrameForwarder source;
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002381 video_stream_encoder_->SetSource(&source,
2382 webrtc::DegradationPreference::BALANCED);
asaperssonf7e294d2017-06-13 23:25:22 -07002383 VerifyNoLimitation(source.sink_wants());
2384 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2385 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2386
2387 // Trigger adapt down, expect limited framerate.
2388 source.IncomingCapturedFrame(CreateFrame(1, kTooSmallWidth, kTooSmallHeight));
sprang4847ae62017-06-27 07:06:52 -07002389 WaitForEncodedFrame(1);
mflodmancc3d4422017-08-03 08:27:51 -07002390 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002391 VerifyFpsEqResolutionMax(source.sink_wants(), kFpsLimit);
2392 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2393 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2394 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2395
2396 // Trigger adapt down, too small frame, expect no change.
2397 source.IncomingCapturedFrame(CreateFrame(2, kTooSmallWidth, kTooSmallHeight));
sprang4847ae62017-06-27 07:06:52 -07002398 WaitForEncodedFrame(2);
mflodmancc3d4422017-08-03 08:27:51 -07002399 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002400 VerifyFpsEqResolutionMax(source.sink_wants(), kFpsLimit);
2401 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2402 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2403 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2404
mflodmancc3d4422017-08-03 08:27:51 -07002405 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07002406}
2407
mflodmancc3d4422017-08-03 08:27:51 -07002408TEST_F(VideoStreamEncoderTest, FailingInitEncodeDoesntCauseCrash) {
asapersson02465b82017-04-10 01:12:52 -07002409 fake_encoder_.ForceInitEncodeFailure(true);
mflodmancc3d4422017-08-03 08:27:51 -07002410 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
Niels Möllerf1338562018-04-26 09:51:47 +02002411 ResetEncoder("VP8", 2, 1, 1, false);
asapersson02465b82017-04-10 01:12:52 -07002412 const int kFrameWidth = 1280;
2413 const int kFrameHeight = 720;
2414 video_source_.IncomingCapturedFrame(
2415 CreateFrame(1, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002416 ExpectDroppedFrame();
mflodmancc3d4422017-08-03 08:27:51 -07002417 video_stream_encoder_->Stop();
asapersson02465b82017-04-10 01:12:52 -07002418}
2419
sprangb1ca0732017-02-01 08:38:12 -08002420// TODO(sprang): Extend this with fps throttling and any "balanced" extensions.
mflodmancc3d4422017-08-03 08:27:51 -07002421TEST_F(VideoStreamEncoderTest,
2422 AdaptsResolutionOnOveruse_MaintainFramerateMode) {
2423 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
sprangb1ca0732017-02-01 08:38:12 -08002424
2425 const int kFrameWidth = 1280;
2426 const int kFrameHeight = 720;
2427 // Enabled default VideoAdapter downscaling. First step is 3/4, not 3/5 as
mflodmancc3d4422017-08-03 08:27:51 -07002428 // requested by
2429 // VideoStreamEncoder::VideoSourceProxy::RequestResolutionLowerThan().
sprangb1ca0732017-02-01 08:38:12 -08002430 video_source_.set_adaptation_enabled(true);
2431
2432 video_source_.IncomingCapturedFrame(
2433 CreateFrame(1, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002434 WaitForEncodedFrame(kFrameWidth, kFrameHeight);
sprangb1ca0732017-02-01 08:38:12 -08002435
2436 // Trigger CPU overuse, downscale by 3/4.
mflodmancc3d4422017-08-03 08:27:51 -07002437 video_stream_encoder_->TriggerCpuOveruse();
sprangb1ca0732017-02-01 08:38:12 -08002438 video_source_.IncomingCapturedFrame(
2439 CreateFrame(2, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002440 WaitForEncodedFrame((kFrameWidth * 3) / 4, (kFrameHeight * 3) / 4);
sprangb1ca0732017-02-01 08:38:12 -08002441
asaperssonfab67072017-04-04 05:51:49 -07002442 // Trigger CPU normal use, return to original resolution.
mflodmancc3d4422017-08-03 08:27:51 -07002443 video_stream_encoder_->TriggerCpuNormalUsage();
sprangb1ca0732017-02-01 08:38:12 -08002444 video_source_.IncomingCapturedFrame(
2445 CreateFrame(3, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002446 WaitForEncodedFrame(kFrameWidth, kFrameHeight);
sprangb1ca0732017-02-01 08:38:12 -08002447
mflodmancc3d4422017-08-03 08:27:51 -07002448 video_stream_encoder_->Stop();
sprangb1ca0732017-02-01 08:38:12 -08002449}
sprangfe627f32017-03-29 08:24:59 -07002450
mflodmancc3d4422017-08-03 08:27:51 -07002451TEST_F(VideoStreamEncoderTest,
2452 AdaptsFramerateOnOveruse_MaintainResolutionMode) {
sprangc5d62e22017-04-02 23:53:04 -07002453 const int kFrameWidth = 1280;
2454 const int kFrameHeight = 720;
sprang4847ae62017-06-27 07:06:52 -07002455 int kFrameIntervalMs = rtc::kNumMillisecsPerSec / max_framerate_;
sprangc5d62e22017-04-02 23:53:04 -07002456
mflodmancc3d4422017-08-03 08:27:51 -07002457 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
2458 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002459 &video_source_, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
sprangc5d62e22017-04-02 23:53:04 -07002460 video_source_.set_adaptation_enabled(true);
2461
sprang4847ae62017-06-27 07:06:52 -07002462 int64_t timestamp_ms = fake_clock_.TimeNanos() / rtc::kNumNanosecsPerMillisec;
sprangc5d62e22017-04-02 23:53:04 -07002463
2464 video_source_.IncomingCapturedFrame(
2465 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002466 WaitForEncodedFrame(timestamp_ms);
sprangc5d62e22017-04-02 23:53:04 -07002467
2468 // Try to trigger overuse. No fps estimate available => no effect.
mflodmancc3d4422017-08-03 08:27:51 -07002469 video_stream_encoder_->TriggerCpuOveruse();
sprangc5d62e22017-04-02 23:53:04 -07002470
2471 // Insert frames for one second to get a stable estimate.
sprang4847ae62017-06-27 07:06:52 -07002472 for (int i = 0; i < max_framerate_; ++i) {
sprangc5d62e22017-04-02 23:53:04 -07002473 timestamp_ms += kFrameIntervalMs;
sprangc5d62e22017-04-02 23:53:04 -07002474 video_source_.IncomingCapturedFrame(
2475 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002476 WaitForEncodedFrame(timestamp_ms);
sprangc5d62e22017-04-02 23:53:04 -07002477 }
2478
2479 // Trigger CPU overuse, reduce framerate by 2/3.
mflodmancc3d4422017-08-03 08:27:51 -07002480 video_stream_encoder_->TriggerCpuOveruse();
sprangc5d62e22017-04-02 23:53:04 -07002481 int num_frames_dropped = 0;
sprang4847ae62017-06-27 07:06:52 -07002482 for (int i = 0; i < max_framerate_; ++i) {
sprangc5d62e22017-04-02 23:53:04 -07002483 timestamp_ms += kFrameIntervalMs;
sprangc5d62e22017-04-02 23:53:04 -07002484 video_source_.IncomingCapturedFrame(
2485 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002486 if (!WaitForFrame(kFrameTimeoutMs)) {
sprangc5d62e22017-04-02 23:53:04 -07002487 ++num_frames_dropped;
2488 } else {
Åsa Perssonc74d8da2017-12-04 14:13:56 +01002489 sink_.CheckLastFrameSizeMatches(kFrameWidth, kFrameHeight);
sprangc5d62e22017-04-02 23:53:04 -07002490 }
2491 }
2492
sprang4847ae62017-06-27 07:06:52 -07002493 // Add some slack to account for frames dropped by the frame dropper.
2494 const int kErrorMargin = 1;
2495 EXPECT_NEAR(num_frames_dropped, max_framerate_ - (max_framerate_ * 2 / 3),
sprangc5d62e22017-04-02 23:53:04 -07002496 kErrorMargin);
2497
2498 // Trigger CPU overuse, reduce framerate by 2/3 again.
mflodmancc3d4422017-08-03 08:27:51 -07002499 video_stream_encoder_->TriggerCpuOveruse();
sprangc5d62e22017-04-02 23:53:04 -07002500 num_frames_dropped = 0;
sprang4847ae62017-06-27 07:06:52 -07002501 for (int i = 0; i < max_framerate_; ++i) {
sprangc5d62e22017-04-02 23:53:04 -07002502 timestamp_ms += kFrameIntervalMs;
sprangc5d62e22017-04-02 23:53:04 -07002503 video_source_.IncomingCapturedFrame(
2504 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002505 if (!WaitForFrame(kFrameTimeoutMs)) {
sprangc5d62e22017-04-02 23:53:04 -07002506 ++num_frames_dropped;
2507 } else {
Åsa Perssonc74d8da2017-12-04 14:13:56 +01002508 sink_.CheckLastFrameSizeMatches(kFrameWidth, kFrameHeight);
sprangc5d62e22017-04-02 23:53:04 -07002509 }
2510 }
sprang4847ae62017-06-27 07:06:52 -07002511 EXPECT_NEAR(num_frames_dropped, max_framerate_ - (max_framerate_ * 4 / 9),
sprangc5d62e22017-04-02 23:53:04 -07002512 kErrorMargin);
2513
2514 // Go back up one step.
mflodmancc3d4422017-08-03 08:27:51 -07002515 video_stream_encoder_->TriggerCpuNormalUsage();
sprangc5d62e22017-04-02 23:53:04 -07002516 num_frames_dropped = 0;
sprang4847ae62017-06-27 07:06:52 -07002517 for (int i = 0; i < max_framerate_; ++i) {
sprangc5d62e22017-04-02 23:53:04 -07002518 timestamp_ms += kFrameIntervalMs;
sprangc5d62e22017-04-02 23:53:04 -07002519 video_source_.IncomingCapturedFrame(
2520 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002521 if (!WaitForFrame(kFrameTimeoutMs)) {
sprangc5d62e22017-04-02 23:53:04 -07002522 ++num_frames_dropped;
2523 } else {
Åsa Perssonc74d8da2017-12-04 14:13:56 +01002524 sink_.CheckLastFrameSizeMatches(kFrameWidth, kFrameHeight);
sprangc5d62e22017-04-02 23:53:04 -07002525 }
2526 }
sprang4847ae62017-06-27 07:06:52 -07002527 EXPECT_NEAR(num_frames_dropped, max_framerate_ - (max_framerate_ * 2 / 3),
sprangc5d62e22017-04-02 23:53:04 -07002528 kErrorMargin);
2529
2530 // Go back up to original mode.
mflodmancc3d4422017-08-03 08:27:51 -07002531 video_stream_encoder_->TriggerCpuNormalUsage();
sprangc5d62e22017-04-02 23:53:04 -07002532 num_frames_dropped = 0;
sprang4847ae62017-06-27 07:06:52 -07002533 for (int i = 0; i < max_framerate_; ++i) {
sprangc5d62e22017-04-02 23:53:04 -07002534 timestamp_ms += kFrameIntervalMs;
sprangc5d62e22017-04-02 23:53:04 -07002535 video_source_.IncomingCapturedFrame(
2536 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002537 if (!WaitForFrame(kFrameTimeoutMs)) {
sprangc5d62e22017-04-02 23:53:04 -07002538 ++num_frames_dropped;
2539 } else {
Åsa Perssonc74d8da2017-12-04 14:13:56 +01002540 sink_.CheckLastFrameSizeMatches(kFrameWidth, kFrameHeight);
sprangc5d62e22017-04-02 23:53:04 -07002541 }
2542 }
2543 EXPECT_NEAR(num_frames_dropped, 0, kErrorMargin);
2544
mflodmancc3d4422017-08-03 08:27:51 -07002545 video_stream_encoder_->Stop();
sprangc5d62e22017-04-02 23:53:04 -07002546}
2547
mflodmancc3d4422017-08-03 08:27:51 -07002548TEST_F(VideoStreamEncoderTest, DoesntAdaptDownPastMinFramerate) {
sprangc5d62e22017-04-02 23:53:04 -07002549 const int kFramerateFps = 5;
2550 const int kFrameIntervalMs = rtc::kNumMillisecsPerSec / kFramerateFps;
sprangc5d62e22017-04-02 23:53:04 -07002551 const int kFrameWidth = 1280;
2552 const int kFrameHeight = 720;
2553
sprang4847ae62017-06-27 07:06:52 -07002554 // Reconfigure encoder with two temporal layers and screensharing, which will
2555 // disable frame dropping and make testing easier.
Niels Möllerf1338562018-04-26 09:51:47 +02002556 ResetEncoder("VP8", 1, 2, 1, true);
sprang4847ae62017-06-27 07:06:52 -07002557
mflodmancc3d4422017-08-03 08:27:51 -07002558 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
2559 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002560 &video_source_, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
sprangc5d62e22017-04-02 23:53:04 -07002561 video_source_.set_adaptation_enabled(true);
2562
sprang4847ae62017-06-27 07:06:52 -07002563 int64_t timestamp_ms = fake_clock_.TimeNanos() / rtc::kNumNanosecsPerMillisec;
sprangc5d62e22017-04-02 23:53:04 -07002564
2565 // Trigger overuse as much as we can.
Jonathan Yubc771b72017-12-08 17:04:29 -08002566 rtc::VideoSinkWants last_wants;
2567 do {
2568 last_wants = video_source_.sink_wants();
2569
sprangc5d62e22017-04-02 23:53:04 -07002570 // Insert frames to get a new fps estimate...
2571 for (int j = 0; j < kFramerateFps; ++j) {
2572 video_source_.IncomingCapturedFrame(
2573 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
Jonathan Yubc771b72017-12-08 17:04:29 -08002574 if (video_source_.last_sent_width()) {
2575 sink_.WaitForEncodedFrame(timestamp_ms);
2576 }
sprangc5d62e22017-04-02 23:53:04 -07002577 timestamp_ms += kFrameIntervalMs;
Jonathan Yubc771b72017-12-08 17:04:29 -08002578 fake_clock_.AdvanceTimeMicros(
2579 kFrameIntervalMs * rtc::kNumMicrosecsPerMillisec);
sprangc5d62e22017-04-02 23:53:04 -07002580 }
2581 // ...and then try to adapt again.
mflodmancc3d4422017-08-03 08:27:51 -07002582 video_stream_encoder_->TriggerCpuOveruse();
Jonathan Yubc771b72017-12-08 17:04:29 -08002583 } while (video_source_.sink_wants().max_framerate_fps <
2584 last_wants.max_framerate_fps);
sprangc5d62e22017-04-02 23:53:04 -07002585
Jonathan Yubc771b72017-12-08 17:04:29 -08002586 VerifyFpsEqResolutionMax(video_source_.sink_wants(), kMinFramerateFps);
asaperssonf7e294d2017-06-13 23:25:22 -07002587
mflodmancc3d4422017-08-03 08:27:51 -07002588 video_stream_encoder_->Stop();
sprangc5d62e22017-04-02 23:53:04 -07002589}
asaperssonf7e294d2017-06-13 23:25:22 -07002590
mflodmancc3d4422017-08-03 08:27:51 -07002591TEST_F(VideoStreamEncoderTest,
2592 AdaptsResolutionAndFramerateForLowQuality_BalancedMode) {
asaperssonf7e294d2017-06-13 23:25:22 -07002593 const int kWidth = 1280;
2594 const int kHeight = 720;
2595 const int64_t kFrameIntervalMs = 150;
2596 int64_t timestamp_ms = kFrameIntervalMs;
mflodmancc3d4422017-08-03 08:27:51 -07002597 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -07002598
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002599 // Enable BALANCED preference, no initial limitation.
asaperssonf7e294d2017-06-13 23:25:22 -07002600 AdaptingFrameForwarder source;
2601 source.set_adaptation_enabled(true);
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002602 video_stream_encoder_->SetSource(&source,
2603 webrtc::DegradationPreference::BALANCED);
asaperssonf7e294d2017-06-13 23:25:22 -07002604 timestamp_ms += kFrameIntervalMs;
2605 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002606 WaitForEncodedFrame(kWidth, kHeight);
asaperssonf7e294d2017-06-13 23:25:22 -07002607 VerifyNoLimitation(source.sink_wants());
2608 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2609 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2610 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2611
2612 // Trigger adapt down, expect scaled down resolution (960x540@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002613 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002614 timestamp_ms += kFrameIntervalMs;
2615 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002616 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002617 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
2618 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2619 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2620 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2621
2622 // Trigger adapt down, expect scaled down resolution (640x360@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002623 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002624 timestamp_ms += kFrameIntervalMs;
2625 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002626 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002627 VerifyFpsMaxResolutionLt(source.sink_wants(), source.last_wants());
2628 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2629 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2630 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2631
2632 // Trigger adapt down, expect reduced fps (640x360@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07002633 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002634 timestamp_ms += kFrameIntervalMs;
2635 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002636 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002637 VerifyFpsLtResolutionEq(source.sink_wants(), source.last_wants());
2638 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2639 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2640 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2641
2642 // Trigger adapt down, expect scaled down resolution (480x270@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07002643 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002644 timestamp_ms += kFrameIntervalMs;
2645 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002646 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002647 VerifyFpsEqResolutionLt(source.sink_wants(), source.last_wants());
2648 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2649 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2650 EXPECT_EQ(4, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2651
2652 // Restrict bitrate, trigger adapt down, expect reduced fps (480x270@10fps).
mflodmancc3d4422017-08-03 08:27:51 -07002653 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002654 timestamp_ms += kFrameIntervalMs;
2655 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002656 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002657 VerifyFpsLtResolutionEq(source.sink_wants(), source.last_wants());
2658 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2659 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2660 EXPECT_EQ(5, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2661
2662 // Trigger adapt down, expect scaled down resolution (320x180@10fps).
mflodmancc3d4422017-08-03 08:27:51 -07002663 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002664 timestamp_ms += kFrameIntervalMs;
2665 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002666 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002667 VerifyFpsEqResolutionLt(source.sink_wants(), source.last_wants());
2668 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2669 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2670 EXPECT_EQ(6, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2671
2672 // Trigger adapt down, expect reduced fps (320x180@7fps).
mflodmancc3d4422017-08-03 08:27:51 -07002673 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002674 timestamp_ms += kFrameIntervalMs;
2675 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002676 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002677 VerifyFpsLtResolutionEq(source.sink_wants(), source.last_wants());
2678 rtc::VideoSinkWants last_wants = source.sink_wants();
2679 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2680 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2681 EXPECT_EQ(7, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2682
2683 // Trigger adapt down, min resolution reached, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07002684 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002685 timestamp_ms += kFrameIntervalMs;
2686 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002687 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002688 VerifyFpsEqResolutionEq(source.sink_wants(), last_wants);
2689 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2690 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2691 EXPECT_EQ(7, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2692
2693 // Trigger adapt down, expect expect increased fps (320x180@10fps).
mflodmancc3d4422017-08-03 08:27:51 -07002694 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002695 timestamp_ms += kFrameIntervalMs;
2696 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002697 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002698 VerifyFpsGtResolutionEq(source.sink_wants(), source.last_wants());
2699 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2700 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2701 EXPECT_EQ(8, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2702
2703 // Trigger adapt up, expect upscaled resolution (480x270@10fps).
mflodmancc3d4422017-08-03 08:27:51 -07002704 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002705 timestamp_ms += kFrameIntervalMs;
2706 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002707 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002708 VerifyFpsEqResolutionGt(source.sink_wants(), source.last_wants());
2709 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2710 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2711 EXPECT_EQ(9, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2712
2713 // Increase bitrate, trigger adapt up, expect increased fps (480x270@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07002714 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002715 timestamp_ms += kFrameIntervalMs;
2716 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002717 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002718 VerifyFpsGtResolutionEq(source.sink_wants(), source.last_wants());
2719 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2720 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2721 EXPECT_EQ(10, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2722
2723 // Trigger adapt up, expect upscaled resolution (640x360@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07002724 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002725 timestamp_ms += kFrameIntervalMs;
2726 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002727 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002728 VerifyFpsEqResolutionGt(source.sink_wants(), source.last_wants());
2729 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2730 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2731 EXPECT_EQ(11, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2732
2733 // Trigger adapt up, expect increased fps (640x360@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002734 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002735 timestamp_ms += kFrameIntervalMs;
2736 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002737 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002738 VerifyFpsMaxResolutionEq(source.sink_wants(), source.last_wants());
2739 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2740 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2741 EXPECT_EQ(12, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2742
2743 // Trigger adapt up, expect upscaled resolution (960x540@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002744 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002745 timestamp_ms += kFrameIntervalMs;
2746 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002747 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002748 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
2749 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2750 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2751 EXPECT_EQ(13, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2752
2753 // Trigger adapt up, expect no restriction (1280x720fps@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002754 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002755 timestamp_ms += kFrameIntervalMs;
2756 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002757 WaitForEncodedFrame(kWidth, kHeight);
asaperssonf7e294d2017-06-13 23:25:22 -07002758 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
2759 VerifyNoLimitation(source.sink_wants());
2760 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2761 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2762 EXPECT_EQ(14, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2763
2764 // Trigger adapt up, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07002765 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002766 VerifyNoLimitation(source.sink_wants());
2767 EXPECT_EQ(14, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2768
mflodmancc3d4422017-08-03 08:27:51 -07002769 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07002770}
2771
mflodmancc3d4422017-08-03 08:27:51 -07002772TEST_F(VideoStreamEncoderTest, AdaptWithTwoReasonsAndDifferentOrder_Framerate) {
asaperssonf7e294d2017-06-13 23:25:22 -07002773 const int kWidth = 1280;
2774 const int kHeight = 720;
2775 const int64_t kFrameIntervalMs = 150;
2776 int64_t timestamp_ms = kFrameIntervalMs;
mflodmancc3d4422017-08-03 08:27:51 -07002777 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -07002778
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002779 // Enable BALANCED preference, no initial limitation.
asaperssonf7e294d2017-06-13 23:25:22 -07002780 AdaptingFrameForwarder source;
2781 source.set_adaptation_enabled(true);
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002782 video_stream_encoder_->SetSource(&source,
2783 webrtc::DegradationPreference::BALANCED);
asaperssonf7e294d2017-06-13 23:25:22 -07002784 timestamp_ms += kFrameIntervalMs;
2785 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002786 WaitForEncodedFrame(kWidth, kHeight);
asaperssonf7e294d2017-06-13 23:25:22 -07002787 VerifyNoLimitation(source.sink_wants());
2788 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2789 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2790 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2791 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
2792 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2793 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2794
2795 // Trigger cpu adapt down, expect scaled down resolution (960x540@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002796 video_stream_encoder_->TriggerCpuOveruse();
asaperssonf7e294d2017-06-13 23:25:22 -07002797 timestamp_ms += kFrameIntervalMs;
2798 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002799 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002800 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
2801 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2802 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2803 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2804 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
2805 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2806 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2807
2808 // Trigger cpu adapt down, expect scaled down resolution (640x360@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002809 video_stream_encoder_->TriggerCpuOveruse();
asaperssonf7e294d2017-06-13 23:25:22 -07002810 timestamp_ms += kFrameIntervalMs;
2811 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002812 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002813 VerifyFpsMaxResolutionLt(source.sink_wants(), source.last_wants());
2814 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2815 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2816 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2817 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
2818 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2819 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2820
2821 // Trigger quality adapt down, expect reduced fps (640x360@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07002822 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002823 timestamp_ms += kFrameIntervalMs;
2824 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002825 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002826 VerifyFpsLtResolutionEq(source.sink_wants(), source.last_wants());
2827 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2828 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2829 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2830 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
2831 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2832 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2833
2834 // Trigger cpu adapt up, expect increased fps (640x360@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002835 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssonf7e294d2017-06-13 23:25:22 -07002836 timestamp_ms += kFrameIntervalMs;
2837 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002838 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002839 VerifyFpsMaxResolutionEq(source.sink_wants(), source.last_wants());
2840 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2841 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2842 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2843 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
2844 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2845 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2846
2847 // Trigger quality adapt up, expect upscaled resolution (960x540@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002848 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002849 timestamp_ms += kFrameIntervalMs;
2850 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002851 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002852 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
2853 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2854 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2855 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2856 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
2857 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2858 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2859
2860 // Trigger cpu adapt up, expect no restriction (1280x720fps@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002861 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssonf7e294d2017-06-13 23:25:22 -07002862 timestamp_ms += kFrameIntervalMs;
2863 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002864 WaitForEncodedFrame(kWidth, kHeight);
asaperssonf7e294d2017-06-13 23:25:22 -07002865 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
2866 VerifyNoLimitation(source.sink_wants());
2867 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2868 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2869 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2870 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
2871 EXPECT_EQ(4, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2872 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2873
2874 // Trigger adapt up, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07002875 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002876 VerifyNoLimitation(source.sink_wants());
2877 EXPECT_EQ(4, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2878 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2879
mflodmancc3d4422017-08-03 08:27:51 -07002880 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07002881}
2882
mflodmancc3d4422017-08-03 08:27:51 -07002883TEST_F(VideoStreamEncoderTest,
2884 AdaptWithTwoReasonsAndDifferentOrder_Resolution) {
asaperssonf7e294d2017-06-13 23:25:22 -07002885 const int kWidth = 640;
2886 const int kHeight = 360;
2887 const int kFpsLimit = 15;
2888 const int64_t kFrameIntervalMs = 150;
2889 int64_t timestamp_ms = kFrameIntervalMs;
mflodmancc3d4422017-08-03 08:27:51 -07002890 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -07002891
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002892 // Enable BALANCED preference, no initial limitation.
asaperssonf7e294d2017-06-13 23:25:22 -07002893 AdaptingFrameForwarder source;
2894 source.set_adaptation_enabled(true);
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002895 video_stream_encoder_->SetSource(&source,
2896 webrtc::DegradationPreference::BALANCED);
asaperssonf7e294d2017-06-13 23:25:22 -07002897 timestamp_ms += kFrameIntervalMs;
2898 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002899 WaitForEncodedFrame(kWidth, kHeight);
asaperssonf7e294d2017-06-13 23:25:22 -07002900 VerifyNoLimitation(source.sink_wants());
2901 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2902 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2903 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2904 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
2905 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2906 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2907
2908 // Trigger cpu adapt down, expect scaled down framerate (640x360@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07002909 video_stream_encoder_->TriggerCpuOveruse();
asaperssonf7e294d2017-06-13 23:25:22 -07002910 timestamp_ms += kFrameIntervalMs;
2911 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002912 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002913 VerifyFpsEqResolutionMax(source.sink_wants(), kFpsLimit);
2914 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2915 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2916 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2917 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_framerate);
2918 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2919 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2920
2921 // Trigger quality adapt down, expect scaled down resolution (480x270@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07002922 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002923 timestamp_ms += kFrameIntervalMs;
2924 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002925 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002926 VerifyFpsEqResolutionLt(source.sink_wants(), source.last_wants());
2927 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2928 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2929 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2930 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_framerate);
2931 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2932 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2933
2934 // Trigger cpu adapt up, expect upscaled resolution (640x360@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07002935 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssonf7e294d2017-06-13 23:25:22 -07002936 timestamp_ms += kFrameIntervalMs;
2937 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002938 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002939 VerifyFpsEqResolutionGt(source.sink_wants(), source.last_wants());
2940 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2941 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2942 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2943 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
2944 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2945 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2946
2947 // Trigger quality adapt up, expect increased fps (640x360@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002948 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002949 timestamp_ms += kFrameIntervalMs;
2950 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002951 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002952 VerifyNoLimitation(source.sink_wants());
2953 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2954 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2955 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2956 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
2957 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2958 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2959
2960 // Trigger adapt up, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07002961 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002962 VerifyNoLimitation(source.sink_wants());
2963 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2964 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2965
mflodmancc3d4422017-08-03 08:27:51 -07002966 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07002967}
2968
mflodmancc3d4422017-08-03 08:27:51 -07002969TEST_F(VideoStreamEncoderTest, AcceptsFullHdAdaptedDownSimulcastFrames) {
ilnik6b826ef2017-06-16 06:53:48 -07002970 // Simulates simulcast behavior and makes highest stream resolutions divisible
2971 // by 4.
2972 class CroppingVideoStreamFactory
2973 : public VideoEncoderConfig::VideoStreamFactoryInterface {
2974 public:
2975 explicit CroppingVideoStreamFactory(size_t num_temporal_layers,
2976 int framerate)
2977 : num_temporal_layers_(num_temporal_layers), framerate_(framerate) {
2978 EXPECT_GT(num_temporal_layers, 0u);
2979 EXPECT_GT(framerate, 0);
2980 }
2981
2982 private:
2983 std::vector<VideoStream> CreateEncoderStreams(
2984 int width,
2985 int height,
2986 const VideoEncoderConfig& encoder_config) override {
2987 std::vector<VideoStream> streams =
2988 test::CreateVideoStreams(width - width % 4, height - height % 4,
2989 encoder_config);
2990 for (VideoStream& stream : streams) {
Sergey Silkina796a7e2018-03-01 15:11:29 +01002991 stream.num_temporal_layers = num_temporal_layers_;
ilnik6b826ef2017-06-16 06:53:48 -07002992 stream.max_framerate = framerate_;
2993 }
2994 return streams;
2995 }
2996
2997 const size_t num_temporal_layers_;
2998 const int framerate_;
2999 };
3000
3001 const int kFrameWidth = 1920;
3002 const int kFrameHeight = 1080;
3003 // 3/4 of 1920.
3004 const int kAdaptedFrameWidth = 1440;
3005 // 3/4 of 1080 rounded down to multiple of 4.
3006 const int kAdaptedFrameHeight = 808;
3007 const int kFramerate = 24;
3008
mflodmancc3d4422017-08-03 08:27:51 -07003009 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
ilnik6b826ef2017-06-16 06:53:48 -07003010 // Trigger reconfigure encoder (without resetting the entire instance).
3011 VideoEncoderConfig video_encoder_config;
Niels Möller259a4972018-04-05 15:36:51 +02003012 video_encoder_config.codec_type = kVideoCodecVP8;
ilnik6b826ef2017-06-16 06:53:48 -07003013 video_encoder_config.max_bitrate_bps = kTargetBitrateBps;
3014 video_encoder_config.number_of_streams = 1;
3015 video_encoder_config.video_stream_factory =
3016 new rtc::RefCountedObject<CroppingVideoStreamFactory>(1, kFramerate);
mflodmancc3d4422017-08-03 08:27:51 -07003017 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
Niels Möllerf1338562018-04-26 09:51:47 +02003018 kMaxPayloadLength);
mflodmancc3d4422017-08-03 08:27:51 -07003019 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
ilnik6b826ef2017-06-16 06:53:48 -07003020
3021 video_source_.set_adaptation_enabled(true);
3022
3023 video_source_.IncomingCapturedFrame(
3024 CreateFrame(1, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07003025 WaitForEncodedFrame(kFrameWidth, kFrameHeight);
ilnik6b826ef2017-06-16 06:53:48 -07003026
3027 // Trigger CPU overuse, downscale by 3/4.
mflodmancc3d4422017-08-03 08:27:51 -07003028 video_stream_encoder_->TriggerCpuOveruse();
ilnik6b826ef2017-06-16 06:53:48 -07003029 video_source_.IncomingCapturedFrame(
3030 CreateFrame(2, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07003031 WaitForEncodedFrame(kAdaptedFrameWidth, kAdaptedFrameHeight);
ilnik6b826ef2017-06-16 06:53:48 -07003032
mflodmancc3d4422017-08-03 08:27:51 -07003033 video_stream_encoder_->Stop();
ilnik6b826ef2017-06-16 06:53:48 -07003034}
3035
mflodmancc3d4422017-08-03 08:27:51 -07003036TEST_F(VideoStreamEncoderTest, PeriodicallyUpdatesChannelParameters) {
sprang4847ae62017-06-27 07:06:52 -07003037 const int kFrameWidth = 1280;
3038 const int kFrameHeight = 720;
3039 const int kLowFps = 2;
3040 const int kHighFps = 30;
3041
mflodmancc3d4422017-08-03 08:27:51 -07003042 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
sprang4847ae62017-06-27 07:06:52 -07003043
3044 int64_t timestamp_ms = fake_clock_.TimeNanos() / rtc::kNumNanosecsPerMillisec;
3045 max_framerate_ = kLowFps;
3046
3047 // Insert 2 seconds of 2fps video.
3048 for (int i = 0; i < kLowFps * 2; ++i) {
3049 video_source_.IncomingCapturedFrame(
3050 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
3051 WaitForEncodedFrame(timestamp_ms);
3052 timestamp_ms += 1000 / kLowFps;
3053 }
3054
3055 // Make sure encoder is updated with new target.
mflodmancc3d4422017-08-03 08:27:51 -07003056 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
sprang4847ae62017-06-27 07:06:52 -07003057 video_source_.IncomingCapturedFrame(
3058 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
3059 WaitForEncodedFrame(timestamp_ms);
3060 timestamp_ms += 1000 / kLowFps;
3061
3062 EXPECT_EQ(kLowFps, fake_encoder_.GetConfiguredInputFramerate());
3063
3064 // Insert 30fps frames for just a little more than the forced update period.
3065 const int kVcmTimerIntervalFrames =
3066 (vcm::VCMProcessTimer::kDefaultProcessIntervalMs * kHighFps) / 1000;
3067 const int kFrameIntervalMs = 1000 / kHighFps;
3068 max_framerate_ = kHighFps;
3069 for (int i = 0; i < kVcmTimerIntervalFrames + 2; ++i) {
3070 video_source_.IncomingCapturedFrame(
3071 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
3072 // Wait for encoded frame, but skip ahead if it doesn't arrive as it might
3073 // be dropped if the encoder hans't been updated with the new higher target
3074 // framerate yet, causing it to overshoot the target bitrate and then
3075 // suffering the wrath of the media optimizer.
3076 TimedWaitForEncodedFrame(timestamp_ms, 2 * kFrameIntervalMs);
3077 timestamp_ms += kFrameIntervalMs;
3078 }
3079
3080 // Don expect correct measurement just yet, but it should be higher than
3081 // before.
3082 EXPECT_GT(fake_encoder_.GetConfiguredInputFramerate(), kLowFps);
3083
mflodmancc3d4422017-08-03 08:27:51 -07003084 video_stream_encoder_->Stop();
sprang4847ae62017-06-27 07:06:52 -07003085}
3086
mflodmancc3d4422017-08-03 08:27:51 -07003087TEST_F(VideoStreamEncoderTest, DoesNotUpdateBitrateAllocationWhenSuspended) {
sprang4847ae62017-06-27 07:06:52 -07003088 const int kFrameWidth = 1280;
3089 const int kFrameHeight = 720;
3090 const int kTargetBitrateBps = 1000000;
3091
3092 MockBitrateObserver bitrate_observer;
mflodmancc3d4422017-08-03 08:27:51 -07003093 video_stream_encoder_->SetBitrateObserver(&bitrate_observer);
sprang4847ae62017-06-27 07:06:52 -07003094
3095 EXPECT_CALL(bitrate_observer, OnBitrateAllocationUpdated(_)).Times(1);
3096 // Initial bitrate update.
mflodmancc3d4422017-08-03 08:27:51 -07003097 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
3098 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
sprang4847ae62017-06-27 07:06:52 -07003099
3100 // Insert a first video frame, causes another bitrate update.
3101 int64_t timestamp_ms = fake_clock_.TimeNanos() / rtc::kNumNanosecsPerMillisec;
3102 EXPECT_CALL(bitrate_observer, OnBitrateAllocationUpdated(_)).Times(1);
3103 video_source_.IncomingCapturedFrame(
3104 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
3105 WaitForEncodedFrame(timestamp_ms);
3106
3107 // Next, simulate video suspension due to pacer queue overrun.
mflodmancc3d4422017-08-03 08:27:51 -07003108 video_stream_encoder_->OnBitrateUpdated(0, 0, 1);
sprang4847ae62017-06-27 07:06:52 -07003109
3110 // Skip ahead until a new periodic parameter update should have occured.
3111 timestamp_ms += vcm::VCMProcessTimer::kDefaultProcessIntervalMs;
3112 fake_clock_.AdvanceTimeMicros(
3113 vcm::VCMProcessTimer::kDefaultProcessIntervalMs *
3114 rtc::kNumMicrosecsPerMillisec);
3115
3116 // Bitrate observer should not be called.
3117 EXPECT_CALL(bitrate_observer, OnBitrateAllocationUpdated(_)).Times(0);
3118 video_source_.IncomingCapturedFrame(
3119 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
3120 ExpectDroppedFrame();
3121
mflodmancc3d4422017-08-03 08:27:51 -07003122 video_stream_encoder_->Stop();
sprang4847ae62017-06-27 07:06:52 -07003123}
ilnik6b826ef2017-06-16 06:53:48 -07003124
Niels Möller4db138e2018-04-19 09:04:13 +02003125TEST_F(VideoStreamEncoderTest,
3126 DefaultCpuAdaptationThresholdsForSoftwareEncoder) {
3127 const int kFrameWidth = 1280;
3128 const int kFrameHeight = 720;
3129 const CpuOveruseOptions default_options;
3130 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
3131 video_source_.IncomingCapturedFrame(
3132 CreateFrame(1, kFrameWidth, kFrameHeight));
3133 WaitForEncodedFrame(1);
3134 EXPECT_EQ(video_stream_encoder_->overuse_detector_proxy_->GetOptions()
3135 .low_encode_usage_threshold_percent,
3136 default_options.low_encode_usage_threshold_percent);
3137 EXPECT_EQ(video_stream_encoder_->overuse_detector_proxy_->GetOptions()
3138 .high_encode_usage_threshold_percent,
3139 default_options.high_encode_usage_threshold_percent);
3140 video_stream_encoder_->Stop();
3141}
3142
3143TEST_F(VideoStreamEncoderTest,
3144 HigherCpuAdaptationThresholdsForHardwareEncoder) {
3145 const int kFrameWidth = 1280;
3146 const int kFrameHeight = 720;
3147 CpuOveruseOptions hardware_options;
3148 hardware_options.low_encode_usage_threshold_percent = 150;
3149 hardware_options.high_encode_usage_threshold_percent = 200;
3150 encoder_factory_.SetIsHardwareAccelerated(true);
3151
3152 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
3153 video_source_.IncomingCapturedFrame(
3154 CreateFrame(1, kFrameWidth, kFrameHeight));
3155 WaitForEncodedFrame(1);
3156 EXPECT_EQ(video_stream_encoder_->overuse_detector_proxy_->GetOptions()
3157 .low_encode_usage_threshold_percent,
3158 hardware_options.low_encode_usage_threshold_percent);
3159 EXPECT_EQ(video_stream_encoder_->overuse_detector_proxy_->GetOptions()
3160 .high_encode_usage_threshold_percent,
3161 hardware_options.high_encode_usage_threshold_percent);
3162 video_stream_encoder_->Stop();
3163}
3164
perkj26091b12016-09-01 01:17:40 -07003165} // namespace webrtc