blob: 32053abf54bcc049dbbb8cbf289a3823f311f41b [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"
Stefan Holmerdbdb3a02018-07-17 16:03:46 +020022#include "rtc_base/refcountedobject.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020023#include "system_wrappers/include/metrics_default.h"
24#include "system_wrappers/include/sleep.h"
Niels Möller4db138e2018-04-19 09:04:13 +020025#include "test/encoder_proxy_factory.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020026#include "test/encoder_settings.h"
27#include "test/fake_encoder.h"
28#include "test/frame_generator.h"
29#include "test/gmock.h"
30#include "test/gtest.h"
31#include "video/send_statistics_proxy.h"
32#include "video/video_stream_encoder.h"
perkj26091b12016-09-01 01:17:40 -070033
Mirko Bonadei948b7e32018-08-14 07:23:21 +000034namespace {
35const int kMinPixelsPerFrame = 320 * 180;
36const int kMinFramerateFps = 2;
37const int kMinBalancedFramerateFps = 7;
38const int64_t kFrameTimeoutMs = 100;
39} // namespace
40
perkj26091b12016-09-01 01:17:40 -070041namespace webrtc {
42
sprangb1ca0732017-02-01 08:38:12 -080043using ScaleReason = AdaptationObserverInterface::AdaptReason;
sprang57c2fff2017-01-16 06:24:02 -080044using ::testing::_;
45using ::testing::Return;
kthelgason876222f2016-11-29 01:44:11 -080046
perkj803d97f2016-11-01 11:45:46 -070047namespace {
asapersson5f7226f2016-11-25 04:37:00 -080048const size_t kMaxPayloadLength = 1440;
kthelgason2bc68642017-02-07 07:02:22 -080049const int kTargetBitrateBps = 1000000;
50const int kLowTargetBitrateBps = kTargetBitrateBps / 10;
51const int kMaxInitialFramedrop = 4;
sprangfda496a2017-06-15 04:21:07 -070052const int kDefaultFramerate = 30;
asapersson5f7226f2016-11-25 04:37:00 -080053
perkj803d97f2016-11-01 11:45:46 -070054class TestBuffer : public webrtc::I420Buffer {
55 public:
56 TestBuffer(rtc::Event* event, int width, int height)
57 : I420Buffer(width, height), event_(event) {}
58
59 private:
60 friend class rtc::RefCountedObject<TestBuffer>;
61 ~TestBuffer() override {
62 if (event_)
63 event_->Set();
64 }
65 rtc::Event* const event_;
66};
67
Niels Möller7dc26b72017-12-06 10:27:48 +010068class CpuOveruseDetectorProxy : public OveruseFrameDetector {
69 public:
Niels Möllerd1f7eb62018-03-28 16:40:58 +020070 explicit CpuOveruseDetectorProxy(CpuOveruseMetricsObserver* metrics_observer)
71 : OveruseFrameDetector(metrics_observer),
Niels Möller7dc26b72017-12-06 10:27:48 +010072 last_target_framerate_fps_(-1) {}
73 virtual ~CpuOveruseDetectorProxy() {}
74
75 void OnTargetFramerateUpdated(int framerate_fps) override {
76 rtc::CritScope cs(&lock_);
77 last_target_framerate_fps_ = framerate_fps;
78 OveruseFrameDetector::OnTargetFramerateUpdated(framerate_fps);
79 }
80
81 int GetLastTargetFramerate() {
82 rtc::CritScope cs(&lock_);
83 return last_target_framerate_fps_;
84 }
85
Niels Möller4db138e2018-04-19 09:04:13 +020086 CpuOveruseOptions GetOptions() { return options_; }
87
Niels Möller7dc26b72017-12-06 10:27:48 +010088 private:
89 rtc::CriticalSection lock_;
90 int last_target_framerate_fps_ RTC_GUARDED_BY(lock_);
91};
92
mflodmancc3d4422017-08-03 08:27:51 -070093class VideoStreamEncoderUnderTest : public VideoStreamEncoder {
perkj803d97f2016-11-01 11:45:46 -070094 public:
Niels Möller213618e2018-07-24 09:29:58 +020095 VideoStreamEncoderUnderTest(SendStatisticsProxy* stats_proxy,
96 const VideoStreamEncoderSettings& settings)
Yves Gerey665174f2018-06-19 15:03:05 +020097 : VideoStreamEncoder(1 /* number_of_cores */,
98 stats_proxy,
99 settings,
100 nullptr /* pre_encode_callback */,
101 std::unique_ptr<OveruseFrameDetector>(
102 overuse_detector_proxy_ =
103 new CpuOveruseDetectorProxy(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);
Yves Gerey665174f2018-06-19 15:03:05 +0200118 encoder_queue()->PostTask([&event] { event.Set(); });
kthelgason2fc52542017-03-03 00:24:41 -0800119 ASSERT_TRUE(event.Wait(5000));
120 }
121
sprangb1ca0732017-02-01 08:38:12 -0800122 void TriggerCpuOveruse() { PostTaskAndWait(true, AdaptReason::kCpu); }
kthelgason876222f2016-11-29 01:44:11 -0800123
sprangb1ca0732017-02-01 08:38:12 -0800124 void TriggerCpuNormalUsage() { PostTaskAndWait(false, AdaptReason::kCpu); }
kthelgason876222f2016-11-29 01:44:11 -0800125
sprangb1ca0732017-02-01 08:38:12 -0800126 void TriggerQualityLow() { PostTaskAndWait(true, AdaptReason::kQuality); }
kthelgason876222f2016-11-29 01:44:11 -0800127
sprangb1ca0732017-02-01 08:38:12 -0800128 void TriggerQualityHigh() { PostTaskAndWait(false, AdaptReason::kQuality); }
sprangfda496a2017-06-15 04:21:07 -0700129
Niels Möller7dc26b72017-12-06 10:27:48 +0100130 CpuOveruseDetectorProxy* overuse_detector_proxy_;
perkj803d97f2016-11-01 11:45:46 -0700131};
132
asapersson5f7226f2016-11-25 04:37:00 -0800133class VideoStreamFactory
134 : public VideoEncoderConfig::VideoStreamFactoryInterface {
135 public:
sprangfda496a2017-06-15 04:21:07 -0700136 explicit VideoStreamFactory(size_t num_temporal_layers, int framerate)
137 : num_temporal_layers_(num_temporal_layers), framerate_(framerate) {
asapersson5f7226f2016-11-25 04:37:00 -0800138 EXPECT_GT(num_temporal_layers, 0u);
sprangfda496a2017-06-15 04:21:07 -0700139 EXPECT_GT(framerate, 0);
asapersson5f7226f2016-11-25 04:37:00 -0800140 }
141
142 private:
143 std::vector<VideoStream> CreateEncoderStreams(
144 int width,
145 int height,
146 const VideoEncoderConfig& encoder_config) override {
147 std::vector<VideoStream> streams =
148 test::CreateVideoStreams(width, height, encoder_config);
149 for (VideoStream& stream : streams) {
Sergey Silkina796a7e2018-03-01 15:11:29 +0100150 stream.num_temporal_layers = num_temporal_layers_;
sprangfda496a2017-06-15 04:21:07 -0700151 stream.max_framerate = framerate_;
asapersson5f7226f2016-11-25 04:37:00 -0800152 }
153 return streams;
154 }
sprangfda496a2017-06-15 04:21:07 -0700155
asapersson5f7226f2016-11-25 04:37:00 -0800156 const size_t num_temporal_layers_;
sprangfda496a2017-06-15 04:21:07 -0700157 const int framerate_;
asapersson5f7226f2016-11-25 04:37:00 -0800158};
159
sprangb1ca0732017-02-01 08:38:12 -0800160class AdaptingFrameForwarder : public test::FrameForwarder {
161 public:
162 AdaptingFrameForwarder() : adaptation_enabled_(false) {}
asaperssonfab67072017-04-04 05:51:49 -0700163 ~AdaptingFrameForwarder() override {}
sprangb1ca0732017-02-01 08:38:12 -0800164
165 void set_adaptation_enabled(bool enabled) {
166 rtc::CritScope cs(&crit_);
167 adaptation_enabled_ = enabled;
168 }
169
asaperssonfab67072017-04-04 05:51:49 -0700170 bool adaption_enabled() const {
sprangb1ca0732017-02-01 08:38:12 -0800171 rtc::CritScope cs(&crit_);
172 return adaptation_enabled_;
173 }
174
asapersson09f05612017-05-15 23:40:18 -0700175 rtc::VideoSinkWants last_wants() const {
176 rtc::CritScope cs(&crit_);
177 return last_wants_;
178 }
179
Danil Chapovalovb9b146c2018-06-15 12:28:07 +0200180 absl::optional<int> last_sent_width() const { return last_width_; }
181 absl::optional<int> last_sent_height() const { return last_height_; }
Jonathan Yubc771b72017-12-08 17:04:29 -0800182
sprangb1ca0732017-02-01 08:38:12 -0800183 void IncomingCapturedFrame(const VideoFrame& video_frame) override {
184 int cropped_width = 0;
185 int cropped_height = 0;
186 int out_width = 0;
187 int out_height = 0;
sprangc5d62e22017-04-02 23:53:04 -0700188 if (adaption_enabled()) {
189 if (adapter_.AdaptFrameResolution(
190 video_frame.width(), video_frame.height(),
191 video_frame.timestamp_us() * 1000, &cropped_width,
192 &cropped_height, &out_width, &out_height)) {
193 VideoFrame adapted_frame(new rtc::RefCountedObject<TestBuffer>(
194 nullptr, out_width, out_height),
195 99, 99, kVideoRotation_0);
196 adapted_frame.set_ntp_time_ms(video_frame.ntp_time_ms());
197 test::FrameForwarder::IncomingCapturedFrame(adapted_frame);
Jonathan Yubc771b72017-12-08 17:04:29 -0800198 last_width_.emplace(adapted_frame.width());
199 last_height_.emplace(adapted_frame.height());
200 } else {
Danil Chapovalovb9b146c2018-06-15 12:28:07 +0200201 last_width_ = absl::nullopt;
202 last_height_ = absl::nullopt;
sprangc5d62e22017-04-02 23:53:04 -0700203 }
sprangb1ca0732017-02-01 08:38:12 -0800204 } else {
205 test::FrameForwarder::IncomingCapturedFrame(video_frame);
Jonathan Yubc771b72017-12-08 17:04:29 -0800206 last_width_.emplace(video_frame.width());
207 last_height_.emplace(video_frame.height());
sprangb1ca0732017-02-01 08:38:12 -0800208 }
209 }
210
211 void AddOrUpdateSink(rtc::VideoSinkInterface<VideoFrame>* sink,
212 const rtc::VideoSinkWants& wants) override {
213 rtc::CritScope cs(&crit_);
asapersson09f05612017-05-15 23:40:18 -0700214 last_wants_ = sink_wants();
sprangc5d62e22017-04-02 23:53:04 -0700215 adapter_.OnResolutionFramerateRequest(wants.target_pixel_count,
216 wants.max_pixel_count,
217 wants.max_framerate_fps);
sprangb1ca0732017-02-01 08:38:12 -0800218 test::FrameForwarder::AddOrUpdateSink(sink, wants);
219 }
sprangb1ca0732017-02-01 08:38:12 -0800220 cricket::VideoAdapter adapter_;
danilchapa37de392017-09-09 04:17:22 -0700221 bool adaptation_enabled_ RTC_GUARDED_BY(crit_);
222 rtc::VideoSinkWants last_wants_ RTC_GUARDED_BY(crit_);
Danil Chapovalovb9b146c2018-06-15 12:28:07 +0200223 absl::optional<int> last_width_;
224 absl::optional<int> last_height_;
sprangb1ca0732017-02-01 08:38:12 -0800225};
sprangc5d62e22017-04-02 23:53:04 -0700226
Niels Möller213618e2018-07-24 09:29:58 +0200227// TODO(nisse): Mock only VideoStreamEncoderObserver.
sprangc5d62e22017-04-02 23:53:04 -0700228class MockableSendStatisticsProxy : public SendStatisticsProxy {
229 public:
230 MockableSendStatisticsProxy(Clock* clock,
231 const VideoSendStream::Config& config,
232 VideoEncoderConfig::ContentType content_type)
233 : SendStatisticsProxy(clock, config, content_type) {}
234
235 VideoSendStream::Stats GetStats() override {
236 rtc::CritScope cs(&lock_);
237 if (mock_stats_)
238 return *mock_stats_;
239 return SendStatisticsProxy::GetStats();
240 }
241
Niels Möller213618e2018-07-24 09:29:58 +0200242 int GetInputFrameRate() const override {
243 rtc::CritScope cs(&lock_);
244 if (mock_stats_)
245 return mock_stats_->input_frame_rate;
246 return SendStatisticsProxy::GetInputFrameRate();
247 }
sprangc5d62e22017-04-02 23:53:04 -0700248 void SetMockStats(const VideoSendStream::Stats& stats) {
249 rtc::CritScope cs(&lock_);
250 mock_stats_.emplace(stats);
251 }
252
253 void ResetMockStats() {
254 rtc::CritScope cs(&lock_);
255 mock_stats_.reset();
256 }
257
258 private:
259 rtc::CriticalSection lock_;
Danil Chapovalovb9b146c2018-06-15 12:28:07 +0200260 absl::optional<VideoSendStream::Stats> mock_stats_ RTC_GUARDED_BY(lock_);
sprangc5d62e22017-04-02 23:53:04 -0700261};
262
sprang4847ae62017-06-27 07:06:52 -0700263class MockBitrateObserver : public VideoBitrateAllocationObserver {
264 public:
Erik Språng566124a2018-04-23 12:32:22 +0200265 MOCK_METHOD1(OnBitrateAllocationUpdated, void(const VideoBitrateAllocation&));
sprang4847ae62017-06-27 07:06:52 -0700266};
267
perkj803d97f2016-11-01 11:45:46 -0700268} // namespace
269
mflodmancc3d4422017-08-03 08:27:51 -0700270class VideoStreamEncoderTest : public ::testing::Test {
perkj26091b12016-09-01 01:17:40 -0700271 public:
272 static const int kDefaultTimeoutMs = 30 * 1000;
273
mflodmancc3d4422017-08-03 08:27:51 -0700274 VideoStreamEncoderTest()
perkj26091b12016-09-01 01:17:40 -0700275 : video_send_config_(VideoSendStream::Config(nullptr)),
perkjfa10b552016-10-02 23:45:26 -0700276 codec_width_(320),
277 codec_height_(240),
Mirko Bonadei948b7e32018-08-14 07:23:21 +0000278 max_framerate_(30),
perkj26091b12016-09-01 01:17:40 -0700279 fake_encoder_(),
Niels Möller4db138e2018-04-19 09:04:13 +0200280 encoder_factory_(&fake_encoder_),
sprangc5d62e22017-04-02 23:53:04 -0700281 stats_proxy_(new MockableSendStatisticsProxy(
perkj803d97f2016-11-01 11:45:46 -0700282 Clock::GetRealTimeClock(),
283 video_send_config_,
284 webrtc::VideoEncoderConfig::ContentType::kRealtimeVideo)),
perkj26091b12016-09-01 01:17:40 -0700285 sink_(&fake_encoder_) {}
286
287 void SetUp() override {
perkj803d97f2016-11-01 11:45:46 -0700288 metrics::Reset();
perkj26091b12016-09-01 01:17:40 -0700289 video_send_config_ = VideoSendStream::Config(nullptr);
Niels Möller4db138e2018-04-19 09:04:13 +0200290 video_send_config_.encoder_settings.encoder_factory = &encoder_factory_;
Niels Möller259a4972018-04-05 15:36:51 +0200291 video_send_config_.rtp.payload_name = "FAKE";
292 video_send_config_.rtp.payload_type = 125;
perkj26091b12016-09-01 01:17:40 -0700293
Per512ecb32016-09-23 15:52:06 +0200294 VideoEncoderConfig video_encoder_config;
Niels Möller259a4972018-04-05 15:36:51 +0200295 test::FillEncoderConfiguration(kVideoCodecVP8, 1, &video_encoder_config);
sprang4847ae62017-06-27 07:06:52 -0700296 video_encoder_config.video_stream_factory =
297 new rtc::RefCountedObject<VideoStreamFactory>(1, max_framerate_);
Erik Språng08127a92016-11-16 16:41:30 +0100298 video_encoder_config_ = video_encoder_config.Copy();
sprang4847ae62017-06-27 07:06:52 -0700299
300 // Framerate limit is specified by the VideoStreamFactory.
301 std::vector<VideoStream> streams =
302 video_encoder_config.video_stream_factory->CreateEncoderStreams(
303 codec_width_, codec_height_, video_encoder_config);
304 max_framerate_ = streams[0].max_framerate;
305 fake_clock_.SetTimeMicros(1234);
306
Niels Möllerf1338562018-04-26 09:51:47 +0200307 ConfigureEncoder(std::move(video_encoder_config));
asapersson5f7226f2016-11-25 04:37:00 -0800308 }
309
Niels Möllerf1338562018-04-26 09:51:47 +0200310 void ConfigureEncoder(VideoEncoderConfig video_encoder_config) {
mflodmancc3d4422017-08-03 08:27:51 -0700311 if (video_stream_encoder_)
312 video_stream_encoder_->Stop();
313 video_stream_encoder_.reset(new VideoStreamEncoderUnderTest(
perkj803d97f2016-11-01 11:45:46 -0700314 stats_proxy_.get(), video_send_config_.encoder_settings));
mflodmancc3d4422017-08-03 08:27:51 -0700315 video_stream_encoder_->SetSink(&sink_, false /* rotation_applied */);
316 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -0700317 &video_source_, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
mflodmancc3d4422017-08-03 08:27:51 -0700318 video_stream_encoder_->SetStartBitrate(kTargetBitrateBps);
319 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
Niels Möllerf1338562018-04-26 09:51:47 +0200320 kMaxPayloadLength);
mflodmancc3d4422017-08-03 08:27:51 -0700321 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
asapersson5f7226f2016-11-25 04:37:00 -0800322 }
323
324 void ResetEncoder(const std::string& payload_name,
325 size_t num_streams,
326 size_t num_temporal_layers,
emircanbbcc3562017-08-18 00:28:40 -0700327 unsigned char num_spatial_layers,
sprang4847ae62017-06-27 07:06:52 -0700328 bool screenshare) {
Niels Möller259a4972018-04-05 15:36:51 +0200329 video_send_config_.rtp.payload_name = payload_name;
asapersson5f7226f2016-11-25 04:37:00 -0800330
331 VideoEncoderConfig video_encoder_config;
Niels Möller259a4972018-04-05 15:36:51 +0200332 video_encoder_config.codec_type = PayloadStringToCodecType(payload_name);
asapersson5f7226f2016-11-25 04:37:00 -0800333 video_encoder_config.number_of_streams = num_streams;
kthelgason2bc68642017-02-07 07:02:22 -0800334 video_encoder_config.max_bitrate_bps = kTargetBitrateBps;
asapersson5f7226f2016-11-25 04:37:00 -0800335 video_encoder_config.video_stream_factory =
sprangfda496a2017-06-15 04:21:07 -0700336 new rtc::RefCountedObject<VideoStreamFactory>(num_temporal_layers,
337 kDefaultFramerate);
sprang4847ae62017-06-27 07:06:52 -0700338 video_encoder_config.content_type =
339 screenshare ? VideoEncoderConfig::ContentType::kScreen
340 : VideoEncoderConfig::ContentType::kRealtimeVideo;
emircanbbcc3562017-08-18 00:28:40 -0700341 if (payload_name == "VP9") {
342 VideoCodecVP9 vp9_settings = VideoEncoder::GetDefaultVp9Settings();
343 vp9_settings.numberOfSpatialLayers = num_spatial_layers;
344 video_encoder_config.encoder_specific_settings =
345 new rtc::RefCountedObject<
346 VideoEncoderConfig::Vp9EncoderSpecificSettings>(vp9_settings);
347 }
Niels Möllerf1338562018-04-26 09:51:47 +0200348 ConfigureEncoder(std::move(video_encoder_config));
perkj26091b12016-09-01 01:17:40 -0700349 }
350
sprang57c2fff2017-01-16 06:24:02 -0800351 VideoFrame CreateFrame(int64_t ntp_time_ms,
352 rtc::Event* destruction_event) const {
Per512ecb32016-09-23 15:52:06 +0200353 VideoFrame frame(new rtc::RefCountedObject<TestBuffer>(
354 destruction_event, codec_width_, codec_height_),
355 99, 99, kVideoRotation_0);
sprang57c2fff2017-01-16 06:24:02 -0800356 frame.set_ntp_time_ms(ntp_time_ms);
perkj26091b12016-09-01 01:17:40 -0700357 return frame;
358 }
359
sprang57c2fff2017-01-16 06:24:02 -0800360 VideoFrame CreateFrame(int64_t ntp_time_ms, int width, int height) const {
perkj803d97f2016-11-01 11:45:46 -0700361 VideoFrame frame(
362 new rtc::RefCountedObject<TestBuffer>(nullptr, width, height), 99, 99,
363 kVideoRotation_0);
sprang57c2fff2017-01-16 06:24:02 -0800364 frame.set_ntp_time_ms(ntp_time_ms);
sprangc5d62e22017-04-02 23:53:04 -0700365 frame.set_timestamp_us(ntp_time_ms * 1000);
perkj803d97f2016-11-01 11:45:46 -0700366 return frame;
367 }
368
asapersson02465b82017-04-10 01:12:52 -0700369 void VerifyNoLimitation(const rtc::VideoSinkWants& wants) {
asapersson02465b82017-04-10 01:12:52 -0700370 EXPECT_EQ(std::numeric_limits<int>::max(), wants.max_framerate_fps);
asapersson09f05612017-05-15 23:40:18 -0700371 EXPECT_EQ(std::numeric_limits<int>::max(), wants.max_pixel_count);
372 EXPECT_FALSE(wants.target_pixel_count);
asapersson02465b82017-04-10 01:12:52 -0700373 }
374
asapersson09f05612017-05-15 23:40:18 -0700375 void VerifyFpsEqResolutionEq(const rtc::VideoSinkWants& wants1,
376 const rtc::VideoSinkWants& wants2) {
377 EXPECT_EQ(wants1.max_framerate_fps, wants2.max_framerate_fps);
378 EXPECT_EQ(wants1.max_pixel_count, wants2.max_pixel_count);
379 }
380
381 void VerifyFpsMaxResolutionLt(const rtc::VideoSinkWants& wants1,
382 const rtc::VideoSinkWants& wants2) {
Mirko Bonadei948b7e32018-08-14 07:23:21 +0000383 EXPECT_EQ(std::numeric_limits<int>::max(), wants1.max_framerate_fps);
asapersson09f05612017-05-15 23:40:18 -0700384 EXPECT_LT(wants1.max_pixel_count, wants2.max_pixel_count);
385 EXPECT_GT(wants1.max_pixel_count, 0);
386 }
387
388 void VerifyFpsMaxResolutionGt(const rtc::VideoSinkWants& wants1,
389 const rtc::VideoSinkWants& wants2) {
Mirko Bonadei948b7e32018-08-14 07:23:21 +0000390 EXPECT_EQ(std::numeric_limits<int>::max(), wants1.max_framerate_fps);
asapersson09f05612017-05-15 23:40:18 -0700391 EXPECT_GT(wants1.max_pixel_count, wants2.max_pixel_count);
392 }
393
asaperssonf7e294d2017-06-13 23:25:22 -0700394 void VerifyFpsMaxResolutionEq(const rtc::VideoSinkWants& wants1,
395 const rtc::VideoSinkWants& wants2) {
Mirko Bonadei948b7e32018-08-14 07:23:21 +0000396 EXPECT_EQ(std::numeric_limits<int>::max(), wants1.max_framerate_fps);
asaperssonf7e294d2017-06-13 23:25:22 -0700397 EXPECT_EQ(wants1.max_pixel_count, wants2.max_pixel_count);
398 }
399
400 void VerifyFpsLtResolutionEq(const rtc::VideoSinkWants& wants1,
401 const rtc::VideoSinkWants& wants2) {
402 EXPECT_LT(wants1.max_framerate_fps, wants2.max_framerate_fps);
403 EXPECT_EQ(wants1.max_pixel_count, wants2.max_pixel_count);
404 }
405
406 void VerifyFpsGtResolutionEq(const rtc::VideoSinkWants& wants1,
407 const rtc::VideoSinkWants& wants2) {
408 EXPECT_GT(wants1.max_framerate_fps, wants2.max_framerate_fps);
409 EXPECT_EQ(wants1.max_pixel_count, wants2.max_pixel_count);
410 }
411
412 void VerifyFpsEqResolutionLt(const rtc::VideoSinkWants& wants1,
413 const rtc::VideoSinkWants& wants2) {
414 EXPECT_EQ(wants1.max_framerate_fps, wants2.max_framerate_fps);
415 EXPECT_LT(wants1.max_pixel_count, wants2.max_pixel_count);
416 EXPECT_GT(wants1.max_pixel_count, 0);
417 }
418
419 void VerifyFpsEqResolutionGt(const rtc::VideoSinkWants& wants1,
420 const rtc::VideoSinkWants& wants2) {
421 EXPECT_EQ(wants1.max_framerate_fps, wants2.max_framerate_fps);
422 EXPECT_GT(wants1.max_pixel_count, wants2.max_pixel_count);
423 }
424
asapersson09f05612017-05-15 23:40:18 -0700425 void VerifyFpsMaxResolutionLt(const rtc::VideoSinkWants& wants,
426 int pixel_count) {
Mirko Bonadei948b7e32018-08-14 07:23:21 +0000427 EXPECT_EQ(std::numeric_limits<int>::max(), wants.max_framerate_fps);
asapersson02465b82017-04-10 01:12:52 -0700428 EXPECT_LT(wants.max_pixel_count, pixel_count);
429 EXPECT_GT(wants.max_pixel_count, 0);
asapersson09f05612017-05-15 23:40:18 -0700430 }
431
432 void VerifyFpsLtResolutionMax(const rtc::VideoSinkWants& wants, int fps) {
433 EXPECT_LT(wants.max_framerate_fps, fps);
434 EXPECT_EQ(std::numeric_limits<int>::max(), wants.max_pixel_count);
435 EXPECT_FALSE(wants.target_pixel_count);
asapersson02465b82017-04-10 01:12:52 -0700436 }
437
asaperssonf7e294d2017-06-13 23:25:22 -0700438 void VerifyFpsEqResolutionMax(const rtc::VideoSinkWants& wants,
439 int expected_fps) {
440 EXPECT_EQ(expected_fps, wants.max_framerate_fps);
441 EXPECT_EQ(std::numeric_limits<int>::max(), wants.max_pixel_count);
442 EXPECT_FALSE(wants.target_pixel_count);
443 }
444
Jonathan Yubc771b72017-12-08 17:04:29 -0800445 void VerifyBalancedModeFpsRange(const rtc::VideoSinkWants& wants,
446 int last_frame_pixels) {
447 // Balanced mode should always scale FPS to the desired range before
448 // attempting to scale resolution.
449 int fps_limit = wants.max_framerate_fps;
450 if (last_frame_pixels <= 320 * 240) {
451 EXPECT_TRUE(7 <= fps_limit && fps_limit <= 10);
452 } else if (last_frame_pixels <= 480 * 270) {
453 EXPECT_TRUE(10 <= fps_limit && fps_limit <= 15);
454 } else if (last_frame_pixels <= 640 * 480) {
455 EXPECT_LE(15, fps_limit);
456 } else {
Mirko Bonadei948b7e32018-08-14 07:23:21 +0000457 EXPECT_EQ(std::numeric_limits<int>::max(), fps_limit);
Jonathan Yubc771b72017-12-08 17:04:29 -0800458 }
459 }
460
sprang4847ae62017-06-27 07:06:52 -0700461 void WaitForEncodedFrame(int64_t expected_ntp_time) {
462 sink_.WaitForEncodedFrame(expected_ntp_time);
463 fake_clock_.AdvanceTimeMicros(rtc::kNumMicrosecsPerSec / max_framerate_);
464 }
465
466 bool TimedWaitForEncodedFrame(int64_t expected_ntp_time, int64_t timeout_ms) {
467 bool ok = sink_.TimedWaitForEncodedFrame(expected_ntp_time, timeout_ms);
468 fake_clock_.AdvanceTimeMicros(rtc::kNumMicrosecsPerSec / max_framerate_);
469 return ok;
470 }
471
472 void WaitForEncodedFrame(uint32_t expected_width, uint32_t expected_height) {
473 sink_.WaitForEncodedFrame(expected_width, expected_height);
474 fake_clock_.AdvanceTimeMicros(rtc::kNumMicrosecsPerSec / max_framerate_);
475 }
476
477 void ExpectDroppedFrame() {
478 sink_.ExpectDroppedFrame();
479 fake_clock_.AdvanceTimeMicros(rtc::kNumMicrosecsPerSec / max_framerate_);
480 }
481
482 bool WaitForFrame(int64_t timeout_ms) {
483 bool ok = sink_.WaitForFrame(timeout_ms);
484 fake_clock_.AdvanceTimeMicros(rtc::kNumMicrosecsPerSec / max_framerate_);
485 return ok;
486 }
487
perkj26091b12016-09-01 01:17:40 -0700488 class TestEncoder : public test::FakeEncoder {
489 public:
490 TestEncoder()
491 : FakeEncoder(Clock::GetRealTimeClock()),
492 continue_encode_event_(false, false) {}
493
asaperssonfab67072017-04-04 05:51:49 -0700494 VideoCodec codec_config() const {
brandtre78d2662017-01-16 05:57:16 -0800495 rtc::CritScope lock(&crit_sect_);
perkjfa10b552016-10-02 23:45:26 -0700496 return config_;
497 }
498
499 void BlockNextEncode() {
brandtre78d2662017-01-16 05:57:16 -0800500 rtc::CritScope lock(&local_crit_sect_);
perkjfa10b552016-10-02 23:45:26 -0700501 block_next_encode_ = true;
502 }
503
kthelgason876222f2016-11-29 01:44:11 -0800504 VideoEncoder::ScalingSettings GetScalingSettings() const override {
kthelgason2fc52542017-03-03 00:24:41 -0800505 rtc::CritScope lock(&local_crit_sect_);
kthelgasonad9010c2017-02-14 00:46:51 -0800506 if (quality_scaling_)
Niels Möller225c7872018-02-22 15:03:53 +0100507 return VideoEncoder::ScalingSettings(1, 2, kMinPixelsPerFrame);
508 return VideoEncoder::ScalingSettings::kOff;
kthelgason876222f2016-11-29 01:44:11 -0800509 }
510
perkjfa10b552016-10-02 23:45:26 -0700511 void ContinueEncode() { continue_encode_event_.Set(); }
512
513 void CheckLastTimeStampsMatch(int64_t ntp_time_ms,
514 uint32_t timestamp) const {
brandtre78d2662017-01-16 05:57:16 -0800515 rtc::CritScope lock(&local_crit_sect_);
perkjfa10b552016-10-02 23:45:26 -0700516 EXPECT_EQ(timestamp_, timestamp);
517 EXPECT_EQ(ntp_time_ms_, ntp_time_ms);
518 }
519
kthelgason2fc52542017-03-03 00:24:41 -0800520 void SetQualityScaling(bool b) {
521 rtc::CritScope lock(&local_crit_sect_);
522 quality_scaling_ = b;
523 }
kthelgasonad9010c2017-02-14 00:46:51 -0800524
sprangfe627f32017-03-29 08:24:59 -0700525 void ForceInitEncodeFailure(bool force_failure) {
526 rtc::CritScope lock(&local_crit_sect_);
527 force_init_encode_failed_ = force_failure;
528 }
529
perkjfa10b552016-10-02 23:45:26 -0700530 private:
perkj26091b12016-09-01 01:17:40 -0700531 int32_t Encode(const VideoFrame& input_image,
532 const CodecSpecificInfo* codec_specific_info,
533 const std::vector<FrameType>* frame_types) override {
534 bool block_encode;
535 {
brandtre78d2662017-01-16 05:57:16 -0800536 rtc::CritScope lock(&local_crit_sect_);
perkj26091b12016-09-01 01:17:40 -0700537 EXPECT_GT(input_image.timestamp(), timestamp_);
538 EXPECT_GT(input_image.ntp_time_ms(), ntp_time_ms_);
539 EXPECT_EQ(input_image.timestamp(), input_image.ntp_time_ms() * 90);
540
541 timestamp_ = input_image.timestamp();
542 ntp_time_ms_ = input_image.ntp_time_ms();
perkj803d97f2016-11-01 11:45:46 -0700543 last_input_width_ = input_image.width();
544 last_input_height_ = input_image.height();
perkj26091b12016-09-01 01:17:40 -0700545 block_encode = block_next_encode_;
546 block_next_encode_ = false;
547 }
548 int32_t result =
549 FakeEncoder::Encode(input_image, codec_specific_info, frame_types);
550 if (block_encode)
perkja49cbd32016-09-16 07:53:41 -0700551 EXPECT_TRUE(continue_encode_event_.Wait(kDefaultTimeoutMs));
perkj26091b12016-09-01 01:17:40 -0700552 return result;
553 }
554
sprangfe627f32017-03-29 08:24:59 -0700555 int32_t InitEncode(const VideoCodec* config,
556 int32_t number_of_cores,
557 size_t max_payload_size) override {
558 int res =
559 FakeEncoder::InitEncode(config, number_of_cores, max_payload_size);
560 rtc::CritScope lock(&local_crit_sect_);
Erik Språng82fad3d2018-03-21 09:57:23 +0100561 if (config->codecType == kVideoCodecVP8) {
sprangfe627f32017-03-29 08:24:59 -0700562 // Simulate setting up temporal layers, in order to validate the life
563 // cycle of these objects.
564 int num_streams = std::max<int>(1, config->numberOfSimulcastStreams);
sprangfe627f32017-03-29 08:24:59 -0700565 for (int i = 0; i < num_streams; ++i) {
566 allocated_temporal_layers_.emplace_back(
Niels Möller150dcb02018-03-27 14:16:55 +0200567 TemporalLayers::CreateTemporalLayers(*config, i));
sprangfe627f32017-03-29 08:24:59 -0700568 }
569 }
570 if (force_init_encode_failed_)
571 return -1;
572 return res;
573 }
574
brandtre78d2662017-01-16 05:57:16 -0800575 rtc::CriticalSection local_crit_sect_;
danilchapa37de392017-09-09 04:17:22 -0700576 bool block_next_encode_ RTC_GUARDED_BY(local_crit_sect_) = false;
perkj26091b12016-09-01 01:17:40 -0700577 rtc::Event continue_encode_event_;
danilchapa37de392017-09-09 04:17:22 -0700578 uint32_t timestamp_ RTC_GUARDED_BY(local_crit_sect_) = 0;
579 int64_t ntp_time_ms_ RTC_GUARDED_BY(local_crit_sect_) = 0;
580 int last_input_width_ RTC_GUARDED_BY(local_crit_sect_) = 0;
581 int last_input_height_ RTC_GUARDED_BY(local_crit_sect_) = 0;
582 bool quality_scaling_ RTC_GUARDED_BY(local_crit_sect_) = true;
sprangfe627f32017-03-29 08:24:59 -0700583 std::vector<std::unique_ptr<TemporalLayers>> allocated_temporal_layers_
danilchapa37de392017-09-09 04:17:22 -0700584 RTC_GUARDED_BY(local_crit_sect_);
585 bool force_init_encode_failed_ RTC_GUARDED_BY(local_crit_sect_) = false;
perkj26091b12016-09-01 01:17:40 -0700586 };
587
mflodmancc3d4422017-08-03 08:27:51 -0700588 class TestSink : public VideoStreamEncoder::EncoderSink {
perkj26091b12016-09-01 01:17:40 -0700589 public:
590 explicit TestSink(TestEncoder* test_encoder)
591 : test_encoder_(test_encoder), encoded_frame_event_(false, false) {}
592
perkj26091b12016-09-01 01:17:40 -0700593 void WaitForEncodedFrame(int64_t expected_ntp_time) {
sprang4847ae62017-06-27 07:06:52 -0700594 EXPECT_TRUE(
595 TimedWaitForEncodedFrame(expected_ntp_time, kDefaultTimeoutMs));
596 }
597
598 bool TimedWaitForEncodedFrame(int64_t expected_ntp_time,
599 int64_t timeout_ms) {
perkj26091b12016-09-01 01:17:40 -0700600 uint32_t timestamp = 0;
sprang4847ae62017-06-27 07:06:52 -0700601 if (!encoded_frame_event_.Wait(timeout_ms))
602 return false;
perkj26091b12016-09-01 01:17:40 -0700603 {
604 rtc::CritScope lock(&crit_);
sprangb1ca0732017-02-01 08:38:12 -0800605 timestamp = last_timestamp_;
perkj26091b12016-09-01 01:17:40 -0700606 }
607 test_encoder_->CheckLastTimeStampsMatch(expected_ntp_time, timestamp);
sprang4847ae62017-06-27 07:06:52 -0700608 return true;
perkj26091b12016-09-01 01:17:40 -0700609 }
610
sprangb1ca0732017-02-01 08:38:12 -0800611 void WaitForEncodedFrame(uint32_t expected_width,
612 uint32_t expected_height) {
sprangc5d62e22017-04-02 23:53:04 -0700613 EXPECT_TRUE(encoded_frame_event_.Wait(kDefaultTimeoutMs));
Åsa Perssonc74d8da2017-12-04 14:13:56 +0100614 CheckLastFrameSizeMatches(expected_width, expected_height);
sprangc5d62e22017-04-02 23:53:04 -0700615 }
616
Åsa Perssonc74d8da2017-12-04 14:13:56 +0100617 void CheckLastFrameSizeMatches(uint32_t expected_width,
sprangc5d62e22017-04-02 23:53:04 -0700618 uint32_t expected_height) {
sprangb1ca0732017-02-01 08:38:12 -0800619 uint32_t width = 0;
620 uint32_t height = 0;
sprangb1ca0732017-02-01 08:38:12 -0800621 {
622 rtc::CritScope lock(&crit_);
623 width = last_width_;
624 height = last_height_;
625 }
626 EXPECT_EQ(expected_height, height);
627 EXPECT_EQ(expected_width, width);
628 }
629
kthelgason2fc52542017-03-03 00:24:41 -0800630 void ExpectDroppedFrame() { EXPECT_FALSE(encoded_frame_event_.Wait(100)); }
kthelgason2bc68642017-02-07 07:02:22 -0800631
sprangc5d62e22017-04-02 23:53:04 -0700632 bool WaitForFrame(int64_t timeout_ms) {
633 return encoded_frame_event_.Wait(timeout_ms);
634 }
635
perkj26091b12016-09-01 01:17:40 -0700636 void SetExpectNoFrames() {
637 rtc::CritScope lock(&crit_);
638 expect_frames_ = false;
639 }
640
asaperssonfab67072017-04-04 05:51:49 -0700641 int number_of_reconfigurations() const {
Per512ecb32016-09-23 15:52:06 +0200642 rtc::CritScope lock(&crit_);
643 return number_of_reconfigurations_;
644 }
645
asaperssonfab67072017-04-04 05:51:49 -0700646 int last_min_transmit_bitrate() const {
Per512ecb32016-09-23 15:52:06 +0200647 rtc::CritScope lock(&crit_);
648 return min_transmit_bitrate_bps_;
649 }
650
perkj26091b12016-09-01 01:17:40 -0700651 private:
sergeyu2cb155a2016-11-04 11:39:29 -0700652 Result OnEncodedImage(
653 const EncodedImage& encoded_image,
654 const CodecSpecificInfo* codec_specific_info,
655 const RTPFragmentationHeader* fragmentation) override {
Per512ecb32016-09-23 15:52:06 +0200656 rtc::CritScope lock(&crit_);
657 EXPECT_TRUE(expect_frames_);
sprangb1ca0732017-02-01 08:38:12 -0800658 last_timestamp_ = encoded_image._timeStamp;
659 last_width_ = encoded_image._encodedWidth;
660 last_height_ = encoded_image._encodedHeight;
Per512ecb32016-09-23 15:52:06 +0200661 encoded_frame_event_.Set();
sprangb1ca0732017-02-01 08:38:12 -0800662 return Result(Result::OK, last_timestamp_);
Per512ecb32016-09-23 15:52:06 +0200663 }
664
665 void OnEncoderConfigurationChanged(std::vector<VideoStream> streams,
666 int min_transmit_bitrate_bps) override {
667 rtc::CriticalSection crit_;
668 ++number_of_reconfigurations_;
669 min_transmit_bitrate_bps_ = min_transmit_bitrate_bps;
670 }
671
perkj26091b12016-09-01 01:17:40 -0700672 rtc::CriticalSection crit_;
673 TestEncoder* test_encoder_;
674 rtc::Event encoded_frame_event_;
sprangb1ca0732017-02-01 08:38:12 -0800675 uint32_t last_timestamp_ = 0;
676 uint32_t last_height_ = 0;
677 uint32_t last_width_ = 0;
perkj26091b12016-09-01 01:17:40 -0700678 bool expect_frames_ = true;
Per512ecb32016-09-23 15:52:06 +0200679 int number_of_reconfigurations_ = 0;
680 int min_transmit_bitrate_bps_ = 0;
perkj26091b12016-09-01 01:17:40 -0700681 };
682
683 VideoSendStream::Config video_send_config_;
Erik Språng08127a92016-11-16 16:41:30 +0100684 VideoEncoderConfig video_encoder_config_;
Per512ecb32016-09-23 15:52:06 +0200685 int codec_width_;
686 int codec_height_;
sprang4847ae62017-06-27 07:06:52 -0700687 int max_framerate_;
perkj26091b12016-09-01 01:17:40 -0700688 TestEncoder fake_encoder_;
Niels Möller4db138e2018-04-19 09:04:13 +0200689 test::EncoderProxyFactory encoder_factory_;
sprangc5d62e22017-04-02 23:53:04 -0700690 std::unique_ptr<MockableSendStatisticsProxy> stats_proxy_;
perkj26091b12016-09-01 01:17:40 -0700691 TestSink sink_;
sprangb1ca0732017-02-01 08:38:12 -0800692 AdaptingFrameForwarder video_source_;
mflodmancc3d4422017-08-03 08:27:51 -0700693 std::unique_ptr<VideoStreamEncoderUnderTest> video_stream_encoder_;
sprang4847ae62017-06-27 07:06:52 -0700694 rtc::ScopedFakeClock fake_clock_;
perkj26091b12016-09-01 01:17:40 -0700695};
696
mflodmancc3d4422017-08-03 08:27:51 -0700697TEST_F(VideoStreamEncoderTest, EncodeOneFrame) {
698 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkj26091b12016-09-01 01:17:40 -0700699 rtc::Event frame_destroyed_event(false, false);
perkja49cbd32016-09-16 07:53:41 -0700700 video_source_.IncomingCapturedFrame(CreateFrame(1, &frame_destroyed_event));
sprang4847ae62017-06-27 07:06:52 -0700701 WaitForEncodedFrame(1);
perkja49cbd32016-09-16 07:53:41 -0700702 EXPECT_TRUE(frame_destroyed_event.Wait(kDefaultTimeoutMs));
mflodmancc3d4422017-08-03 08:27:51 -0700703 video_stream_encoder_->Stop();
perkj26091b12016-09-01 01:17:40 -0700704}
705
mflodmancc3d4422017-08-03 08:27:51 -0700706TEST_F(VideoStreamEncoderTest, DropsFramesBeforeFirstOnBitrateUpdated) {
perkj26091b12016-09-01 01:17:40 -0700707 // Dropped since no target bitrate has been set.
708 rtc::Event frame_destroyed_event(false, false);
Sebastian Janssona3177052018-04-10 13:05:49 +0200709 // The encoder will cache up to one frame for a short duration. Adding two
710 // frames means that the first frame will be dropped and the second frame will
711 // be sent when the encoder is enabled.
perkja49cbd32016-09-16 07:53:41 -0700712 video_source_.IncomingCapturedFrame(CreateFrame(1, &frame_destroyed_event));
Sebastian Janssona3177052018-04-10 13:05:49 +0200713 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
perkja49cbd32016-09-16 07:53:41 -0700714 EXPECT_TRUE(frame_destroyed_event.Wait(kDefaultTimeoutMs));
perkj26091b12016-09-01 01:17:40 -0700715
mflodmancc3d4422017-08-03 08:27:51 -0700716 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkj26091b12016-09-01 01:17:40 -0700717
Sebastian Janssona3177052018-04-10 13:05:49 +0200718 // The pending frame should be received.
sprang4847ae62017-06-27 07:06:52 -0700719 WaitForEncodedFrame(2);
Sebastian Janssona3177052018-04-10 13:05:49 +0200720 video_source_.IncomingCapturedFrame(CreateFrame(3, nullptr));
721
722 WaitForEncodedFrame(3);
mflodmancc3d4422017-08-03 08:27:51 -0700723 video_stream_encoder_->Stop();
perkj26091b12016-09-01 01:17:40 -0700724}
725
mflodmancc3d4422017-08-03 08:27:51 -0700726TEST_F(VideoStreamEncoderTest, DropsFramesWhenRateSetToZero) {
727 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkja49cbd32016-09-16 07:53:41 -0700728 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700729 WaitForEncodedFrame(1);
perkj26091b12016-09-01 01:17:40 -0700730
mflodmancc3d4422017-08-03 08:27:51 -0700731 video_stream_encoder_->OnBitrateUpdated(0, 0, 0);
Sebastian Janssona3177052018-04-10 13:05:49 +0200732 // The encoder will cache up to one frame for a short duration. Adding two
733 // frames means that the first frame will be dropped and the second frame will
734 // be sent when the encoder is resumed.
perkja49cbd32016-09-16 07:53:41 -0700735 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
Sebastian Janssona3177052018-04-10 13:05:49 +0200736 video_source_.IncomingCapturedFrame(CreateFrame(3, nullptr));
perkj26091b12016-09-01 01:17:40 -0700737
mflodmancc3d4422017-08-03 08:27:51 -0700738 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
sprang4847ae62017-06-27 07:06:52 -0700739 WaitForEncodedFrame(3);
Sebastian Janssona3177052018-04-10 13:05:49 +0200740 video_source_.IncomingCapturedFrame(CreateFrame(4, nullptr));
741 WaitForEncodedFrame(4);
mflodmancc3d4422017-08-03 08:27:51 -0700742 video_stream_encoder_->Stop();
perkj26091b12016-09-01 01:17:40 -0700743}
744
mflodmancc3d4422017-08-03 08:27:51 -0700745TEST_F(VideoStreamEncoderTest, DropsFramesWithSameOrOldNtpTimestamp) {
746 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkja49cbd32016-09-16 07:53:41 -0700747 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700748 WaitForEncodedFrame(1);
perkj26091b12016-09-01 01:17:40 -0700749
750 // This frame will be dropped since it has the same ntp timestamp.
perkja49cbd32016-09-16 07:53:41 -0700751 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
perkj26091b12016-09-01 01:17:40 -0700752
perkja49cbd32016-09-16 07:53:41 -0700753 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700754 WaitForEncodedFrame(2);
mflodmancc3d4422017-08-03 08:27:51 -0700755 video_stream_encoder_->Stop();
perkj26091b12016-09-01 01:17:40 -0700756}
757
mflodmancc3d4422017-08-03 08:27:51 -0700758TEST_F(VideoStreamEncoderTest, DropsFrameAfterStop) {
759 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkj26091b12016-09-01 01:17:40 -0700760
perkja49cbd32016-09-16 07:53:41 -0700761 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700762 WaitForEncodedFrame(1);
perkj26091b12016-09-01 01:17:40 -0700763
mflodmancc3d4422017-08-03 08:27:51 -0700764 video_stream_encoder_->Stop();
perkj26091b12016-09-01 01:17:40 -0700765 sink_.SetExpectNoFrames();
766 rtc::Event frame_destroyed_event(false, false);
perkja49cbd32016-09-16 07:53:41 -0700767 video_source_.IncomingCapturedFrame(CreateFrame(2, &frame_destroyed_event));
768 EXPECT_TRUE(frame_destroyed_event.Wait(kDefaultTimeoutMs));
perkj26091b12016-09-01 01:17:40 -0700769}
770
mflodmancc3d4422017-08-03 08:27:51 -0700771TEST_F(VideoStreamEncoderTest, DropsPendingFramesOnSlowEncode) {
772 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkj26091b12016-09-01 01:17:40 -0700773
774 fake_encoder_.BlockNextEncode();
perkja49cbd32016-09-16 07:53:41 -0700775 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700776 WaitForEncodedFrame(1);
perkj26091b12016-09-01 01:17:40 -0700777 // Here, the encoder thread will be blocked in the TestEncoder waiting for a
778 // call to ContinueEncode.
perkja49cbd32016-09-16 07:53:41 -0700779 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
780 video_source_.IncomingCapturedFrame(CreateFrame(3, nullptr));
perkj26091b12016-09-01 01:17:40 -0700781 fake_encoder_.ContinueEncode();
sprang4847ae62017-06-27 07:06:52 -0700782 WaitForEncodedFrame(3);
perkj26091b12016-09-01 01:17:40 -0700783
mflodmancc3d4422017-08-03 08:27:51 -0700784 video_stream_encoder_->Stop();
perkj26091b12016-09-01 01:17:40 -0700785}
786
mflodmancc3d4422017-08-03 08:27:51 -0700787TEST_F(VideoStreamEncoderTest,
788 ConfigureEncoderTriggersOnEncoderConfigurationChanged) {
789 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
Per21d45d22016-10-30 21:37:57 +0100790 EXPECT_EQ(0, sink_.number_of_reconfigurations());
Per512ecb32016-09-23 15:52:06 +0200791
792 // Capture a frame and wait for it to synchronize with the encoder thread.
Perf8c5f2b2016-09-23 16:24:55 +0200793 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700794 WaitForEncodedFrame(1);
Per21d45d22016-10-30 21:37:57 +0100795 // The encoder will have been configured once when the first frame is
796 // received.
797 EXPECT_EQ(1, sink_.number_of_reconfigurations());
Per512ecb32016-09-23 15:52:06 +0200798
799 VideoEncoderConfig video_encoder_config;
Niels Möller259a4972018-04-05 15:36:51 +0200800 test::FillEncoderConfiguration(kVideoCodecVP8, 1, &video_encoder_config);
Per512ecb32016-09-23 15:52:06 +0200801 video_encoder_config.min_transmit_bitrate_bps = 9999;
mflodmancc3d4422017-08-03 08:27:51 -0700802 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
Niels Möllerf1338562018-04-26 09:51:47 +0200803 kMaxPayloadLength);
Per512ecb32016-09-23 15:52:06 +0200804
805 // Capture a frame and wait for it to synchronize with the encoder thread.
Perf8c5f2b2016-09-23 16:24:55 +0200806 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700807 WaitForEncodedFrame(2);
Per21d45d22016-10-30 21:37:57 +0100808 EXPECT_EQ(2, sink_.number_of_reconfigurations());
perkj3b703ed2016-09-29 23:25:40 -0700809 EXPECT_EQ(9999, sink_.last_min_transmit_bitrate());
perkj26105b42016-09-29 22:39:10 -0700810
mflodmancc3d4422017-08-03 08:27:51 -0700811 video_stream_encoder_->Stop();
perkj26105b42016-09-29 22:39:10 -0700812}
813
mflodmancc3d4422017-08-03 08:27:51 -0700814TEST_F(VideoStreamEncoderTest, FrameResolutionChangeReconfigureEncoder) {
815 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkjfa10b552016-10-02 23:45:26 -0700816
817 // Capture a frame and wait for it to synchronize with the encoder thread.
818 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700819 WaitForEncodedFrame(1);
Per21d45d22016-10-30 21:37:57 +0100820 // The encoder will have been configured once.
821 EXPECT_EQ(1, sink_.number_of_reconfigurations());
perkjfa10b552016-10-02 23:45:26 -0700822 EXPECT_EQ(codec_width_, fake_encoder_.codec_config().width);
823 EXPECT_EQ(codec_height_, fake_encoder_.codec_config().height);
824
825 codec_width_ *= 2;
826 codec_height_ *= 2;
827 // Capture a frame with a higher resolution and wait for it to synchronize
828 // with the encoder thread.
829 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700830 WaitForEncodedFrame(2);
perkjfa10b552016-10-02 23:45:26 -0700831 EXPECT_EQ(codec_width_, fake_encoder_.codec_config().width);
832 EXPECT_EQ(codec_height_, fake_encoder_.codec_config().height);
Per21d45d22016-10-30 21:37:57 +0100833 EXPECT_EQ(2, sink_.number_of_reconfigurations());
perkjfa10b552016-10-02 23:45:26 -0700834
mflodmancc3d4422017-08-03 08:27:51 -0700835 video_stream_encoder_->Stop();
perkjfa10b552016-10-02 23:45:26 -0700836}
837
mflodmancc3d4422017-08-03 08:27:51 -0700838TEST_F(VideoStreamEncoderTest, SwitchSourceDeregisterEncoderAsSink) {
perkj803d97f2016-11-01 11:45:46 -0700839 EXPECT_TRUE(video_source_.has_sinks());
840 test::FrameForwarder new_video_source;
mflodmancc3d4422017-08-03 08:27:51 -0700841 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -0700842 &new_video_source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
perkj803d97f2016-11-01 11:45:46 -0700843 EXPECT_FALSE(video_source_.has_sinks());
844 EXPECT_TRUE(new_video_source.has_sinks());
845
mflodmancc3d4422017-08-03 08:27:51 -0700846 video_stream_encoder_->Stop();
perkj803d97f2016-11-01 11:45:46 -0700847}
848
mflodmancc3d4422017-08-03 08:27:51 -0700849TEST_F(VideoStreamEncoderTest, SinkWantsRotationApplied) {
perkj803d97f2016-11-01 11:45:46 -0700850 EXPECT_FALSE(video_source_.sink_wants().rotation_applied);
mflodmancc3d4422017-08-03 08:27:51 -0700851 video_stream_encoder_->SetSink(&sink_, true /*rotation_applied*/);
perkj803d97f2016-11-01 11:45:46 -0700852 EXPECT_TRUE(video_source_.sink_wants().rotation_applied);
mflodmancc3d4422017-08-03 08:27:51 -0700853 video_stream_encoder_->Stop();
perkj803d97f2016-11-01 11:45:46 -0700854}
855
Jonathan Yubc771b72017-12-08 17:04:29 -0800856TEST_F(VideoStreamEncoderTest, TestCpuDowngrades_BalancedMode) {
857 const int kFramerateFps = 30;
asaperssonf7e294d2017-06-13 23:25:22 -0700858 const int kWidth = 1280;
859 const int kHeight = 720;
Jonathan Yubc771b72017-12-08 17:04:29 -0800860
861 // We rely on the automatic resolution adaptation, but we handle framerate
862 // adaptation manually by mocking the stats proxy.
863 video_source_.set_adaptation_enabled(true);
asaperssonf7e294d2017-06-13 23:25:22 -0700864
Taylor Brandstetter49fcc102018-05-16 14:20:41 -0700865 // Enable BALANCED preference, no initial limitation.
Jonathan Yubc771b72017-12-08 17:04:29 -0800866 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
Taylor Brandstetter49fcc102018-05-16 14:20:41 -0700867 video_stream_encoder_->SetSource(&video_source_,
868 webrtc::DegradationPreference::BALANCED);
Jonathan Yubc771b72017-12-08 17:04:29 -0800869 VerifyNoLimitation(video_source_.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -0700870 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
Jonathan Yubc771b72017-12-08 17:04:29 -0800871 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
asaperssonf7e294d2017-06-13 23:25:22 -0700872 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
873
Jonathan Yubc771b72017-12-08 17:04:29 -0800874 // Adapt down as far as possible.
875 rtc::VideoSinkWants last_wants;
876 int64_t t = 1;
877 int loop_count = 0;
878 do {
879 ++loop_count;
880 last_wants = video_source_.sink_wants();
881
882 // Simulate the framerate we've been asked to adapt to.
883 const int fps = std::min(kFramerateFps, last_wants.max_framerate_fps);
884 const int frame_interval_ms = rtc::kNumMillisecsPerSec / fps;
885 VideoSendStream::Stats mock_stats = stats_proxy_->GetStats();
886 mock_stats.input_frame_rate = fps;
887 stats_proxy_->SetMockStats(mock_stats);
888
889 video_source_.IncomingCapturedFrame(CreateFrame(t, kWidth, kHeight));
890 sink_.WaitForEncodedFrame(t);
891 t += frame_interval_ms;
892
mflodmancc3d4422017-08-03 08:27:51 -0700893 video_stream_encoder_->TriggerCpuOveruse();
Jonathan Yubc771b72017-12-08 17:04:29 -0800894 VerifyBalancedModeFpsRange(
895 video_source_.sink_wants(),
896 *video_source_.last_sent_width() * *video_source_.last_sent_height());
897 } while (video_source_.sink_wants().max_pixel_count <
898 last_wants.max_pixel_count ||
899 video_source_.sink_wants().max_framerate_fps <
900 last_wants.max_framerate_fps);
asaperssonf7e294d2017-06-13 23:25:22 -0700901
Jonathan Yubc771b72017-12-08 17:04:29 -0800902 // Verify that we've adapted all the way down.
903 stats_proxy_->ResetMockStats();
asaperssonf7e294d2017-06-13 23:25:22 -0700904 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
Jonathan Yubc771b72017-12-08 17:04:29 -0800905 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_framerate);
906 EXPECT_EQ(loop_count - 1,
asaperssonf7e294d2017-06-13 23:25:22 -0700907 stats_proxy_->GetStats().number_of_cpu_adapt_changes);
Jonathan Yubc771b72017-12-08 17:04:29 -0800908 EXPECT_EQ(kMinPixelsPerFrame, *video_source_.last_sent_width() *
909 *video_source_.last_sent_height());
910 EXPECT_EQ(kMinBalancedFramerateFps,
911 video_source_.sink_wants().max_framerate_fps);
asaperssonf7e294d2017-06-13 23:25:22 -0700912
Jonathan Yubc771b72017-12-08 17:04:29 -0800913 // Adapt back up the same number of times we adapted down.
914 for (int i = 0; i < loop_count - 1; ++i) {
915 last_wants = video_source_.sink_wants();
916
917 // Simulate the framerate we've been asked to adapt to.
918 const int fps = std::min(kFramerateFps, last_wants.max_framerate_fps);
919 const int frame_interval_ms = rtc::kNumMillisecsPerSec / fps;
920 VideoSendStream::Stats mock_stats = stats_proxy_->GetStats();
921 mock_stats.input_frame_rate = fps;
922 stats_proxy_->SetMockStats(mock_stats);
923
924 video_source_.IncomingCapturedFrame(CreateFrame(t, kWidth, kHeight));
925 sink_.WaitForEncodedFrame(t);
926 t += frame_interval_ms;
927
mflodmancc3d4422017-08-03 08:27:51 -0700928 video_stream_encoder_->TriggerCpuNormalUsage();
Jonathan Yubc771b72017-12-08 17:04:29 -0800929 VerifyBalancedModeFpsRange(
930 video_source_.sink_wants(),
931 *video_source_.last_sent_width() * *video_source_.last_sent_height());
932 EXPECT_TRUE(video_source_.sink_wants().max_pixel_count >
933 last_wants.max_pixel_count ||
934 video_source_.sink_wants().max_framerate_fps >
935 last_wants.max_framerate_fps);
asaperssonf7e294d2017-06-13 23:25:22 -0700936 }
937
Mirko Bonadei948b7e32018-08-14 07:23:21 +0000938 VerifyNoLimitation(video_source_.sink_wants());
Jonathan Yubc771b72017-12-08 17:04:29 -0800939 stats_proxy_->ResetMockStats();
asaperssonf7e294d2017-06-13 23:25:22 -0700940 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
Jonathan Yubc771b72017-12-08 17:04:29 -0800941 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
942 EXPECT_EQ((loop_count - 1) * 2,
943 stats_proxy_->GetStats().number_of_cpu_adapt_changes);
asaperssonf7e294d2017-06-13 23:25:22 -0700944
mflodmancc3d4422017-08-03 08:27:51 -0700945 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -0700946}
mflodmancc3d4422017-08-03 08:27:51 -0700947TEST_F(VideoStreamEncoderTest, SinkWantsStoredByDegradationPreference) {
948 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson02465b82017-04-10 01:12:52 -0700949 VerifyNoLimitation(video_source_.sink_wants());
perkj803d97f2016-11-01 11:45:46 -0700950
sprangc5d62e22017-04-02 23:53:04 -0700951 const int kFrameWidth = 1280;
952 const int kFrameHeight = 720;
Mirko Bonadei948b7e32018-08-14 07:23:21 +0000953 const int kFrameIntervalMs = 1000 / 30;
sprangc5d62e22017-04-02 23:53:04 -0700954
Mirko Bonadei948b7e32018-08-14 07:23:21 +0000955 int frame_timestamp = 1;
perkj803d97f2016-11-01 11:45:46 -0700956
kthelgason5e13d412016-12-01 03:59:51 -0800957 video_source_.IncomingCapturedFrame(
sprangc5d62e22017-04-02 23:53:04 -0700958 CreateFrame(frame_timestamp, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -0700959 WaitForEncodedFrame(frame_timestamp);
sprangc5d62e22017-04-02 23:53:04 -0700960 frame_timestamp += kFrameIntervalMs;
961
perkj803d97f2016-11-01 11:45:46 -0700962 // Trigger CPU overuse.
mflodmancc3d4422017-08-03 08:27:51 -0700963 video_stream_encoder_->TriggerCpuOveruse();
perkj803d97f2016-11-01 11:45:46 -0700964 video_source_.IncomingCapturedFrame(
sprangc5d62e22017-04-02 23:53:04 -0700965 CreateFrame(frame_timestamp, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -0700966 WaitForEncodedFrame(frame_timestamp);
sprangc5d62e22017-04-02 23:53:04 -0700967 frame_timestamp += kFrameIntervalMs;
sprang3ea3c772017-03-30 07:23:48 -0700968
asapersson0944a802017-04-07 00:57:58 -0700969 // Default degradation preference is maintain-framerate, so will lower max
sprangc5d62e22017-04-02 23:53:04 -0700970 // wanted resolution.
971 EXPECT_FALSE(video_source_.sink_wants().target_pixel_count);
972 EXPECT_LT(video_source_.sink_wants().max_pixel_count,
973 kFrameWidth * kFrameHeight);
Mirko Bonadei948b7e32018-08-14 07:23:21 +0000974 EXPECT_EQ(std::numeric_limits<int>::max(),
975 video_source_.sink_wants().max_framerate_fps);
sprangc5d62e22017-04-02 23:53:04 -0700976
977 // Set new source, switch to maintain-resolution.
perkj803d97f2016-11-01 11:45:46 -0700978 test::FrameForwarder new_video_source;
mflodmancc3d4422017-08-03 08:27:51 -0700979 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -0700980 &new_video_source, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
perkj803d97f2016-11-01 11:45:46 -0700981
sprangc5d62e22017-04-02 23:53:04 -0700982 // Initially no degradation registered.
Mirko Bonadei948b7e32018-08-14 07:23:21 +0000983 VerifyNoLimitation(new_video_source.sink_wants());
perkj803d97f2016-11-01 11:45:46 -0700984
sprangc5d62e22017-04-02 23:53:04 -0700985 // Force an input frame rate to be available, or the adaptation call won't
986 // know what framerate to adapt form.
asapersson02465b82017-04-10 01:12:52 -0700987 const int kInputFps = 30;
sprangc5d62e22017-04-02 23:53:04 -0700988 VideoSendStream::Stats stats = stats_proxy_->GetStats();
asapersson02465b82017-04-10 01:12:52 -0700989 stats.input_frame_rate = kInputFps;
sprangc5d62e22017-04-02 23:53:04 -0700990 stats_proxy_->SetMockStats(stats);
991
mflodmancc3d4422017-08-03 08:27:51 -0700992 video_stream_encoder_->TriggerCpuOveruse();
perkj803d97f2016-11-01 11:45:46 -0700993 new_video_source.IncomingCapturedFrame(
sprangc5d62e22017-04-02 23:53:04 -0700994 CreateFrame(frame_timestamp, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -0700995 WaitForEncodedFrame(frame_timestamp);
sprangc5d62e22017-04-02 23:53:04 -0700996 frame_timestamp += kFrameIntervalMs;
997
998 // Some framerate constraint should be set.
sprang84a37592017-02-10 07:04:27 -0800999 EXPECT_FALSE(new_video_source.sink_wants().target_pixel_count);
sprangc5d62e22017-04-02 23:53:04 -07001000 EXPECT_EQ(std::numeric_limits<int>::max(),
1001 new_video_source.sink_wants().max_pixel_count);
asapersson02465b82017-04-10 01:12:52 -07001002 EXPECT_LT(new_video_source.sink_wants().max_framerate_fps, kInputFps);
sprangc5d62e22017-04-02 23:53:04 -07001003
asapersson02465b82017-04-10 01:12:52 -07001004 // Turn off degradation completely.
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001005 video_stream_encoder_->SetSource(&new_video_source,
1006 webrtc::DegradationPreference::DISABLED);
Mirko Bonadei948b7e32018-08-14 07:23:21 +00001007 VerifyNoLimitation(new_video_source.sink_wants());
sprangc5d62e22017-04-02 23:53:04 -07001008
mflodmancc3d4422017-08-03 08:27:51 -07001009 video_stream_encoder_->TriggerCpuOveruse();
sprangc5d62e22017-04-02 23:53:04 -07001010 new_video_source.IncomingCapturedFrame(
1011 CreateFrame(frame_timestamp, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07001012 WaitForEncodedFrame(frame_timestamp);
sprangc5d62e22017-04-02 23:53:04 -07001013 frame_timestamp += kFrameIntervalMs;
1014
1015 // Still no degradation.
Mirko Bonadei948b7e32018-08-14 07:23:21 +00001016 VerifyNoLimitation(new_video_source.sink_wants());
perkj803d97f2016-11-01 11:45:46 -07001017
1018 // Calling SetSource with resolution scaling enabled apply the old SinkWants.
mflodmancc3d4422017-08-03 08:27:51 -07001019 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001020 &new_video_source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
sprangc5d62e22017-04-02 23:53:04 -07001021 EXPECT_LT(new_video_source.sink_wants().max_pixel_count,
1022 kFrameWidth * kFrameHeight);
sprang84a37592017-02-10 07:04:27 -08001023 EXPECT_FALSE(new_video_source.sink_wants().target_pixel_count);
Mirko Bonadei948b7e32018-08-14 07:23:21 +00001024 EXPECT_EQ(std::numeric_limits<int>::max(),
1025 new_video_source.sink_wants().max_framerate_fps);
sprangc5d62e22017-04-02 23:53:04 -07001026
1027 // Calling SetSource with framerate scaling enabled apply the old SinkWants.
mflodmancc3d4422017-08-03 08:27:51 -07001028 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001029 &new_video_source, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
sprangc5d62e22017-04-02 23:53:04 -07001030 EXPECT_FALSE(new_video_source.sink_wants().target_pixel_count);
1031 EXPECT_EQ(std::numeric_limits<int>::max(),
1032 new_video_source.sink_wants().max_pixel_count);
asapersson02465b82017-04-10 01:12:52 -07001033 EXPECT_LT(new_video_source.sink_wants().max_framerate_fps, kInputFps);
perkj803d97f2016-11-01 11:45:46 -07001034
mflodmancc3d4422017-08-03 08:27:51 -07001035 video_stream_encoder_->Stop();
perkj803d97f2016-11-01 11:45:46 -07001036}
1037
mflodmancc3d4422017-08-03 08:27:51 -07001038TEST_F(VideoStreamEncoderTest, StatsTracksQualityAdaptationStats) {
1039 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkj803d97f2016-11-01 11:45:46 -07001040
asaperssonfab67072017-04-04 05:51:49 -07001041 const int kWidth = 1280;
1042 const int kHeight = 720;
asaperssonfab67072017-04-04 05:51:49 -07001043 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001044 WaitForEncodedFrame(1);
asaperssonfab67072017-04-04 05:51:49 -07001045 VideoSendStream::Stats stats = stats_proxy_->GetStats();
1046 EXPECT_FALSE(stats.bw_limited_resolution);
1047 EXPECT_EQ(0, stats.number_of_quality_adapt_changes);
1048
1049 // Trigger adapt down.
mflodmancc3d4422017-08-03 08:27:51 -07001050 video_stream_encoder_->TriggerQualityLow();
asaperssonfab67072017-04-04 05:51:49 -07001051 video_source_.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001052 WaitForEncodedFrame(2);
asaperssonfab67072017-04-04 05:51:49 -07001053
1054 stats = stats_proxy_->GetStats();
1055 EXPECT_TRUE(stats.bw_limited_resolution);
1056 EXPECT_EQ(1, stats.number_of_quality_adapt_changes);
1057
1058 // Trigger adapt up.
mflodmancc3d4422017-08-03 08:27:51 -07001059 video_stream_encoder_->TriggerQualityHigh();
asaperssonfab67072017-04-04 05:51:49 -07001060 video_source_.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001061 WaitForEncodedFrame(3);
asaperssonfab67072017-04-04 05:51:49 -07001062
1063 stats = stats_proxy_->GetStats();
1064 EXPECT_FALSE(stats.bw_limited_resolution);
1065 EXPECT_EQ(2, stats.number_of_quality_adapt_changes);
1066 EXPECT_EQ(0, stats.number_of_cpu_adapt_changes);
1067
mflodmancc3d4422017-08-03 08:27:51 -07001068 video_stream_encoder_->Stop();
asaperssonfab67072017-04-04 05:51:49 -07001069}
1070
mflodmancc3d4422017-08-03 08:27:51 -07001071TEST_F(VideoStreamEncoderTest, StatsTracksCpuAdaptationStats) {
1072 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonfab67072017-04-04 05:51:49 -07001073
1074 const int kWidth = 1280;
1075 const int kHeight = 720;
asaperssonfab67072017-04-04 05:51:49 -07001076 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001077 WaitForEncodedFrame(1);
perkj803d97f2016-11-01 11:45:46 -07001078 VideoSendStream::Stats stats = stats_proxy_->GetStats();
1079 EXPECT_FALSE(stats.cpu_limited_resolution);
1080 EXPECT_EQ(0, stats.number_of_cpu_adapt_changes);
1081
1082 // Trigger CPU overuse.
mflodmancc3d4422017-08-03 08:27:51 -07001083 video_stream_encoder_->TriggerCpuOveruse();
asaperssonfab67072017-04-04 05:51:49 -07001084 video_source_.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001085 WaitForEncodedFrame(2);
perkj803d97f2016-11-01 11:45:46 -07001086
1087 stats = stats_proxy_->GetStats();
1088 EXPECT_TRUE(stats.cpu_limited_resolution);
1089 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1090
1091 // Trigger CPU normal use.
mflodmancc3d4422017-08-03 08:27:51 -07001092 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssonfab67072017-04-04 05:51:49 -07001093 video_source_.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001094 WaitForEncodedFrame(3);
perkj803d97f2016-11-01 11:45:46 -07001095
1096 stats = stats_proxy_->GetStats();
1097 EXPECT_FALSE(stats.cpu_limited_resolution);
1098 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
asaperssonfab67072017-04-04 05:51:49 -07001099 EXPECT_EQ(0, stats.number_of_quality_adapt_changes);
perkj803d97f2016-11-01 11:45:46 -07001100
mflodmancc3d4422017-08-03 08:27:51 -07001101 video_stream_encoder_->Stop();
perkj803d97f2016-11-01 11:45:46 -07001102}
1103
mflodmancc3d4422017-08-03 08:27:51 -07001104TEST_F(VideoStreamEncoderTest, SwitchingSourceKeepsCpuAdaptation) {
1105 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
kthelgason876222f2016-11-29 01:44:11 -08001106
asaperssonfab67072017-04-04 05:51:49 -07001107 const int kWidth = 1280;
1108 const int kHeight = 720;
1109 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001110 WaitForEncodedFrame(1);
kthelgason876222f2016-11-29 01:44:11 -08001111 VideoSendStream::Stats stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001112 EXPECT_FALSE(stats.bw_limited_resolution);
kthelgason876222f2016-11-29 01:44:11 -08001113 EXPECT_FALSE(stats.cpu_limited_resolution);
1114 EXPECT_EQ(0, stats.number_of_cpu_adapt_changes);
1115
asaperssonfab67072017-04-04 05:51:49 -07001116 // Trigger CPU overuse.
mflodmancc3d4422017-08-03 08:27:51 -07001117 video_stream_encoder_->TriggerCpuOveruse();
asaperssonfab67072017-04-04 05:51:49 -07001118 video_source_.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001119 WaitForEncodedFrame(2);
kthelgason876222f2016-11-29 01:44:11 -08001120 stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001121 EXPECT_FALSE(stats.bw_limited_resolution);
kthelgason876222f2016-11-29 01:44:11 -08001122 EXPECT_TRUE(stats.cpu_limited_resolution);
1123 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1124
1125 // Set new source with adaptation still enabled.
1126 test::FrameForwarder new_video_source;
mflodmancc3d4422017-08-03 08:27:51 -07001127 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001128 &new_video_source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
kthelgason876222f2016-11-29 01:44:11 -08001129
asaperssonfab67072017-04-04 05:51:49 -07001130 new_video_source.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001131 WaitForEncodedFrame(3);
kthelgason876222f2016-11-29 01:44:11 -08001132 stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001133 EXPECT_FALSE(stats.bw_limited_resolution);
kthelgason876222f2016-11-29 01:44:11 -08001134 EXPECT_TRUE(stats.cpu_limited_resolution);
1135 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1136
1137 // Set adaptation disabled.
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001138 video_stream_encoder_->SetSource(&new_video_source,
1139 webrtc::DegradationPreference::DISABLED);
kthelgason876222f2016-11-29 01:44:11 -08001140
asaperssonfab67072017-04-04 05:51:49 -07001141 new_video_source.IncomingCapturedFrame(CreateFrame(4, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001142 WaitForEncodedFrame(4);
kthelgason876222f2016-11-29 01:44:11 -08001143 stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001144 EXPECT_FALSE(stats.bw_limited_resolution);
kthelgason876222f2016-11-29 01:44:11 -08001145 EXPECT_FALSE(stats.cpu_limited_resolution);
1146 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1147
1148 // Set adaptation back to enabled.
mflodmancc3d4422017-08-03 08:27:51 -07001149 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001150 &new_video_source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
kthelgason876222f2016-11-29 01:44:11 -08001151
asaperssonfab67072017-04-04 05:51:49 -07001152 new_video_source.IncomingCapturedFrame(CreateFrame(5, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001153 WaitForEncodedFrame(5);
kthelgason876222f2016-11-29 01:44:11 -08001154 stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001155 EXPECT_FALSE(stats.bw_limited_resolution);
kthelgason876222f2016-11-29 01:44:11 -08001156 EXPECT_TRUE(stats.cpu_limited_resolution);
1157 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1158
asaperssonfab67072017-04-04 05:51:49 -07001159 // Trigger CPU normal use.
mflodmancc3d4422017-08-03 08:27:51 -07001160 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssonfab67072017-04-04 05:51:49 -07001161 new_video_source.IncomingCapturedFrame(CreateFrame(6, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001162 WaitForEncodedFrame(6);
kthelgason876222f2016-11-29 01:44:11 -08001163 stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001164 EXPECT_FALSE(stats.bw_limited_resolution);
kthelgason876222f2016-11-29 01:44:11 -08001165 EXPECT_FALSE(stats.cpu_limited_resolution);
1166 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
asapersson02465b82017-04-10 01:12:52 -07001167 EXPECT_EQ(0, stats.number_of_quality_adapt_changes);
kthelgason876222f2016-11-29 01:44:11 -08001168
mflodmancc3d4422017-08-03 08:27:51 -07001169 video_stream_encoder_->Stop();
kthelgason876222f2016-11-29 01:44:11 -08001170}
1171
mflodmancc3d4422017-08-03 08:27:51 -07001172TEST_F(VideoStreamEncoderTest, SwitchingSourceKeepsQualityAdaptation) {
1173 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
kthelgason876222f2016-11-29 01:44:11 -08001174
asaperssonfab67072017-04-04 05:51:49 -07001175 const int kWidth = 1280;
1176 const int kHeight = 720;
1177 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001178 WaitForEncodedFrame(1);
kthelgason876222f2016-11-29 01:44:11 -08001179 VideoSendStream::Stats stats = stats_proxy_->GetStats();
kthelgason876222f2016-11-29 01:44:11 -08001180 EXPECT_FALSE(stats.bw_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001181 EXPECT_FALSE(stats.bw_limited_framerate);
asaperssonfab67072017-04-04 05:51:49 -07001182 EXPECT_EQ(0, stats.number_of_quality_adapt_changes);
kthelgason876222f2016-11-29 01:44:11 -08001183
1184 // Set new source with adaptation still enabled.
1185 test::FrameForwarder new_video_source;
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001186 video_stream_encoder_->SetSource(&new_video_source,
1187 webrtc::DegradationPreference::BALANCED);
kthelgason876222f2016-11-29 01:44:11 -08001188
asaperssonfab67072017-04-04 05:51:49 -07001189 new_video_source.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001190 WaitForEncodedFrame(2);
kthelgason876222f2016-11-29 01:44:11 -08001191 stats = stats_proxy_->GetStats();
kthelgason876222f2016-11-29 01:44:11 -08001192 EXPECT_FALSE(stats.bw_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001193 EXPECT_FALSE(stats.bw_limited_framerate);
asaperssonfab67072017-04-04 05:51:49 -07001194 EXPECT_EQ(0, stats.number_of_quality_adapt_changes);
kthelgason876222f2016-11-29 01:44:11 -08001195
asaperssonfab67072017-04-04 05:51:49 -07001196 // Trigger adapt down.
mflodmancc3d4422017-08-03 08:27:51 -07001197 video_stream_encoder_->TriggerQualityLow();
asaperssonfab67072017-04-04 05:51:49 -07001198 new_video_source.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001199 WaitForEncodedFrame(3);
kthelgason876222f2016-11-29 01:44:11 -08001200 stats = stats_proxy_->GetStats();
kthelgason876222f2016-11-29 01:44:11 -08001201 EXPECT_TRUE(stats.bw_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001202 EXPECT_FALSE(stats.bw_limited_framerate);
asaperssonfab67072017-04-04 05:51:49 -07001203 EXPECT_EQ(1, stats.number_of_quality_adapt_changes);
kthelgason876222f2016-11-29 01:44:11 -08001204
asaperssonfab67072017-04-04 05:51:49 -07001205 // Set new source with adaptation still enabled.
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001206 video_stream_encoder_->SetSource(&new_video_source,
1207 webrtc::DegradationPreference::BALANCED);
kthelgason876222f2016-11-29 01:44:11 -08001208
asaperssonfab67072017-04-04 05:51:49 -07001209 new_video_source.IncomingCapturedFrame(CreateFrame(4, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001210 WaitForEncodedFrame(4);
kthelgason876222f2016-11-29 01:44:11 -08001211 stats = stats_proxy_->GetStats();
kthelgason876222f2016-11-29 01:44:11 -08001212 EXPECT_TRUE(stats.bw_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001213 EXPECT_FALSE(stats.bw_limited_framerate);
asaperssonfab67072017-04-04 05:51:49 -07001214 EXPECT_EQ(1, stats.number_of_quality_adapt_changes);
kthelgason876222f2016-11-29 01:44:11 -08001215
asapersson02465b82017-04-10 01:12:52 -07001216 // Disable resolution scaling.
mflodmancc3d4422017-08-03 08:27:51 -07001217 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001218 &new_video_source, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
kthelgason876222f2016-11-29 01:44:11 -08001219
asaperssonfab67072017-04-04 05:51:49 -07001220 new_video_source.IncomingCapturedFrame(CreateFrame(5, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001221 WaitForEncodedFrame(5);
kthelgason876222f2016-11-29 01:44:11 -08001222 stats = stats_proxy_->GetStats();
kthelgason876222f2016-11-29 01:44:11 -08001223 EXPECT_FALSE(stats.bw_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001224 EXPECT_FALSE(stats.bw_limited_framerate);
asaperssonfab67072017-04-04 05:51:49 -07001225 EXPECT_EQ(1, stats.number_of_quality_adapt_changes);
1226 EXPECT_EQ(0, stats.number_of_cpu_adapt_changes);
kthelgason876222f2016-11-29 01:44:11 -08001227
mflodmancc3d4422017-08-03 08:27:51 -07001228 video_stream_encoder_->Stop();
kthelgason876222f2016-11-29 01:44:11 -08001229}
1230
mflodmancc3d4422017-08-03 08:27:51 -07001231TEST_F(VideoStreamEncoderTest,
1232 QualityAdaptationStatsAreResetWhenScalerIsDisabled) {
1233 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson36e9eb42017-03-31 05:29:12 -07001234
1235 const int kWidth = 1280;
1236 const int kHeight = 720;
1237 video_source_.set_adaptation_enabled(true);
Mirko Bonadei948b7e32018-08-14 07:23:21 +00001238 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
1239 WaitForEncodedFrame(1);
asapersson36e9eb42017-03-31 05:29:12 -07001240 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1241 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1242 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1243
1244 // Trigger adapt down.
mflodmancc3d4422017-08-03 08:27:51 -07001245 video_stream_encoder_->TriggerQualityLow();
Mirko Bonadei948b7e32018-08-14 07:23:21 +00001246 video_source_.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
1247 WaitForEncodedFrame(2);
asapersson36e9eb42017-03-31 05:29:12 -07001248 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1249 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1250 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1251
1252 // Trigger overuse.
mflodmancc3d4422017-08-03 08:27:51 -07001253 video_stream_encoder_->TriggerCpuOveruse();
Mirko Bonadei948b7e32018-08-14 07:23:21 +00001254 video_source_.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
1255 WaitForEncodedFrame(3);
asapersson36e9eb42017-03-31 05:29:12 -07001256 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1257 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1258 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1259
Niels Möller4db138e2018-04-19 09:04:13 +02001260 // Leave source unchanged, but disable quality scaler.
asapersson36e9eb42017-03-31 05:29:12 -07001261 fake_encoder_.SetQualityScaling(false);
Niels Möller4db138e2018-04-19 09:04:13 +02001262
1263 VideoEncoderConfig video_encoder_config;
1264 test::FillEncoderConfiguration(kVideoCodecVP8, 1, &video_encoder_config);
1265 // Make format different, to force recreation of encoder.
1266 video_encoder_config.video_format.parameters["foo"] = "foo";
1267 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
Niels Möllerf1338562018-04-26 09:51:47 +02001268 kMaxPayloadLength);
Mirko Bonadei948b7e32018-08-14 07:23:21 +00001269
1270 video_source_.IncomingCapturedFrame(CreateFrame(4, kWidth, kHeight));
1271 WaitForEncodedFrame(4);
asapersson36e9eb42017-03-31 05:29:12 -07001272 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1273 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1274 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1275
mflodmancc3d4422017-08-03 08:27:51 -07001276 video_stream_encoder_->Stop();
asapersson36e9eb42017-03-31 05:29:12 -07001277}
1278
mflodmancc3d4422017-08-03 08:27:51 -07001279TEST_F(VideoStreamEncoderTest,
1280 StatsTracksCpuAdaptationStatsWhenSwitchingSource) {
1281 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkj803d97f2016-11-01 11:45:46 -07001282
asapersson0944a802017-04-07 00:57:58 -07001283 const int kWidth = 1280;
1284 const int kHeight = 720;
sprang84a37592017-02-10 07:04:27 -08001285 int sequence = 1;
perkj803d97f2016-11-01 11:45:46 -07001286
asaperssonfab67072017-04-04 05:51:49 -07001287 video_source_.IncomingCapturedFrame(CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001288 WaitForEncodedFrame(sequence++);
perkj803d97f2016-11-01 11:45:46 -07001289 VideoSendStream::Stats stats = stats_proxy_->GetStats();
sprang84a37592017-02-10 07:04:27 -08001290 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001291 EXPECT_FALSE(stats.cpu_limited_framerate);
sprang84a37592017-02-10 07:04:27 -08001292 EXPECT_EQ(0, stats.number_of_cpu_adapt_changes);
1293
asapersson02465b82017-04-10 01:12:52 -07001294 // Trigger CPU overuse, should now adapt down.
mflodmancc3d4422017-08-03 08:27:51 -07001295 video_stream_encoder_->TriggerCpuOveruse();
asaperssonfab67072017-04-04 05:51:49 -07001296 video_source_.IncomingCapturedFrame(CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001297 WaitForEncodedFrame(sequence++);
sprang84a37592017-02-10 07:04:27 -08001298 stats = stats_proxy_->GetStats();
perkj803d97f2016-11-01 11:45:46 -07001299 EXPECT_TRUE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001300 EXPECT_FALSE(stats.cpu_limited_framerate);
perkj803d97f2016-11-01 11:45:46 -07001301 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1302
1303 // Set new source with adaptation still enabled.
1304 test::FrameForwarder new_video_source;
mflodmancc3d4422017-08-03 08:27:51 -07001305 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001306 &new_video_source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
perkj803d97f2016-11-01 11:45:46 -07001307
1308 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001309 CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001310 WaitForEncodedFrame(sequence++);
perkj803d97f2016-11-01 11:45:46 -07001311 stats = stats_proxy_->GetStats();
1312 EXPECT_TRUE(stats.cpu_limited_resolution);
asapersson09f05612017-05-15 23:40:18 -07001313 EXPECT_FALSE(stats.cpu_limited_framerate);
perkj803d97f2016-11-01 11:45:46 -07001314 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1315
sprangc5d62e22017-04-02 23:53:04 -07001316 // Set cpu adaptation by frame dropping.
mflodmancc3d4422017-08-03 08:27:51 -07001317 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001318 &new_video_source, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
perkj803d97f2016-11-01 11:45:46 -07001319 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001320 CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001321 WaitForEncodedFrame(sequence++);
perkj803d97f2016-11-01 11:45:46 -07001322 stats = stats_proxy_->GetStats();
sprangc5d62e22017-04-02 23:53:04 -07001323 // Not adapted at first.
perkj803d97f2016-11-01 11:45:46 -07001324 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson09f05612017-05-15 23:40:18 -07001325 EXPECT_FALSE(stats.cpu_limited_framerate);
perkj803d97f2016-11-01 11:45:46 -07001326 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1327
sprangc5d62e22017-04-02 23:53:04 -07001328 // Force an input frame rate to be available, or the adaptation call won't
asapersson09f05612017-05-15 23:40:18 -07001329 // know what framerate to adapt from.
sprangc5d62e22017-04-02 23:53:04 -07001330 VideoSendStream::Stats mock_stats = stats_proxy_->GetStats();
1331 mock_stats.input_frame_rate = 30;
1332 stats_proxy_->SetMockStats(mock_stats);
mflodmancc3d4422017-08-03 08:27:51 -07001333 video_stream_encoder_->TriggerCpuOveruse();
sprangc5d62e22017-04-02 23:53:04 -07001334 stats_proxy_->ResetMockStats();
1335
1336 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001337 CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001338 WaitForEncodedFrame(sequence++);
sprangc5d62e22017-04-02 23:53:04 -07001339
1340 // Framerate now adapted.
1341 stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001342 EXPECT_FALSE(stats.cpu_limited_resolution);
1343 EXPECT_TRUE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001344 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
1345
1346 // Disable CPU adaptation.
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001347 video_stream_encoder_->SetSource(&new_video_source,
1348 webrtc::DegradationPreference::DISABLED);
sprangc5d62e22017-04-02 23:53:04 -07001349 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001350 CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001351 WaitForEncodedFrame(sequence++);
sprangc5d62e22017-04-02 23:53:04 -07001352
1353 stats = stats_proxy_->GetStats();
1354 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001355 EXPECT_FALSE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001356 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
1357
1358 // Try to trigger overuse. Should not succeed.
1359 stats_proxy_->SetMockStats(mock_stats);
mflodmancc3d4422017-08-03 08:27:51 -07001360 video_stream_encoder_->TriggerCpuOveruse();
sprangc5d62e22017-04-02 23:53:04 -07001361 stats_proxy_->ResetMockStats();
1362
1363 stats = stats_proxy_->GetStats();
1364 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001365 EXPECT_FALSE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001366 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
1367
1368 // Switch back the source with resolution adaptation enabled.
mflodmancc3d4422017-08-03 08:27:51 -07001369 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001370 &video_source_, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
asaperssonfab67072017-04-04 05:51:49 -07001371 video_source_.IncomingCapturedFrame(CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001372 WaitForEncodedFrame(sequence++);
perkj803d97f2016-11-01 11:45:46 -07001373 stats = stats_proxy_->GetStats();
1374 EXPECT_TRUE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001375 EXPECT_FALSE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001376 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
perkj803d97f2016-11-01 11:45:46 -07001377
1378 // Trigger CPU normal usage.
mflodmancc3d4422017-08-03 08:27:51 -07001379 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssonfab67072017-04-04 05:51:49 -07001380 video_source_.IncomingCapturedFrame(CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001381 WaitForEncodedFrame(sequence++);
perkj803d97f2016-11-01 11:45:46 -07001382 stats = stats_proxy_->GetStats();
1383 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001384 EXPECT_FALSE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001385 EXPECT_EQ(3, stats.number_of_cpu_adapt_changes);
1386
1387 // Back to the source with adaptation off, set it back to maintain-resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001388 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001389 &new_video_source, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
sprangc5d62e22017-04-02 23:53:04 -07001390 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001391 CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001392 WaitForEncodedFrame(sequence++);
sprangc5d62e22017-04-02 23:53:04 -07001393 stats = stats_proxy_->GetStats();
asapersson13874762017-06-07 00:01:02 -07001394 // Disabled, since we previously switched the source to disabled.
sprangc5d62e22017-04-02 23:53:04 -07001395 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001396 EXPECT_TRUE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001397 EXPECT_EQ(3, stats.number_of_cpu_adapt_changes);
1398
1399 // Trigger CPU normal usage.
mflodmancc3d4422017-08-03 08:27:51 -07001400 video_stream_encoder_->TriggerCpuNormalUsage();
sprangc5d62e22017-04-02 23:53:04 -07001401 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001402 CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001403 WaitForEncodedFrame(sequence++);
sprangc5d62e22017-04-02 23:53:04 -07001404 stats = stats_proxy_->GetStats();
1405 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001406 EXPECT_FALSE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001407 EXPECT_EQ(4, stats.number_of_cpu_adapt_changes);
asapersson02465b82017-04-10 01:12:52 -07001408 EXPECT_EQ(0, stats.number_of_quality_adapt_changes);
perkj803d97f2016-11-01 11:45:46 -07001409
mflodmancc3d4422017-08-03 08:27:51 -07001410 video_stream_encoder_->Stop();
perkj803d97f2016-11-01 11:45:46 -07001411}
1412
mflodmancc3d4422017-08-03 08:27:51 -07001413TEST_F(VideoStreamEncoderTest,
1414 ScalingUpAndDownDoesNothingWithMaintainResolution) {
asaperssonfab67072017-04-04 05:51:49 -07001415 const int kWidth = 1280;
1416 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001417 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
kthelgason876222f2016-11-29 01:44:11 -08001418
asaperssonfab67072017-04-04 05:51:49 -07001419 // Expect no scaling to begin with.
asapersson02465b82017-04-10 01:12:52 -07001420 VerifyNoLimitation(video_source_.sink_wants());
kthelgason876222f2016-11-29 01:44:11 -08001421
asaperssonfab67072017-04-04 05:51:49 -07001422 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001423 WaitForEncodedFrame(1);
kthelgason876222f2016-11-29 01:44:11 -08001424
asaperssonfab67072017-04-04 05:51:49 -07001425 // Trigger scale down.
mflodmancc3d4422017-08-03 08:27:51 -07001426 video_stream_encoder_->TriggerQualityLow();
kthelgason5e13d412016-12-01 03:59:51 -08001427
asaperssonfab67072017-04-04 05:51:49 -07001428 video_source_.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001429 WaitForEncodedFrame(2);
kthelgason5e13d412016-12-01 03:59:51 -08001430
kthelgason876222f2016-11-29 01:44:11 -08001431 // Expect a scale down.
1432 EXPECT_TRUE(video_source_.sink_wants().max_pixel_count);
asaperssonfab67072017-04-04 05:51:49 -07001433 EXPECT_LT(video_source_.sink_wants().max_pixel_count, kWidth * kHeight);
kthelgason876222f2016-11-29 01:44:11 -08001434
asapersson02465b82017-04-10 01:12:52 -07001435 // Set resolution scaling disabled.
kthelgason876222f2016-11-29 01:44:11 -08001436 test::FrameForwarder new_video_source;
mflodmancc3d4422017-08-03 08:27:51 -07001437 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001438 &new_video_source, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
kthelgason876222f2016-11-29 01:44:11 -08001439
asaperssonfab67072017-04-04 05:51:49 -07001440 // Trigger scale down.
mflodmancc3d4422017-08-03 08:27:51 -07001441 video_stream_encoder_->TriggerQualityLow();
asaperssonfab67072017-04-04 05:51:49 -07001442 new_video_source.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001443 WaitForEncodedFrame(3);
kthelgason876222f2016-11-29 01:44:11 -08001444
asaperssonfab67072017-04-04 05:51:49 -07001445 // Expect no scaling.
sprangc5d62e22017-04-02 23:53:04 -07001446 EXPECT_EQ(std::numeric_limits<int>::max(),
1447 new_video_source.sink_wants().max_pixel_count);
kthelgason876222f2016-11-29 01:44:11 -08001448
asaperssonfab67072017-04-04 05:51:49 -07001449 // Trigger scale up.
mflodmancc3d4422017-08-03 08:27:51 -07001450 video_stream_encoder_->TriggerQualityHigh();
asaperssonfab67072017-04-04 05:51:49 -07001451 new_video_source.IncomingCapturedFrame(CreateFrame(4, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001452 WaitForEncodedFrame(4);
kthelgason876222f2016-11-29 01:44:11 -08001453
asapersson02465b82017-04-10 01:12:52 -07001454 // Expect nothing to change, still no scaling.
sprangc5d62e22017-04-02 23:53:04 -07001455 EXPECT_EQ(std::numeric_limits<int>::max(),
1456 new_video_source.sink_wants().max_pixel_count);
kthelgason876222f2016-11-29 01:44:11 -08001457
mflodmancc3d4422017-08-03 08:27:51 -07001458 video_stream_encoder_->Stop();
kthelgason876222f2016-11-29 01:44:11 -08001459}
1460
mflodmancc3d4422017-08-03 08:27:51 -07001461TEST_F(VideoStreamEncoderTest,
1462 SkipsSameAdaptDownRequest_MaintainFramerateMode) {
asapersson02465b82017-04-10 01:12:52 -07001463 const int kWidth = 1280;
1464 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001465 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson02465b82017-04-10 01:12:52 -07001466
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001467 // Enable MAINTAIN_FRAMERATE preference, no initial limitation.
asapersson02465b82017-04-10 01:12:52 -07001468 test::FrameForwarder source;
mflodmancc3d4422017-08-03 08:27:51 -07001469 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001470 &source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
asapersson02465b82017-04-10 01:12:52 -07001471
1472 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001473 WaitForEncodedFrame(1);
Mirko Bonadei948b7e32018-08-14 07:23:21 +00001474 VerifyNoLimitation(source.sink_wants());
asapersson02465b82017-04-10 01:12:52 -07001475 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1476 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1477
1478 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001479 video_stream_encoder_->TriggerCpuOveruse();
asapersson09f05612017-05-15 23:40:18 -07001480 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
asapersson02465b82017-04-10 01:12:52 -07001481 const int kLastMaxPixelCount = source.sink_wants().max_pixel_count;
1482 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1483 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1484
1485 // Trigger adapt down for same input resolution, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07001486 video_stream_encoder_->TriggerCpuOveruse();
asapersson02465b82017-04-10 01:12:52 -07001487 EXPECT_EQ(kLastMaxPixelCount, source.sink_wants().max_pixel_count);
1488 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1489 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1490
mflodmancc3d4422017-08-03 08:27:51 -07001491 video_stream_encoder_->Stop();
asapersson02465b82017-04-10 01:12:52 -07001492}
1493
mflodmancc3d4422017-08-03 08:27:51 -07001494TEST_F(VideoStreamEncoderTest, SkipsSameOrLargerAdaptDownRequest_BalancedMode) {
asaperssonf7e294d2017-06-13 23:25:22 -07001495 const int kWidth = 1280;
1496 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001497 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -07001498
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001499 // Enable BALANCED preference, no initial limitation.
asaperssonf7e294d2017-06-13 23:25:22 -07001500 test::FrameForwarder source;
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001501 video_stream_encoder_->SetSource(&source,
1502 webrtc::DegradationPreference::BALANCED);
asaperssonf7e294d2017-06-13 23:25:22 -07001503 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
1504 sink_.WaitForEncodedFrame(1);
Mirko Bonadei948b7e32018-08-14 07:23:21 +00001505 VerifyNoLimitation(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07001506
1507 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001508 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07001509 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
1510 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1511 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1512 const int kLastMaxPixelCount = source.sink_wants().max_pixel_count;
1513
1514 // Trigger adapt down for same input resolution, expect no change.
1515 source.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
1516 sink_.WaitForEncodedFrame(2);
mflodmancc3d4422017-08-03 08:27:51 -07001517 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07001518 EXPECT_EQ(kLastMaxPixelCount, source.sink_wants().max_pixel_count);
1519 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1520 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1521
1522 // Trigger adapt down for larger input resolution, expect no change.
1523 source.IncomingCapturedFrame(CreateFrame(3, kWidth + 1, kHeight + 1));
1524 sink_.WaitForEncodedFrame(3);
mflodmancc3d4422017-08-03 08:27:51 -07001525 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07001526 EXPECT_EQ(kLastMaxPixelCount, source.sink_wants().max_pixel_count);
1527 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1528 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1529
mflodmancc3d4422017-08-03 08:27:51 -07001530 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07001531}
1532
mflodmancc3d4422017-08-03 08:27:51 -07001533TEST_F(VideoStreamEncoderTest,
1534 NoChangeForInitialNormalUsage_MaintainFramerateMode) {
asapersson02465b82017-04-10 01:12:52 -07001535 const int kWidth = 1280;
1536 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001537 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson02465b82017-04-10 01:12:52 -07001538
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001539 // Enable MAINTAIN_FRAMERATE preference, no initial limitation.
asapersson02465b82017-04-10 01:12:52 -07001540 test::FrameForwarder source;
mflodmancc3d4422017-08-03 08:27:51 -07001541 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001542 &source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
asapersson02465b82017-04-10 01:12:52 -07001543
1544 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001545 WaitForEncodedFrame(kWidth, kHeight);
Mirko Bonadei948b7e32018-08-14 07:23:21 +00001546 VerifyNoLimitation(source.sink_wants());
asapersson02465b82017-04-10 01:12:52 -07001547 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1548 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1549
1550 // Trigger adapt up, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07001551 video_stream_encoder_->TriggerCpuNormalUsage();
Mirko Bonadei948b7e32018-08-14 07:23:21 +00001552 VerifyNoLimitation(source.sink_wants());
asapersson02465b82017-04-10 01:12:52 -07001553 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1554 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1555
mflodmancc3d4422017-08-03 08:27:51 -07001556 video_stream_encoder_->Stop();
asapersson02465b82017-04-10 01:12:52 -07001557}
1558
mflodmancc3d4422017-08-03 08:27:51 -07001559TEST_F(VideoStreamEncoderTest,
1560 NoChangeForInitialNormalUsage_MaintainResolutionMode) {
asapersson02465b82017-04-10 01:12:52 -07001561 const int kWidth = 1280;
1562 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001563 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson02465b82017-04-10 01:12:52 -07001564
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001565 // Enable MAINTAIN_RESOLUTION preference, no initial limitation.
asapersson02465b82017-04-10 01:12:52 -07001566 test::FrameForwarder source;
mflodmancc3d4422017-08-03 08:27:51 -07001567 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001568 &source, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
asapersson02465b82017-04-10 01:12:52 -07001569
1570 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001571 WaitForEncodedFrame(kWidth, kHeight);
Mirko Bonadei948b7e32018-08-14 07:23:21 +00001572 VerifyNoLimitation(source.sink_wants());
asapersson09f05612017-05-15 23:40:18 -07001573 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
asapersson02465b82017-04-10 01:12:52 -07001574 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1575
1576 // Trigger adapt up, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07001577 video_stream_encoder_->TriggerCpuNormalUsage();
Mirko Bonadei948b7e32018-08-14 07:23:21 +00001578 VerifyNoLimitation(source.sink_wants());
asapersson09f05612017-05-15 23:40:18 -07001579 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
asapersson02465b82017-04-10 01:12:52 -07001580 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1581
mflodmancc3d4422017-08-03 08:27:51 -07001582 video_stream_encoder_->Stop();
asapersson02465b82017-04-10 01:12:52 -07001583}
1584
mflodmancc3d4422017-08-03 08:27:51 -07001585TEST_F(VideoStreamEncoderTest, NoChangeForInitialNormalUsage_BalancedMode) {
asaperssonf7e294d2017-06-13 23:25:22 -07001586 const int kWidth = 1280;
1587 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001588 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -07001589
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001590 // Enable BALANCED preference, no initial limitation.
asaperssonf7e294d2017-06-13 23:25:22 -07001591 test::FrameForwarder source;
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001592 video_stream_encoder_->SetSource(&source,
1593 webrtc::DegradationPreference::BALANCED);
asaperssonf7e294d2017-06-13 23:25:22 -07001594
1595 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
1596 sink_.WaitForEncodedFrame(kWidth, kHeight);
Mirko Bonadei948b7e32018-08-14 07:23:21 +00001597 VerifyNoLimitation(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07001598 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1599 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
1600 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1601
1602 // Trigger adapt up, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07001603 video_stream_encoder_->TriggerQualityHigh();
Mirko Bonadei948b7e32018-08-14 07:23:21 +00001604 VerifyNoLimitation(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07001605 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1606 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
1607 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1608
mflodmancc3d4422017-08-03 08:27:51 -07001609 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07001610}
1611
mflodmancc3d4422017-08-03 08:27:51 -07001612TEST_F(VideoStreamEncoderTest, NoChangeForInitialNormalUsage_DisabledMode) {
asapersson09f05612017-05-15 23:40:18 -07001613 const int kWidth = 1280;
1614 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001615 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson09f05612017-05-15 23:40:18 -07001616
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001617 // Enable DISABLED preference, no initial limitation.
asapersson09f05612017-05-15 23:40:18 -07001618 test::FrameForwarder source;
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001619 video_stream_encoder_->SetSource(&source,
1620 webrtc::DegradationPreference::DISABLED);
asapersson09f05612017-05-15 23:40:18 -07001621
1622 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
1623 sink_.WaitForEncodedFrame(kWidth, kHeight);
Mirko Bonadei948b7e32018-08-14 07:23:21 +00001624 VerifyNoLimitation(source.sink_wants());
asapersson09f05612017-05-15 23:40:18 -07001625 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1626 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
1627 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1628
1629 // Trigger adapt up, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07001630 video_stream_encoder_->TriggerQualityHigh();
Mirko Bonadei948b7e32018-08-14 07:23:21 +00001631 VerifyNoLimitation(source.sink_wants());
asapersson09f05612017-05-15 23:40:18 -07001632 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1633 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
1634 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1635
mflodmancc3d4422017-08-03 08:27:51 -07001636 video_stream_encoder_->Stop();
asapersson09f05612017-05-15 23:40:18 -07001637}
1638
mflodmancc3d4422017-08-03 08:27:51 -07001639TEST_F(VideoStreamEncoderTest,
1640 AdaptsResolutionForLowQuality_MaintainFramerateMode) {
asapersson02465b82017-04-10 01:12:52 -07001641 const int kWidth = 1280;
1642 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001643 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson02465b82017-04-10 01:12:52 -07001644
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001645 // Enable MAINTAIN_FRAMERATE preference, no initial limitation.
asapersson02465b82017-04-10 01:12:52 -07001646 AdaptingFrameForwarder source;
1647 source.set_adaptation_enabled(true);
mflodmancc3d4422017-08-03 08:27:51 -07001648 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001649 &source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
asapersson02465b82017-04-10 01:12:52 -07001650
1651 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001652 WaitForEncodedFrame(1);
Mirko Bonadei948b7e32018-08-14 07:23:21 +00001653 VerifyNoLimitation(source.sink_wants());
asapersson02465b82017-04-10 01:12:52 -07001654 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1655 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1656
1657 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001658 video_stream_encoder_->TriggerQualityLow();
asapersson02465b82017-04-10 01:12:52 -07001659 source.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001660 WaitForEncodedFrame(2);
asapersson09f05612017-05-15 23:40:18 -07001661 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
asapersson02465b82017-04-10 01:12:52 -07001662 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1663 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1664
1665 // Trigger adapt up, expect no restriction.
mflodmancc3d4422017-08-03 08:27:51 -07001666 video_stream_encoder_->TriggerQualityHigh();
Mirko Bonadei948b7e32018-08-14 07:23:21 +00001667 VerifyNoLimitation(source.sink_wants());
asapersson02465b82017-04-10 01:12:52 -07001668 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1669 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1670 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1671
mflodmancc3d4422017-08-03 08:27:51 -07001672 video_stream_encoder_->Stop();
asapersson02465b82017-04-10 01:12:52 -07001673}
1674
mflodmancc3d4422017-08-03 08:27:51 -07001675TEST_F(VideoStreamEncoderTest,
1676 AdaptsFramerateForLowQuality_MaintainResolutionMode) {
asapersson09f05612017-05-15 23:40:18 -07001677 const int kWidth = 1280;
1678 const int kHeight = 720;
1679 const int kInputFps = 30;
mflodmancc3d4422017-08-03 08:27:51 -07001680 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson09f05612017-05-15 23:40:18 -07001681
1682 VideoSendStream::Stats stats = stats_proxy_->GetStats();
1683 stats.input_frame_rate = kInputFps;
1684 stats_proxy_->SetMockStats(stats);
1685
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001686 // Expect no scaling to begin with (preference: MAINTAIN_FRAMERATE).
asapersson09f05612017-05-15 23:40:18 -07001687 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
1688 sink_.WaitForEncodedFrame(1);
Mirko Bonadei948b7e32018-08-14 07:23:21 +00001689 VerifyNoLimitation(video_source_.sink_wants());
asapersson09f05612017-05-15 23:40:18 -07001690
1691 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001692 video_stream_encoder_->TriggerQualityLow();
asapersson09f05612017-05-15 23:40:18 -07001693 video_source_.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
1694 sink_.WaitForEncodedFrame(2);
1695 VerifyFpsMaxResolutionLt(video_source_.sink_wants(), kWidth * kHeight);
1696
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001697 // Enable MAINTAIN_RESOLUTION preference.
asapersson09f05612017-05-15 23:40:18 -07001698 test::FrameForwarder new_video_source;
mflodmancc3d4422017-08-03 08:27:51 -07001699 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001700 &new_video_source, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
Mirko Bonadei948b7e32018-08-14 07:23:21 +00001701 VerifyNoLimitation(new_video_source.sink_wants());
asapersson09f05612017-05-15 23:40:18 -07001702
1703 // Trigger adapt down, expect reduced framerate.
mflodmancc3d4422017-08-03 08:27:51 -07001704 video_stream_encoder_->TriggerQualityLow();
asapersson09f05612017-05-15 23:40:18 -07001705 new_video_source.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
1706 sink_.WaitForEncodedFrame(3);
1707 VerifyFpsLtResolutionMax(new_video_source.sink_wants(), kInputFps);
1708
1709 // Trigger adapt up, expect no restriction.
mflodmancc3d4422017-08-03 08:27:51 -07001710 video_stream_encoder_->TriggerQualityHigh();
Mirko Bonadei948b7e32018-08-14 07:23:21 +00001711 VerifyNoLimitation(new_video_source.sink_wants());
asapersson09f05612017-05-15 23:40:18 -07001712
mflodmancc3d4422017-08-03 08:27:51 -07001713 video_stream_encoder_->Stop();
asapersson09f05612017-05-15 23:40:18 -07001714}
1715
mflodmancc3d4422017-08-03 08:27:51 -07001716TEST_F(VideoStreamEncoderTest, DoesNotScaleBelowSetResolutionLimit) {
asaperssond0de2952017-04-21 01:47:31 -07001717 const int kWidth = 1280;
1718 const int kHeight = 720;
1719 const size_t kNumFrames = 10;
1720
mflodmancc3d4422017-08-03 08:27:51 -07001721 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
kthelgason5e13d412016-12-01 03:59:51 -08001722
asaperssond0de2952017-04-21 01:47:31 -07001723 // Enable adapter, expected input resolutions when downscaling:
asapersson142fcc92017-08-17 08:58:54 -07001724 // 1280x720 -> 960x540 -> 640x360 -> 480x270 -> 320x180 (kMinPixelsPerFrame)
asaperssond0de2952017-04-21 01:47:31 -07001725 video_source_.set_adaptation_enabled(true);
1726
1727 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1728 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1729
1730 int downscales = 0;
1731 for (size_t i = 1; i <= kNumFrames; i++) {
Mirko Bonadei948b7e32018-08-14 07:23:21 +00001732 video_source_.IncomingCapturedFrame(CreateFrame(i, kWidth, kHeight));
1733 WaitForEncodedFrame(i);
asaperssond0de2952017-04-21 01:47:31 -07001734
asaperssonfab67072017-04-04 05:51:49 -07001735 // Trigger scale down.
asaperssond0de2952017-04-21 01:47:31 -07001736 rtc::VideoSinkWants last_wants = video_source_.sink_wants();
mflodmancc3d4422017-08-03 08:27:51 -07001737 video_stream_encoder_->TriggerQualityLow();
sprangc5d62e22017-04-02 23:53:04 -07001738 EXPECT_GE(video_source_.sink_wants().max_pixel_count, kMinPixelsPerFrame);
asaperssond0de2952017-04-21 01:47:31 -07001739
1740 if (video_source_.sink_wants().max_pixel_count < last_wants.max_pixel_count)
1741 ++downscales;
1742
1743 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1744 EXPECT_EQ(downscales,
1745 stats_proxy_->GetStats().number_of_quality_adapt_changes);
1746 EXPECT_GT(downscales, 0);
kthelgason5e13d412016-12-01 03:59:51 -08001747 }
mflodmancc3d4422017-08-03 08:27:51 -07001748 video_stream_encoder_->Stop();
asaperssond0de2952017-04-21 01:47:31 -07001749}
1750
mflodmancc3d4422017-08-03 08:27:51 -07001751TEST_F(VideoStreamEncoderTest,
asaperssond0de2952017-04-21 01:47:31 -07001752 AdaptsResolutionUpAndDownTwiceOnOveruse_MaintainFramerateMode) {
1753 const int kWidth = 1280;
1754 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001755 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssond0de2952017-04-21 01:47:31 -07001756
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001757 // Enable MAINTAIN_FRAMERATE preference, no initial limitation.
asaperssond0de2952017-04-21 01:47:31 -07001758 AdaptingFrameForwarder source;
1759 source.set_adaptation_enabled(true);
mflodmancc3d4422017-08-03 08:27:51 -07001760 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001761 &source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
asaperssond0de2952017-04-21 01:47:31 -07001762
Mirko Bonadei948b7e32018-08-14 07:23:21 +00001763 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001764 WaitForEncodedFrame(kWidth, kHeight);
Mirko Bonadei948b7e32018-08-14 07:23:21 +00001765 VerifyNoLimitation(source.sink_wants());
asaperssond0de2952017-04-21 01:47:31 -07001766 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1767 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1768
1769 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001770 video_stream_encoder_->TriggerCpuOveruse();
Mirko Bonadei948b7e32018-08-14 07:23:21 +00001771 source.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
1772 WaitForEncodedFrame(2);
asapersson09f05612017-05-15 23:40:18 -07001773 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
asaperssond0de2952017-04-21 01:47:31 -07001774 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1775 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1776
1777 // Trigger adapt up, expect no restriction.
mflodmancc3d4422017-08-03 08:27:51 -07001778 video_stream_encoder_->TriggerCpuNormalUsage();
Mirko Bonadei948b7e32018-08-14 07:23:21 +00001779 source.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001780 WaitForEncodedFrame(kWidth, kHeight);
Mirko Bonadei948b7e32018-08-14 07:23:21 +00001781 VerifyNoLimitation(source.sink_wants());
asaperssond0de2952017-04-21 01:47:31 -07001782 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1783 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1784
1785 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001786 video_stream_encoder_->TriggerCpuOveruse();
Mirko Bonadei948b7e32018-08-14 07:23:21 +00001787 source.IncomingCapturedFrame(CreateFrame(4, kWidth, kHeight));
1788 WaitForEncodedFrame(4);
asapersson09f05612017-05-15 23:40:18 -07001789 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
asaperssond0de2952017-04-21 01:47:31 -07001790 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1791 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1792
1793 // Trigger adapt up, expect no restriction.
mflodmancc3d4422017-08-03 08:27:51 -07001794 video_stream_encoder_->TriggerCpuNormalUsage();
Mirko Bonadei948b7e32018-08-14 07:23:21 +00001795 source.IncomingCapturedFrame(CreateFrame(5, kWidth, kHeight));
asapersson09f05612017-05-15 23:40:18 -07001796 sink_.WaitForEncodedFrame(kWidth, kHeight);
Mirko Bonadei948b7e32018-08-14 07:23:21 +00001797 VerifyNoLimitation(source.sink_wants());
asaperssond0de2952017-04-21 01:47:31 -07001798 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1799 EXPECT_EQ(4, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1800
mflodmancc3d4422017-08-03 08:27:51 -07001801 video_stream_encoder_->Stop();
asaperssond0de2952017-04-21 01:47:31 -07001802}
1803
mflodmancc3d4422017-08-03 08:27:51 -07001804TEST_F(VideoStreamEncoderTest,
asaperssonf7e294d2017-06-13 23:25:22 -07001805 AdaptsResolutionUpAndDownTwiceForLowQuality_BalancedMode_NoFpsLimit) {
1806 const int kWidth = 1280;
1807 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001808 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -07001809
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001810 // Enable BALANCED preference, no initial limitation.
asaperssonf7e294d2017-06-13 23:25:22 -07001811 AdaptingFrameForwarder source;
1812 source.set_adaptation_enabled(true);
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001813 video_stream_encoder_->SetSource(&source,
1814 webrtc::DegradationPreference::BALANCED);
asaperssonf7e294d2017-06-13 23:25:22 -07001815
Mirko Bonadei948b7e32018-08-14 07:23:21 +00001816 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
asaperssonf7e294d2017-06-13 23:25:22 -07001817 sink_.WaitForEncodedFrame(kWidth, kHeight);
Mirko Bonadei948b7e32018-08-14 07:23:21 +00001818 VerifyNoLimitation(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07001819 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1820 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1821
1822 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001823 video_stream_encoder_->TriggerQualityLow();
Mirko Bonadei948b7e32018-08-14 07:23:21 +00001824 source.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
1825 sink_.WaitForEncodedFrame(2);
asaperssonf7e294d2017-06-13 23:25:22 -07001826 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
1827 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1828 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1829
1830 // Trigger adapt up, expect no restriction.
mflodmancc3d4422017-08-03 08:27:51 -07001831 video_stream_encoder_->TriggerQualityHigh();
Mirko Bonadei948b7e32018-08-14 07:23:21 +00001832 source.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
asaperssonf7e294d2017-06-13 23:25:22 -07001833 sink_.WaitForEncodedFrame(kWidth, kHeight);
Mirko Bonadei948b7e32018-08-14 07:23:21 +00001834 VerifyNoLimitation(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07001835 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1836 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1837
1838 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001839 video_stream_encoder_->TriggerQualityLow();
Mirko Bonadei948b7e32018-08-14 07:23:21 +00001840 source.IncomingCapturedFrame(CreateFrame(4, kWidth, kHeight));
1841 sink_.WaitForEncodedFrame(4);
asaperssonf7e294d2017-06-13 23:25:22 -07001842 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
1843 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1844 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1845
1846 // Trigger adapt up, expect no restriction.
mflodmancc3d4422017-08-03 08:27:51 -07001847 video_stream_encoder_->TriggerQualityHigh();
Mirko Bonadei948b7e32018-08-14 07:23:21 +00001848 source.IncomingCapturedFrame(CreateFrame(5, kWidth, kHeight));
asaperssonf7e294d2017-06-13 23:25:22 -07001849 sink_.WaitForEncodedFrame(kWidth, kHeight);
Mirko Bonadei948b7e32018-08-14 07:23:21 +00001850 VerifyNoLimitation(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07001851 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1852 EXPECT_EQ(4, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1853
mflodmancc3d4422017-08-03 08:27:51 -07001854 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07001855}
1856
mflodmancc3d4422017-08-03 08:27:51 -07001857TEST_F(VideoStreamEncoderTest,
asaperssond0de2952017-04-21 01:47:31 -07001858 AdaptsResolutionOnOveruseAndLowQuality_MaintainFramerateMode) {
1859 const int kWidth = 1280;
1860 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001861 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssond0de2952017-04-21 01:47:31 -07001862
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001863 // Enable MAINTAIN_FRAMERATE preference, no initial limitation.
asaperssond0de2952017-04-21 01:47:31 -07001864 AdaptingFrameForwarder source;
1865 source.set_adaptation_enabled(true);
mflodmancc3d4422017-08-03 08:27:51 -07001866 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001867 &source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
asaperssond0de2952017-04-21 01:47:31 -07001868
Mirko Bonadei948b7e32018-08-14 07:23:21 +00001869 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001870 WaitForEncodedFrame(kWidth, kHeight);
Mirko Bonadei948b7e32018-08-14 07:23:21 +00001871 VerifyNoLimitation(source.sink_wants());
asaperssond0de2952017-04-21 01:47:31 -07001872 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1873 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1874 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1875 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1876
1877 // Trigger cpu adapt down, expect scaled down resolution (960x540).
mflodmancc3d4422017-08-03 08:27:51 -07001878 video_stream_encoder_->TriggerCpuOveruse();
Mirko Bonadei948b7e32018-08-14 07:23:21 +00001879 source.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
1880 WaitForEncodedFrame(2);
asapersson09f05612017-05-15 23:40:18 -07001881 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
asaperssond0de2952017-04-21 01:47:31 -07001882 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1883 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1884 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1885 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1886
1887 // Trigger cpu adapt down, expect scaled down resolution (640x360).
mflodmancc3d4422017-08-03 08:27:51 -07001888 video_stream_encoder_->TriggerCpuOveruse();
Mirko Bonadei948b7e32018-08-14 07:23:21 +00001889 source.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
1890 WaitForEncodedFrame(3);
asapersson09f05612017-05-15 23:40:18 -07001891 VerifyFpsMaxResolutionLt(source.sink_wants(), source.last_wants());
asaperssond0de2952017-04-21 01:47:31 -07001892 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1893 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1894 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1895 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1896
Jonathan Yubc771b72017-12-08 17:04:29 -08001897 // Trigger cpu adapt down, expect scaled down resolution (480x270).
mflodmancc3d4422017-08-03 08:27:51 -07001898 video_stream_encoder_->TriggerCpuOveruse();
Mirko Bonadei948b7e32018-08-14 07:23:21 +00001899 source.IncomingCapturedFrame(CreateFrame(4, kWidth, kHeight));
1900 WaitForEncodedFrame(4);
Jonathan Yubc771b72017-12-08 17:04:29 -08001901 VerifyFpsMaxResolutionLt(source.sink_wants(), source.last_wants());
asaperssond0de2952017-04-21 01:47:31 -07001902 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1903 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
Jonathan Yubc771b72017-12-08 17:04:29 -08001904 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
asaperssond0de2952017-04-21 01:47:31 -07001905 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1906
Jonathan Yubc771b72017-12-08 17:04:29 -08001907 // Trigger quality adapt down, expect scaled down resolution (320x180).
mflodmancc3d4422017-08-03 08:27:51 -07001908 video_stream_encoder_->TriggerQualityLow();
Mirko Bonadei948b7e32018-08-14 07:23:21 +00001909 source.IncomingCapturedFrame(CreateFrame(5, kWidth, kHeight));
1910 WaitForEncodedFrame(5);
asapersson09f05612017-05-15 23:40:18 -07001911 VerifyFpsMaxResolutionLt(source.sink_wants(), source.last_wants());
Jonathan Yubc771b72017-12-08 17:04:29 -08001912 rtc::VideoSinkWants last_wants = source.sink_wants();
asaperssond0de2952017-04-21 01:47:31 -07001913 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1914 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1915 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1916 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1917
Jonathan Yubc771b72017-12-08 17:04:29 -08001918 // Trigger quality adapt down, expect no change (min resolution reached).
1919 video_stream_encoder_->TriggerQualityLow();
Mirko Bonadei948b7e32018-08-14 07:23:21 +00001920 source.IncomingCapturedFrame(CreateFrame(6, kWidth, kHeight));
1921 WaitForEncodedFrame(6);
Jonathan Yubc771b72017-12-08 17:04:29 -08001922 VerifyFpsMaxResolutionEq(source.sink_wants(), last_wants);
1923 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1924 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1925 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1926 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1927
1928 // Trigger cpu adapt up, expect upscaled resolution (480x270).
mflodmancc3d4422017-08-03 08:27:51 -07001929 video_stream_encoder_->TriggerCpuNormalUsage();
Mirko Bonadei948b7e32018-08-14 07:23:21 +00001930 source.IncomingCapturedFrame(CreateFrame(7, kWidth, kHeight));
1931 WaitForEncodedFrame(7);
asapersson09f05612017-05-15 23:40:18 -07001932 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
Jonathan Yubc771b72017-12-08 17:04:29 -08001933 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1934 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1935 EXPECT_EQ(4, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1936 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1937
1938 // Trigger cpu adapt up, expect upscaled resolution (640x360).
1939 video_stream_encoder_->TriggerCpuNormalUsage();
Mirko Bonadei948b7e32018-08-14 07:23:21 +00001940 source.IncomingCapturedFrame(CreateFrame(8, kWidth, kHeight));
1941 WaitForEncodedFrame(8);
Jonathan Yubc771b72017-12-08 17:04:29 -08001942 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
1943 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1944 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1945 EXPECT_EQ(5, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1946 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1947
1948 // Trigger cpu adapt up, expect upscaled resolution (960x540).
1949 video_stream_encoder_->TriggerCpuNormalUsage();
Mirko Bonadei948b7e32018-08-14 07:23:21 +00001950 source.IncomingCapturedFrame(CreateFrame(9, kWidth, kHeight));
1951 WaitForEncodedFrame(9);
Jonathan Yubc771b72017-12-08 17:04:29 -08001952 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
asaperssond0de2952017-04-21 01:47:31 -07001953 last_wants = source.sink_wants();
1954 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1955 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
Jonathan Yubc771b72017-12-08 17:04:29 -08001956 EXPECT_EQ(6, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
asaperssond0de2952017-04-21 01:47:31 -07001957 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1958
1959 // Trigger cpu adapt up, no cpu downgrades, expect no change (960x540).
mflodmancc3d4422017-08-03 08:27:51 -07001960 video_stream_encoder_->TriggerCpuNormalUsage();
Mirko Bonadei948b7e32018-08-14 07:23:21 +00001961 source.IncomingCapturedFrame(CreateFrame(10, kWidth, kHeight));
1962 WaitForEncodedFrame(10);
asapersson09f05612017-05-15 23:40:18 -07001963 VerifyFpsEqResolutionEq(source.sink_wants(), last_wants);
asaperssond0de2952017-04-21 01:47:31 -07001964 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1965 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
Jonathan Yubc771b72017-12-08 17:04:29 -08001966 EXPECT_EQ(6, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
asaperssond0de2952017-04-21 01:47:31 -07001967 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1968
1969 // Trigger quality adapt up, expect no restriction (1280x720).
mflodmancc3d4422017-08-03 08:27:51 -07001970 video_stream_encoder_->TriggerQualityHigh();
Mirko Bonadei948b7e32018-08-14 07:23:21 +00001971 source.IncomingCapturedFrame(CreateFrame(11, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001972 WaitForEncodedFrame(kWidth, kHeight);
asapersson09f05612017-05-15 23:40:18 -07001973 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
Mirko Bonadei948b7e32018-08-14 07:23:21 +00001974 VerifyNoLimitation(source.sink_wants());
asaperssond0de2952017-04-21 01:47:31 -07001975 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1976 EXPECT_FALSE(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(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
kthelgason5e13d412016-12-01 03:59:51 -08001979
mflodmancc3d4422017-08-03 08:27:51 -07001980 video_stream_encoder_->Stop();
kthelgason5e13d412016-12-01 03:59:51 -08001981}
1982
mflodmancc3d4422017-08-03 08:27:51 -07001983TEST_F(VideoStreamEncoderTest, CpuLimitedHistogramIsReported) {
asaperssonfab67072017-04-04 05:51:49 -07001984 const int kWidth = 640;
1985 const int kHeight = 360;
perkj803d97f2016-11-01 11:45:46 -07001986
mflodmancc3d4422017-08-03 08:27:51 -07001987 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
sprang4847ae62017-06-27 07:06:52 -07001988
perkj803d97f2016-11-01 11:45:46 -07001989 for (int i = 1; i <= SendStatisticsProxy::kMinRequiredMetricsSamples; ++i) {
asaperssonfab67072017-04-04 05:51:49 -07001990 video_source_.IncomingCapturedFrame(CreateFrame(i, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001991 WaitForEncodedFrame(i);
perkj803d97f2016-11-01 11:45:46 -07001992 }
1993
mflodmancc3d4422017-08-03 08:27:51 -07001994 video_stream_encoder_->TriggerCpuOveruse();
perkj803d97f2016-11-01 11:45:46 -07001995 for (int i = 1; i <= SendStatisticsProxy::kMinRequiredMetricsSamples; ++i) {
asaperssonfab67072017-04-04 05:51:49 -07001996 video_source_.IncomingCapturedFrame(CreateFrame(
1997 SendStatisticsProxy::kMinRequiredMetricsSamples + i, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001998 WaitForEncodedFrame(SendStatisticsProxy::kMinRequiredMetricsSamples + i);
perkj803d97f2016-11-01 11:45:46 -07001999 }
2000
mflodmancc3d4422017-08-03 08:27:51 -07002001 video_stream_encoder_->Stop();
2002 video_stream_encoder_.reset();
perkj803d97f2016-11-01 11:45:46 -07002003 stats_proxy_.reset();
sprangf8ee65e2017-02-28 08:49:33 -08002004
perkj803d97f2016-11-01 11:45:46 -07002005 EXPECT_EQ(1,
2006 metrics::NumSamples("WebRTC.Video.CpuLimitedResolutionInPercent"));
2007 EXPECT_EQ(
2008 1, metrics::NumEvents("WebRTC.Video.CpuLimitedResolutionInPercent", 50));
2009}
2010
mflodmancc3d4422017-08-03 08:27:51 -07002011TEST_F(VideoStreamEncoderTest,
2012 CpuLimitedHistogramIsNotReportedForDisabledDegradation) {
2013 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonf4e44af2017-04-19 02:01:06 -07002014 const int kWidth = 640;
2015 const int kHeight = 360;
2016
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002017 video_stream_encoder_->SetSource(&video_source_,
2018 webrtc::DegradationPreference::DISABLED);
asaperssonf4e44af2017-04-19 02:01:06 -07002019
2020 for (int i = 1; i <= SendStatisticsProxy::kMinRequiredMetricsSamples; ++i) {
2021 video_source_.IncomingCapturedFrame(CreateFrame(i, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002022 WaitForEncodedFrame(i);
asaperssonf4e44af2017-04-19 02:01:06 -07002023 }
2024
mflodmancc3d4422017-08-03 08:27:51 -07002025 video_stream_encoder_->Stop();
2026 video_stream_encoder_.reset();
asaperssonf4e44af2017-04-19 02:01:06 -07002027 stats_proxy_.reset();
2028
2029 EXPECT_EQ(0,
2030 metrics::NumSamples("WebRTC.Video.CpuLimitedResolutionInPercent"));
2031}
2032
mflodmancc3d4422017-08-03 08:27:51 -07002033TEST_F(VideoStreamEncoderTest, CallsBitrateObserver) {
sprang4847ae62017-06-27 07:06:52 -07002034 MockBitrateObserver bitrate_observer;
Niels Möller0327c2d2018-05-21 14:09:31 +02002035 video_stream_encoder_->SetBitrateAllocationObserver(&bitrate_observer);
sprang57c2fff2017-01-16 06:24:02 -08002036
2037 const int kDefaultFps = 30;
Erik Språng566124a2018-04-23 12:32:22 +02002038 const VideoBitrateAllocation expected_bitrate =
sprang57c2fff2017-01-16 06:24:02 -08002039 DefaultVideoBitrateAllocator(fake_encoder_.codec_config())
kthelgason2bc68642017-02-07 07:02:22 -08002040 .GetAllocation(kLowTargetBitrateBps, kDefaultFps);
sprang57c2fff2017-01-16 06:24:02 -08002041
2042 // First called on bitrate updated, then again on first frame.
2043 EXPECT_CALL(bitrate_observer, OnBitrateAllocationUpdated(expected_bitrate))
2044 .Times(2);
mflodmancc3d4422017-08-03 08:27:51 -07002045 video_stream_encoder_->OnBitrateUpdated(kLowTargetBitrateBps, 0, 0);
sprang57c2fff2017-01-16 06:24:02 -08002046
2047 const int64_t kStartTimeMs = 1;
2048 video_source_.IncomingCapturedFrame(
2049 CreateFrame(kStartTimeMs, codec_width_, codec_height_));
sprang4847ae62017-06-27 07:06:52 -07002050 WaitForEncodedFrame(kStartTimeMs);
sprang57c2fff2017-01-16 06:24:02 -08002051
2052 // Not called on second frame.
2053 EXPECT_CALL(bitrate_observer, OnBitrateAllocationUpdated(expected_bitrate))
2054 .Times(0);
2055 video_source_.IncomingCapturedFrame(
2056 CreateFrame(kStartTimeMs + 1, codec_width_, codec_height_));
sprang4847ae62017-06-27 07:06:52 -07002057 WaitForEncodedFrame(kStartTimeMs + 1);
sprang57c2fff2017-01-16 06:24:02 -08002058
2059 // Called after a process interval.
2060 const int64_t kProcessIntervalMs =
2061 vcm::VCMProcessTimer::kDefaultProcessIntervalMs;
sprang4847ae62017-06-27 07:06:52 -07002062 fake_clock_.AdvanceTimeMicros(rtc::kNumMicrosecsPerMillisec *
2063 (kProcessIntervalMs + (1000 / kDefaultFps)));
sprang57c2fff2017-01-16 06:24:02 -08002064 EXPECT_CALL(bitrate_observer, OnBitrateAllocationUpdated(expected_bitrate))
2065 .Times(1);
2066 video_source_.IncomingCapturedFrame(CreateFrame(
2067 kStartTimeMs + kProcessIntervalMs, codec_width_, codec_height_));
sprang4847ae62017-06-27 07:06:52 -07002068 WaitForEncodedFrame(kStartTimeMs + kProcessIntervalMs);
sprang57c2fff2017-01-16 06:24:02 -08002069
mflodmancc3d4422017-08-03 08:27:51 -07002070 video_stream_encoder_->Stop();
sprang57c2fff2017-01-16 06:24:02 -08002071}
2072
Niels Möller7dc26b72017-12-06 10:27:48 +01002073TEST_F(VideoStreamEncoderTest, OveruseDetectorUpdatedOnReconfigureAndAdaption) {
2074 const int kFrameWidth = 1280;
2075 const int kFrameHeight = 720;
2076 const int kFramerate = 24;
2077
2078 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
2079 test::FrameForwarder source;
2080 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002081 &source, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
Niels Möller7dc26b72017-12-06 10:27:48 +01002082
2083 // Insert a single frame, triggering initial configuration.
2084 source.IncomingCapturedFrame(CreateFrame(1, kFrameWidth, kFrameHeight));
2085 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2086
2087 EXPECT_EQ(
2088 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2089 kDefaultFramerate);
2090
2091 // Trigger reconfigure encoder (without resetting the entire instance).
2092 VideoEncoderConfig video_encoder_config;
Niels Möller259a4972018-04-05 15:36:51 +02002093 video_encoder_config.codec_type = kVideoCodecVP8;
Niels Möller7dc26b72017-12-06 10:27:48 +01002094 video_encoder_config.max_bitrate_bps = kTargetBitrateBps;
2095 video_encoder_config.number_of_streams = 1;
2096 video_encoder_config.video_stream_factory =
2097 new rtc::RefCountedObject<VideoStreamFactory>(1, kFramerate);
2098 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
Niels Möllerf1338562018-04-26 09:51:47 +02002099 kMaxPayloadLength);
Niels Möller7dc26b72017-12-06 10:27:48 +01002100 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2101
2102 // Detector should be updated with fps limit from codec config.
2103 EXPECT_EQ(
2104 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2105 kFramerate);
2106
2107 // Trigger overuse, max framerate should be reduced.
2108 VideoSendStream::Stats stats = stats_proxy_->GetStats();
2109 stats.input_frame_rate = kFramerate;
2110 stats_proxy_->SetMockStats(stats);
2111 video_stream_encoder_->TriggerCpuOveruse();
2112 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2113 int adapted_framerate =
2114 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate();
2115 EXPECT_LT(adapted_framerate, kFramerate);
2116
2117 // Trigger underuse, max framerate should go back to codec configured fps.
2118 // Set extra low fps, to make sure it's actually reset, not just incremented.
2119 stats = stats_proxy_->GetStats();
2120 stats.input_frame_rate = adapted_framerate / 2;
2121 stats_proxy_->SetMockStats(stats);
2122 video_stream_encoder_->TriggerCpuNormalUsage();
2123 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2124 EXPECT_EQ(
2125 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2126 kFramerate);
2127
2128 video_stream_encoder_->Stop();
2129}
2130
2131TEST_F(VideoStreamEncoderTest,
2132 OveruseDetectorUpdatedRespectsFramerateAfterUnderuse) {
2133 const int kFrameWidth = 1280;
2134 const int kFrameHeight = 720;
2135 const int kLowFramerate = 15;
2136 const int kHighFramerate = 25;
2137
2138 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
2139 test::FrameForwarder source;
2140 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002141 &source, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
Niels Möller7dc26b72017-12-06 10:27:48 +01002142
2143 // Trigger initial configuration.
2144 VideoEncoderConfig video_encoder_config;
Niels Möller259a4972018-04-05 15:36:51 +02002145 video_encoder_config.codec_type = kVideoCodecVP8;
Niels Möller7dc26b72017-12-06 10:27:48 +01002146 video_encoder_config.max_bitrate_bps = kTargetBitrateBps;
2147 video_encoder_config.number_of_streams = 1;
2148 video_encoder_config.video_stream_factory =
2149 new rtc::RefCountedObject<VideoStreamFactory>(1, kLowFramerate);
2150 source.IncomingCapturedFrame(CreateFrame(1, kFrameWidth, kFrameHeight));
2151 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
Niels Möllerf1338562018-04-26 09:51:47 +02002152 kMaxPayloadLength);
Niels Möller7dc26b72017-12-06 10:27:48 +01002153 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2154
2155 EXPECT_EQ(
2156 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2157 kLowFramerate);
2158
2159 // Trigger overuse, max framerate should be reduced.
2160 VideoSendStream::Stats stats = stats_proxy_->GetStats();
2161 stats.input_frame_rate = kLowFramerate;
2162 stats_proxy_->SetMockStats(stats);
2163 video_stream_encoder_->TriggerCpuOveruse();
2164 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2165 int adapted_framerate =
2166 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate();
2167 EXPECT_LT(adapted_framerate, kLowFramerate);
2168
2169 // Reconfigure the encoder with a new (higher max framerate), max fps should
2170 // still respect the adaptation.
2171 video_encoder_config.video_stream_factory =
2172 new rtc::RefCountedObject<VideoStreamFactory>(1, kHighFramerate);
2173 source.IncomingCapturedFrame(CreateFrame(1, kFrameWidth, kFrameHeight));
2174 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
Niels Möllerf1338562018-04-26 09:51:47 +02002175 kMaxPayloadLength);
Niels Möller7dc26b72017-12-06 10:27:48 +01002176 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2177
2178 EXPECT_EQ(
2179 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2180 adapted_framerate);
2181
2182 // Trigger underuse, max framerate should go back to codec configured fps.
2183 stats = stats_proxy_->GetStats();
2184 stats.input_frame_rate = adapted_framerate;
2185 stats_proxy_->SetMockStats(stats);
2186 video_stream_encoder_->TriggerCpuNormalUsage();
2187 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2188 EXPECT_EQ(
2189 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2190 kHighFramerate);
2191
2192 video_stream_encoder_->Stop();
2193}
2194
mflodmancc3d4422017-08-03 08:27:51 -07002195TEST_F(VideoStreamEncoderTest,
2196 OveruseDetectorUpdatedOnDegradationPreferenceChange) {
sprangfda496a2017-06-15 04:21:07 -07002197 const int kFrameWidth = 1280;
2198 const int kFrameHeight = 720;
2199 const int kFramerate = 24;
2200
mflodmancc3d4422017-08-03 08:27:51 -07002201 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
sprangfda496a2017-06-15 04:21:07 -07002202 test::FrameForwarder source;
mflodmancc3d4422017-08-03 08:27:51 -07002203 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002204 &source, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
sprangfda496a2017-06-15 04:21:07 -07002205
2206 // Trigger initial configuration.
2207 VideoEncoderConfig video_encoder_config;
Niels Möller259a4972018-04-05 15:36:51 +02002208 video_encoder_config.codec_type = kVideoCodecVP8;
sprangfda496a2017-06-15 04:21:07 -07002209 video_encoder_config.max_bitrate_bps = kTargetBitrateBps;
2210 video_encoder_config.number_of_streams = 1;
2211 video_encoder_config.video_stream_factory =
2212 new rtc::RefCountedObject<VideoStreamFactory>(1, kFramerate);
2213 source.IncomingCapturedFrame(CreateFrame(1, kFrameWidth, kFrameHeight));
mflodmancc3d4422017-08-03 08:27:51 -07002214 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
Niels Möllerf1338562018-04-26 09:51:47 +02002215 kMaxPayloadLength);
mflodmancc3d4422017-08-03 08:27:51 -07002216 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
sprangfda496a2017-06-15 04:21:07 -07002217
Niels Möller7dc26b72017-12-06 10:27:48 +01002218 EXPECT_EQ(
2219 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2220 kFramerate);
sprangfda496a2017-06-15 04:21:07 -07002221
2222 // Trigger overuse, max framerate should be reduced.
2223 VideoSendStream::Stats stats = stats_proxy_->GetStats();
2224 stats.input_frame_rate = kFramerate;
2225 stats_proxy_->SetMockStats(stats);
mflodmancc3d4422017-08-03 08:27:51 -07002226 video_stream_encoder_->TriggerCpuOveruse();
2227 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
Niels Möller7dc26b72017-12-06 10:27:48 +01002228 int adapted_framerate =
2229 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate();
sprangfda496a2017-06-15 04:21:07 -07002230 EXPECT_LT(adapted_framerate, kFramerate);
2231
2232 // Change degradation preference to not enable framerate scaling. Target
2233 // framerate should be changed to codec defined limit.
mflodmancc3d4422017-08-03 08:27:51 -07002234 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002235 &source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
mflodmancc3d4422017-08-03 08:27:51 -07002236 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
Niels Möller7dc26b72017-12-06 10:27:48 +01002237 EXPECT_EQ(
2238 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2239 kFramerate);
sprangfda496a2017-06-15 04:21:07 -07002240
mflodmancc3d4422017-08-03 08:27:51 -07002241 video_stream_encoder_->Stop();
sprangfda496a2017-06-15 04:21:07 -07002242}
2243
mflodmancc3d4422017-08-03 08:27:51 -07002244TEST_F(VideoStreamEncoderTest, DropsFramesAndScalesWhenBitrateIsTooLow) {
asaperssonfab67072017-04-04 05:51:49 -07002245 const int kTooLowBitrateForFrameSizeBps = 10000;
mflodmancc3d4422017-08-03 08:27:51 -07002246 video_stream_encoder_->OnBitrateUpdated(kTooLowBitrateForFrameSizeBps, 0, 0);
asaperssonfab67072017-04-04 05:51:49 -07002247 const int kWidth = 640;
2248 const int kHeight = 360;
kthelgason2bc68642017-02-07 07:02:22 -08002249
asaperssonfab67072017-04-04 05:51:49 -07002250 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
kthelgason2bc68642017-02-07 07:02:22 -08002251
2252 // Expect to drop this frame, the wait should time out.
sprang4847ae62017-06-27 07:06:52 -07002253 ExpectDroppedFrame();
kthelgason2bc68642017-02-07 07:02:22 -08002254
2255 // Expect the sink_wants to specify a scaled frame.
asapersson0944a802017-04-07 00:57:58 -07002256 EXPECT_LT(video_source_.sink_wants().max_pixel_count, kWidth * kHeight);
kthelgason2bc68642017-02-07 07:02:22 -08002257
sprangc5d62e22017-04-02 23:53:04 -07002258 int last_pixel_count = video_source_.sink_wants().max_pixel_count;
kthelgason2bc68642017-02-07 07:02:22 -08002259
asaperssonfab67072017-04-04 05:51:49 -07002260 // Next frame is scaled.
kthelgason2bc68642017-02-07 07:02:22 -08002261 video_source_.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07002262 CreateFrame(2, kWidth * 3 / 4, kHeight * 3 / 4));
kthelgason2bc68642017-02-07 07:02:22 -08002263
2264 // Expect to drop this frame, the wait should time out.
sprang4847ae62017-06-27 07:06:52 -07002265 ExpectDroppedFrame();
kthelgason2bc68642017-02-07 07:02:22 -08002266
sprangc5d62e22017-04-02 23:53:04 -07002267 EXPECT_LT(video_source_.sink_wants().max_pixel_count, last_pixel_count);
kthelgason2bc68642017-02-07 07:02:22 -08002268
mflodmancc3d4422017-08-03 08:27:51 -07002269 video_stream_encoder_->Stop();
kthelgason2bc68642017-02-07 07:02:22 -08002270}
2271
mflodmancc3d4422017-08-03 08:27:51 -07002272TEST_F(VideoStreamEncoderTest,
2273 NumberOfDroppedFramesLimitedWhenBitrateIsTooLow) {
asaperssonfab67072017-04-04 05:51:49 -07002274 const int kTooLowBitrateForFrameSizeBps = 10000;
mflodmancc3d4422017-08-03 08:27:51 -07002275 video_stream_encoder_->OnBitrateUpdated(kTooLowBitrateForFrameSizeBps, 0, 0);
asaperssonfab67072017-04-04 05:51:49 -07002276 const int kWidth = 640;
2277 const int kHeight = 360;
kthelgason2bc68642017-02-07 07:02:22 -08002278
2279 // We expect the n initial frames to get dropped.
2280 int i;
2281 for (i = 1; i <= kMaxInitialFramedrop; ++i) {
asaperssonfab67072017-04-04 05:51:49 -07002282 video_source_.IncomingCapturedFrame(CreateFrame(i, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002283 ExpectDroppedFrame();
kthelgason2bc68642017-02-07 07:02:22 -08002284 }
2285 // The n+1th frame should not be dropped, even though it's size is too large.
asaperssonfab67072017-04-04 05:51:49 -07002286 video_source_.IncomingCapturedFrame(CreateFrame(i, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002287 WaitForEncodedFrame(i);
kthelgason2bc68642017-02-07 07:02:22 -08002288
2289 // Expect the sink_wants to specify a scaled frame.
asaperssonfab67072017-04-04 05:51:49 -07002290 EXPECT_LT(video_source_.sink_wants().max_pixel_count, kWidth * kHeight);
kthelgason2bc68642017-02-07 07:02:22 -08002291
mflodmancc3d4422017-08-03 08:27:51 -07002292 video_stream_encoder_->Stop();
kthelgason2bc68642017-02-07 07:02:22 -08002293}
2294
mflodmancc3d4422017-08-03 08:27:51 -07002295TEST_F(VideoStreamEncoderTest,
2296 InitialFrameDropOffWithMaintainResolutionPreference) {
asaperssonfab67072017-04-04 05:51:49 -07002297 const int kWidth = 640;
2298 const int kHeight = 360;
mflodmancc3d4422017-08-03 08:27:51 -07002299 video_stream_encoder_->OnBitrateUpdated(kLowTargetBitrateBps, 0, 0);
kthelgason2bc68642017-02-07 07:02:22 -08002300
2301 // Set degradation preference.
mflodmancc3d4422017-08-03 08:27:51 -07002302 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002303 &video_source_, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
kthelgason2bc68642017-02-07 07:02:22 -08002304
asaperssonfab67072017-04-04 05:51:49 -07002305 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
kthelgason2bc68642017-02-07 07:02:22 -08002306 // Frame should not be dropped, even if it's too large.
sprang4847ae62017-06-27 07:06:52 -07002307 WaitForEncodedFrame(1);
kthelgason2bc68642017-02-07 07:02:22 -08002308
mflodmancc3d4422017-08-03 08:27:51 -07002309 video_stream_encoder_->Stop();
kthelgason2bc68642017-02-07 07:02:22 -08002310}
2311
mflodmancc3d4422017-08-03 08:27:51 -07002312TEST_F(VideoStreamEncoderTest, InitialFrameDropOffWhenEncoderDisabledScaling) {
asaperssonfab67072017-04-04 05:51:49 -07002313 const int kWidth = 640;
2314 const int kHeight = 360;
kthelgasonad9010c2017-02-14 00:46:51 -08002315 fake_encoder_.SetQualityScaling(false);
Niels Möller4db138e2018-04-19 09:04:13 +02002316
2317 VideoEncoderConfig video_encoder_config;
2318 test::FillEncoderConfiguration(kVideoCodecVP8, 1, &video_encoder_config);
2319 // Make format different, to force recreation of encoder.
2320 video_encoder_config.video_format.parameters["foo"] = "foo";
2321 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
Niels Möllerf1338562018-04-26 09:51:47 +02002322 kMaxPayloadLength);
mflodmancc3d4422017-08-03 08:27:51 -07002323 video_stream_encoder_->OnBitrateUpdated(kLowTargetBitrateBps, 0, 0);
asapersson09f05612017-05-15 23:40:18 -07002324
kthelgasonb83797b2017-02-14 11:57:25 -08002325 // Force quality scaler reconfiguration by resetting the source.
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002326 video_stream_encoder_->SetSource(&video_source_,
2327 webrtc::DegradationPreference::BALANCED);
kthelgasonad9010c2017-02-14 00:46:51 -08002328
asaperssonfab67072017-04-04 05:51:49 -07002329 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
kthelgasonad9010c2017-02-14 00:46:51 -08002330 // Frame should not be dropped, even if it's too large.
sprang4847ae62017-06-27 07:06:52 -07002331 WaitForEncodedFrame(1);
kthelgasonad9010c2017-02-14 00:46:51 -08002332
mflodmancc3d4422017-08-03 08:27:51 -07002333 video_stream_encoder_->Stop();
kthelgasonad9010c2017-02-14 00:46:51 -08002334 fake_encoder_.SetQualityScaling(true);
2335}
2336
mflodmancc3d4422017-08-03 08:27:51 -07002337TEST_F(VideoStreamEncoderTest,
asaperssond0de2952017-04-21 01:47:31 -07002338 ResolutionNotAdaptedForTooSmallFrame_MaintainFramerateMode) {
2339 const int kTooSmallWidth = 10;
2340 const int kTooSmallHeight = 10;
mflodmancc3d4422017-08-03 08:27:51 -07002341 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssond0de2952017-04-21 01:47:31 -07002342
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002343 // Enable MAINTAIN_FRAMERATE preference, no initial limitation.
asaperssond0de2952017-04-21 01:47:31 -07002344 test::FrameForwarder source;
mflodmancc3d4422017-08-03 08:27:51 -07002345 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002346 &source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
asaperssond0de2952017-04-21 01:47:31 -07002347 VerifyNoLimitation(source.sink_wants());
2348 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2349
2350 // Trigger adapt down, too small frame, expect no change.
2351 source.IncomingCapturedFrame(CreateFrame(1, kTooSmallWidth, kTooSmallHeight));
sprang4847ae62017-06-27 07:06:52 -07002352 WaitForEncodedFrame(1);
mflodmancc3d4422017-08-03 08:27:51 -07002353 video_stream_encoder_->TriggerCpuOveruse();
Mirko Bonadei948b7e32018-08-14 07:23:21 +00002354 VerifyNoLimitation(source.sink_wants());
asaperssond0de2952017-04-21 01:47:31 -07002355 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2356 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2357
mflodmancc3d4422017-08-03 08:27:51 -07002358 video_stream_encoder_->Stop();
asaperssond0de2952017-04-21 01:47:31 -07002359}
2360
mflodmancc3d4422017-08-03 08:27:51 -07002361TEST_F(VideoStreamEncoderTest,
2362 ResolutionNotAdaptedForTooSmallFrame_BalancedMode) {
asaperssonf7e294d2017-06-13 23:25:22 -07002363 const int kTooSmallWidth = 10;
2364 const int kTooSmallHeight = 10;
2365 const int kFpsLimit = 7;
mflodmancc3d4422017-08-03 08:27:51 -07002366 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -07002367
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002368 // Enable BALANCED preference, no initial limitation.
asaperssonf7e294d2017-06-13 23:25:22 -07002369 test::FrameForwarder source;
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002370 video_stream_encoder_->SetSource(&source,
2371 webrtc::DegradationPreference::BALANCED);
asaperssonf7e294d2017-06-13 23:25:22 -07002372 VerifyNoLimitation(source.sink_wants());
2373 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2374 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2375
2376 // Trigger adapt down, expect limited framerate.
2377 source.IncomingCapturedFrame(CreateFrame(1, kTooSmallWidth, kTooSmallHeight));
sprang4847ae62017-06-27 07:06:52 -07002378 WaitForEncodedFrame(1);
mflodmancc3d4422017-08-03 08:27:51 -07002379 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002380 VerifyFpsEqResolutionMax(source.sink_wants(), kFpsLimit);
2381 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2382 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2383 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2384
2385 // Trigger adapt down, too small frame, expect no change.
2386 source.IncomingCapturedFrame(CreateFrame(2, kTooSmallWidth, kTooSmallHeight));
sprang4847ae62017-06-27 07:06:52 -07002387 WaitForEncodedFrame(2);
mflodmancc3d4422017-08-03 08:27:51 -07002388 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002389 VerifyFpsEqResolutionMax(source.sink_wants(), kFpsLimit);
2390 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2391 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2392 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2393
mflodmancc3d4422017-08-03 08:27:51 -07002394 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07002395}
2396
mflodmancc3d4422017-08-03 08:27:51 -07002397TEST_F(VideoStreamEncoderTest, FailingInitEncodeDoesntCauseCrash) {
asapersson02465b82017-04-10 01:12:52 -07002398 fake_encoder_.ForceInitEncodeFailure(true);
mflodmancc3d4422017-08-03 08:27:51 -07002399 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
Niels Möllerf1338562018-04-26 09:51:47 +02002400 ResetEncoder("VP8", 2, 1, 1, false);
asapersson02465b82017-04-10 01:12:52 -07002401 const int kFrameWidth = 1280;
2402 const int kFrameHeight = 720;
2403 video_source_.IncomingCapturedFrame(
2404 CreateFrame(1, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002405 ExpectDroppedFrame();
mflodmancc3d4422017-08-03 08:27:51 -07002406 video_stream_encoder_->Stop();
asapersson02465b82017-04-10 01:12:52 -07002407}
2408
sprangb1ca0732017-02-01 08:38:12 -08002409// TODO(sprang): Extend this with fps throttling and any "balanced" extensions.
mflodmancc3d4422017-08-03 08:27:51 -07002410TEST_F(VideoStreamEncoderTest,
2411 AdaptsResolutionOnOveruse_MaintainFramerateMode) {
2412 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
sprangb1ca0732017-02-01 08:38:12 -08002413
2414 const int kFrameWidth = 1280;
2415 const int kFrameHeight = 720;
2416 // Enabled default VideoAdapter downscaling. First step is 3/4, not 3/5 as
mflodmancc3d4422017-08-03 08:27:51 -07002417 // requested by
2418 // VideoStreamEncoder::VideoSourceProxy::RequestResolutionLowerThan().
sprangb1ca0732017-02-01 08:38:12 -08002419 video_source_.set_adaptation_enabled(true);
2420
2421 video_source_.IncomingCapturedFrame(
Mirko Bonadei948b7e32018-08-14 07:23:21 +00002422 CreateFrame(1, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002423 WaitForEncodedFrame(kFrameWidth, kFrameHeight);
sprangb1ca0732017-02-01 08:38:12 -08002424
2425 // Trigger CPU overuse, downscale by 3/4.
mflodmancc3d4422017-08-03 08:27:51 -07002426 video_stream_encoder_->TriggerCpuOveruse();
sprangb1ca0732017-02-01 08:38:12 -08002427 video_source_.IncomingCapturedFrame(
Mirko Bonadei948b7e32018-08-14 07:23:21 +00002428 CreateFrame(2, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002429 WaitForEncodedFrame((kFrameWidth * 3) / 4, (kFrameHeight * 3) / 4);
sprangb1ca0732017-02-01 08:38:12 -08002430
asaperssonfab67072017-04-04 05:51:49 -07002431 // Trigger CPU normal use, return to original resolution.
mflodmancc3d4422017-08-03 08:27:51 -07002432 video_stream_encoder_->TriggerCpuNormalUsage();
sprangb1ca0732017-02-01 08:38:12 -08002433 video_source_.IncomingCapturedFrame(
Mirko Bonadei948b7e32018-08-14 07:23:21 +00002434 CreateFrame(3, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002435 WaitForEncodedFrame(kFrameWidth, kFrameHeight);
sprangb1ca0732017-02-01 08:38:12 -08002436
mflodmancc3d4422017-08-03 08:27:51 -07002437 video_stream_encoder_->Stop();
sprangb1ca0732017-02-01 08:38:12 -08002438}
sprangfe627f32017-03-29 08:24:59 -07002439
mflodmancc3d4422017-08-03 08:27:51 -07002440TEST_F(VideoStreamEncoderTest,
2441 AdaptsFramerateOnOveruse_MaintainResolutionMode) {
sprangc5d62e22017-04-02 23:53:04 -07002442 const int kFrameWidth = 1280;
2443 const int kFrameHeight = 720;
Mirko Bonadei948b7e32018-08-14 07:23:21 +00002444 int kFrameIntervalMs = rtc::kNumMillisecsPerSec / max_framerate_;
sprangc5d62e22017-04-02 23:53:04 -07002445
mflodmancc3d4422017-08-03 08:27:51 -07002446 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
2447 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002448 &video_source_, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
sprangc5d62e22017-04-02 23:53:04 -07002449 video_source_.set_adaptation_enabled(true);
2450
sprang4847ae62017-06-27 07:06:52 -07002451 int64_t timestamp_ms = fake_clock_.TimeNanos() / rtc::kNumNanosecsPerMillisec;
sprangc5d62e22017-04-02 23:53:04 -07002452
2453 video_source_.IncomingCapturedFrame(
2454 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002455 WaitForEncodedFrame(timestamp_ms);
sprangc5d62e22017-04-02 23:53:04 -07002456
2457 // Try to trigger overuse. No fps estimate available => no effect.
mflodmancc3d4422017-08-03 08:27:51 -07002458 video_stream_encoder_->TriggerCpuOveruse();
sprangc5d62e22017-04-02 23:53:04 -07002459
2460 // Insert frames for one second to get a stable estimate.
sprang4847ae62017-06-27 07:06:52 -07002461 for (int i = 0; i < max_framerate_; ++i) {
sprangc5d62e22017-04-02 23:53:04 -07002462 timestamp_ms += kFrameIntervalMs;
sprangc5d62e22017-04-02 23:53:04 -07002463 video_source_.IncomingCapturedFrame(
2464 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002465 WaitForEncodedFrame(timestamp_ms);
sprangc5d62e22017-04-02 23:53:04 -07002466 }
2467
2468 // Trigger CPU overuse, reduce framerate by 2/3.
mflodmancc3d4422017-08-03 08:27:51 -07002469 video_stream_encoder_->TriggerCpuOveruse();
sprangc5d62e22017-04-02 23:53:04 -07002470 int num_frames_dropped = 0;
sprang4847ae62017-06-27 07:06:52 -07002471 for (int i = 0; i < max_framerate_; ++i) {
sprangc5d62e22017-04-02 23:53:04 -07002472 timestamp_ms += kFrameIntervalMs;
sprangc5d62e22017-04-02 23:53:04 -07002473 video_source_.IncomingCapturedFrame(
2474 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002475 if (!WaitForFrame(kFrameTimeoutMs)) {
sprangc5d62e22017-04-02 23:53:04 -07002476 ++num_frames_dropped;
2477 } else {
Åsa Perssonc74d8da2017-12-04 14:13:56 +01002478 sink_.CheckLastFrameSizeMatches(kFrameWidth, kFrameHeight);
sprangc5d62e22017-04-02 23:53:04 -07002479 }
2480 }
2481
sprang4847ae62017-06-27 07:06:52 -07002482 // Add some slack to account for frames dropped by the frame dropper.
2483 const int kErrorMargin = 1;
2484 EXPECT_NEAR(num_frames_dropped, max_framerate_ - (max_framerate_ * 2 / 3),
sprangc5d62e22017-04-02 23:53:04 -07002485 kErrorMargin);
2486
2487 // Trigger CPU overuse, reduce framerate by 2/3 again.
mflodmancc3d4422017-08-03 08:27:51 -07002488 video_stream_encoder_->TriggerCpuOveruse();
sprangc5d62e22017-04-02 23:53:04 -07002489 num_frames_dropped = 0;
Mirko Bonadei948b7e32018-08-14 07:23:21 +00002490 for (int i = 0; i < max_framerate_; ++i) {
sprangc5d62e22017-04-02 23:53:04 -07002491 timestamp_ms += kFrameIntervalMs;
sprangc5d62e22017-04-02 23:53:04 -07002492 video_source_.IncomingCapturedFrame(
2493 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002494 if (!WaitForFrame(kFrameTimeoutMs)) {
sprangc5d62e22017-04-02 23:53:04 -07002495 ++num_frames_dropped;
2496 } else {
Åsa Perssonc74d8da2017-12-04 14:13:56 +01002497 sink_.CheckLastFrameSizeMatches(kFrameWidth, kFrameHeight);
sprangc5d62e22017-04-02 23:53:04 -07002498 }
2499 }
sprang4847ae62017-06-27 07:06:52 -07002500 EXPECT_NEAR(num_frames_dropped, max_framerate_ - (max_framerate_ * 4 / 9),
sprangc5d62e22017-04-02 23:53:04 -07002501 kErrorMargin);
2502
2503 // Go back up one step.
mflodmancc3d4422017-08-03 08:27:51 -07002504 video_stream_encoder_->TriggerCpuNormalUsage();
sprangc5d62e22017-04-02 23:53:04 -07002505 num_frames_dropped = 0;
sprang4847ae62017-06-27 07:06:52 -07002506 for (int i = 0; i < max_framerate_; ++i) {
sprangc5d62e22017-04-02 23:53:04 -07002507 timestamp_ms += kFrameIntervalMs;
sprangc5d62e22017-04-02 23:53:04 -07002508 video_source_.IncomingCapturedFrame(
2509 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002510 if (!WaitForFrame(kFrameTimeoutMs)) {
sprangc5d62e22017-04-02 23:53:04 -07002511 ++num_frames_dropped;
2512 } else {
Åsa Perssonc74d8da2017-12-04 14:13:56 +01002513 sink_.CheckLastFrameSizeMatches(kFrameWidth, kFrameHeight);
sprangc5d62e22017-04-02 23:53:04 -07002514 }
2515 }
sprang4847ae62017-06-27 07:06:52 -07002516 EXPECT_NEAR(num_frames_dropped, max_framerate_ - (max_framerate_ * 2 / 3),
sprangc5d62e22017-04-02 23:53:04 -07002517 kErrorMargin);
2518
2519 // Go back up to original mode.
mflodmancc3d4422017-08-03 08:27:51 -07002520 video_stream_encoder_->TriggerCpuNormalUsage();
sprangc5d62e22017-04-02 23:53:04 -07002521 num_frames_dropped = 0;
sprang4847ae62017-06-27 07:06:52 -07002522 for (int i = 0; i < max_framerate_; ++i) {
sprangc5d62e22017-04-02 23:53:04 -07002523 timestamp_ms += kFrameIntervalMs;
sprangc5d62e22017-04-02 23:53:04 -07002524 video_source_.IncomingCapturedFrame(
2525 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002526 if (!WaitForFrame(kFrameTimeoutMs)) {
sprangc5d62e22017-04-02 23:53:04 -07002527 ++num_frames_dropped;
2528 } else {
Åsa Perssonc74d8da2017-12-04 14:13:56 +01002529 sink_.CheckLastFrameSizeMatches(kFrameWidth, kFrameHeight);
sprangc5d62e22017-04-02 23:53:04 -07002530 }
2531 }
2532 EXPECT_NEAR(num_frames_dropped, 0, kErrorMargin);
2533
mflodmancc3d4422017-08-03 08:27:51 -07002534 video_stream_encoder_->Stop();
sprangc5d62e22017-04-02 23:53:04 -07002535}
2536
mflodmancc3d4422017-08-03 08:27:51 -07002537TEST_F(VideoStreamEncoderTest, DoesntAdaptDownPastMinFramerate) {
sprangc5d62e22017-04-02 23:53:04 -07002538 const int kFramerateFps = 5;
2539 const int kFrameIntervalMs = rtc::kNumMillisecsPerSec / kFramerateFps;
sprangc5d62e22017-04-02 23:53:04 -07002540 const int kFrameWidth = 1280;
2541 const int kFrameHeight = 720;
2542
sprang4847ae62017-06-27 07:06:52 -07002543 // Reconfigure encoder with two temporal layers and screensharing, which will
2544 // disable frame dropping and make testing easier.
Niels Möllerf1338562018-04-26 09:51:47 +02002545 ResetEncoder("VP8", 1, 2, 1, true);
sprang4847ae62017-06-27 07:06:52 -07002546
mflodmancc3d4422017-08-03 08:27:51 -07002547 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
2548 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002549 &video_source_, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
sprangc5d62e22017-04-02 23:53:04 -07002550 video_source_.set_adaptation_enabled(true);
2551
sprang4847ae62017-06-27 07:06:52 -07002552 int64_t timestamp_ms = fake_clock_.TimeNanos() / rtc::kNumNanosecsPerMillisec;
sprangc5d62e22017-04-02 23:53:04 -07002553
2554 // Trigger overuse as much as we can.
Jonathan Yubc771b72017-12-08 17:04:29 -08002555 rtc::VideoSinkWants last_wants;
2556 do {
2557 last_wants = video_source_.sink_wants();
2558
sprangc5d62e22017-04-02 23:53:04 -07002559 // Insert frames to get a new fps estimate...
2560 for (int j = 0; j < kFramerateFps; ++j) {
2561 video_source_.IncomingCapturedFrame(
2562 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
Jonathan Yubc771b72017-12-08 17:04:29 -08002563 if (video_source_.last_sent_width()) {
2564 sink_.WaitForEncodedFrame(timestamp_ms);
2565 }
sprangc5d62e22017-04-02 23:53:04 -07002566 timestamp_ms += kFrameIntervalMs;
Yves Gerey665174f2018-06-19 15:03:05 +02002567 fake_clock_.AdvanceTimeMicros(kFrameIntervalMs *
2568 rtc::kNumMicrosecsPerMillisec);
sprangc5d62e22017-04-02 23:53:04 -07002569 }
2570 // ...and then try to adapt again.
mflodmancc3d4422017-08-03 08:27:51 -07002571 video_stream_encoder_->TriggerCpuOveruse();
Jonathan Yubc771b72017-12-08 17:04:29 -08002572 } while (video_source_.sink_wants().max_framerate_fps <
2573 last_wants.max_framerate_fps);
sprangc5d62e22017-04-02 23:53:04 -07002574
Jonathan Yubc771b72017-12-08 17:04:29 -08002575 VerifyFpsEqResolutionMax(video_source_.sink_wants(), kMinFramerateFps);
asaperssonf7e294d2017-06-13 23:25:22 -07002576
mflodmancc3d4422017-08-03 08:27:51 -07002577 video_stream_encoder_->Stop();
sprangc5d62e22017-04-02 23:53:04 -07002578}
asaperssonf7e294d2017-06-13 23:25:22 -07002579
mflodmancc3d4422017-08-03 08:27:51 -07002580TEST_F(VideoStreamEncoderTest,
2581 AdaptsResolutionAndFramerateForLowQuality_BalancedMode) {
asaperssonf7e294d2017-06-13 23:25:22 -07002582 const int kWidth = 1280;
2583 const int kHeight = 720;
2584 const int64_t kFrameIntervalMs = 150;
2585 int64_t timestamp_ms = kFrameIntervalMs;
mflodmancc3d4422017-08-03 08:27:51 -07002586 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -07002587
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002588 // Enable BALANCED preference, no initial limitation.
asaperssonf7e294d2017-06-13 23:25:22 -07002589 AdaptingFrameForwarder source;
2590 source.set_adaptation_enabled(true);
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002591 video_stream_encoder_->SetSource(&source,
2592 webrtc::DegradationPreference::BALANCED);
asaperssonf7e294d2017-06-13 23:25:22 -07002593 timestamp_ms += kFrameIntervalMs;
2594 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002595 WaitForEncodedFrame(kWidth, kHeight);
Mirko Bonadei948b7e32018-08-14 07:23:21 +00002596 VerifyNoLimitation(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07002597 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2598 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2599 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2600
2601 // Trigger adapt down, expect scaled down resolution (960x540@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002602 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002603 timestamp_ms += kFrameIntervalMs;
2604 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002605 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002606 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
2607 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2608 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2609 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2610
2611 // Trigger adapt down, expect scaled down resolution (640x360@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002612 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002613 timestamp_ms += kFrameIntervalMs;
2614 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002615 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002616 VerifyFpsMaxResolutionLt(source.sink_wants(), source.last_wants());
2617 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2618 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2619 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2620
2621 // Trigger adapt down, expect reduced fps (640x360@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07002622 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002623 timestamp_ms += kFrameIntervalMs;
2624 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002625 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002626 VerifyFpsLtResolutionEq(source.sink_wants(), source.last_wants());
2627 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2628 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2629 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2630
2631 // Trigger adapt down, expect scaled down resolution (480x270@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07002632 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002633 timestamp_ms += kFrameIntervalMs;
2634 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002635 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002636 VerifyFpsEqResolutionLt(source.sink_wants(), source.last_wants());
2637 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2638 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2639 EXPECT_EQ(4, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2640
2641 // Restrict bitrate, trigger adapt down, expect reduced fps (480x270@10fps).
mflodmancc3d4422017-08-03 08:27:51 -07002642 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002643 timestamp_ms += kFrameIntervalMs;
2644 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002645 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002646 VerifyFpsLtResolutionEq(source.sink_wants(), source.last_wants());
2647 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2648 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2649 EXPECT_EQ(5, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2650
2651 // Trigger adapt down, expect scaled down resolution (320x180@10fps).
mflodmancc3d4422017-08-03 08:27:51 -07002652 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002653 timestamp_ms += kFrameIntervalMs;
2654 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002655 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002656 VerifyFpsEqResolutionLt(source.sink_wants(), source.last_wants());
2657 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2658 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2659 EXPECT_EQ(6, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2660
2661 // Trigger adapt down, expect reduced fps (320x180@7fps).
mflodmancc3d4422017-08-03 08:27:51 -07002662 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002663 timestamp_ms += kFrameIntervalMs;
2664 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002665 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002666 VerifyFpsLtResolutionEq(source.sink_wants(), source.last_wants());
2667 rtc::VideoSinkWants last_wants = source.sink_wants();
2668 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2669 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2670 EXPECT_EQ(7, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2671
2672 // Trigger adapt down, min resolution reached, expect no change.
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 VerifyFpsEqResolutionEq(source.sink_wants(), last_wants);
2678 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2679 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2680 EXPECT_EQ(7, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2681
2682 // Trigger adapt down, expect expect increased fps (320x180@10fps).
mflodmancc3d4422017-08-03 08:27:51 -07002683 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002684 timestamp_ms += kFrameIntervalMs;
2685 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002686 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002687 VerifyFpsGtResolutionEq(source.sink_wants(), source.last_wants());
2688 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2689 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2690 EXPECT_EQ(8, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2691
2692 // Trigger adapt up, expect upscaled resolution (480x270@10fps).
mflodmancc3d4422017-08-03 08:27:51 -07002693 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002694 timestamp_ms += kFrameIntervalMs;
2695 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002696 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002697 VerifyFpsEqResolutionGt(source.sink_wants(), source.last_wants());
2698 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2699 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2700 EXPECT_EQ(9, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2701
2702 // Increase bitrate, trigger adapt up, expect increased fps (480x270@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07002703 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002704 timestamp_ms += kFrameIntervalMs;
2705 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002706 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002707 VerifyFpsGtResolutionEq(source.sink_wants(), source.last_wants());
2708 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2709 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2710 EXPECT_EQ(10, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2711
2712 // Trigger adapt up, expect upscaled resolution (640x360@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07002713 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002714 timestamp_ms += kFrameIntervalMs;
2715 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002716 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002717 VerifyFpsEqResolutionGt(source.sink_wants(), source.last_wants());
2718 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2719 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2720 EXPECT_EQ(11, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2721
2722 // Trigger adapt up, expect increased fps (640x360@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002723 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002724 timestamp_ms += kFrameIntervalMs;
2725 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002726 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002727 VerifyFpsMaxResolutionEq(source.sink_wants(), source.last_wants());
2728 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2729 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2730 EXPECT_EQ(12, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2731
2732 // Trigger adapt up, expect upscaled resolution (960x540@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002733 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002734 timestamp_ms += kFrameIntervalMs;
2735 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002736 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002737 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
2738 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2739 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2740 EXPECT_EQ(13, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2741
2742 // Trigger adapt up, expect no restriction (1280x720fps@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002743 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002744 timestamp_ms += kFrameIntervalMs;
2745 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002746 WaitForEncodedFrame(kWidth, kHeight);
asaperssonf7e294d2017-06-13 23:25:22 -07002747 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
Mirko Bonadei948b7e32018-08-14 07:23:21 +00002748 VerifyNoLimitation(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07002749 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2750 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2751 EXPECT_EQ(14, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2752
2753 // Trigger adapt up, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07002754 video_stream_encoder_->TriggerQualityHigh();
Mirko Bonadei948b7e32018-08-14 07:23:21 +00002755 VerifyNoLimitation(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07002756 EXPECT_EQ(14, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2757
mflodmancc3d4422017-08-03 08:27:51 -07002758 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07002759}
2760
mflodmancc3d4422017-08-03 08:27:51 -07002761TEST_F(VideoStreamEncoderTest, AdaptWithTwoReasonsAndDifferentOrder_Framerate) {
asaperssonf7e294d2017-06-13 23:25:22 -07002762 const int kWidth = 1280;
2763 const int kHeight = 720;
2764 const int64_t kFrameIntervalMs = 150;
2765 int64_t timestamp_ms = kFrameIntervalMs;
mflodmancc3d4422017-08-03 08:27:51 -07002766 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -07002767
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002768 // Enable BALANCED preference, no initial limitation.
asaperssonf7e294d2017-06-13 23:25:22 -07002769 AdaptingFrameForwarder source;
2770 source.set_adaptation_enabled(true);
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002771 video_stream_encoder_->SetSource(&source,
2772 webrtc::DegradationPreference::BALANCED);
asaperssonf7e294d2017-06-13 23:25:22 -07002773 timestamp_ms += kFrameIntervalMs;
2774 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002775 WaitForEncodedFrame(kWidth, kHeight);
Mirko Bonadei948b7e32018-08-14 07:23:21 +00002776 VerifyNoLimitation(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07002777 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2778 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2779 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2780 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
2781 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2782 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2783
2784 // Trigger cpu adapt down, expect scaled down resolution (960x540@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002785 video_stream_encoder_->TriggerCpuOveruse();
asaperssonf7e294d2017-06-13 23:25:22 -07002786 timestamp_ms += kFrameIntervalMs;
2787 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002788 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002789 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
2790 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2791 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2792 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2793 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
2794 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2795 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2796
2797 // Trigger cpu adapt down, expect scaled down resolution (640x360@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002798 video_stream_encoder_->TriggerCpuOveruse();
asaperssonf7e294d2017-06-13 23:25:22 -07002799 timestamp_ms += kFrameIntervalMs;
2800 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002801 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002802 VerifyFpsMaxResolutionLt(source.sink_wants(), source.last_wants());
2803 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2804 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2805 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2806 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
2807 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2808 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2809
2810 // Trigger quality adapt down, expect reduced fps (640x360@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07002811 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002812 timestamp_ms += kFrameIntervalMs;
2813 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002814 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002815 VerifyFpsLtResolutionEq(source.sink_wants(), source.last_wants());
2816 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2817 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2818 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2819 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
2820 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2821 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2822
2823 // Trigger cpu adapt up, expect increased fps (640x360@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002824 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssonf7e294d2017-06-13 23:25:22 -07002825 timestamp_ms += kFrameIntervalMs;
2826 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002827 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002828 VerifyFpsMaxResolutionEq(source.sink_wants(), source.last_wants());
2829 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2830 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2831 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2832 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
2833 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2834 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2835
2836 // Trigger quality adapt up, expect upscaled resolution (960x540@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002837 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002838 timestamp_ms += kFrameIntervalMs;
2839 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002840 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002841 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
2842 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2843 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2844 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2845 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
2846 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2847 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2848
2849 // Trigger cpu adapt up, expect no restriction (1280x720fps@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002850 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssonf7e294d2017-06-13 23:25:22 -07002851 timestamp_ms += kFrameIntervalMs;
2852 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002853 WaitForEncodedFrame(kWidth, kHeight);
asaperssonf7e294d2017-06-13 23:25:22 -07002854 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
Mirko Bonadei948b7e32018-08-14 07:23:21 +00002855 VerifyNoLimitation(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07002856 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2857 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2858 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2859 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
2860 EXPECT_EQ(4, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2861 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2862
2863 // Trigger adapt up, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07002864 video_stream_encoder_->TriggerQualityHigh();
Mirko Bonadei948b7e32018-08-14 07:23:21 +00002865 VerifyNoLimitation(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07002866 EXPECT_EQ(4, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2867 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2868
mflodmancc3d4422017-08-03 08:27:51 -07002869 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07002870}
2871
mflodmancc3d4422017-08-03 08:27:51 -07002872TEST_F(VideoStreamEncoderTest,
2873 AdaptWithTwoReasonsAndDifferentOrder_Resolution) {
asaperssonf7e294d2017-06-13 23:25:22 -07002874 const int kWidth = 640;
2875 const int kHeight = 360;
2876 const int kFpsLimit = 15;
2877 const int64_t kFrameIntervalMs = 150;
2878 int64_t timestamp_ms = kFrameIntervalMs;
mflodmancc3d4422017-08-03 08:27:51 -07002879 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -07002880
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002881 // Enable BALANCED preference, no initial limitation.
asaperssonf7e294d2017-06-13 23:25:22 -07002882 AdaptingFrameForwarder source;
2883 source.set_adaptation_enabled(true);
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002884 video_stream_encoder_->SetSource(&source,
2885 webrtc::DegradationPreference::BALANCED);
asaperssonf7e294d2017-06-13 23:25:22 -07002886 timestamp_ms += kFrameIntervalMs;
2887 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002888 WaitForEncodedFrame(kWidth, kHeight);
Mirko Bonadei948b7e32018-08-14 07:23:21 +00002889 VerifyNoLimitation(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07002890 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2891 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2892 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2893 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
2894 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2895 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2896
2897 // Trigger cpu adapt down, expect scaled down framerate (640x360@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07002898 video_stream_encoder_->TriggerCpuOveruse();
asaperssonf7e294d2017-06-13 23:25:22 -07002899 timestamp_ms += kFrameIntervalMs;
2900 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002901 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002902 VerifyFpsEqResolutionMax(source.sink_wants(), kFpsLimit);
2903 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2904 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2905 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2906 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_framerate);
2907 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2908 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2909
2910 // Trigger quality adapt down, expect scaled down resolution (480x270@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07002911 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002912 timestamp_ms += kFrameIntervalMs;
2913 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002914 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002915 VerifyFpsEqResolutionLt(source.sink_wants(), source.last_wants());
2916 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2917 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2918 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2919 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_framerate);
2920 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2921 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2922
2923 // Trigger cpu adapt up, expect upscaled resolution (640x360@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07002924 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssonf7e294d2017-06-13 23:25:22 -07002925 timestamp_ms += kFrameIntervalMs;
2926 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002927 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002928 VerifyFpsEqResolutionGt(source.sink_wants(), source.last_wants());
2929 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2930 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2931 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2932 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
2933 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2934 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2935
2936 // Trigger quality adapt up, expect increased fps (640x360@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002937 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002938 timestamp_ms += kFrameIntervalMs;
2939 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002940 WaitForEncodedFrame(timestamp_ms);
Mirko Bonadei948b7e32018-08-14 07:23:21 +00002941 VerifyNoLimitation(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07002942 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2943 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2944 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2945 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
2946 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2947 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2948
2949 // Trigger adapt up, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07002950 video_stream_encoder_->TriggerQualityHigh();
Mirko Bonadei948b7e32018-08-14 07:23:21 +00002951 VerifyNoLimitation(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07002952 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2953 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2954
mflodmancc3d4422017-08-03 08:27:51 -07002955 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07002956}
2957
mflodmancc3d4422017-08-03 08:27:51 -07002958TEST_F(VideoStreamEncoderTest, AcceptsFullHdAdaptedDownSimulcastFrames) {
ilnik6b826ef2017-06-16 06:53:48 -07002959 // Simulates simulcast behavior and makes highest stream resolutions divisible
2960 // by 4.
2961 class CroppingVideoStreamFactory
2962 : public VideoEncoderConfig::VideoStreamFactoryInterface {
2963 public:
2964 explicit CroppingVideoStreamFactory(size_t num_temporal_layers,
2965 int framerate)
2966 : num_temporal_layers_(num_temporal_layers), framerate_(framerate) {
2967 EXPECT_GT(num_temporal_layers, 0u);
2968 EXPECT_GT(framerate, 0);
2969 }
2970
2971 private:
2972 std::vector<VideoStream> CreateEncoderStreams(
2973 int width,
2974 int height,
2975 const VideoEncoderConfig& encoder_config) override {
Yves Gerey665174f2018-06-19 15:03:05 +02002976 std::vector<VideoStream> streams = test::CreateVideoStreams(
2977 width - width % 4, height - height % 4, encoder_config);
ilnik6b826ef2017-06-16 06:53:48 -07002978 for (VideoStream& stream : streams) {
Sergey Silkina796a7e2018-03-01 15:11:29 +01002979 stream.num_temporal_layers = num_temporal_layers_;
ilnik6b826ef2017-06-16 06:53:48 -07002980 stream.max_framerate = framerate_;
2981 }
2982 return streams;
2983 }
2984
2985 const size_t num_temporal_layers_;
2986 const int framerate_;
2987 };
2988
2989 const int kFrameWidth = 1920;
2990 const int kFrameHeight = 1080;
2991 // 3/4 of 1920.
2992 const int kAdaptedFrameWidth = 1440;
2993 // 3/4 of 1080 rounded down to multiple of 4.
2994 const int kAdaptedFrameHeight = 808;
2995 const int kFramerate = 24;
2996
mflodmancc3d4422017-08-03 08:27:51 -07002997 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
ilnik6b826ef2017-06-16 06:53:48 -07002998 // Trigger reconfigure encoder (without resetting the entire instance).
2999 VideoEncoderConfig video_encoder_config;
Niels Möller259a4972018-04-05 15:36:51 +02003000 video_encoder_config.codec_type = kVideoCodecVP8;
ilnik6b826ef2017-06-16 06:53:48 -07003001 video_encoder_config.max_bitrate_bps = kTargetBitrateBps;
3002 video_encoder_config.number_of_streams = 1;
3003 video_encoder_config.video_stream_factory =
3004 new rtc::RefCountedObject<CroppingVideoStreamFactory>(1, kFramerate);
mflodmancc3d4422017-08-03 08:27:51 -07003005 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
Niels Möllerf1338562018-04-26 09:51:47 +02003006 kMaxPayloadLength);
mflodmancc3d4422017-08-03 08:27:51 -07003007 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
ilnik6b826ef2017-06-16 06:53:48 -07003008
3009 video_source_.set_adaptation_enabled(true);
3010
3011 video_source_.IncomingCapturedFrame(
3012 CreateFrame(1, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07003013 WaitForEncodedFrame(kFrameWidth, kFrameHeight);
ilnik6b826ef2017-06-16 06:53:48 -07003014
3015 // Trigger CPU overuse, downscale by 3/4.
mflodmancc3d4422017-08-03 08:27:51 -07003016 video_stream_encoder_->TriggerCpuOveruse();
ilnik6b826ef2017-06-16 06:53:48 -07003017 video_source_.IncomingCapturedFrame(
3018 CreateFrame(2, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07003019 WaitForEncodedFrame(kAdaptedFrameWidth, kAdaptedFrameHeight);
ilnik6b826ef2017-06-16 06:53:48 -07003020
mflodmancc3d4422017-08-03 08:27:51 -07003021 video_stream_encoder_->Stop();
ilnik6b826ef2017-06-16 06:53:48 -07003022}
3023
mflodmancc3d4422017-08-03 08:27:51 -07003024TEST_F(VideoStreamEncoderTest, PeriodicallyUpdatesChannelParameters) {
sprang4847ae62017-06-27 07:06:52 -07003025 const int kFrameWidth = 1280;
3026 const int kFrameHeight = 720;
3027 const int kLowFps = 2;
3028 const int kHighFps = 30;
3029
mflodmancc3d4422017-08-03 08:27:51 -07003030 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
sprang4847ae62017-06-27 07:06:52 -07003031
3032 int64_t timestamp_ms = fake_clock_.TimeNanos() / rtc::kNumNanosecsPerMillisec;
3033 max_framerate_ = kLowFps;
3034
3035 // Insert 2 seconds of 2fps video.
3036 for (int i = 0; i < kLowFps * 2; ++i) {
3037 video_source_.IncomingCapturedFrame(
3038 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
3039 WaitForEncodedFrame(timestamp_ms);
3040 timestamp_ms += 1000 / kLowFps;
3041 }
3042
3043 // Make sure encoder is updated with new target.
mflodmancc3d4422017-08-03 08:27:51 -07003044 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
sprang4847ae62017-06-27 07:06:52 -07003045 video_source_.IncomingCapturedFrame(
3046 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
3047 WaitForEncodedFrame(timestamp_ms);
3048 timestamp_ms += 1000 / kLowFps;
3049
3050 EXPECT_EQ(kLowFps, fake_encoder_.GetConfiguredInputFramerate());
3051
3052 // Insert 30fps frames for just a little more than the forced update period.
3053 const int kVcmTimerIntervalFrames =
3054 (vcm::VCMProcessTimer::kDefaultProcessIntervalMs * kHighFps) / 1000;
3055 const int kFrameIntervalMs = 1000 / kHighFps;
3056 max_framerate_ = kHighFps;
3057 for (int i = 0; i < kVcmTimerIntervalFrames + 2; ++i) {
3058 video_source_.IncomingCapturedFrame(
3059 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
3060 // Wait for encoded frame, but skip ahead if it doesn't arrive as it might
3061 // be dropped if the encoder hans't been updated with the new higher target
3062 // framerate yet, causing it to overshoot the target bitrate and then
3063 // suffering the wrath of the media optimizer.
3064 TimedWaitForEncodedFrame(timestamp_ms, 2 * kFrameIntervalMs);
3065 timestamp_ms += kFrameIntervalMs;
3066 }
3067
3068 // Don expect correct measurement just yet, but it should be higher than
3069 // before.
3070 EXPECT_GT(fake_encoder_.GetConfiguredInputFramerate(), kLowFps);
3071
mflodmancc3d4422017-08-03 08:27:51 -07003072 video_stream_encoder_->Stop();
sprang4847ae62017-06-27 07:06:52 -07003073}
3074
mflodmancc3d4422017-08-03 08:27:51 -07003075TEST_F(VideoStreamEncoderTest, DoesNotUpdateBitrateAllocationWhenSuspended) {
sprang4847ae62017-06-27 07:06:52 -07003076 const int kFrameWidth = 1280;
3077 const int kFrameHeight = 720;
3078 const int kTargetBitrateBps = 1000000;
3079
3080 MockBitrateObserver bitrate_observer;
Niels Möller0327c2d2018-05-21 14:09:31 +02003081 video_stream_encoder_->SetBitrateAllocationObserver(&bitrate_observer);
sprang4847ae62017-06-27 07:06:52 -07003082
3083 EXPECT_CALL(bitrate_observer, OnBitrateAllocationUpdated(_)).Times(1);
3084 // Initial bitrate update.
mflodmancc3d4422017-08-03 08:27:51 -07003085 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
3086 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
sprang4847ae62017-06-27 07:06:52 -07003087
3088 // Insert a first video frame, causes another bitrate update.
3089 int64_t timestamp_ms = fake_clock_.TimeNanos() / rtc::kNumNanosecsPerMillisec;
3090 EXPECT_CALL(bitrate_observer, OnBitrateAllocationUpdated(_)).Times(1);
3091 video_source_.IncomingCapturedFrame(
3092 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
3093 WaitForEncodedFrame(timestamp_ms);
3094
3095 // Next, simulate video suspension due to pacer queue overrun.
mflodmancc3d4422017-08-03 08:27:51 -07003096 video_stream_encoder_->OnBitrateUpdated(0, 0, 1);
sprang4847ae62017-06-27 07:06:52 -07003097
3098 // Skip ahead until a new periodic parameter update should have occured.
3099 timestamp_ms += vcm::VCMProcessTimer::kDefaultProcessIntervalMs;
3100 fake_clock_.AdvanceTimeMicros(
3101 vcm::VCMProcessTimer::kDefaultProcessIntervalMs *
3102 rtc::kNumMicrosecsPerMillisec);
3103
3104 // Bitrate observer should not be called.
3105 EXPECT_CALL(bitrate_observer, OnBitrateAllocationUpdated(_)).Times(0);
3106 video_source_.IncomingCapturedFrame(
3107 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
3108 ExpectDroppedFrame();
3109
mflodmancc3d4422017-08-03 08:27:51 -07003110 video_stream_encoder_->Stop();
sprang4847ae62017-06-27 07:06:52 -07003111}
ilnik6b826ef2017-06-16 06:53:48 -07003112
Niels Möller4db138e2018-04-19 09:04:13 +02003113TEST_F(VideoStreamEncoderTest,
3114 DefaultCpuAdaptationThresholdsForSoftwareEncoder) {
3115 const int kFrameWidth = 1280;
3116 const int kFrameHeight = 720;
3117 const CpuOveruseOptions default_options;
3118 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
3119 video_source_.IncomingCapturedFrame(
3120 CreateFrame(1, kFrameWidth, kFrameHeight));
3121 WaitForEncodedFrame(1);
3122 EXPECT_EQ(video_stream_encoder_->overuse_detector_proxy_->GetOptions()
3123 .low_encode_usage_threshold_percent,
3124 default_options.low_encode_usage_threshold_percent);
3125 EXPECT_EQ(video_stream_encoder_->overuse_detector_proxy_->GetOptions()
3126 .high_encode_usage_threshold_percent,
3127 default_options.high_encode_usage_threshold_percent);
3128 video_stream_encoder_->Stop();
3129}
3130
3131TEST_F(VideoStreamEncoderTest,
3132 HigherCpuAdaptationThresholdsForHardwareEncoder) {
3133 const int kFrameWidth = 1280;
3134 const int kFrameHeight = 720;
3135 CpuOveruseOptions hardware_options;
3136 hardware_options.low_encode_usage_threshold_percent = 150;
3137 hardware_options.high_encode_usage_threshold_percent = 200;
3138 encoder_factory_.SetIsHardwareAccelerated(true);
3139
3140 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
3141 video_source_.IncomingCapturedFrame(
3142 CreateFrame(1, kFrameWidth, kFrameHeight));
3143 WaitForEncodedFrame(1);
3144 EXPECT_EQ(video_stream_encoder_->overuse_detector_proxy_->GetOptions()
3145 .low_encode_usage_threshold_percent,
3146 hardware_options.low_encode_usage_threshold_percent);
3147 EXPECT_EQ(video_stream_encoder_->overuse_detector_proxy_->GetOptions()
3148 .high_encode_usage_threshold_percent,
3149 hardware_options.high_encode_usage_threshold_percent);
3150 video_stream_encoder_->Stop();
3151}
3152
perkj26091b12016-09-01 01:17:40 -07003153} // namespace webrtc