blob: ba21cf99596597a97ad6f34a144422ed694f1f95 [file] [log] [blame]
perkj26091b12016-09-01 01:17:40 -07001/*
2 * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved.
3 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
sprangfe627f32017-03-29 08:24:59 -070011#include <algorithm>
perkj803d97f2016-11-01 11:45:46 -070012#include <limits>
Per512ecb32016-09-23 15:52:06 +020013#include <utility>
14
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020015#include "api/video/i420_buffer.h"
16#include "media/base/videoadapter.h"
17#include "modules/video_coding/codecs/vp8/temporal_layers.h"
Sergey Silkin86684962018-03-28 19:32:37 +020018#include "modules/video_coding/codecs/vp9/include/vp9_globals.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020019#include "modules/video_coding/utility/default_video_bitrate_allocator.h"
20#include "rtc_base/fakeclock.h"
21#include "rtc_base/logging.h"
22#include "system_wrappers/include/metrics_default.h"
23#include "system_wrappers/include/sleep.h"
Niels Möller4db138e2018-04-19 09:04:13 +020024#include "test/encoder_proxy_factory.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020025#include "test/encoder_settings.h"
26#include "test/fake_encoder.h"
27#include "test/frame_generator.h"
28#include "test/gmock.h"
29#include "test/gtest.h"
30#include "video/send_statistics_proxy.h"
31#include "video/video_stream_encoder.h"
perkj26091b12016-09-01 01:17:40 -070032
kthelgason33ce8892016-12-09 03:53:59 -080033namespace {
kthelgason33ce8892016-12-09 03:53:59 -080034const int kMinPixelsPerFrame = 320 * 180;
sprangc5d62e22017-04-02 23:53:04 -070035const int kMinFramerateFps = 2;
Jonathan Yubc771b72017-12-08 17:04:29 -080036const int kMinBalancedFramerateFps = 7;
sprangc5d62e22017-04-02 23:53:04 -070037const int64_t kFrameTimeoutMs = 100;
38} // namespace
kthelgason33ce8892016-12-09 03:53:59 -080039
perkj26091b12016-09-01 01:17:40 -070040namespace webrtc {
41
kthelgason876222f2016-11-29 01:44:11 -080042using DegredationPreference = VideoSendStream::DegradationPreference;
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öller7dc26b72017-12-06 10:27:48 +010095 VideoStreamEncoderUnderTest(SendStatisticsProxy* stats_proxy,
96 const VideoSendStream::Config::EncoderSettings& settings)
mflodmancc3d4422017-08-03 08:27:51 -070097 : VideoStreamEncoder(
98 1 /* number_of_cores */,
99 stats_proxy,
100 settings,
101 nullptr /* pre_encode_callback */,
mflodmancc3d4422017-08-03 08:27:51 -0700102 std::unique_ptr<OveruseFrameDetector>(
Niels Möller7dc26b72017-12-06 10:27:48 +0100103 overuse_detector_proxy_ = new CpuOveruseDetectorProxy(
mflodmancc3d4422017-08-03 08:27:51 -0700104 stats_proxy))) {}
perkj803d97f2016-11-01 11:45:46 -0700105
sprangb1ca0732017-02-01 08:38:12 -0800106 void PostTaskAndWait(bool down, AdaptReason reason) {
perkj803d97f2016-11-01 11:45:46 -0700107 rtc::Event event(false, false);
kthelgason876222f2016-11-29 01:44:11 -0800108 encoder_queue()->PostTask([this, &event, reason, down] {
sprangb1ca0732017-02-01 08:38:12 -0800109 down ? AdaptDown(reason) : AdaptUp(reason);
perkj803d97f2016-11-01 11:45:46 -0700110 event.Set();
111 });
perkj070ba852017-02-16 15:46:27 -0800112 ASSERT_TRUE(event.Wait(5000));
perkj803d97f2016-11-01 11:45:46 -0700113 }
114
kthelgason2fc52542017-03-03 00:24:41 -0800115 // This is used as a synchronisation mechanism, to make sure that the
116 // encoder queue is not blocked before we start sending it frames.
117 void WaitUntilTaskQueueIsIdle() {
118 rtc::Event event(false, false);
119 encoder_queue()->PostTask([&event] {
120 event.Set();
121 });
122 ASSERT_TRUE(event.Wait(5000));
123 }
124
sprangb1ca0732017-02-01 08:38:12 -0800125 void TriggerCpuOveruse() { PostTaskAndWait(true, AdaptReason::kCpu); }
kthelgason876222f2016-11-29 01:44:11 -0800126
sprangb1ca0732017-02-01 08:38:12 -0800127 void TriggerCpuNormalUsage() { PostTaskAndWait(false, AdaptReason::kCpu); }
kthelgason876222f2016-11-29 01:44:11 -0800128
sprangb1ca0732017-02-01 08:38:12 -0800129 void TriggerQualityLow() { PostTaskAndWait(true, AdaptReason::kQuality); }
kthelgason876222f2016-11-29 01:44:11 -0800130
sprangb1ca0732017-02-01 08:38:12 -0800131 void TriggerQualityHigh() { PostTaskAndWait(false, AdaptReason::kQuality); }
sprangfda496a2017-06-15 04:21:07 -0700132
Niels Möller7dc26b72017-12-06 10:27:48 +0100133 CpuOveruseDetectorProxy* overuse_detector_proxy_;
perkj803d97f2016-11-01 11:45:46 -0700134};
135
asapersson5f7226f2016-11-25 04:37:00 -0800136class VideoStreamFactory
137 : public VideoEncoderConfig::VideoStreamFactoryInterface {
138 public:
sprangfda496a2017-06-15 04:21:07 -0700139 explicit VideoStreamFactory(size_t num_temporal_layers, int framerate)
140 : num_temporal_layers_(num_temporal_layers), framerate_(framerate) {
asapersson5f7226f2016-11-25 04:37:00 -0800141 EXPECT_GT(num_temporal_layers, 0u);
sprangfda496a2017-06-15 04:21:07 -0700142 EXPECT_GT(framerate, 0);
asapersson5f7226f2016-11-25 04:37:00 -0800143 }
144
145 private:
146 std::vector<VideoStream> CreateEncoderStreams(
147 int width,
148 int height,
149 const VideoEncoderConfig& encoder_config) override {
150 std::vector<VideoStream> streams =
151 test::CreateVideoStreams(width, height, encoder_config);
152 for (VideoStream& stream : streams) {
Sergey Silkina796a7e2018-03-01 15:11:29 +0100153 stream.num_temporal_layers = num_temporal_layers_;
sprangfda496a2017-06-15 04:21:07 -0700154 stream.max_framerate = framerate_;
asapersson5f7226f2016-11-25 04:37:00 -0800155 }
156 return streams;
157 }
sprangfda496a2017-06-15 04:21:07 -0700158
asapersson5f7226f2016-11-25 04:37:00 -0800159 const size_t num_temporal_layers_;
sprangfda496a2017-06-15 04:21:07 -0700160 const int framerate_;
asapersson5f7226f2016-11-25 04:37:00 -0800161};
162
ilnik6b826ef2017-06-16 06:53:48 -0700163
sprangb1ca0732017-02-01 08:38:12 -0800164class AdaptingFrameForwarder : public test::FrameForwarder {
165 public:
166 AdaptingFrameForwarder() : adaptation_enabled_(false) {}
asaperssonfab67072017-04-04 05:51:49 -0700167 ~AdaptingFrameForwarder() override {}
sprangb1ca0732017-02-01 08:38:12 -0800168
169 void set_adaptation_enabled(bool enabled) {
170 rtc::CritScope cs(&crit_);
171 adaptation_enabled_ = enabled;
172 }
173
asaperssonfab67072017-04-04 05:51:49 -0700174 bool adaption_enabled() const {
sprangb1ca0732017-02-01 08:38:12 -0800175 rtc::CritScope cs(&crit_);
176 return adaptation_enabled_;
177 }
178
asapersson09f05612017-05-15 23:40:18 -0700179 rtc::VideoSinkWants last_wants() const {
180 rtc::CritScope cs(&crit_);
181 return last_wants_;
182 }
183
Jonathan Yubc771b72017-12-08 17:04:29 -0800184 rtc::Optional<int> last_sent_width() const { return last_width_; }
185 rtc::Optional<int> last_sent_height() const { return last_height_; }
186
sprangb1ca0732017-02-01 08:38:12 -0800187 void IncomingCapturedFrame(const VideoFrame& video_frame) override {
188 int cropped_width = 0;
189 int cropped_height = 0;
190 int out_width = 0;
191 int out_height = 0;
sprangc5d62e22017-04-02 23:53:04 -0700192 if (adaption_enabled()) {
193 if (adapter_.AdaptFrameResolution(
194 video_frame.width(), video_frame.height(),
195 video_frame.timestamp_us() * 1000, &cropped_width,
196 &cropped_height, &out_width, &out_height)) {
197 VideoFrame adapted_frame(new rtc::RefCountedObject<TestBuffer>(
198 nullptr, out_width, out_height),
199 99, 99, kVideoRotation_0);
200 adapted_frame.set_ntp_time_ms(video_frame.ntp_time_ms());
201 test::FrameForwarder::IncomingCapturedFrame(adapted_frame);
Jonathan Yubc771b72017-12-08 17:04:29 -0800202 last_width_.emplace(adapted_frame.width());
203 last_height_.emplace(adapted_frame.height());
204 } else {
205 last_width_ = rtc::nullopt;
206 last_height_ = rtc::nullopt;
sprangc5d62e22017-04-02 23:53:04 -0700207 }
sprangb1ca0732017-02-01 08:38:12 -0800208 } else {
209 test::FrameForwarder::IncomingCapturedFrame(video_frame);
Jonathan Yubc771b72017-12-08 17:04:29 -0800210 last_width_.emplace(video_frame.width());
211 last_height_.emplace(video_frame.height());
sprangb1ca0732017-02-01 08:38:12 -0800212 }
213 }
214
215 void AddOrUpdateSink(rtc::VideoSinkInterface<VideoFrame>* sink,
216 const rtc::VideoSinkWants& wants) override {
217 rtc::CritScope cs(&crit_);
asapersson09f05612017-05-15 23:40:18 -0700218 last_wants_ = sink_wants();
sprangc5d62e22017-04-02 23:53:04 -0700219 adapter_.OnResolutionFramerateRequest(wants.target_pixel_count,
220 wants.max_pixel_count,
221 wants.max_framerate_fps);
sprangb1ca0732017-02-01 08:38:12 -0800222 test::FrameForwarder::AddOrUpdateSink(sink, wants);
223 }
sprangb1ca0732017-02-01 08:38:12 -0800224 cricket::VideoAdapter adapter_;
danilchapa37de392017-09-09 04:17:22 -0700225 bool adaptation_enabled_ RTC_GUARDED_BY(crit_);
226 rtc::VideoSinkWants last_wants_ RTC_GUARDED_BY(crit_);
Jonathan Yubc771b72017-12-08 17:04:29 -0800227 rtc::Optional<int> last_width_;
228 rtc::Optional<int> last_height_;
sprangb1ca0732017-02-01 08:38:12 -0800229};
sprangc5d62e22017-04-02 23:53:04 -0700230
231class MockableSendStatisticsProxy : public SendStatisticsProxy {
232 public:
233 MockableSendStatisticsProxy(Clock* clock,
234 const VideoSendStream::Config& config,
235 VideoEncoderConfig::ContentType content_type)
236 : SendStatisticsProxy(clock, config, content_type) {}
237
238 VideoSendStream::Stats GetStats() override {
239 rtc::CritScope cs(&lock_);
240 if (mock_stats_)
241 return *mock_stats_;
242 return SendStatisticsProxy::GetStats();
243 }
244
245 void SetMockStats(const VideoSendStream::Stats& stats) {
246 rtc::CritScope cs(&lock_);
247 mock_stats_.emplace(stats);
248 }
249
250 void ResetMockStats() {
251 rtc::CritScope cs(&lock_);
252 mock_stats_.reset();
253 }
254
255 private:
256 rtc::CriticalSection lock_;
danilchapa37de392017-09-09 04:17:22 -0700257 rtc::Optional<VideoSendStream::Stats> mock_stats_ RTC_GUARDED_BY(lock_);
sprangc5d62e22017-04-02 23:53:04 -0700258};
259
sprang4847ae62017-06-27 07:06:52 -0700260class MockBitrateObserver : public VideoBitrateAllocationObserver {
261 public:
Erik Språng566124a2018-04-23 12:32:22 +0200262 MOCK_METHOD1(OnBitrateAllocationUpdated, void(const VideoBitrateAllocation&));
sprang4847ae62017-06-27 07:06:52 -0700263};
264
perkj803d97f2016-11-01 11:45:46 -0700265} // namespace
266
mflodmancc3d4422017-08-03 08:27:51 -0700267class VideoStreamEncoderTest : public ::testing::Test {
perkj26091b12016-09-01 01:17:40 -0700268 public:
269 static const int kDefaultTimeoutMs = 30 * 1000;
270
mflodmancc3d4422017-08-03 08:27:51 -0700271 VideoStreamEncoderTest()
perkj26091b12016-09-01 01:17:40 -0700272 : video_send_config_(VideoSendStream::Config(nullptr)),
perkjfa10b552016-10-02 23:45:26 -0700273 codec_width_(320),
274 codec_height_(240),
sprang4847ae62017-06-27 07:06:52 -0700275 max_framerate_(30),
perkj26091b12016-09-01 01:17:40 -0700276 fake_encoder_(),
Niels Möller4db138e2018-04-19 09:04:13 +0200277 encoder_factory_(&fake_encoder_),
sprangc5d62e22017-04-02 23:53:04 -0700278 stats_proxy_(new MockableSendStatisticsProxy(
perkj803d97f2016-11-01 11:45:46 -0700279 Clock::GetRealTimeClock(),
280 video_send_config_,
281 webrtc::VideoEncoderConfig::ContentType::kRealtimeVideo)),
perkj26091b12016-09-01 01:17:40 -0700282 sink_(&fake_encoder_) {}
283
284 void SetUp() override {
perkj803d97f2016-11-01 11:45:46 -0700285 metrics::Reset();
perkj26091b12016-09-01 01:17:40 -0700286 video_send_config_ = VideoSendStream::Config(nullptr);
Niels Möller4db138e2018-04-19 09:04:13 +0200287 video_send_config_.encoder_settings.encoder_factory = &encoder_factory_;
Niels Möller259a4972018-04-05 15:36:51 +0200288 video_send_config_.rtp.payload_name = "FAKE";
289 video_send_config_.rtp.payload_type = 125;
perkj26091b12016-09-01 01:17:40 -0700290
Per512ecb32016-09-23 15:52:06 +0200291 VideoEncoderConfig video_encoder_config;
Niels Möller259a4972018-04-05 15:36:51 +0200292 test::FillEncoderConfiguration(kVideoCodecVP8, 1, &video_encoder_config);
sprang4847ae62017-06-27 07:06:52 -0700293 video_encoder_config.video_stream_factory =
294 new rtc::RefCountedObject<VideoStreamFactory>(1, max_framerate_);
Erik Språng08127a92016-11-16 16:41:30 +0100295 video_encoder_config_ = video_encoder_config.Copy();
sprang4847ae62017-06-27 07:06:52 -0700296
297 // Framerate limit is specified by the VideoStreamFactory.
298 std::vector<VideoStream> streams =
299 video_encoder_config.video_stream_factory->CreateEncoderStreams(
300 codec_width_, codec_height_, video_encoder_config);
301 max_framerate_ = streams[0].max_framerate;
302 fake_clock_.SetTimeMicros(1234);
303
asapersson5f7226f2016-11-25 04:37:00 -0800304 ConfigureEncoder(std::move(video_encoder_config), true /* nack_enabled */);
305 }
306
307 void ConfigureEncoder(VideoEncoderConfig video_encoder_config,
308 bool nack_enabled) {
mflodmancc3d4422017-08-03 08:27:51 -0700309 if (video_stream_encoder_)
310 video_stream_encoder_->Stop();
311 video_stream_encoder_.reset(new VideoStreamEncoderUnderTest(
perkj803d97f2016-11-01 11:45:46 -0700312 stats_proxy_.get(), video_send_config_.encoder_settings));
mflodmancc3d4422017-08-03 08:27:51 -0700313 video_stream_encoder_->SetSink(&sink_, false /* rotation_applied */);
314 video_stream_encoder_->SetSource(
sprangc5d62e22017-04-02 23:53:04 -0700315 &video_source_,
316 VideoSendStream::DegradationPreference::kMaintainFramerate);
mflodmancc3d4422017-08-03 08:27:51 -0700317 video_stream_encoder_->SetStartBitrate(kTargetBitrateBps);
318 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
319 kMaxPayloadLength, nack_enabled);
320 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
asapersson5f7226f2016-11-25 04:37:00 -0800321 }
322
323 void ResetEncoder(const std::string& payload_name,
324 size_t num_streams,
325 size_t num_temporal_layers,
emircanbbcc3562017-08-18 00:28:40 -0700326 unsigned char num_spatial_layers,
sprang4847ae62017-06-27 07:06:52 -0700327 bool nack_enabled,
328 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 }
asapersson5f7226f2016-11-25 04:37:00 -0800348 ConfigureEncoder(std::move(video_encoder_config), nack_enabled);
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) {
383 EXPECT_EQ(std::numeric_limits<int>::max(), wants1.max_framerate_fps);
384 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) {
390 EXPECT_EQ(std::numeric_limits<int>::max(), wants1.max_framerate_fps);
391 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) {
396 EXPECT_EQ(std::numeric_limits<int>::max(), wants1.max_framerate_fps);
397 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) {
427 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 {
457 EXPECT_EQ(std::numeric_limits<int>::max(), fps_limit);
458 }
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),
803 kMaxPayloadLength,
804 true /* nack_enabled */);
Per512ecb32016-09-23 15:52:06 +0200805
806 // Capture a frame and wait for it to synchronize with the encoder thread.
Perf8c5f2b2016-09-23 16:24:55 +0200807 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700808 WaitForEncodedFrame(2);
Per21d45d22016-10-30 21:37:57 +0100809 EXPECT_EQ(2, sink_.number_of_reconfigurations());
perkj3b703ed2016-09-29 23:25:40 -0700810 EXPECT_EQ(9999, sink_.last_min_transmit_bitrate());
perkj26105b42016-09-29 22:39:10 -0700811
mflodmancc3d4422017-08-03 08:27:51 -0700812 video_stream_encoder_->Stop();
perkj26105b42016-09-29 22:39:10 -0700813}
814
mflodmancc3d4422017-08-03 08:27:51 -0700815TEST_F(VideoStreamEncoderTest, FrameResolutionChangeReconfigureEncoder) {
816 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkjfa10b552016-10-02 23:45:26 -0700817
818 // Capture a frame and wait for it to synchronize with the encoder thread.
819 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700820 WaitForEncodedFrame(1);
Per21d45d22016-10-30 21:37:57 +0100821 // The encoder will have been configured once.
822 EXPECT_EQ(1, sink_.number_of_reconfigurations());
perkjfa10b552016-10-02 23:45:26 -0700823 EXPECT_EQ(codec_width_, fake_encoder_.codec_config().width);
824 EXPECT_EQ(codec_height_, fake_encoder_.codec_config().height);
825
826 codec_width_ *= 2;
827 codec_height_ *= 2;
828 // Capture a frame with a higher resolution and wait for it to synchronize
829 // with the encoder thread.
830 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700831 WaitForEncodedFrame(2);
perkjfa10b552016-10-02 23:45:26 -0700832 EXPECT_EQ(codec_width_, fake_encoder_.codec_config().width);
833 EXPECT_EQ(codec_height_, fake_encoder_.codec_config().height);
Per21d45d22016-10-30 21:37:57 +0100834 EXPECT_EQ(2, sink_.number_of_reconfigurations());
perkjfa10b552016-10-02 23:45:26 -0700835
mflodmancc3d4422017-08-03 08:27:51 -0700836 video_stream_encoder_->Stop();
perkjfa10b552016-10-02 23:45:26 -0700837}
838
mflodmancc3d4422017-08-03 08:27:51 -0700839TEST_F(VideoStreamEncoderTest, SwitchSourceDeregisterEncoderAsSink) {
perkj803d97f2016-11-01 11:45:46 -0700840 EXPECT_TRUE(video_source_.has_sinks());
841 test::FrameForwarder new_video_source;
mflodmancc3d4422017-08-03 08:27:51 -0700842 video_stream_encoder_->SetSource(
sprangc5d62e22017-04-02 23:53:04 -0700843 &new_video_source,
844 VideoSendStream::DegradationPreference::kMaintainFramerate);
perkj803d97f2016-11-01 11:45:46 -0700845 EXPECT_FALSE(video_source_.has_sinks());
846 EXPECT_TRUE(new_video_source.has_sinks());
847
mflodmancc3d4422017-08-03 08:27:51 -0700848 video_stream_encoder_->Stop();
perkj803d97f2016-11-01 11:45:46 -0700849}
850
mflodmancc3d4422017-08-03 08:27:51 -0700851TEST_F(VideoStreamEncoderTest, SinkWantsRotationApplied) {
perkj803d97f2016-11-01 11:45:46 -0700852 EXPECT_FALSE(video_source_.sink_wants().rotation_applied);
mflodmancc3d4422017-08-03 08:27:51 -0700853 video_stream_encoder_->SetSink(&sink_, true /*rotation_applied*/);
perkj803d97f2016-11-01 11:45:46 -0700854 EXPECT_TRUE(video_source_.sink_wants().rotation_applied);
mflodmancc3d4422017-08-03 08:27:51 -0700855 video_stream_encoder_->Stop();
perkj803d97f2016-11-01 11:45:46 -0700856}
857
Jonathan Yubc771b72017-12-08 17:04:29 -0800858TEST_F(VideoStreamEncoderTest, TestCpuDowngrades_BalancedMode) {
859 const int kFramerateFps = 30;
asaperssonf7e294d2017-06-13 23:25:22 -0700860 const int kWidth = 1280;
861 const int kHeight = 720;
Jonathan Yubc771b72017-12-08 17:04:29 -0800862
863 // We rely on the automatic resolution adaptation, but we handle framerate
864 // adaptation manually by mocking the stats proxy.
865 video_source_.set_adaptation_enabled(true);
asaperssonf7e294d2017-06-13 23:25:22 -0700866
867 // Enable kBalanced preference, no initial limitation.
Jonathan Yubc771b72017-12-08 17:04:29 -0800868 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
mflodmancc3d4422017-08-03 08:27:51 -0700869 video_stream_encoder_->SetSource(
Jonathan Yubc771b72017-12-08 17:04:29 -0800870 &video_source_,
mflodmancc3d4422017-08-03 08:27:51 -0700871 VideoSendStream::DegradationPreference::kBalanced);
Jonathan Yubc771b72017-12-08 17:04:29 -0800872 VerifyNoLimitation(video_source_.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -0700873 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
Jonathan Yubc771b72017-12-08 17:04:29 -0800874 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
asaperssonf7e294d2017-06-13 23:25:22 -0700875 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
876
Jonathan Yubc771b72017-12-08 17:04:29 -0800877 // Adapt down as far as possible.
878 rtc::VideoSinkWants last_wants;
879 int64_t t = 1;
880 int loop_count = 0;
881 do {
882 ++loop_count;
883 last_wants = video_source_.sink_wants();
884
885 // Simulate the framerate we've been asked to adapt to.
886 const int fps = std::min(kFramerateFps, last_wants.max_framerate_fps);
887 const int frame_interval_ms = rtc::kNumMillisecsPerSec / fps;
888 VideoSendStream::Stats mock_stats = stats_proxy_->GetStats();
889 mock_stats.input_frame_rate = fps;
890 stats_proxy_->SetMockStats(mock_stats);
891
892 video_source_.IncomingCapturedFrame(CreateFrame(t, kWidth, kHeight));
893 sink_.WaitForEncodedFrame(t);
894 t += frame_interval_ms;
895
mflodmancc3d4422017-08-03 08:27:51 -0700896 video_stream_encoder_->TriggerCpuOveruse();
Jonathan Yubc771b72017-12-08 17:04:29 -0800897 VerifyBalancedModeFpsRange(
898 video_source_.sink_wants(),
899 *video_source_.last_sent_width() * *video_source_.last_sent_height());
900 } while (video_source_.sink_wants().max_pixel_count <
901 last_wants.max_pixel_count ||
902 video_source_.sink_wants().max_framerate_fps <
903 last_wants.max_framerate_fps);
asaperssonf7e294d2017-06-13 23:25:22 -0700904
Jonathan Yubc771b72017-12-08 17:04:29 -0800905 // Verify that we've adapted all the way down.
906 stats_proxy_->ResetMockStats();
asaperssonf7e294d2017-06-13 23:25:22 -0700907 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
Jonathan Yubc771b72017-12-08 17:04:29 -0800908 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_framerate);
909 EXPECT_EQ(loop_count - 1,
asaperssonf7e294d2017-06-13 23:25:22 -0700910 stats_proxy_->GetStats().number_of_cpu_adapt_changes);
Jonathan Yubc771b72017-12-08 17:04:29 -0800911 EXPECT_EQ(kMinPixelsPerFrame, *video_source_.last_sent_width() *
912 *video_source_.last_sent_height());
913 EXPECT_EQ(kMinBalancedFramerateFps,
914 video_source_.sink_wants().max_framerate_fps);
asaperssonf7e294d2017-06-13 23:25:22 -0700915
Jonathan Yubc771b72017-12-08 17:04:29 -0800916 // Adapt back up the same number of times we adapted down.
917 for (int i = 0; i < loop_count - 1; ++i) {
918 last_wants = video_source_.sink_wants();
919
920 // Simulate the framerate we've been asked to adapt to.
921 const int fps = std::min(kFramerateFps, last_wants.max_framerate_fps);
922 const int frame_interval_ms = rtc::kNumMillisecsPerSec / fps;
923 VideoSendStream::Stats mock_stats = stats_proxy_->GetStats();
924 mock_stats.input_frame_rate = fps;
925 stats_proxy_->SetMockStats(mock_stats);
926
927 video_source_.IncomingCapturedFrame(CreateFrame(t, kWidth, kHeight));
928 sink_.WaitForEncodedFrame(t);
929 t += frame_interval_ms;
930
mflodmancc3d4422017-08-03 08:27:51 -0700931 video_stream_encoder_->TriggerCpuNormalUsage();
Jonathan Yubc771b72017-12-08 17:04:29 -0800932 VerifyBalancedModeFpsRange(
933 video_source_.sink_wants(),
934 *video_source_.last_sent_width() * *video_source_.last_sent_height());
935 EXPECT_TRUE(video_source_.sink_wants().max_pixel_count >
936 last_wants.max_pixel_count ||
937 video_source_.sink_wants().max_framerate_fps >
938 last_wants.max_framerate_fps);
asaperssonf7e294d2017-06-13 23:25:22 -0700939 }
940
Jonathan Yubc771b72017-12-08 17:04:29 -0800941 VerifyNoLimitation(video_source_.sink_wants());
942 stats_proxy_->ResetMockStats();
asaperssonf7e294d2017-06-13 23:25:22 -0700943 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
Jonathan Yubc771b72017-12-08 17:04:29 -0800944 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
945 EXPECT_EQ((loop_count - 1) * 2,
946 stats_proxy_->GetStats().number_of_cpu_adapt_changes);
asaperssonf7e294d2017-06-13 23:25:22 -0700947
mflodmancc3d4422017-08-03 08:27:51 -0700948 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -0700949}
mflodmancc3d4422017-08-03 08:27:51 -0700950TEST_F(VideoStreamEncoderTest, SinkWantsStoredByDegradationPreference) {
951 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson02465b82017-04-10 01:12:52 -0700952 VerifyNoLimitation(video_source_.sink_wants());
perkj803d97f2016-11-01 11:45:46 -0700953
sprangc5d62e22017-04-02 23:53:04 -0700954 const int kFrameWidth = 1280;
955 const int kFrameHeight = 720;
956 const int kFrameIntervalMs = 1000 / 30;
957
958 int frame_timestamp = 1;
perkj803d97f2016-11-01 11:45:46 -0700959
kthelgason5e13d412016-12-01 03:59:51 -0800960 video_source_.IncomingCapturedFrame(
sprangc5d62e22017-04-02 23:53:04 -0700961 CreateFrame(frame_timestamp, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -0700962 WaitForEncodedFrame(frame_timestamp);
sprangc5d62e22017-04-02 23:53:04 -0700963 frame_timestamp += kFrameIntervalMs;
964
perkj803d97f2016-11-01 11:45:46 -0700965 // Trigger CPU overuse.
mflodmancc3d4422017-08-03 08:27:51 -0700966 video_stream_encoder_->TriggerCpuOveruse();
perkj803d97f2016-11-01 11:45:46 -0700967 video_source_.IncomingCapturedFrame(
sprangc5d62e22017-04-02 23:53:04 -0700968 CreateFrame(frame_timestamp, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -0700969 WaitForEncodedFrame(frame_timestamp);
sprangc5d62e22017-04-02 23:53:04 -0700970 frame_timestamp += kFrameIntervalMs;
sprang3ea3c772017-03-30 07:23:48 -0700971
asapersson0944a802017-04-07 00:57:58 -0700972 // Default degradation preference is maintain-framerate, so will lower max
sprangc5d62e22017-04-02 23:53:04 -0700973 // wanted resolution.
974 EXPECT_FALSE(video_source_.sink_wants().target_pixel_count);
975 EXPECT_LT(video_source_.sink_wants().max_pixel_count,
976 kFrameWidth * kFrameHeight);
977 EXPECT_EQ(std::numeric_limits<int>::max(),
978 video_source_.sink_wants().max_framerate_fps);
979
980 // Set new source, switch to maintain-resolution.
perkj803d97f2016-11-01 11:45:46 -0700981 test::FrameForwarder new_video_source;
mflodmancc3d4422017-08-03 08:27:51 -0700982 video_stream_encoder_->SetSource(
perkj803d97f2016-11-01 11:45:46 -0700983 &new_video_source,
984 VideoSendStream::DegradationPreference::kMaintainResolution);
985
sprangc5d62e22017-04-02 23:53:04 -0700986 // Initially no degradation registered.
asapersson02465b82017-04-10 01:12:52 -0700987 VerifyNoLimitation(new_video_source.sink_wants());
perkj803d97f2016-11-01 11:45:46 -0700988
sprangc5d62e22017-04-02 23:53:04 -0700989 // Force an input frame rate to be available, or the adaptation call won't
990 // know what framerate to adapt form.
asapersson02465b82017-04-10 01:12:52 -0700991 const int kInputFps = 30;
sprangc5d62e22017-04-02 23:53:04 -0700992 VideoSendStream::Stats stats = stats_proxy_->GetStats();
asapersson02465b82017-04-10 01:12:52 -0700993 stats.input_frame_rate = kInputFps;
sprangc5d62e22017-04-02 23:53:04 -0700994 stats_proxy_->SetMockStats(stats);
995
mflodmancc3d4422017-08-03 08:27:51 -0700996 video_stream_encoder_->TriggerCpuOveruse();
perkj803d97f2016-11-01 11:45:46 -0700997 new_video_source.IncomingCapturedFrame(
sprangc5d62e22017-04-02 23:53:04 -0700998 CreateFrame(frame_timestamp, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -0700999 WaitForEncodedFrame(frame_timestamp);
sprangc5d62e22017-04-02 23:53:04 -07001000 frame_timestamp += kFrameIntervalMs;
1001
1002 // Some framerate constraint should be set.
sprang84a37592017-02-10 07:04:27 -08001003 EXPECT_FALSE(new_video_source.sink_wants().target_pixel_count);
sprangc5d62e22017-04-02 23:53:04 -07001004 EXPECT_EQ(std::numeric_limits<int>::max(),
1005 new_video_source.sink_wants().max_pixel_count);
asapersson02465b82017-04-10 01:12:52 -07001006 EXPECT_LT(new_video_source.sink_wants().max_framerate_fps, kInputFps);
sprangc5d62e22017-04-02 23:53:04 -07001007
asapersson02465b82017-04-10 01:12:52 -07001008 // Turn off degradation completely.
mflodmancc3d4422017-08-03 08:27:51 -07001009 video_stream_encoder_->SetSource(
sprangc5d62e22017-04-02 23:53:04 -07001010 &new_video_source,
1011 VideoSendStream::DegradationPreference::kDegradationDisabled);
asapersson02465b82017-04-10 01:12:52 -07001012 VerifyNoLimitation(new_video_source.sink_wants());
sprangc5d62e22017-04-02 23:53:04 -07001013
mflodmancc3d4422017-08-03 08:27:51 -07001014 video_stream_encoder_->TriggerCpuOveruse();
sprangc5d62e22017-04-02 23:53:04 -07001015 new_video_source.IncomingCapturedFrame(
1016 CreateFrame(frame_timestamp, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07001017 WaitForEncodedFrame(frame_timestamp);
sprangc5d62e22017-04-02 23:53:04 -07001018 frame_timestamp += kFrameIntervalMs;
1019
1020 // Still no degradation.
asapersson02465b82017-04-10 01:12:52 -07001021 VerifyNoLimitation(new_video_source.sink_wants());
perkj803d97f2016-11-01 11:45:46 -07001022
1023 // Calling SetSource with resolution scaling enabled apply the old SinkWants.
mflodmancc3d4422017-08-03 08:27:51 -07001024 video_stream_encoder_->SetSource(
sprangc5d62e22017-04-02 23:53:04 -07001025 &new_video_source,
1026 VideoSendStream::DegradationPreference::kMaintainFramerate);
1027 EXPECT_LT(new_video_source.sink_wants().max_pixel_count,
1028 kFrameWidth * kFrameHeight);
sprang84a37592017-02-10 07:04:27 -08001029 EXPECT_FALSE(new_video_source.sink_wants().target_pixel_count);
sprangc5d62e22017-04-02 23:53:04 -07001030 EXPECT_EQ(std::numeric_limits<int>::max(),
1031 new_video_source.sink_wants().max_framerate_fps);
1032
1033 // Calling SetSource with framerate scaling enabled apply the old SinkWants.
mflodmancc3d4422017-08-03 08:27:51 -07001034 video_stream_encoder_->SetSource(
sprangc5d62e22017-04-02 23:53:04 -07001035 &new_video_source,
1036 VideoSendStream::DegradationPreference::kMaintainResolution);
1037 EXPECT_FALSE(new_video_source.sink_wants().target_pixel_count);
1038 EXPECT_EQ(std::numeric_limits<int>::max(),
1039 new_video_source.sink_wants().max_pixel_count);
asapersson02465b82017-04-10 01:12:52 -07001040 EXPECT_LT(new_video_source.sink_wants().max_framerate_fps, kInputFps);
perkj803d97f2016-11-01 11:45:46 -07001041
mflodmancc3d4422017-08-03 08:27:51 -07001042 video_stream_encoder_->Stop();
perkj803d97f2016-11-01 11:45:46 -07001043}
1044
mflodmancc3d4422017-08-03 08:27:51 -07001045TEST_F(VideoStreamEncoderTest, StatsTracksQualityAdaptationStats) {
1046 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkj803d97f2016-11-01 11:45:46 -07001047
asaperssonfab67072017-04-04 05:51:49 -07001048 const int kWidth = 1280;
1049 const int kHeight = 720;
asaperssonfab67072017-04-04 05:51:49 -07001050 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001051 WaitForEncodedFrame(1);
asaperssonfab67072017-04-04 05:51:49 -07001052 VideoSendStream::Stats stats = stats_proxy_->GetStats();
1053 EXPECT_FALSE(stats.bw_limited_resolution);
1054 EXPECT_EQ(0, stats.number_of_quality_adapt_changes);
1055
1056 // Trigger adapt down.
mflodmancc3d4422017-08-03 08:27:51 -07001057 video_stream_encoder_->TriggerQualityLow();
asaperssonfab67072017-04-04 05:51:49 -07001058 video_source_.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001059 WaitForEncodedFrame(2);
asaperssonfab67072017-04-04 05:51:49 -07001060
1061 stats = stats_proxy_->GetStats();
1062 EXPECT_TRUE(stats.bw_limited_resolution);
1063 EXPECT_EQ(1, stats.number_of_quality_adapt_changes);
1064
1065 // Trigger adapt up.
mflodmancc3d4422017-08-03 08:27:51 -07001066 video_stream_encoder_->TriggerQualityHigh();
asaperssonfab67072017-04-04 05:51:49 -07001067 video_source_.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001068 WaitForEncodedFrame(3);
asaperssonfab67072017-04-04 05:51:49 -07001069
1070 stats = stats_proxy_->GetStats();
1071 EXPECT_FALSE(stats.bw_limited_resolution);
1072 EXPECT_EQ(2, stats.number_of_quality_adapt_changes);
1073 EXPECT_EQ(0, stats.number_of_cpu_adapt_changes);
1074
mflodmancc3d4422017-08-03 08:27:51 -07001075 video_stream_encoder_->Stop();
asaperssonfab67072017-04-04 05:51:49 -07001076}
1077
mflodmancc3d4422017-08-03 08:27:51 -07001078TEST_F(VideoStreamEncoderTest, StatsTracksCpuAdaptationStats) {
1079 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonfab67072017-04-04 05:51:49 -07001080
1081 const int kWidth = 1280;
1082 const int kHeight = 720;
asaperssonfab67072017-04-04 05:51:49 -07001083 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001084 WaitForEncodedFrame(1);
perkj803d97f2016-11-01 11:45:46 -07001085 VideoSendStream::Stats stats = stats_proxy_->GetStats();
1086 EXPECT_FALSE(stats.cpu_limited_resolution);
1087 EXPECT_EQ(0, stats.number_of_cpu_adapt_changes);
1088
1089 // Trigger CPU overuse.
mflodmancc3d4422017-08-03 08:27:51 -07001090 video_stream_encoder_->TriggerCpuOveruse();
asaperssonfab67072017-04-04 05:51:49 -07001091 video_source_.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001092 WaitForEncodedFrame(2);
perkj803d97f2016-11-01 11:45:46 -07001093
1094 stats = stats_proxy_->GetStats();
1095 EXPECT_TRUE(stats.cpu_limited_resolution);
1096 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1097
1098 // Trigger CPU normal use.
mflodmancc3d4422017-08-03 08:27:51 -07001099 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssonfab67072017-04-04 05:51:49 -07001100 video_source_.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001101 WaitForEncodedFrame(3);
perkj803d97f2016-11-01 11:45:46 -07001102
1103 stats = stats_proxy_->GetStats();
1104 EXPECT_FALSE(stats.cpu_limited_resolution);
1105 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
asaperssonfab67072017-04-04 05:51:49 -07001106 EXPECT_EQ(0, stats.number_of_quality_adapt_changes);
perkj803d97f2016-11-01 11:45:46 -07001107
mflodmancc3d4422017-08-03 08:27:51 -07001108 video_stream_encoder_->Stop();
perkj803d97f2016-11-01 11:45:46 -07001109}
1110
mflodmancc3d4422017-08-03 08:27:51 -07001111TEST_F(VideoStreamEncoderTest, SwitchingSourceKeepsCpuAdaptation) {
1112 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
kthelgason876222f2016-11-29 01:44:11 -08001113
asaperssonfab67072017-04-04 05:51:49 -07001114 const int kWidth = 1280;
1115 const int kHeight = 720;
1116 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001117 WaitForEncodedFrame(1);
kthelgason876222f2016-11-29 01:44:11 -08001118 VideoSendStream::Stats stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001119 EXPECT_FALSE(stats.bw_limited_resolution);
kthelgason876222f2016-11-29 01:44:11 -08001120 EXPECT_FALSE(stats.cpu_limited_resolution);
1121 EXPECT_EQ(0, stats.number_of_cpu_adapt_changes);
1122
asaperssonfab67072017-04-04 05:51:49 -07001123 // Trigger CPU overuse.
mflodmancc3d4422017-08-03 08:27:51 -07001124 video_stream_encoder_->TriggerCpuOveruse();
asaperssonfab67072017-04-04 05:51:49 -07001125 video_source_.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001126 WaitForEncodedFrame(2);
kthelgason876222f2016-11-29 01:44:11 -08001127 stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001128 EXPECT_FALSE(stats.bw_limited_resolution);
kthelgason876222f2016-11-29 01:44:11 -08001129 EXPECT_TRUE(stats.cpu_limited_resolution);
1130 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1131
1132 // Set new source with adaptation still enabled.
1133 test::FrameForwarder new_video_source;
mflodmancc3d4422017-08-03 08:27:51 -07001134 video_stream_encoder_->SetSource(
sprangc5d62e22017-04-02 23:53:04 -07001135 &new_video_source,
1136 VideoSendStream::DegradationPreference::kMaintainFramerate);
kthelgason876222f2016-11-29 01:44:11 -08001137
asaperssonfab67072017-04-04 05:51:49 -07001138 new_video_source.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001139 WaitForEncodedFrame(3);
kthelgason876222f2016-11-29 01:44:11 -08001140 stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001141 EXPECT_FALSE(stats.bw_limited_resolution);
kthelgason876222f2016-11-29 01:44:11 -08001142 EXPECT_TRUE(stats.cpu_limited_resolution);
1143 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1144
1145 // Set adaptation disabled.
mflodmancc3d4422017-08-03 08:27:51 -07001146 video_stream_encoder_->SetSource(
kthelgason876222f2016-11-29 01:44:11 -08001147 &new_video_source,
sprangc5d62e22017-04-02 23:53:04 -07001148 VideoSendStream::DegradationPreference::kDegradationDisabled);
kthelgason876222f2016-11-29 01:44:11 -08001149
asaperssonfab67072017-04-04 05:51:49 -07001150 new_video_source.IncomingCapturedFrame(CreateFrame(4, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001151 WaitForEncodedFrame(4);
kthelgason876222f2016-11-29 01:44:11 -08001152 stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001153 EXPECT_FALSE(stats.bw_limited_resolution);
kthelgason876222f2016-11-29 01:44:11 -08001154 EXPECT_FALSE(stats.cpu_limited_resolution);
1155 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1156
1157 // Set adaptation back to enabled.
mflodmancc3d4422017-08-03 08:27:51 -07001158 video_stream_encoder_->SetSource(
sprangc5d62e22017-04-02 23:53:04 -07001159 &new_video_source,
1160 VideoSendStream::DegradationPreference::kMaintainFramerate);
kthelgason876222f2016-11-29 01:44:11 -08001161
asaperssonfab67072017-04-04 05:51:49 -07001162 new_video_source.IncomingCapturedFrame(CreateFrame(5, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001163 WaitForEncodedFrame(5);
kthelgason876222f2016-11-29 01:44:11 -08001164 stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001165 EXPECT_FALSE(stats.bw_limited_resolution);
kthelgason876222f2016-11-29 01:44:11 -08001166 EXPECT_TRUE(stats.cpu_limited_resolution);
1167 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1168
asaperssonfab67072017-04-04 05:51:49 -07001169 // Trigger CPU normal use.
mflodmancc3d4422017-08-03 08:27:51 -07001170 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssonfab67072017-04-04 05:51:49 -07001171 new_video_source.IncomingCapturedFrame(CreateFrame(6, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001172 WaitForEncodedFrame(6);
kthelgason876222f2016-11-29 01:44:11 -08001173 stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001174 EXPECT_FALSE(stats.bw_limited_resolution);
kthelgason876222f2016-11-29 01:44:11 -08001175 EXPECT_FALSE(stats.cpu_limited_resolution);
1176 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
asapersson02465b82017-04-10 01:12:52 -07001177 EXPECT_EQ(0, stats.number_of_quality_adapt_changes);
kthelgason876222f2016-11-29 01:44:11 -08001178
mflodmancc3d4422017-08-03 08:27:51 -07001179 video_stream_encoder_->Stop();
kthelgason876222f2016-11-29 01:44:11 -08001180}
1181
mflodmancc3d4422017-08-03 08:27:51 -07001182TEST_F(VideoStreamEncoderTest, SwitchingSourceKeepsQualityAdaptation) {
1183 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
kthelgason876222f2016-11-29 01:44:11 -08001184
asaperssonfab67072017-04-04 05:51:49 -07001185 const int kWidth = 1280;
1186 const int kHeight = 720;
1187 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001188 WaitForEncodedFrame(1);
kthelgason876222f2016-11-29 01:44:11 -08001189 VideoSendStream::Stats stats = stats_proxy_->GetStats();
kthelgason876222f2016-11-29 01:44:11 -08001190 EXPECT_FALSE(stats.bw_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001191 EXPECT_FALSE(stats.bw_limited_framerate);
asaperssonfab67072017-04-04 05:51:49 -07001192 EXPECT_EQ(0, stats.number_of_quality_adapt_changes);
kthelgason876222f2016-11-29 01:44:11 -08001193
1194 // Set new source with adaptation still enabled.
1195 test::FrameForwarder new_video_source;
mflodmancc3d4422017-08-03 08:27:51 -07001196 video_stream_encoder_->SetSource(
1197 &new_video_source,
1198 VideoSendStream::DegradationPreference::kBalanced);
kthelgason876222f2016-11-29 01:44:11 -08001199
asaperssonfab67072017-04-04 05:51:49 -07001200 new_video_source.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001201 WaitForEncodedFrame(2);
kthelgason876222f2016-11-29 01:44:11 -08001202 stats = stats_proxy_->GetStats();
kthelgason876222f2016-11-29 01:44:11 -08001203 EXPECT_FALSE(stats.bw_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001204 EXPECT_FALSE(stats.bw_limited_framerate);
asaperssonfab67072017-04-04 05:51:49 -07001205 EXPECT_EQ(0, stats.number_of_quality_adapt_changes);
kthelgason876222f2016-11-29 01:44:11 -08001206
asaperssonfab67072017-04-04 05:51:49 -07001207 // Trigger adapt down.
mflodmancc3d4422017-08-03 08:27:51 -07001208 video_stream_encoder_->TriggerQualityLow();
asaperssonfab67072017-04-04 05:51:49 -07001209 new_video_source.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001210 WaitForEncodedFrame(3);
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
asaperssonfab67072017-04-04 05:51:49 -07001216 // Set new source with adaptation still enabled.
mflodmancc3d4422017-08-03 08:27:51 -07001217 video_stream_encoder_->SetSource(
1218 &new_video_source,
1219 VideoSendStream::DegradationPreference::kBalanced);
kthelgason876222f2016-11-29 01:44:11 -08001220
asaperssonfab67072017-04-04 05:51:49 -07001221 new_video_source.IncomingCapturedFrame(CreateFrame(4, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001222 WaitForEncodedFrame(4);
kthelgason876222f2016-11-29 01:44:11 -08001223 stats = stats_proxy_->GetStats();
kthelgason876222f2016-11-29 01:44:11 -08001224 EXPECT_TRUE(stats.bw_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001225 EXPECT_FALSE(stats.bw_limited_framerate);
asaperssonfab67072017-04-04 05:51:49 -07001226 EXPECT_EQ(1, stats.number_of_quality_adapt_changes);
kthelgason876222f2016-11-29 01:44:11 -08001227
asapersson02465b82017-04-10 01:12:52 -07001228 // Disable resolution scaling.
mflodmancc3d4422017-08-03 08:27:51 -07001229 video_stream_encoder_->SetSource(
kthelgason876222f2016-11-29 01:44:11 -08001230 &new_video_source,
1231 VideoSendStream::DegradationPreference::kMaintainResolution);
1232
asaperssonfab67072017-04-04 05:51:49 -07001233 new_video_source.IncomingCapturedFrame(CreateFrame(5, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001234 WaitForEncodedFrame(5);
kthelgason876222f2016-11-29 01:44:11 -08001235 stats = stats_proxy_->GetStats();
kthelgason876222f2016-11-29 01:44:11 -08001236 EXPECT_FALSE(stats.bw_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001237 EXPECT_FALSE(stats.bw_limited_framerate);
asaperssonfab67072017-04-04 05:51:49 -07001238 EXPECT_EQ(1, stats.number_of_quality_adapt_changes);
1239 EXPECT_EQ(0, stats.number_of_cpu_adapt_changes);
kthelgason876222f2016-11-29 01:44:11 -08001240
mflodmancc3d4422017-08-03 08:27:51 -07001241 video_stream_encoder_->Stop();
kthelgason876222f2016-11-29 01:44:11 -08001242}
1243
mflodmancc3d4422017-08-03 08:27:51 -07001244TEST_F(VideoStreamEncoderTest,
1245 QualityAdaptationStatsAreResetWhenScalerIsDisabled) {
1246 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson36e9eb42017-03-31 05:29:12 -07001247
1248 const int kWidth = 1280;
1249 const int kHeight = 720;
1250 video_source_.set_adaptation_enabled(true);
1251 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001252 WaitForEncodedFrame(1);
asapersson36e9eb42017-03-31 05:29:12 -07001253 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1254 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1255 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1256
1257 // Trigger adapt down.
mflodmancc3d4422017-08-03 08:27:51 -07001258 video_stream_encoder_->TriggerQualityLow();
asapersson36e9eb42017-03-31 05:29:12 -07001259 video_source_.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001260 WaitForEncodedFrame(2);
asapersson36e9eb42017-03-31 05:29:12 -07001261 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1262 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1263 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1264
1265 // Trigger overuse.
mflodmancc3d4422017-08-03 08:27:51 -07001266 video_stream_encoder_->TriggerCpuOveruse();
asapersson36e9eb42017-03-31 05:29:12 -07001267 video_source_.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001268 WaitForEncodedFrame(3);
asapersson36e9eb42017-03-31 05:29:12 -07001269 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1270 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1271 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1272
Niels Möller4db138e2018-04-19 09:04:13 +02001273 // Leave source unchanged, but disable quality scaler.
asapersson36e9eb42017-03-31 05:29:12 -07001274 fake_encoder_.SetQualityScaling(false);
Niels Möller4db138e2018-04-19 09:04:13 +02001275
1276 VideoEncoderConfig video_encoder_config;
1277 test::FillEncoderConfiguration(kVideoCodecVP8, 1, &video_encoder_config);
1278 // Make format different, to force recreation of encoder.
1279 video_encoder_config.video_format.parameters["foo"] = "foo";
1280 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
1281 kMaxPayloadLength,
1282 true /* nack_enabled */);
asapersson36e9eb42017-03-31 05:29:12 -07001283
1284 video_source_.IncomingCapturedFrame(CreateFrame(4, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001285 WaitForEncodedFrame(4);
asapersson36e9eb42017-03-31 05:29:12 -07001286 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1287 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1288 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1289
mflodmancc3d4422017-08-03 08:27:51 -07001290 video_stream_encoder_->Stop();
asapersson36e9eb42017-03-31 05:29:12 -07001291}
1292
mflodmancc3d4422017-08-03 08:27:51 -07001293TEST_F(VideoStreamEncoderTest,
1294 StatsTracksCpuAdaptationStatsWhenSwitchingSource) {
1295 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkj803d97f2016-11-01 11:45:46 -07001296
asapersson0944a802017-04-07 00:57:58 -07001297 const int kWidth = 1280;
1298 const int kHeight = 720;
sprang84a37592017-02-10 07:04:27 -08001299 int sequence = 1;
perkj803d97f2016-11-01 11:45:46 -07001300
asaperssonfab67072017-04-04 05:51:49 -07001301 video_source_.IncomingCapturedFrame(CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001302 WaitForEncodedFrame(sequence++);
perkj803d97f2016-11-01 11:45:46 -07001303 VideoSendStream::Stats stats = stats_proxy_->GetStats();
sprang84a37592017-02-10 07:04:27 -08001304 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001305 EXPECT_FALSE(stats.cpu_limited_framerate);
sprang84a37592017-02-10 07:04:27 -08001306 EXPECT_EQ(0, stats.number_of_cpu_adapt_changes);
1307
asapersson02465b82017-04-10 01:12:52 -07001308 // Trigger CPU overuse, should now adapt down.
mflodmancc3d4422017-08-03 08:27:51 -07001309 video_stream_encoder_->TriggerCpuOveruse();
asaperssonfab67072017-04-04 05:51:49 -07001310 video_source_.IncomingCapturedFrame(CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001311 WaitForEncodedFrame(sequence++);
sprang84a37592017-02-10 07:04:27 -08001312 stats = stats_proxy_->GetStats();
perkj803d97f2016-11-01 11:45:46 -07001313 EXPECT_TRUE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001314 EXPECT_FALSE(stats.cpu_limited_framerate);
perkj803d97f2016-11-01 11:45:46 -07001315 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1316
1317 // Set new source with adaptation still enabled.
1318 test::FrameForwarder new_video_source;
mflodmancc3d4422017-08-03 08:27:51 -07001319 video_stream_encoder_->SetSource(
sprangc5d62e22017-04-02 23:53:04 -07001320 &new_video_source,
1321 VideoSendStream::DegradationPreference::kMaintainFramerate);
perkj803d97f2016-11-01 11:45:46 -07001322
1323 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001324 CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001325 WaitForEncodedFrame(sequence++);
perkj803d97f2016-11-01 11:45:46 -07001326 stats = stats_proxy_->GetStats();
1327 EXPECT_TRUE(stats.cpu_limited_resolution);
asapersson09f05612017-05-15 23:40:18 -07001328 EXPECT_FALSE(stats.cpu_limited_framerate);
perkj803d97f2016-11-01 11:45:46 -07001329 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1330
sprangc5d62e22017-04-02 23:53:04 -07001331 // Set cpu adaptation by frame dropping.
mflodmancc3d4422017-08-03 08:27:51 -07001332 video_stream_encoder_->SetSource(
perkj803d97f2016-11-01 11:45:46 -07001333 &new_video_source,
1334 VideoSendStream::DegradationPreference::kMaintainResolution);
1335 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001336 CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001337 WaitForEncodedFrame(sequence++);
perkj803d97f2016-11-01 11:45:46 -07001338 stats = stats_proxy_->GetStats();
sprangc5d62e22017-04-02 23:53:04 -07001339 // Not adapted at first.
perkj803d97f2016-11-01 11:45:46 -07001340 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson09f05612017-05-15 23:40:18 -07001341 EXPECT_FALSE(stats.cpu_limited_framerate);
perkj803d97f2016-11-01 11:45:46 -07001342 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1343
sprangc5d62e22017-04-02 23:53:04 -07001344 // Force an input frame rate to be available, or the adaptation call won't
asapersson09f05612017-05-15 23:40:18 -07001345 // know what framerate to adapt from.
sprangc5d62e22017-04-02 23:53:04 -07001346 VideoSendStream::Stats mock_stats = stats_proxy_->GetStats();
1347 mock_stats.input_frame_rate = 30;
1348 stats_proxy_->SetMockStats(mock_stats);
mflodmancc3d4422017-08-03 08:27:51 -07001349 video_stream_encoder_->TriggerCpuOveruse();
sprangc5d62e22017-04-02 23:53:04 -07001350 stats_proxy_->ResetMockStats();
1351
1352 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001353 CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001354 WaitForEncodedFrame(sequence++);
sprangc5d62e22017-04-02 23:53:04 -07001355
1356 // Framerate now adapted.
1357 stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001358 EXPECT_FALSE(stats.cpu_limited_resolution);
1359 EXPECT_TRUE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001360 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
1361
1362 // Disable CPU adaptation.
mflodmancc3d4422017-08-03 08:27:51 -07001363 video_stream_encoder_->SetSource(
sprangc5d62e22017-04-02 23:53:04 -07001364 &new_video_source,
1365 VideoSendStream::DegradationPreference::kDegradationDisabled);
1366 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001367 CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001368 WaitForEncodedFrame(sequence++);
sprangc5d62e22017-04-02 23:53:04 -07001369
1370 stats = stats_proxy_->GetStats();
1371 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001372 EXPECT_FALSE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001373 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
1374
1375 // Try to trigger overuse. Should not succeed.
1376 stats_proxy_->SetMockStats(mock_stats);
mflodmancc3d4422017-08-03 08:27:51 -07001377 video_stream_encoder_->TriggerCpuOveruse();
sprangc5d62e22017-04-02 23:53:04 -07001378 stats_proxy_->ResetMockStats();
1379
1380 stats = stats_proxy_->GetStats();
1381 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001382 EXPECT_FALSE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001383 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
1384
1385 // Switch back the source with resolution adaptation enabled.
mflodmancc3d4422017-08-03 08:27:51 -07001386 video_stream_encoder_->SetSource(
sprangc5d62e22017-04-02 23:53:04 -07001387 &video_source_,
1388 VideoSendStream::DegradationPreference::kMaintainFramerate);
asaperssonfab67072017-04-04 05:51:49 -07001389 video_source_.IncomingCapturedFrame(CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001390 WaitForEncodedFrame(sequence++);
perkj803d97f2016-11-01 11:45:46 -07001391 stats = stats_proxy_->GetStats();
1392 EXPECT_TRUE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001393 EXPECT_FALSE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001394 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
perkj803d97f2016-11-01 11:45:46 -07001395
1396 // Trigger CPU normal usage.
mflodmancc3d4422017-08-03 08:27:51 -07001397 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssonfab67072017-04-04 05:51:49 -07001398 video_source_.IncomingCapturedFrame(CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001399 WaitForEncodedFrame(sequence++);
perkj803d97f2016-11-01 11:45:46 -07001400 stats = stats_proxy_->GetStats();
1401 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001402 EXPECT_FALSE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001403 EXPECT_EQ(3, stats.number_of_cpu_adapt_changes);
1404
1405 // Back to the source with adaptation off, set it back to maintain-resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001406 video_stream_encoder_->SetSource(
sprangc5d62e22017-04-02 23:53:04 -07001407 &new_video_source,
1408 VideoSendStream::DegradationPreference::kMaintainResolution);
1409 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001410 CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001411 WaitForEncodedFrame(sequence++);
sprangc5d62e22017-04-02 23:53:04 -07001412 stats = stats_proxy_->GetStats();
asapersson13874762017-06-07 00:01:02 -07001413 // Disabled, since we previously switched the source to disabled.
sprangc5d62e22017-04-02 23:53:04 -07001414 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001415 EXPECT_TRUE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001416 EXPECT_EQ(3, stats.number_of_cpu_adapt_changes);
1417
1418 // Trigger CPU normal usage.
mflodmancc3d4422017-08-03 08:27:51 -07001419 video_stream_encoder_->TriggerCpuNormalUsage();
sprangc5d62e22017-04-02 23:53:04 -07001420 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001421 CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001422 WaitForEncodedFrame(sequence++);
sprangc5d62e22017-04-02 23:53:04 -07001423 stats = stats_proxy_->GetStats();
1424 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001425 EXPECT_FALSE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001426 EXPECT_EQ(4, stats.number_of_cpu_adapt_changes);
asapersson02465b82017-04-10 01:12:52 -07001427 EXPECT_EQ(0, stats.number_of_quality_adapt_changes);
perkj803d97f2016-11-01 11:45:46 -07001428
mflodmancc3d4422017-08-03 08:27:51 -07001429 video_stream_encoder_->Stop();
perkj803d97f2016-11-01 11:45:46 -07001430}
1431
mflodmancc3d4422017-08-03 08:27:51 -07001432TEST_F(VideoStreamEncoderTest, StatsTracksPreferredBitrate) {
1433 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
Erik Språng08127a92016-11-16 16:41:30 +01001434
asaperssonfab67072017-04-04 05:51:49 -07001435 const int kWidth = 1280;
1436 const int kHeight = 720;
1437 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001438 WaitForEncodedFrame(1);
Erik Språng08127a92016-11-16 16:41:30 +01001439
1440 VideoSendStream::Stats stats = stats_proxy_->GetStats();
1441 EXPECT_EQ(video_encoder_config_.max_bitrate_bps,
1442 stats.preferred_media_bitrate_bps);
1443
mflodmancc3d4422017-08-03 08:27:51 -07001444 video_stream_encoder_->Stop();
Erik Språng08127a92016-11-16 16:41:30 +01001445}
1446
mflodmancc3d4422017-08-03 08:27:51 -07001447TEST_F(VideoStreamEncoderTest,
1448 ScalingUpAndDownDoesNothingWithMaintainResolution) {
asaperssonfab67072017-04-04 05:51:49 -07001449 const int kWidth = 1280;
1450 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001451 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
kthelgason876222f2016-11-29 01:44:11 -08001452
asaperssonfab67072017-04-04 05:51:49 -07001453 // Expect no scaling to begin with.
asapersson02465b82017-04-10 01:12:52 -07001454 VerifyNoLimitation(video_source_.sink_wants());
kthelgason876222f2016-11-29 01:44:11 -08001455
asaperssonfab67072017-04-04 05:51:49 -07001456 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001457 WaitForEncodedFrame(1);
kthelgason876222f2016-11-29 01:44:11 -08001458
asaperssonfab67072017-04-04 05:51:49 -07001459 // Trigger scale down.
mflodmancc3d4422017-08-03 08:27:51 -07001460 video_stream_encoder_->TriggerQualityLow();
kthelgason5e13d412016-12-01 03:59:51 -08001461
asaperssonfab67072017-04-04 05:51:49 -07001462 video_source_.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001463 WaitForEncodedFrame(2);
kthelgason5e13d412016-12-01 03:59:51 -08001464
kthelgason876222f2016-11-29 01:44:11 -08001465 // Expect a scale down.
1466 EXPECT_TRUE(video_source_.sink_wants().max_pixel_count);
asaperssonfab67072017-04-04 05:51:49 -07001467 EXPECT_LT(video_source_.sink_wants().max_pixel_count, kWidth * kHeight);
kthelgason876222f2016-11-29 01:44:11 -08001468
asapersson02465b82017-04-10 01:12:52 -07001469 // Set resolution scaling disabled.
kthelgason876222f2016-11-29 01:44:11 -08001470 test::FrameForwarder new_video_source;
mflodmancc3d4422017-08-03 08:27:51 -07001471 video_stream_encoder_->SetSource(
kthelgason876222f2016-11-29 01:44:11 -08001472 &new_video_source,
1473 VideoSendStream::DegradationPreference::kMaintainResolution);
1474
asaperssonfab67072017-04-04 05:51:49 -07001475 // Trigger scale down.
mflodmancc3d4422017-08-03 08:27:51 -07001476 video_stream_encoder_->TriggerQualityLow();
asaperssonfab67072017-04-04 05:51:49 -07001477 new_video_source.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001478 WaitForEncodedFrame(3);
kthelgason876222f2016-11-29 01:44:11 -08001479
asaperssonfab67072017-04-04 05:51:49 -07001480 // Expect no scaling.
sprangc5d62e22017-04-02 23:53:04 -07001481 EXPECT_EQ(std::numeric_limits<int>::max(),
1482 new_video_source.sink_wants().max_pixel_count);
kthelgason876222f2016-11-29 01:44:11 -08001483
asaperssonfab67072017-04-04 05:51:49 -07001484 // Trigger scale up.
mflodmancc3d4422017-08-03 08:27:51 -07001485 video_stream_encoder_->TriggerQualityHigh();
asaperssonfab67072017-04-04 05:51:49 -07001486 new_video_source.IncomingCapturedFrame(CreateFrame(4, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001487 WaitForEncodedFrame(4);
kthelgason876222f2016-11-29 01:44:11 -08001488
asapersson02465b82017-04-10 01:12:52 -07001489 // Expect nothing to change, still no scaling.
sprangc5d62e22017-04-02 23:53:04 -07001490 EXPECT_EQ(std::numeric_limits<int>::max(),
1491 new_video_source.sink_wants().max_pixel_count);
kthelgason876222f2016-11-29 01:44:11 -08001492
mflodmancc3d4422017-08-03 08:27:51 -07001493 video_stream_encoder_->Stop();
kthelgason876222f2016-11-29 01:44:11 -08001494}
1495
mflodmancc3d4422017-08-03 08:27:51 -07001496TEST_F(VideoStreamEncoderTest,
1497 SkipsSameAdaptDownRequest_MaintainFramerateMode) {
asapersson02465b82017-04-10 01:12:52 -07001498 const int kWidth = 1280;
1499 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001500 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson02465b82017-04-10 01:12:52 -07001501
1502 // Enable kMaintainFramerate preference, no initial limitation.
1503 test::FrameForwarder source;
mflodmancc3d4422017-08-03 08:27:51 -07001504 video_stream_encoder_->SetSource(
asapersson02465b82017-04-10 01:12:52 -07001505 &source, VideoSendStream::DegradationPreference::kMaintainFramerate);
1506
1507 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001508 WaitForEncodedFrame(1);
asapersson02465b82017-04-10 01:12:52 -07001509 VerifyNoLimitation(source.sink_wants());
1510 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1511 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1512
1513 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001514 video_stream_encoder_->TriggerCpuOveruse();
asapersson09f05612017-05-15 23:40:18 -07001515 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
asapersson02465b82017-04-10 01:12:52 -07001516 const int kLastMaxPixelCount = source.sink_wants().max_pixel_count;
1517 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1518 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1519
1520 // Trigger adapt down for same input resolution, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07001521 video_stream_encoder_->TriggerCpuOveruse();
asapersson02465b82017-04-10 01:12:52 -07001522 EXPECT_EQ(kLastMaxPixelCount, source.sink_wants().max_pixel_count);
1523 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1524 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1525
mflodmancc3d4422017-08-03 08:27:51 -07001526 video_stream_encoder_->Stop();
asapersson02465b82017-04-10 01:12:52 -07001527}
1528
mflodmancc3d4422017-08-03 08:27:51 -07001529TEST_F(VideoStreamEncoderTest, SkipsSameOrLargerAdaptDownRequest_BalancedMode) {
asaperssonf7e294d2017-06-13 23:25:22 -07001530 const int kWidth = 1280;
1531 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001532 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -07001533
1534 // Enable kBalanced preference, no initial limitation.
1535 test::FrameForwarder source;
mflodmancc3d4422017-08-03 08:27:51 -07001536 video_stream_encoder_->SetSource(
1537 &source,
1538 VideoSendStream::DegradationPreference::kBalanced);
asaperssonf7e294d2017-06-13 23:25:22 -07001539 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
1540 sink_.WaitForEncodedFrame(1);
1541 VerifyNoLimitation(source.sink_wants());
1542
1543 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001544 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07001545 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
1546 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1547 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1548 const int kLastMaxPixelCount = source.sink_wants().max_pixel_count;
1549
1550 // Trigger adapt down for same input resolution, expect no change.
1551 source.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
1552 sink_.WaitForEncodedFrame(2);
mflodmancc3d4422017-08-03 08:27:51 -07001553 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07001554 EXPECT_EQ(kLastMaxPixelCount, source.sink_wants().max_pixel_count);
1555 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1556 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1557
1558 // Trigger adapt down for larger input resolution, expect no change.
1559 source.IncomingCapturedFrame(CreateFrame(3, kWidth + 1, kHeight + 1));
1560 sink_.WaitForEncodedFrame(3);
mflodmancc3d4422017-08-03 08:27:51 -07001561 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07001562 EXPECT_EQ(kLastMaxPixelCount, source.sink_wants().max_pixel_count);
1563 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1564 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1565
mflodmancc3d4422017-08-03 08:27:51 -07001566 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07001567}
1568
mflodmancc3d4422017-08-03 08:27:51 -07001569TEST_F(VideoStreamEncoderTest,
1570 NoChangeForInitialNormalUsage_MaintainFramerateMode) {
asapersson02465b82017-04-10 01:12:52 -07001571 const int kWidth = 1280;
1572 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001573 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson02465b82017-04-10 01:12:52 -07001574
1575 // Enable kMaintainFramerate preference, no initial limitation.
1576 test::FrameForwarder source;
mflodmancc3d4422017-08-03 08:27:51 -07001577 video_stream_encoder_->SetSource(
asapersson02465b82017-04-10 01:12:52 -07001578 &source, VideoSendStream::DegradationPreference::kMaintainFramerate);
1579
1580 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001581 WaitForEncodedFrame(kWidth, kHeight);
asapersson02465b82017-04-10 01:12:52 -07001582 VerifyNoLimitation(source.sink_wants());
1583 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1584 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1585
1586 // Trigger adapt up, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07001587 video_stream_encoder_->TriggerCpuNormalUsage();
asapersson02465b82017-04-10 01:12:52 -07001588 VerifyNoLimitation(source.sink_wants());
1589 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1590 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1591
mflodmancc3d4422017-08-03 08:27:51 -07001592 video_stream_encoder_->Stop();
asapersson02465b82017-04-10 01:12:52 -07001593}
1594
mflodmancc3d4422017-08-03 08:27:51 -07001595TEST_F(VideoStreamEncoderTest,
1596 NoChangeForInitialNormalUsage_MaintainResolutionMode) {
asapersson02465b82017-04-10 01:12:52 -07001597 const int kWidth = 1280;
1598 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001599 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson02465b82017-04-10 01:12:52 -07001600
1601 // Enable kMaintainResolution preference, no initial limitation.
1602 test::FrameForwarder source;
mflodmancc3d4422017-08-03 08:27:51 -07001603 video_stream_encoder_->SetSource(
asapersson02465b82017-04-10 01:12:52 -07001604 &source, VideoSendStream::DegradationPreference::kMaintainResolution);
1605
1606 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001607 WaitForEncodedFrame(kWidth, kHeight);
asapersson02465b82017-04-10 01:12:52 -07001608 VerifyNoLimitation(source.sink_wants());
asapersson09f05612017-05-15 23:40:18 -07001609 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
asapersson02465b82017-04-10 01:12:52 -07001610 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1611
1612 // Trigger adapt up, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07001613 video_stream_encoder_->TriggerCpuNormalUsage();
asapersson02465b82017-04-10 01:12:52 -07001614 VerifyNoLimitation(source.sink_wants());
asapersson09f05612017-05-15 23:40:18 -07001615 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
asapersson02465b82017-04-10 01:12:52 -07001616 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1617
mflodmancc3d4422017-08-03 08:27:51 -07001618 video_stream_encoder_->Stop();
asapersson02465b82017-04-10 01:12:52 -07001619}
1620
mflodmancc3d4422017-08-03 08:27:51 -07001621TEST_F(VideoStreamEncoderTest, NoChangeForInitialNormalUsage_BalancedMode) {
asaperssonf7e294d2017-06-13 23:25:22 -07001622 const int kWidth = 1280;
1623 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001624 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -07001625
1626 // Enable kBalanced preference, no initial limitation.
1627 test::FrameForwarder source;
mflodmancc3d4422017-08-03 08:27:51 -07001628 video_stream_encoder_->SetSource(
1629 &source,
1630 VideoSendStream::DegradationPreference::kBalanced);
asaperssonf7e294d2017-06-13 23:25:22 -07001631
1632 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
1633 sink_.WaitForEncodedFrame(kWidth, kHeight);
1634 VerifyNoLimitation(source.sink_wants());
1635 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1636 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
1637 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1638
1639 // Trigger adapt up, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07001640 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07001641 VerifyNoLimitation(source.sink_wants());
1642 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1643 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
1644 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1645
mflodmancc3d4422017-08-03 08:27:51 -07001646 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07001647}
1648
mflodmancc3d4422017-08-03 08:27:51 -07001649TEST_F(VideoStreamEncoderTest, NoChangeForInitialNormalUsage_DisabledMode) {
asapersson09f05612017-05-15 23:40:18 -07001650 const int kWidth = 1280;
1651 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001652 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson09f05612017-05-15 23:40:18 -07001653
1654 // Enable kDegradationDisabled preference, no initial limitation.
1655 test::FrameForwarder source;
mflodmancc3d4422017-08-03 08:27:51 -07001656 video_stream_encoder_->SetSource(
asapersson09f05612017-05-15 23:40:18 -07001657 &source, VideoSendStream::DegradationPreference::kDegradationDisabled);
1658
1659 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
1660 sink_.WaitForEncodedFrame(kWidth, kHeight);
1661 VerifyNoLimitation(source.sink_wants());
1662 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1663 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
1664 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1665
1666 // Trigger adapt up, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07001667 video_stream_encoder_->TriggerQualityHigh();
asapersson09f05612017-05-15 23:40:18 -07001668 VerifyNoLimitation(source.sink_wants());
1669 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1670 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
1671 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1672
mflodmancc3d4422017-08-03 08:27:51 -07001673 video_stream_encoder_->Stop();
asapersson09f05612017-05-15 23:40:18 -07001674}
1675
mflodmancc3d4422017-08-03 08:27:51 -07001676TEST_F(VideoStreamEncoderTest,
1677 AdaptsResolutionForLowQuality_MaintainFramerateMode) {
asapersson02465b82017-04-10 01:12:52 -07001678 const int kWidth = 1280;
1679 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001680 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson02465b82017-04-10 01:12:52 -07001681
1682 // Enable kMaintainFramerate preference, no initial limitation.
1683 AdaptingFrameForwarder source;
1684 source.set_adaptation_enabled(true);
mflodmancc3d4422017-08-03 08:27:51 -07001685 video_stream_encoder_->SetSource(
asapersson02465b82017-04-10 01:12:52 -07001686 &source, VideoSendStream::DegradationPreference::kMaintainFramerate);
1687
1688 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001689 WaitForEncodedFrame(1);
asapersson02465b82017-04-10 01:12:52 -07001690 VerifyNoLimitation(source.sink_wants());
1691 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1692 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1693
1694 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001695 video_stream_encoder_->TriggerQualityLow();
asapersson02465b82017-04-10 01:12:52 -07001696 source.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001697 WaitForEncodedFrame(2);
asapersson09f05612017-05-15 23:40:18 -07001698 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
asapersson02465b82017-04-10 01:12:52 -07001699 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1700 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1701
1702 // Trigger adapt up, expect no restriction.
mflodmancc3d4422017-08-03 08:27:51 -07001703 video_stream_encoder_->TriggerQualityHigh();
asapersson02465b82017-04-10 01:12:52 -07001704 VerifyNoLimitation(source.sink_wants());
1705 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1706 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1707 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1708
mflodmancc3d4422017-08-03 08:27:51 -07001709 video_stream_encoder_->Stop();
asapersson02465b82017-04-10 01:12:52 -07001710}
1711
mflodmancc3d4422017-08-03 08:27:51 -07001712TEST_F(VideoStreamEncoderTest,
1713 AdaptsFramerateForLowQuality_MaintainResolutionMode) {
asapersson09f05612017-05-15 23:40:18 -07001714 const int kWidth = 1280;
1715 const int kHeight = 720;
1716 const int kInputFps = 30;
mflodmancc3d4422017-08-03 08:27:51 -07001717 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson09f05612017-05-15 23:40:18 -07001718
1719 VideoSendStream::Stats stats = stats_proxy_->GetStats();
1720 stats.input_frame_rate = kInputFps;
1721 stats_proxy_->SetMockStats(stats);
1722
1723 // Expect no scaling to begin with (preference: kMaintainFramerate).
1724 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
1725 sink_.WaitForEncodedFrame(1);
1726 VerifyNoLimitation(video_source_.sink_wants());
1727
1728 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001729 video_stream_encoder_->TriggerQualityLow();
asapersson09f05612017-05-15 23:40:18 -07001730 video_source_.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
1731 sink_.WaitForEncodedFrame(2);
1732 VerifyFpsMaxResolutionLt(video_source_.sink_wants(), kWidth * kHeight);
1733
1734 // Enable kMaintainResolution preference.
1735 test::FrameForwarder new_video_source;
mflodmancc3d4422017-08-03 08:27:51 -07001736 video_stream_encoder_->SetSource(
asapersson09f05612017-05-15 23:40:18 -07001737 &new_video_source,
1738 VideoSendStream::DegradationPreference::kMaintainResolution);
1739 VerifyNoLimitation(new_video_source.sink_wants());
1740
1741 // Trigger adapt down, expect reduced framerate.
mflodmancc3d4422017-08-03 08:27:51 -07001742 video_stream_encoder_->TriggerQualityLow();
asapersson09f05612017-05-15 23:40:18 -07001743 new_video_source.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
1744 sink_.WaitForEncodedFrame(3);
1745 VerifyFpsLtResolutionMax(new_video_source.sink_wants(), kInputFps);
1746
1747 // Trigger adapt up, expect no restriction.
mflodmancc3d4422017-08-03 08:27:51 -07001748 video_stream_encoder_->TriggerQualityHigh();
asapersson09f05612017-05-15 23:40:18 -07001749 VerifyNoLimitation(new_video_source.sink_wants());
1750
mflodmancc3d4422017-08-03 08:27:51 -07001751 video_stream_encoder_->Stop();
asapersson09f05612017-05-15 23:40:18 -07001752}
1753
mflodmancc3d4422017-08-03 08:27:51 -07001754TEST_F(VideoStreamEncoderTest, DoesNotScaleBelowSetResolutionLimit) {
asaperssond0de2952017-04-21 01:47:31 -07001755 const int kWidth = 1280;
1756 const int kHeight = 720;
1757 const size_t kNumFrames = 10;
1758
mflodmancc3d4422017-08-03 08:27:51 -07001759 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
kthelgason5e13d412016-12-01 03:59:51 -08001760
asaperssond0de2952017-04-21 01:47:31 -07001761 // Enable adapter, expected input resolutions when downscaling:
asapersson142fcc92017-08-17 08:58:54 -07001762 // 1280x720 -> 960x540 -> 640x360 -> 480x270 -> 320x180 (kMinPixelsPerFrame)
asaperssond0de2952017-04-21 01:47:31 -07001763 video_source_.set_adaptation_enabled(true);
1764
1765 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1766 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1767
1768 int downscales = 0;
1769 for (size_t i = 1; i <= kNumFrames; i++) {
1770 video_source_.IncomingCapturedFrame(CreateFrame(i, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001771 WaitForEncodedFrame(i);
asaperssond0de2952017-04-21 01:47:31 -07001772
asaperssonfab67072017-04-04 05:51:49 -07001773 // Trigger scale down.
asaperssond0de2952017-04-21 01:47:31 -07001774 rtc::VideoSinkWants last_wants = video_source_.sink_wants();
mflodmancc3d4422017-08-03 08:27:51 -07001775 video_stream_encoder_->TriggerQualityLow();
sprangc5d62e22017-04-02 23:53:04 -07001776 EXPECT_GE(video_source_.sink_wants().max_pixel_count, kMinPixelsPerFrame);
asaperssond0de2952017-04-21 01:47:31 -07001777
1778 if (video_source_.sink_wants().max_pixel_count < last_wants.max_pixel_count)
1779 ++downscales;
1780
1781 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1782 EXPECT_EQ(downscales,
1783 stats_proxy_->GetStats().number_of_quality_adapt_changes);
1784 EXPECT_GT(downscales, 0);
kthelgason5e13d412016-12-01 03:59:51 -08001785 }
mflodmancc3d4422017-08-03 08:27:51 -07001786 video_stream_encoder_->Stop();
asaperssond0de2952017-04-21 01:47:31 -07001787}
1788
mflodmancc3d4422017-08-03 08:27:51 -07001789TEST_F(VideoStreamEncoderTest,
asaperssond0de2952017-04-21 01:47:31 -07001790 AdaptsResolutionUpAndDownTwiceOnOveruse_MaintainFramerateMode) {
1791 const int kWidth = 1280;
1792 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001793 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssond0de2952017-04-21 01:47:31 -07001794
1795 // Enable kMaintainFramerate preference, no initial limitation.
1796 AdaptingFrameForwarder source;
1797 source.set_adaptation_enabled(true);
mflodmancc3d4422017-08-03 08:27:51 -07001798 video_stream_encoder_->SetSource(
asaperssond0de2952017-04-21 01:47:31 -07001799 &source, VideoSendStream::DegradationPreference::kMaintainFramerate);
1800
1801 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001802 WaitForEncodedFrame(kWidth, kHeight);
asaperssond0de2952017-04-21 01:47:31 -07001803 VerifyNoLimitation(source.sink_wants());
1804 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1805 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1806
1807 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001808 video_stream_encoder_->TriggerCpuOveruse();
asaperssond0de2952017-04-21 01:47:31 -07001809 source.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001810 WaitForEncodedFrame(2);
asapersson09f05612017-05-15 23:40:18 -07001811 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
asaperssond0de2952017-04-21 01:47:31 -07001812 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1813 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1814
1815 // Trigger adapt up, expect no restriction.
mflodmancc3d4422017-08-03 08:27:51 -07001816 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssond0de2952017-04-21 01:47:31 -07001817 source.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001818 WaitForEncodedFrame(kWidth, kHeight);
asaperssond0de2952017-04-21 01:47:31 -07001819 VerifyNoLimitation(source.sink_wants());
1820 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1821 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1822
1823 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001824 video_stream_encoder_->TriggerCpuOveruse();
asaperssond0de2952017-04-21 01:47:31 -07001825 source.IncomingCapturedFrame(CreateFrame(4, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001826 WaitForEncodedFrame(4);
asapersson09f05612017-05-15 23:40:18 -07001827 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
asaperssond0de2952017-04-21 01:47:31 -07001828 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1829 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1830
1831 // Trigger adapt up, expect no restriction.
mflodmancc3d4422017-08-03 08:27:51 -07001832 video_stream_encoder_->TriggerCpuNormalUsage();
asapersson09f05612017-05-15 23:40:18 -07001833 source.IncomingCapturedFrame(CreateFrame(5, kWidth, kHeight));
1834 sink_.WaitForEncodedFrame(kWidth, kHeight);
asaperssond0de2952017-04-21 01:47:31 -07001835 VerifyNoLimitation(source.sink_wants());
1836 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1837 EXPECT_EQ(4, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1838
mflodmancc3d4422017-08-03 08:27:51 -07001839 video_stream_encoder_->Stop();
asaperssond0de2952017-04-21 01:47:31 -07001840}
1841
mflodmancc3d4422017-08-03 08:27:51 -07001842TEST_F(VideoStreamEncoderTest,
asaperssonf7e294d2017-06-13 23:25:22 -07001843 AdaptsResolutionUpAndDownTwiceForLowQuality_BalancedMode_NoFpsLimit) {
1844 const int kWidth = 1280;
1845 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001846 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -07001847
1848 // Enable kBalanced preference, no initial limitation.
1849 AdaptingFrameForwarder source;
1850 source.set_adaptation_enabled(true);
mflodmancc3d4422017-08-03 08:27:51 -07001851 video_stream_encoder_->SetSource(
1852 &source,
1853 VideoSendStream::DegradationPreference::kBalanced);
asaperssonf7e294d2017-06-13 23:25:22 -07001854
1855 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
1856 sink_.WaitForEncodedFrame(kWidth, kHeight);
1857 VerifyNoLimitation(source.sink_wants());
1858 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1859 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1860
1861 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001862 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07001863 source.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
1864 sink_.WaitForEncodedFrame(2);
1865 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
1866 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1867 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1868
1869 // Trigger adapt up, expect no restriction.
mflodmancc3d4422017-08-03 08:27:51 -07001870 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07001871 source.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
1872 sink_.WaitForEncodedFrame(kWidth, kHeight);
1873 VerifyNoLimitation(source.sink_wants());
1874 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1875 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1876
1877 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001878 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07001879 source.IncomingCapturedFrame(CreateFrame(4, kWidth, kHeight));
1880 sink_.WaitForEncodedFrame(4);
1881 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
1882 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1883 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1884
1885 // Trigger adapt up, expect no restriction.
mflodmancc3d4422017-08-03 08:27:51 -07001886 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07001887 source.IncomingCapturedFrame(CreateFrame(5, kWidth, kHeight));
1888 sink_.WaitForEncodedFrame(kWidth, kHeight);
1889 VerifyNoLimitation(source.sink_wants());
1890 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1891 EXPECT_EQ(4, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1892
mflodmancc3d4422017-08-03 08:27:51 -07001893 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07001894}
1895
mflodmancc3d4422017-08-03 08:27:51 -07001896TEST_F(VideoStreamEncoderTest,
asaperssond0de2952017-04-21 01:47:31 -07001897 AdaptsResolutionOnOveruseAndLowQuality_MaintainFramerateMode) {
1898 const int kWidth = 1280;
1899 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001900 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssond0de2952017-04-21 01:47:31 -07001901
1902 // Enable kMaintainFramerate preference, no initial limitation.
1903 AdaptingFrameForwarder source;
1904 source.set_adaptation_enabled(true);
mflodmancc3d4422017-08-03 08:27:51 -07001905 video_stream_encoder_->SetSource(
asaperssond0de2952017-04-21 01:47:31 -07001906 &source, VideoSendStream::DegradationPreference::kMaintainFramerate);
1907
1908 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001909 WaitForEncodedFrame(kWidth, kHeight);
asaperssond0de2952017-04-21 01:47:31 -07001910 VerifyNoLimitation(source.sink_wants());
1911 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1912 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1913 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1914 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1915
1916 // Trigger cpu adapt down, expect scaled down resolution (960x540).
mflodmancc3d4422017-08-03 08:27:51 -07001917 video_stream_encoder_->TriggerCpuOveruse();
asaperssond0de2952017-04-21 01:47:31 -07001918 source.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001919 WaitForEncodedFrame(2);
asapersson09f05612017-05-15 23:40:18 -07001920 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
asaperssond0de2952017-04-21 01:47:31 -07001921 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1922 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1923 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1924 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1925
1926 // Trigger cpu adapt down, expect scaled down resolution (640x360).
mflodmancc3d4422017-08-03 08:27:51 -07001927 video_stream_encoder_->TriggerCpuOveruse();
asaperssond0de2952017-04-21 01:47:31 -07001928 source.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001929 WaitForEncodedFrame(3);
asapersson09f05612017-05-15 23:40:18 -07001930 VerifyFpsMaxResolutionLt(source.sink_wants(), source.last_wants());
asaperssond0de2952017-04-21 01:47:31 -07001931 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1932 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1933 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1934 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1935
Jonathan Yubc771b72017-12-08 17:04:29 -08001936 // Trigger cpu adapt down, expect scaled down resolution (480x270).
mflodmancc3d4422017-08-03 08:27:51 -07001937 video_stream_encoder_->TriggerCpuOveruse();
asaperssond0de2952017-04-21 01:47:31 -07001938 source.IncomingCapturedFrame(CreateFrame(4, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001939 WaitForEncodedFrame(4);
Jonathan Yubc771b72017-12-08 17:04:29 -08001940 VerifyFpsMaxResolutionLt(source.sink_wants(), source.last_wants());
asaperssond0de2952017-04-21 01:47:31 -07001941 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1942 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
Jonathan Yubc771b72017-12-08 17:04:29 -08001943 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
asaperssond0de2952017-04-21 01:47:31 -07001944 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1945
Jonathan Yubc771b72017-12-08 17:04:29 -08001946 // Trigger quality adapt down, expect scaled down resolution (320x180).
mflodmancc3d4422017-08-03 08:27:51 -07001947 video_stream_encoder_->TriggerQualityLow();
asaperssond0de2952017-04-21 01:47:31 -07001948 source.IncomingCapturedFrame(CreateFrame(5, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001949 WaitForEncodedFrame(5);
asapersson09f05612017-05-15 23:40:18 -07001950 VerifyFpsMaxResolutionLt(source.sink_wants(), source.last_wants());
Jonathan Yubc771b72017-12-08 17:04:29 -08001951 rtc::VideoSinkWants last_wants = source.sink_wants();
asaperssond0de2952017-04-21 01:47:31 -07001952 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1953 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1954 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1955 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1956
Jonathan Yubc771b72017-12-08 17:04:29 -08001957 // Trigger quality adapt down, expect no change (min resolution reached).
1958 video_stream_encoder_->TriggerQualityLow();
1959 source.IncomingCapturedFrame(CreateFrame(6, kWidth, kHeight));
1960 WaitForEncodedFrame(6);
1961 VerifyFpsMaxResolutionEq(source.sink_wants(), last_wants);
1962 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1963 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1964 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1965 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1966
1967 // Trigger cpu adapt up, expect upscaled resolution (480x270).
mflodmancc3d4422017-08-03 08:27:51 -07001968 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssond0de2952017-04-21 01:47:31 -07001969 source.IncomingCapturedFrame(CreateFrame(7, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001970 WaitForEncodedFrame(7);
asapersson09f05612017-05-15 23:40:18 -07001971 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
Jonathan Yubc771b72017-12-08 17:04:29 -08001972 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1973 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1974 EXPECT_EQ(4, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1975 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1976
1977 // Trigger cpu adapt up, expect upscaled resolution (640x360).
1978 video_stream_encoder_->TriggerCpuNormalUsage();
1979 source.IncomingCapturedFrame(CreateFrame(8, kWidth, kHeight));
1980 WaitForEncodedFrame(8);
1981 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
1982 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1983 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1984 EXPECT_EQ(5, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1985 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1986
1987 // Trigger cpu adapt up, expect upscaled resolution (960x540).
1988 video_stream_encoder_->TriggerCpuNormalUsage();
1989 source.IncomingCapturedFrame(CreateFrame(9, kWidth, kHeight));
1990 WaitForEncodedFrame(9);
1991 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
asaperssond0de2952017-04-21 01:47:31 -07001992 last_wants = source.sink_wants();
1993 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1994 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
Jonathan Yubc771b72017-12-08 17:04:29 -08001995 EXPECT_EQ(6, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
asaperssond0de2952017-04-21 01:47:31 -07001996 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1997
1998 // Trigger cpu adapt up, no cpu downgrades, expect no change (960x540).
mflodmancc3d4422017-08-03 08:27:51 -07001999 video_stream_encoder_->TriggerCpuNormalUsage();
Jonathan Yubc771b72017-12-08 17:04:29 -08002000 source.IncomingCapturedFrame(CreateFrame(10, kWidth, kHeight));
2001 WaitForEncodedFrame(10);
asapersson09f05612017-05-15 23:40:18 -07002002 VerifyFpsEqResolutionEq(source.sink_wants(), last_wants);
asaperssond0de2952017-04-21 01:47:31 -07002003 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2004 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
Jonathan Yubc771b72017-12-08 17:04:29 -08002005 EXPECT_EQ(6, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
asaperssond0de2952017-04-21 01:47:31 -07002006 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2007
2008 // Trigger quality adapt up, expect no restriction (1280x720).
mflodmancc3d4422017-08-03 08:27:51 -07002009 video_stream_encoder_->TriggerQualityHigh();
Jonathan Yubc771b72017-12-08 17:04:29 -08002010 source.IncomingCapturedFrame(CreateFrame(11, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002011 WaitForEncodedFrame(kWidth, kHeight);
asapersson09f05612017-05-15 23:40:18 -07002012 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
asaperssond0de2952017-04-21 01:47:31 -07002013 VerifyNoLimitation(source.sink_wants());
2014 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2015 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
Jonathan Yubc771b72017-12-08 17:04:29 -08002016 EXPECT_EQ(6, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
asaperssond0de2952017-04-21 01:47:31 -07002017 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
kthelgason5e13d412016-12-01 03:59:51 -08002018
mflodmancc3d4422017-08-03 08:27:51 -07002019 video_stream_encoder_->Stop();
kthelgason5e13d412016-12-01 03:59:51 -08002020}
2021
mflodmancc3d4422017-08-03 08:27:51 -07002022TEST_F(VideoStreamEncoderTest, CpuLimitedHistogramIsReported) {
asaperssonfab67072017-04-04 05:51:49 -07002023 const int kWidth = 640;
2024 const int kHeight = 360;
perkj803d97f2016-11-01 11:45:46 -07002025
mflodmancc3d4422017-08-03 08:27:51 -07002026 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
sprang4847ae62017-06-27 07:06:52 -07002027
perkj803d97f2016-11-01 11:45:46 -07002028 for (int i = 1; i <= SendStatisticsProxy::kMinRequiredMetricsSamples; ++i) {
asaperssonfab67072017-04-04 05:51:49 -07002029 video_source_.IncomingCapturedFrame(CreateFrame(i, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002030 WaitForEncodedFrame(i);
perkj803d97f2016-11-01 11:45:46 -07002031 }
2032
mflodmancc3d4422017-08-03 08:27:51 -07002033 video_stream_encoder_->TriggerCpuOveruse();
perkj803d97f2016-11-01 11:45:46 -07002034 for (int i = 1; i <= SendStatisticsProxy::kMinRequiredMetricsSamples; ++i) {
asaperssonfab67072017-04-04 05:51:49 -07002035 video_source_.IncomingCapturedFrame(CreateFrame(
2036 SendStatisticsProxy::kMinRequiredMetricsSamples + i, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002037 WaitForEncodedFrame(SendStatisticsProxy::kMinRequiredMetricsSamples + i);
perkj803d97f2016-11-01 11:45:46 -07002038 }
2039
mflodmancc3d4422017-08-03 08:27:51 -07002040 video_stream_encoder_->Stop();
2041 video_stream_encoder_.reset();
perkj803d97f2016-11-01 11:45:46 -07002042 stats_proxy_.reset();
sprangf8ee65e2017-02-28 08:49:33 -08002043
perkj803d97f2016-11-01 11:45:46 -07002044 EXPECT_EQ(1,
2045 metrics::NumSamples("WebRTC.Video.CpuLimitedResolutionInPercent"));
2046 EXPECT_EQ(
2047 1, metrics::NumEvents("WebRTC.Video.CpuLimitedResolutionInPercent", 50));
2048}
2049
mflodmancc3d4422017-08-03 08:27:51 -07002050TEST_F(VideoStreamEncoderTest,
2051 CpuLimitedHistogramIsNotReportedForDisabledDegradation) {
2052 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonf4e44af2017-04-19 02:01:06 -07002053 const int kWidth = 640;
2054 const int kHeight = 360;
2055
mflodmancc3d4422017-08-03 08:27:51 -07002056 video_stream_encoder_->SetSource(
asaperssonf4e44af2017-04-19 02:01:06 -07002057 &video_source_,
2058 VideoSendStream::DegradationPreference::kDegradationDisabled);
2059
2060 for (int i = 1; i <= SendStatisticsProxy::kMinRequiredMetricsSamples; ++i) {
2061 video_source_.IncomingCapturedFrame(CreateFrame(i, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002062 WaitForEncodedFrame(i);
asaperssonf4e44af2017-04-19 02:01:06 -07002063 }
2064
mflodmancc3d4422017-08-03 08:27:51 -07002065 video_stream_encoder_->Stop();
2066 video_stream_encoder_.reset();
asaperssonf4e44af2017-04-19 02:01:06 -07002067 stats_proxy_.reset();
2068
2069 EXPECT_EQ(0,
2070 metrics::NumSamples("WebRTC.Video.CpuLimitedResolutionInPercent"));
2071}
2072
mflodmancc3d4422017-08-03 08:27:51 -07002073TEST_F(VideoStreamEncoderTest, CallsBitrateObserver) {
sprang4847ae62017-06-27 07:06:52 -07002074 MockBitrateObserver bitrate_observer;
mflodmancc3d4422017-08-03 08:27:51 -07002075 video_stream_encoder_->SetBitrateObserver(&bitrate_observer);
sprang57c2fff2017-01-16 06:24:02 -08002076
2077 const int kDefaultFps = 30;
Erik Språng566124a2018-04-23 12:32:22 +02002078 const VideoBitrateAllocation expected_bitrate =
sprang57c2fff2017-01-16 06:24:02 -08002079 DefaultVideoBitrateAllocator(fake_encoder_.codec_config())
kthelgason2bc68642017-02-07 07:02:22 -08002080 .GetAllocation(kLowTargetBitrateBps, kDefaultFps);
sprang57c2fff2017-01-16 06:24:02 -08002081
2082 // First called on bitrate updated, then again on first frame.
2083 EXPECT_CALL(bitrate_observer, OnBitrateAllocationUpdated(expected_bitrate))
2084 .Times(2);
mflodmancc3d4422017-08-03 08:27:51 -07002085 video_stream_encoder_->OnBitrateUpdated(kLowTargetBitrateBps, 0, 0);
sprang57c2fff2017-01-16 06:24:02 -08002086
2087 const int64_t kStartTimeMs = 1;
2088 video_source_.IncomingCapturedFrame(
2089 CreateFrame(kStartTimeMs, codec_width_, codec_height_));
sprang4847ae62017-06-27 07:06:52 -07002090 WaitForEncodedFrame(kStartTimeMs);
sprang57c2fff2017-01-16 06:24:02 -08002091
2092 // Not called on second frame.
2093 EXPECT_CALL(bitrate_observer, OnBitrateAllocationUpdated(expected_bitrate))
2094 .Times(0);
2095 video_source_.IncomingCapturedFrame(
2096 CreateFrame(kStartTimeMs + 1, codec_width_, codec_height_));
sprang4847ae62017-06-27 07:06:52 -07002097 WaitForEncodedFrame(kStartTimeMs + 1);
sprang57c2fff2017-01-16 06:24:02 -08002098
2099 // Called after a process interval.
2100 const int64_t kProcessIntervalMs =
2101 vcm::VCMProcessTimer::kDefaultProcessIntervalMs;
sprang4847ae62017-06-27 07:06:52 -07002102 fake_clock_.AdvanceTimeMicros(rtc::kNumMicrosecsPerMillisec *
2103 (kProcessIntervalMs + (1000 / kDefaultFps)));
sprang57c2fff2017-01-16 06:24:02 -08002104 EXPECT_CALL(bitrate_observer, OnBitrateAllocationUpdated(expected_bitrate))
2105 .Times(1);
2106 video_source_.IncomingCapturedFrame(CreateFrame(
2107 kStartTimeMs + kProcessIntervalMs, codec_width_, codec_height_));
sprang4847ae62017-06-27 07:06:52 -07002108 WaitForEncodedFrame(kStartTimeMs + kProcessIntervalMs);
sprang57c2fff2017-01-16 06:24:02 -08002109
mflodmancc3d4422017-08-03 08:27:51 -07002110 video_stream_encoder_->Stop();
sprang57c2fff2017-01-16 06:24:02 -08002111}
2112
Niels Möller7dc26b72017-12-06 10:27:48 +01002113TEST_F(VideoStreamEncoderTest, OveruseDetectorUpdatedOnReconfigureAndAdaption) {
2114 const int kFrameWidth = 1280;
2115 const int kFrameHeight = 720;
2116 const int kFramerate = 24;
2117
2118 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
2119 test::FrameForwarder source;
2120 video_stream_encoder_->SetSource(
2121 &source, VideoSendStream::DegradationPreference::kMaintainResolution);
2122
2123 // Insert a single frame, triggering initial configuration.
2124 source.IncomingCapturedFrame(CreateFrame(1, kFrameWidth, kFrameHeight));
2125 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2126
2127 EXPECT_EQ(
2128 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2129 kDefaultFramerate);
2130
2131 // Trigger reconfigure encoder (without resetting the entire instance).
2132 VideoEncoderConfig video_encoder_config;
Niels Möller259a4972018-04-05 15:36:51 +02002133 video_encoder_config.codec_type = kVideoCodecVP8;
Niels Möller7dc26b72017-12-06 10:27:48 +01002134 video_encoder_config.max_bitrate_bps = kTargetBitrateBps;
2135 video_encoder_config.number_of_streams = 1;
2136 video_encoder_config.video_stream_factory =
2137 new rtc::RefCountedObject<VideoStreamFactory>(1, kFramerate);
2138 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
2139 kMaxPayloadLength, false);
2140 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2141
2142 // Detector should be updated with fps limit from codec config.
2143 EXPECT_EQ(
2144 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2145 kFramerate);
2146
2147 // Trigger overuse, max framerate should be reduced.
2148 VideoSendStream::Stats stats = stats_proxy_->GetStats();
2149 stats.input_frame_rate = kFramerate;
2150 stats_proxy_->SetMockStats(stats);
2151 video_stream_encoder_->TriggerCpuOveruse();
2152 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2153 int adapted_framerate =
2154 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate();
2155 EXPECT_LT(adapted_framerate, kFramerate);
2156
2157 // Trigger underuse, max framerate should go back to codec configured fps.
2158 // Set extra low fps, to make sure it's actually reset, not just incremented.
2159 stats = stats_proxy_->GetStats();
2160 stats.input_frame_rate = adapted_framerate / 2;
2161 stats_proxy_->SetMockStats(stats);
2162 video_stream_encoder_->TriggerCpuNormalUsage();
2163 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2164 EXPECT_EQ(
2165 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2166 kFramerate);
2167
2168 video_stream_encoder_->Stop();
2169}
2170
2171TEST_F(VideoStreamEncoderTest,
2172 OveruseDetectorUpdatedRespectsFramerateAfterUnderuse) {
2173 const int kFrameWidth = 1280;
2174 const int kFrameHeight = 720;
2175 const int kLowFramerate = 15;
2176 const int kHighFramerate = 25;
2177
2178 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
2179 test::FrameForwarder source;
2180 video_stream_encoder_->SetSource(
2181 &source, VideoSendStream::DegradationPreference::kMaintainResolution);
2182
2183 // Trigger initial configuration.
2184 VideoEncoderConfig video_encoder_config;
Niels Möller259a4972018-04-05 15:36:51 +02002185 video_encoder_config.codec_type = kVideoCodecVP8;
Niels Möller7dc26b72017-12-06 10:27:48 +01002186 video_encoder_config.max_bitrate_bps = kTargetBitrateBps;
2187 video_encoder_config.number_of_streams = 1;
2188 video_encoder_config.video_stream_factory =
2189 new rtc::RefCountedObject<VideoStreamFactory>(1, kLowFramerate);
2190 source.IncomingCapturedFrame(CreateFrame(1, kFrameWidth, kFrameHeight));
2191 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
2192 kMaxPayloadLength, false);
2193 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2194
2195 EXPECT_EQ(
2196 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2197 kLowFramerate);
2198
2199 // Trigger overuse, max framerate should be reduced.
2200 VideoSendStream::Stats stats = stats_proxy_->GetStats();
2201 stats.input_frame_rate = kLowFramerate;
2202 stats_proxy_->SetMockStats(stats);
2203 video_stream_encoder_->TriggerCpuOveruse();
2204 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2205 int adapted_framerate =
2206 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate();
2207 EXPECT_LT(adapted_framerate, kLowFramerate);
2208
2209 // Reconfigure the encoder with a new (higher max framerate), max fps should
2210 // still respect the adaptation.
2211 video_encoder_config.video_stream_factory =
2212 new rtc::RefCountedObject<VideoStreamFactory>(1, kHighFramerate);
2213 source.IncomingCapturedFrame(CreateFrame(1, kFrameWidth, kFrameHeight));
2214 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
2215 kMaxPayloadLength, false);
2216 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2217
2218 EXPECT_EQ(
2219 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2220 adapted_framerate);
2221
2222 // Trigger underuse, max framerate should go back to codec configured fps.
2223 stats = stats_proxy_->GetStats();
2224 stats.input_frame_rate = adapted_framerate;
2225 stats_proxy_->SetMockStats(stats);
2226 video_stream_encoder_->TriggerCpuNormalUsage();
2227 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2228 EXPECT_EQ(
2229 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2230 kHighFramerate);
2231
2232 video_stream_encoder_->Stop();
2233}
2234
mflodmancc3d4422017-08-03 08:27:51 -07002235TEST_F(VideoStreamEncoderTest,
2236 OveruseDetectorUpdatedOnDegradationPreferenceChange) {
sprangfda496a2017-06-15 04:21:07 -07002237 const int kFrameWidth = 1280;
2238 const int kFrameHeight = 720;
2239 const int kFramerate = 24;
2240
mflodmancc3d4422017-08-03 08:27:51 -07002241 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
sprangfda496a2017-06-15 04:21:07 -07002242 test::FrameForwarder source;
mflodmancc3d4422017-08-03 08:27:51 -07002243 video_stream_encoder_->SetSource(
sprangfda496a2017-06-15 04:21:07 -07002244 &source, VideoSendStream::DegradationPreference::kMaintainResolution);
2245
2246 // Trigger initial configuration.
2247 VideoEncoderConfig video_encoder_config;
Niels Möller259a4972018-04-05 15:36:51 +02002248 video_encoder_config.codec_type = kVideoCodecVP8;
sprangfda496a2017-06-15 04:21:07 -07002249 video_encoder_config.max_bitrate_bps = kTargetBitrateBps;
2250 video_encoder_config.number_of_streams = 1;
2251 video_encoder_config.video_stream_factory =
2252 new rtc::RefCountedObject<VideoStreamFactory>(1, kFramerate);
2253 source.IncomingCapturedFrame(CreateFrame(1, kFrameWidth, kFrameHeight));
mflodmancc3d4422017-08-03 08:27:51 -07002254 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
2255 kMaxPayloadLength, false);
2256 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
sprangfda496a2017-06-15 04:21:07 -07002257
Niels Möller7dc26b72017-12-06 10:27:48 +01002258 EXPECT_EQ(
2259 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2260 kFramerate);
sprangfda496a2017-06-15 04:21:07 -07002261
2262 // Trigger overuse, max framerate should be reduced.
2263 VideoSendStream::Stats stats = stats_proxy_->GetStats();
2264 stats.input_frame_rate = kFramerate;
2265 stats_proxy_->SetMockStats(stats);
mflodmancc3d4422017-08-03 08:27:51 -07002266 video_stream_encoder_->TriggerCpuOveruse();
2267 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
Niels Möller7dc26b72017-12-06 10:27:48 +01002268 int adapted_framerate =
2269 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate();
sprangfda496a2017-06-15 04:21:07 -07002270 EXPECT_LT(adapted_framerate, kFramerate);
2271
2272 // Change degradation preference to not enable framerate scaling. Target
2273 // framerate should be changed to codec defined limit.
mflodmancc3d4422017-08-03 08:27:51 -07002274 video_stream_encoder_->SetSource(
sprangfda496a2017-06-15 04:21:07 -07002275 &source, VideoSendStream::DegradationPreference::kMaintainFramerate);
mflodmancc3d4422017-08-03 08:27:51 -07002276 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
Niels Möller7dc26b72017-12-06 10:27:48 +01002277 EXPECT_EQ(
2278 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2279 kFramerate);
sprangfda496a2017-06-15 04:21:07 -07002280
mflodmancc3d4422017-08-03 08:27:51 -07002281 video_stream_encoder_->Stop();
sprangfda496a2017-06-15 04:21:07 -07002282}
2283
mflodmancc3d4422017-08-03 08:27:51 -07002284TEST_F(VideoStreamEncoderTest, DropsFramesAndScalesWhenBitrateIsTooLow) {
asaperssonfab67072017-04-04 05:51:49 -07002285 const int kTooLowBitrateForFrameSizeBps = 10000;
mflodmancc3d4422017-08-03 08:27:51 -07002286 video_stream_encoder_->OnBitrateUpdated(kTooLowBitrateForFrameSizeBps, 0, 0);
asaperssonfab67072017-04-04 05:51:49 -07002287 const int kWidth = 640;
2288 const int kHeight = 360;
kthelgason2bc68642017-02-07 07:02:22 -08002289
asaperssonfab67072017-04-04 05:51:49 -07002290 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
kthelgason2bc68642017-02-07 07:02:22 -08002291
2292 // Expect to drop this frame, the wait should time out.
sprang4847ae62017-06-27 07:06:52 -07002293 ExpectDroppedFrame();
kthelgason2bc68642017-02-07 07:02:22 -08002294
2295 // Expect the sink_wants to specify a scaled frame.
asapersson0944a802017-04-07 00:57:58 -07002296 EXPECT_LT(video_source_.sink_wants().max_pixel_count, kWidth * kHeight);
kthelgason2bc68642017-02-07 07:02:22 -08002297
sprangc5d62e22017-04-02 23:53:04 -07002298 int last_pixel_count = video_source_.sink_wants().max_pixel_count;
kthelgason2bc68642017-02-07 07:02:22 -08002299
asaperssonfab67072017-04-04 05:51:49 -07002300 // Next frame is scaled.
kthelgason2bc68642017-02-07 07:02:22 -08002301 video_source_.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07002302 CreateFrame(2, kWidth * 3 / 4, kHeight * 3 / 4));
kthelgason2bc68642017-02-07 07:02:22 -08002303
2304 // Expect to drop this frame, the wait should time out.
sprang4847ae62017-06-27 07:06:52 -07002305 ExpectDroppedFrame();
kthelgason2bc68642017-02-07 07:02:22 -08002306
sprangc5d62e22017-04-02 23:53:04 -07002307 EXPECT_LT(video_source_.sink_wants().max_pixel_count, last_pixel_count);
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,
2313 NumberOfDroppedFramesLimitedWhenBitrateIsTooLow) {
asaperssonfab67072017-04-04 05:51:49 -07002314 const int kTooLowBitrateForFrameSizeBps = 10000;
mflodmancc3d4422017-08-03 08:27:51 -07002315 video_stream_encoder_->OnBitrateUpdated(kTooLowBitrateForFrameSizeBps, 0, 0);
asaperssonfab67072017-04-04 05:51:49 -07002316 const int kWidth = 640;
2317 const int kHeight = 360;
kthelgason2bc68642017-02-07 07:02:22 -08002318
2319 // We expect the n initial frames to get dropped.
2320 int i;
2321 for (i = 1; i <= kMaxInitialFramedrop; ++i) {
asaperssonfab67072017-04-04 05:51:49 -07002322 video_source_.IncomingCapturedFrame(CreateFrame(i, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002323 ExpectDroppedFrame();
kthelgason2bc68642017-02-07 07:02:22 -08002324 }
2325 // The n+1th frame should not be dropped, even though it's size is too large.
asaperssonfab67072017-04-04 05:51:49 -07002326 video_source_.IncomingCapturedFrame(CreateFrame(i, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002327 WaitForEncodedFrame(i);
kthelgason2bc68642017-02-07 07:02:22 -08002328
2329 // Expect the sink_wants to specify a scaled frame.
asaperssonfab67072017-04-04 05:51:49 -07002330 EXPECT_LT(video_source_.sink_wants().max_pixel_count, kWidth * kHeight);
kthelgason2bc68642017-02-07 07:02:22 -08002331
mflodmancc3d4422017-08-03 08:27:51 -07002332 video_stream_encoder_->Stop();
kthelgason2bc68642017-02-07 07:02:22 -08002333}
2334
mflodmancc3d4422017-08-03 08:27:51 -07002335TEST_F(VideoStreamEncoderTest,
2336 InitialFrameDropOffWithMaintainResolutionPreference) {
asaperssonfab67072017-04-04 05:51:49 -07002337 const int kWidth = 640;
2338 const int kHeight = 360;
mflodmancc3d4422017-08-03 08:27:51 -07002339 video_stream_encoder_->OnBitrateUpdated(kLowTargetBitrateBps, 0, 0);
kthelgason2bc68642017-02-07 07:02:22 -08002340
2341 // Set degradation preference.
mflodmancc3d4422017-08-03 08:27:51 -07002342 video_stream_encoder_->SetSource(
kthelgason2bc68642017-02-07 07:02:22 -08002343 &video_source_,
2344 VideoSendStream::DegradationPreference::kMaintainResolution);
2345
asaperssonfab67072017-04-04 05:51:49 -07002346 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
kthelgason2bc68642017-02-07 07:02:22 -08002347 // Frame should not be dropped, even if it's too large.
sprang4847ae62017-06-27 07:06:52 -07002348 WaitForEncodedFrame(1);
kthelgason2bc68642017-02-07 07:02:22 -08002349
mflodmancc3d4422017-08-03 08:27:51 -07002350 video_stream_encoder_->Stop();
kthelgason2bc68642017-02-07 07:02:22 -08002351}
2352
mflodmancc3d4422017-08-03 08:27:51 -07002353TEST_F(VideoStreamEncoderTest, InitialFrameDropOffWhenEncoderDisabledScaling) {
asaperssonfab67072017-04-04 05:51:49 -07002354 const int kWidth = 640;
2355 const int kHeight = 360;
kthelgasonad9010c2017-02-14 00:46:51 -08002356 fake_encoder_.SetQualityScaling(false);
Niels Möller4db138e2018-04-19 09:04:13 +02002357
2358 VideoEncoderConfig video_encoder_config;
2359 test::FillEncoderConfiguration(kVideoCodecVP8, 1, &video_encoder_config);
2360 // Make format different, to force recreation of encoder.
2361 video_encoder_config.video_format.parameters["foo"] = "foo";
2362 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
2363 kMaxPayloadLength,
2364 true /* nack_enabled */);
mflodmancc3d4422017-08-03 08:27:51 -07002365 video_stream_encoder_->OnBitrateUpdated(kLowTargetBitrateBps, 0, 0);
asapersson09f05612017-05-15 23:40:18 -07002366
kthelgasonb83797b2017-02-14 11:57:25 -08002367 // Force quality scaler reconfiguration by resetting the source.
mflodmancc3d4422017-08-03 08:27:51 -07002368 video_stream_encoder_->SetSource(
2369 &video_source_,
2370 VideoSendStream::DegradationPreference::kBalanced);
kthelgasonad9010c2017-02-14 00:46:51 -08002371
asaperssonfab67072017-04-04 05:51:49 -07002372 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
kthelgasonad9010c2017-02-14 00:46:51 -08002373 // Frame should not be dropped, even if it's too large.
sprang4847ae62017-06-27 07:06:52 -07002374 WaitForEncodedFrame(1);
kthelgasonad9010c2017-02-14 00:46:51 -08002375
mflodmancc3d4422017-08-03 08:27:51 -07002376 video_stream_encoder_->Stop();
kthelgasonad9010c2017-02-14 00:46:51 -08002377 fake_encoder_.SetQualityScaling(true);
2378}
2379
mflodmancc3d4422017-08-03 08:27:51 -07002380TEST_F(VideoStreamEncoderTest,
asaperssond0de2952017-04-21 01:47:31 -07002381 ResolutionNotAdaptedForTooSmallFrame_MaintainFramerateMode) {
2382 const int kTooSmallWidth = 10;
2383 const int kTooSmallHeight = 10;
mflodmancc3d4422017-08-03 08:27:51 -07002384 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssond0de2952017-04-21 01:47:31 -07002385
2386 // Enable kMaintainFramerate preference, no initial limitation.
2387 test::FrameForwarder source;
mflodmancc3d4422017-08-03 08:27:51 -07002388 video_stream_encoder_->SetSource(
asaperssond0de2952017-04-21 01:47:31 -07002389 &source, VideoSendStream::DegradationPreference::kMaintainFramerate);
2390 VerifyNoLimitation(source.sink_wants());
2391 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2392
2393 // Trigger adapt down, too small frame, expect no change.
2394 source.IncomingCapturedFrame(CreateFrame(1, kTooSmallWidth, kTooSmallHeight));
sprang4847ae62017-06-27 07:06:52 -07002395 WaitForEncodedFrame(1);
mflodmancc3d4422017-08-03 08:27:51 -07002396 video_stream_encoder_->TriggerCpuOveruse();
asaperssond0de2952017-04-21 01:47:31 -07002397 VerifyNoLimitation(source.sink_wants());
2398 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2399 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2400
mflodmancc3d4422017-08-03 08:27:51 -07002401 video_stream_encoder_->Stop();
asaperssond0de2952017-04-21 01:47:31 -07002402}
2403
mflodmancc3d4422017-08-03 08:27:51 -07002404TEST_F(VideoStreamEncoderTest,
2405 ResolutionNotAdaptedForTooSmallFrame_BalancedMode) {
asaperssonf7e294d2017-06-13 23:25:22 -07002406 const int kTooSmallWidth = 10;
2407 const int kTooSmallHeight = 10;
2408 const int kFpsLimit = 7;
mflodmancc3d4422017-08-03 08:27:51 -07002409 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -07002410
2411 // Enable kBalanced preference, no initial limitation.
2412 test::FrameForwarder source;
mflodmancc3d4422017-08-03 08:27:51 -07002413 video_stream_encoder_->SetSource(
2414 &source,
2415 VideoSendStream::DegradationPreference::kBalanced);
asaperssonf7e294d2017-06-13 23:25:22 -07002416 VerifyNoLimitation(source.sink_wants());
2417 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2418 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2419
2420 // Trigger adapt down, expect limited framerate.
2421 source.IncomingCapturedFrame(CreateFrame(1, kTooSmallWidth, kTooSmallHeight));
sprang4847ae62017-06-27 07:06:52 -07002422 WaitForEncodedFrame(1);
mflodmancc3d4422017-08-03 08:27:51 -07002423 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002424 VerifyFpsEqResolutionMax(source.sink_wants(), kFpsLimit);
2425 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2426 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2427 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2428
2429 // Trigger adapt down, too small frame, expect no change.
2430 source.IncomingCapturedFrame(CreateFrame(2, kTooSmallWidth, kTooSmallHeight));
sprang4847ae62017-06-27 07:06:52 -07002431 WaitForEncodedFrame(2);
mflodmancc3d4422017-08-03 08:27:51 -07002432 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002433 VerifyFpsEqResolutionMax(source.sink_wants(), kFpsLimit);
2434 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2435 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2436 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2437
mflodmancc3d4422017-08-03 08:27:51 -07002438 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07002439}
2440
mflodmancc3d4422017-08-03 08:27:51 -07002441TEST_F(VideoStreamEncoderTest, FailingInitEncodeDoesntCauseCrash) {
asapersson02465b82017-04-10 01:12:52 -07002442 fake_encoder_.ForceInitEncodeFailure(true);
mflodmancc3d4422017-08-03 08:27:51 -07002443 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
emircanbbcc3562017-08-18 00:28:40 -07002444 ResetEncoder("VP8", 2, 1, 1, true, false);
asapersson02465b82017-04-10 01:12:52 -07002445 const int kFrameWidth = 1280;
2446 const int kFrameHeight = 720;
2447 video_source_.IncomingCapturedFrame(
2448 CreateFrame(1, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002449 ExpectDroppedFrame();
mflodmancc3d4422017-08-03 08:27:51 -07002450 video_stream_encoder_->Stop();
asapersson02465b82017-04-10 01:12:52 -07002451}
2452
sprangb1ca0732017-02-01 08:38:12 -08002453// TODO(sprang): Extend this with fps throttling and any "balanced" extensions.
mflodmancc3d4422017-08-03 08:27:51 -07002454TEST_F(VideoStreamEncoderTest,
2455 AdaptsResolutionOnOveruse_MaintainFramerateMode) {
2456 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
sprangb1ca0732017-02-01 08:38:12 -08002457
2458 const int kFrameWidth = 1280;
2459 const int kFrameHeight = 720;
2460 // Enabled default VideoAdapter downscaling. First step is 3/4, not 3/5 as
mflodmancc3d4422017-08-03 08:27:51 -07002461 // requested by
2462 // VideoStreamEncoder::VideoSourceProxy::RequestResolutionLowerThan().
sprangb1ca0732017-02-01 08:38:12 -08002463 video_source_.set_adaptation_enabled(true);
2464
2465 video_source_.IncomingCapturedFrame(
2466 CreateFrame(1, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002467 WaitForEncodedFrame(kFrameWidth, kFrameHeight);
sprangb1ca0732017-02-01 08:38:12 -08002468
2469 // Trigger CPU overuse, downscale by 3/4.
mflodmancc3d4422017-08-03 08:27:51 -07002470 video_stream_encoder_->TriggerCpuOveruse();
sprangb1ca0732017-02-01 08:38:12 -08002471 video_source_.IncomingCapturedFrame(
2472 CreateFrame(2, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002473 WaitForEncodedFrame((kFrameWidth * 3) / 4, (kFrameHeight * 3) / 4);
sprangb1ca0732017-02-01 08:38:12 -08002474
asaperssonfab67072017-04-04 05:51:49 -07002475 // Trigger CPU normal use, return to original resolution.
mflodmancc3d4422017-08-03 08:27:51 -07002476 video_stream_encoder_->TriggerCpuNormalUsage();
sprangb1ca0732017-02-01 08:38:12 -08002477 video_source_.IncomingCapturedFrame(
2478 CreateFrame(3, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002479 WaitForEncodedFrame(kFrameWidth, kFrameHeight);
sprangb1ca0732017-02-01 08:38:12 -08002480
mflodmancc3d4422017-08-03 08:27:51 -07002481 video_stream_encoder_->Stop();
sprangb1ca0732017-02-01 08:38:12 -08002482}
sprangfe627f32017-03-29 08:24:59 -07002483
mflodmancc3d4422017-08-03 08:27:51 -07002484TEST_F(VideoStreamEncoderTest,
2485 AdaptsFramerateOnOveruse_MaintainResolutionMode) {
sprangc5d62e22017-04-02 23:53:04 -07002486 const int kFrameWidth = 1280;
2487 const int kFrameHeight = 720;
sprang4847ae62017-06-27 07:06:52 -07002488 int kFrameIntervalMs = rtc::kNumMillisecsPerSec / max_framerate_;
sprangc5d62e22017-04-02 23:53:04 -07002489
mflodmancc3d4422017-08-03 08:27:51 -07002490 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
2491 video_stream_encoder_->SetSource(
sprangc5d62e22017-04-02 23:53:04 -07002492 &video_source_,
2493 VideoSendStream::DegradationPreference::kMaintainResolution);
2494 video_source_.set_adaptation_enabled(true);
2495
sprang4847ae62017-06-27 07:06:52 -07002496 int64_t timestamp_ms = fake_clock_.TimeNanos() / rtc::kNumNanosecsPerMillisec;
sprangc5d62e22017-04-02 23:53:04 -07002497
2498 video_source_.IncomingCapturedFrame(
2499 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002500 WaitForEncodedFrame(timestamp_ms);
sprangc5d62e22017-04-02 23:53:04 -07002501
2502 // Try to trigger overuse. No fps estimate available => no effect.
mflodmancc3d4422017-08-03 08:27:51 -07002503 video_stream_encoder_->TriggerCpuOveruse();
sprangc5d62e22017-04-02 23:53:04 -07002504
2505 // Insert frames for one second to get a stable estimate.
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 WaitForEncodedFrame(timestamp_ms);
sprangc5d62e22017-04-02 23:53:04 -07002511 }
2512
2513 // Trigger CPU overuse, reduce framerate by 2/3.
mflodmancc3d4422017-08-03 08:27:51 -07002514 video_stream_encoder_->TriggerCpuOveruse();
sprangc5d62e22017-04-02 23:53:04 -07002515 int num_frames_dropped = 0;
sprang4847ae62017-06-27 07:06:52 -07002516 for (int i = 0; i < max_framerate_; ++i) {
sprangc5d62e22017-04-02 23:53:04 -07002517 timestamp_ms += kFrameIntervalMs;
sprangc5d62e22017-04-02 23:53:04 -07002518 video_source_.IncomingCapturedFrame(
2519 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002520 if (!WaitForFrame(kFrameTimeoutMs)) {
sprangc5d62e22017-04-02 23:53:04 -07002521 ++num_frames_dropped;
2522 } else {
Åsa Perssonc74d8da2017-12-04 14:13:56 +01002523 sink_.CheckLastFrameSizeMatches(kFrameWidth, kFrameHeight);
sprangc5d62e22017-04-02 23:53:04 -07002524 }
2525 }
2526
sprang4847ae62017-06-27 07:06:52 -07002527 // Add some slack to account for frames dropped by the frame dropper.
2528 const int kErrorMargin = 1;
2529 EXPECT_NEAR(num_frames_dropped, max_framerate_ - (max_framerate_ * 2 / 3),
sprangc5d62e22017-04-02 23:53:04 -07002530 kErrorMargin);
2531
2532 // Trigger CPU overuse, reduce framerate by 2/3 again.
mflodmancc3d4422017-08-03 08:27:51 -07002533 video_stream_encoder_->TriggerCpuOveruse();
sprangc5d62e22017-04-02 23:53:04 -07002534 num_frames_dropped = 0;
sprang4847ae62017-06-27 07:06:52 -07002535 for (int i = 0; i < max_framerate_; ++i) {
sprangc5d62e22017-04-02 23:53:04 -07002536 timestamp_ms += kFrameIntervalMs;
sprangc5d62e22017-04-02 23:53:04 -07002537 video_source_.IncomingCapturedFrame(
2538 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002539 if (!WaitForFrame(kFrameTimeoutMs)) {
sprangc5d62e22017-04-02 23:53:04 -07002540 ++num_frames_dropped;
2541 } else {
Åsa Perssonc74d8da2017-12-04 14:13:56 +01002542 sink_.CheckLastFrameSizeMatches(kFrameWidth, kFrameHeight);
sprangc5d62e22017-04-02 23:53:04 -07002543 }
2544 }
sprang4847ae62017-06-27 07:06:52 -07002545 EXPECT_NEAR(num_frames_dropped, max_framerate_ - (max_framerate_ * 4 / 9),
sprangc5d62e22017-04-02 23:53:04 -07002546 kErrorMargin);
2547
2548 // Go back up one step.
mflodmancc3d4422017-08-03 08:27:51 -07002549 video_stream_encoder_->TriggerCpuNormalUsage();
sprangc5d62e22017-04-02 23:53:04 -07002550 num_frames_dropped = 0;
sprang4847ae62017-06-27 07:06:52 -07002551 for (int i = 0; i < max_framerate_; ++i) {
sprangc5d62e22017-04-02 23:53:04 -07002552 timestamp_ms += kFrameIntervalMs;
sprangc5d62e22017-04-02 23:53:04 -07002553 video_source_.IncomingCapturedFrame(
2554 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002555 if (!WaitForFrame(kFrameTimeoutMs)) {
sprangc5d62e22017-04-02 23:53:04 -07002556 ++num_frames_dropped;
2557 } else {
Åsa Perssonc74d8da2017-12-04 14:13:56 +01002558 sink_.CheckLastFrameSizeMatches(kFrameWidth, kFrameHeight);
sprangc5d62e22017-04-02 23:53:04 -07002559 }
2560 }
sprang4847ae62017-06-27 07:06:52 -07002561 EXPECT_NEAR(num_frames_dropped, max_framerate_ - (max_framerate_ * 2 / 3),
sprangc5d62e22017-04-02 23:53:04 -07002562 kErrorMargin);
2563
2564 // Go back up to original mode.
mflodmancc3d4422017-08-03 08:27:51 -07002565 video_stream_encoder_->TriggerCpuNormalUsage();
sprangc5d62e22017-04-02 23:53:04 -07002566 num_frames_dropped = 0;
sprang4847ae62017-06-27 07:06:52 -07002567 for (int i = 0; i < max_framerate_; ++i) {
sprangc5d62e22017-04-02 23:53:04 -07002568 timestamp_ms += kFrameIntervalMs;
sprangc5d62e22017-04-02 23:53:04 -07002569 video_source_.IncomingCapturedFrame(
2570 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002571 if (!WaitForFrame(kFrameTimeoutMs)) {
sprangc5d62e22017-04-02 23:53:04 -07002572 ++num_frames_dropped;
2573 } else {
Åsa Perssonc74d8da2017-12-04 14:13:56 +01002574 sink_.CheckLastFrameSizeMatches(kFrameWidth, kFrameHeight);
sprangc5d62e22017-04-02 23:53:04 -07002575 }
2576 }
2577 EXPECT_NEAR(num_frames_dropped, 0, kErrorMargin);
2578
mflodmancc3d4422017-08-03 08:27:51 -07002579 video_stream_encoder_->Stop();
sprangc5d62e22017-04-02 23:53:04 -07002580}
2581
mflodmancc3d4422017-08-03 08:27:51 -07002582TEST_F(VideoStreamEncoderTest, DoesntAdaptDownPastMinFramerate) {
sprangc5d62e22017-04-02 23:53:04 -07002583 const int kFramerateFps = 5;
2584 const int kFrameIntervalMs = rtc::kNumMillisecsPerSec / kFramerateFps;
sprangc5d62e22017-04-02 23:53:04 -07002585 const int kFrameWidth = 1280;
2586 const int kFrameHeight = 720;
2587
sprang4847ae62017-06-27 07:06:52 -07002588 // Reconfigure encoder with two temporal layers and screensharing, which will
2589 // disable frame dropping and make testing easier.
emircanbbcc3562017-08-18 00:28:40 -07002590 ResetEncoder("VP8", 1, 2, 1, true, true);
sprang4847ae62017-06-27 07:06:52 -07002591
mflodmancc3d4422017-08-03 08:27:51 -07002592 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
2593 video_stream_encoder_->SetSource(
sprangc5d62e22017-04-02 23:53:04 -07002594 &video_source_,
2595 VideoSendStream::DegradationPreference::kMaintainResolution);
2596 video_source_.set_adaptation_enabled(true);
2597
sprang4847ae62017-06-27 07:06:52 -07002598 int64_t timestamp_ms = fake_clock_.TimeNanos() / rtc::kNumNanosecsPerMillisec;
sprangc5d62e22017-04-02 23:53:04 -07002599
2600 // Trigger overuse as much as we can.
Jonathan Yubc771b72017-12-08 17:04:29 -08002601 rtc::VideoSinkWants last_wants;
2602 do {
2603 last_wants = video_source_.sink_wants();
2604
sprangc5d62e22017-04-02 23:53:04 -07002605 // Insert frames to get a new fps estimate...
2606 for (int j = 0; j < kFramerateFps; ++j) {
2607 video_source_.IncomingCapturedFrame(
2608 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
Jonathan Yubc771b72017-12-08 17:04:29 -08002609 if (video_source_.last_sent_width()) {
2610 sink_.WaitForEncodedFrame(timestamp_ms);
2611 }
sprangc5d62e22017-04-02 23:53:04 -07002612 timestamp_ms += kFrameIntervalMs;
Jonathan Yubc771b72017-12-08 17:04:29 -08002613 fake_clock_.AdvanceTimeMicros(
2614 kFrameIntervalMs * rtc::kNumMicrosecsPerMillisec);
sprangc5d62e22017-04-02 23:53:04 -07002615 }
2616 // ...and then try to adapt again.
mflodmancc3d4422017-08-03 08:27:51 -07002617 video_stream_encoder_->TriggerCpuOveruse();
Jonathan Yubc771b72017-12-08 17:04:29 -08002618 } while (video_source_.sink_wants().max_framerate_fps <
2619 last_wants.max_framerate_fps);
sprangc5d62e22017-04-02 23:53:04 -07002620
Jonathan Yubc771b72017-12-08 17:04:29 -08002621 VerifyFpsEqResolutionMax(video_source_.sink_wants(), kMinFramerateFps);
asaperssonf7e294d2017-06-13 23:25:22 -07002622
mflodmancc3d4422017-08-03 08:27:51 -07002623 video_stream_encoder_->Stop();
sprangc5d62e22017-04-02 23:53:04 -07002624}
asaperssonf7e294d2017-06-13 23:25:22 -07002625
mflodmancc3d4422017-08-03 08:27:51 -07002626TEST_F(VideoStreamEncoderTest,
2627 AdaptsResolutionAndFramerateForLowQuality_BalancedMode) {
asaperssonf7e294d2017-06-13 23:25:22 -07002628 const int kWidth = 1280;
2629 const int kHeight = 720;
2630 const int64_t kFrameIntervalMs = 150;
2631 int64_t timestamp_ms = kFrameIntervalMs;
mflodmancc3d4422017-08-03 08:27:51 -07002632 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -07002633
2634 // Enable kBalanced preference, no initial limitation.
2635 AdaptingFrameForwarder source;
2636 source.set_adaptation_enabled(true);
mflodmancc3d4422017-08-03 08:27:51 -07002637 video_stream_encoder_->SetSource(
2638 &source,
2639 VideoSendStream::DegradationPreference::kBalanced);
asaperssonf7e294d2017-06-13 23:25:22 -07002640 timestamp_ms += kFrameIntervalMs;
2641 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002642 WaitForEncodedFrame(kWidth, kHeight);
asaperssonf7e294d2017-06-13 23:25:22 -07002643 VerifyNoLimitation(source.sink_wants());
2644 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2645 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2646 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2647
2648 // Trigger adapt down, expect scaled down resolution (960x540@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002649 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002650 timestamp_ms += kFrameIntervalMs;
2651 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002652 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002653 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
2654 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2655 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2656 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2657
2658 // Trigger adapt down, expect scaled down resolution (640x360@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002659 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002660 timestamp_ms += kFrameIntervalMs;
2661 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002662 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002663 VerifyFpsMaxResolutionLt(source.sink_wants(), source.last_wants());
2664 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2665 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2666 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2667
2668 // Trigger adapt down, expect reduced fps (640x360@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07002669 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002670 timestamp_ms += kFrameIntervalMs;
2671 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002672 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002673 VerifyFpsLtResolutionEq(source.sink_wants(), source.last_wants());
2674 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2675 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2676 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2677
2678 // Trigger adapt down, expect scaled down resolution (480x270@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07002679 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002680 timestamp_ms += kFrameIntervalMs;
2681 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002682 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002683 VerifyFpsEqResolutionLt(source.sink_wants(), source.last_wants());
2684 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2685 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2686 EXPECT_EQ(4, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2687
2688 // Restrict bitrate, trigger adapt down, expect reduced fps (480x270@10fps).
mflodmancc3d4422017-08-03 08:27:51 -07002689 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002690 timestamp_ms += kFrameIntervalMs;
2691 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002692 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002693 VerifyFpsLtResolutionEq(source.sink_wants(), source.last_wants());
2694 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2695 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2696 EXPECT_EQ(5, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2697
2698 // Trigger adapt down, expect scaled down resolution (320x180@10fps).
mflodmancc3d4422017-08-03 08:27:51 -07002699 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002700 timestamp_ms += kFrameIntervalMs;
2701 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002702 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002703 VerifyFpsEqResolutionLt(source.sink_wants(), source.last_wants());
2704 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2705 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2706 EXPECT_EQ(6, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2707
2708 // Trigger adapt down, expect reduced fps (320x180@7fps).
mflodmancc3d4422017-08-03 08:27:51 -07002709 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002710 timestamp_ms += kFrameIntervalMs;
2711 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002712 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002713 VerifyFpsLtResolutionEq(source.sink_wants(), source.last_wants());
2714 rtc::VideoSinkWants last_wants = source.sink_wants();
2715 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2716 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2717 EXPECT_EQ(7, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2718
2719 // Trigger adapt down, min resolution reached, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07002720 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002721 timestamp_ms += kFrameIntervalMs;
2722 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002723 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002724 VerifyFpsEqResolutionEq(source.sink_wants(), last_wants);
2725 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2726 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2727 EXPECT_EQ(7, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2728
2729 // Trigger adapt down, expect expect increased fps (320x180@10fps).
mflodmancc3d4422017-08-03 08:27:51 -07002730 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002731 timestamp_ms += kFrameIntervalMs;
2732 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002733 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002734 VerifyFpsGtResolutionEq(source.sink_wants(), source.last_wants());
2735 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2736 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2737 EXPECT_EQ(8, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2738
2739 // Trigger adapt up, expect upscaled resolution (480x270@10fps).
mflodmancc3d4422017-08-03 08:27:51 -07002740 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002741 timestamp_ms += kFrameIntervalMs;
2742 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002743 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002744 VerifyFpsEqResolutionGt(source.sink_wants(), source.last_wants());
2745 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2746 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2747 EXPECT_EQ(9, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2748
2749 // Increase bitrate, trigger adapt up, expect increased fps (480x270@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07002750 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002751 timestamp_ms += kFrameIntervalMs;
2752 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002753 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002754 VerifyFpsGtResolutionEq(source.sink_wants(), source.last_wants());
2755 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2756 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2757 EXPECT_EQ(10, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2758
2759 // Trigger adapt up, expect upscaled resolution (640x360@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07002760 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002761 timestamp_ms += kFrameIntervalMs;
2762 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002763 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002764 VerifyFpsEqResolutionGt(source.sink_wants(), source.last_wants());
2765 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2766 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2767 EXPECT_EQ(11, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2768
2769 // Trigger adapt up, expect increased fps (640x360@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002770 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002771 timestamp_ms += kFrameIntervalMs;
2772 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002773 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002774 VerifyFpsMaxResolutionEq(source.sink_wants(), source.last_wants());
2775 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2776 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2777 EXPECT_EQ(12, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2778
2779 // Trigger adapt up, expect upscaled resolution (960x540@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002780 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002781 timestamp_ms += kFrameIntervalMs;
2782 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002783 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002784 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
2785 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2786 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2787 EXPECT_EQ(13, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2788
2789 // Trigger adapt up, expect no restriction (1280x720fps@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002790 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002791 timestamp_ms += kFrameIntervalMs;
2792 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002793 WaitForEncodedFrame(kWidth, kHeight);
asaperssonf7e294d2017-06-13 23:25:22 -07002794 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
2795 VerifyNoLimitation(source.sink_wants());
2796 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2797 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2798 EXPECT_EQ(14, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2799
2800 // Trigger adapt up, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07002801 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002802 VerifyNoLimitation(source.sink_wants());
2803 EXPECT_EQ(14, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2804
mflodmancc3d4422017-08-03 08:27:51 -07002805 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07002806}
2807
mflodmancc3d4422017-08-03 08:27:51 -07002808TEST_F(VideoStreamEncoderTest, AdaptWithTwoReasonsAndDifferentOrder_Framerate) {
asaperssonf7e294d2017-06-13 23:25:22 -07002809 const int kWidth = 1280;
2810 const int kHeight = 720;
2811 const int64_t kFrameIntervalMs = 150;
2812 int64_t timestamp_ms = kFrameIntervalMs;
mflodmancc3d4422017-08-03 08:27:51 -07002813 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -07002814
2815 // Enable kBalanced preference, no initial limitation.
2816 AdaptingFrameForwarder source;
2817 source.set_adaptation_enabled(true);
mflodmancc3d4422017-08-03 08:27:51 -07002818 video_stream_encoder_->SetSource(
2819 &source,
2820 VideoSendStream::DegradationPreference::kBalanced);
asaperssonf7e294d2017-06-13 23:25:22 -07002821 timestamp_ms += kFrameIntervalMs;
2822 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002823 WaitForEncodedFrame(kWidth, kHeight);
asaperssonf7e294d2017-06-13 23:25:22 -07002824 VerifyNoLimitation(source.sink_wants());
2825 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2826 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2827 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2828 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
2829 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2830 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2831
2832 // Trigger cpu adapt down, expect scaled down resolution (960x540@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002833 video_stream_encoder_->TriggerCpuOveruse();
asaperssonf7e294d2017-06-13 23:25:22 -07002834 timestamp_ms += kFrameIntervalMs;
2835 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002836 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002837 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
2838 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2839 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2840 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2841 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
2842 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2843 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2844
2845 // Trigger cpu adapt down, expect scaled down resolution (640x360@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002846 video_stream_encoder_->TriggerCpuOveruse();
asaperssonf7e294d2017-06-13 23:25:22 -07002847 timestamp_ms += kFrameIntervalMs;
2848 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002849 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002850 VerifyFpsMaxResolutionLt(source.sink_wants(), source.last_wants());
2851 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2852 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2853 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2854 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
2855 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2856 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2857
2858 // Trigger quality adapt down, expect reduced fps (640x360@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07002859 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002860 timestamp_ms += kFrameIntervalMs;
2861 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002862 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002863 VerifyFpsLtResolutionEq(source.sink_wants(), source.last_wants());
2864 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2865 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2866 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2867 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
2868 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2869 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2870
2871 // Trigger cpu adapt up, expect increased fps (640x360@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002872 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssonf7e294d2017-06-13 23:25:22 -07002873 timestamp_ms += kFrameIntervalMs;
2874 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002875 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002876 VerifyFpsMaxResolutionEq(source.sink_wants(), source.last_wants());
2877 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2878 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2879 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2880 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
2881 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2882 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2883
2884 // Trigger quality adapt up, expect upscaled resolution (960x540@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002885 video_stream_encoder_->TriggerQualityHigh();
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(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002889 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
2890 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2891 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2892 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2893 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
2894 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2895 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2896
2897 // Trigger cpu adapt up, expect no restriction (1280x720fps@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002898 video_stream_encoder_->TriggerCpuNormalUsage();
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(kWidth, kHeight);
asaperssonf7e294d2017-06-13 23:25:22 -07002902 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
2903 VerifyNoLimitation(source.sink_wants());
2904 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2905 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2906 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2907 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
2908 EXPECT_EQ(4, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2909 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2910
2911 // Trigger adapt up, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07002912 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002913 VerifyNoLimitation(source.sink_wants());
2914 EXPECT_EQ(4, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2915 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2916
mflodmancc3d4422017-08-03 08:27:51 -07002917 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07002918}
2919
mflodmancc3d4422017-08-03 08:27:51 -07002920TEST_F(VideoStreamEncoderTest,
2921 AdaptWithTwoReasonsAndDifferentOrder_Resolution) {
asaperssonf7e294d2017-06-13 23:25:22 -07002922 const int kWidth = 640;
2923 const int kHeight = 360;
2924 const int kFpsLimit = 15;
2925 const int64_t kFrameIntervalMs = 150;
2926 int64_t timestamp_ms = kFrameIntervalMs;
mflodmancc3d4422017-08-03 08:27:51 -07002927 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -07002928
2929 // Enable kBalanced preference, no initial limitation.
2930 AdaptingFrameForwarder source;
2931 source.set_adaptation_enabled(true);
mflodmancc3d4422017-08-03 08:27:51 -07002932 video_stream_encoder_->SetSource(
2933 &source,
2934 VideoSendStream::DegradationPreference::kBalanced);
asaperssonf7e294d2017-06-13 23:25:22 -07002935 timestamp_ms += kFrameIntervalMs;
2936 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002937 WaitForEncodedFrame(kWidth, kHeight);
asaperssonf7e294d2017-06-13 23:25:22 -07002938 VerifyNoLimitation(source.sink_wants());
2939 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2940 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2941 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2942 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
2943 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2944 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2945
2946 // Trigger cpu adapt down, expect scaled down framerate (640x360@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07002947 video_stream_encoder_->TriggerCpuOveruse();
asaperssonf7e294d2017-06-13 23:25:22 -07002948 timestamp_ms += kFrameIntervalMs;
2949 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002950 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002951 VerifyFpsEqResolutionMax(source.sink_wants(), kFpsLimit);
2952 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2953 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2954 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2955 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_framerate);
2956 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2957 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2958
2959 // Trigger quality adapt down, expect scaled down resolution (480x270@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07002960 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002961 timestamp_ms += kFrameIntervalMs;
2962 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002963 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002964 VerifyFpsEqResolutionLt(source.sink_wants(), source.last_wants());
2965 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2966 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2967 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2968 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_framerate);
2969 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2970 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2971
2972 // Trigger cpu adapt up, expect upscaled resolution (640x360@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07002973 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssonf7e294d2017-06-13 23:25:22 -07002974 timestamp_ms += kFrameIntervalMs;
2975 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002976 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002977 VerifyFpsEqResolutionGt(source.sink_wants(), source.last_wants());
2978 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2979 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2980 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2981 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
2982 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2983 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2984
2985 // Trigger quality adapt up, expect increased fps (640x360@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002986 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002987 timestamp_ms += kFrameIntervalMs;
2988 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002989 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002990 VerifyNoLimitation(source.sink_wants());
2991 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2992 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2993 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2994 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
2995 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2996 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2997
2998 // Trigger adapt up, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07002999 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07003000 VerifyNoLimitation(source.sink_wants());
3001 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
3002 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3003
mflodmancc3d4422017-08-03 08:27:51 -07003004 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07003005}
3006
mflodmancc3d4422017-08-03 08:27:51 -07003007TEST_F(VideoStreamEncoderTest, AcceptsFullHdAdaptedDownSimulcastFrames) {
ilnik6b826ef2017-06-16 06:53:48 -07003008 // Simulates simulcast behavior and makes highest stream resolutions divisible
3009 // by 4.
3010 class CroppingVideoStreamFactory
3011 : public VideoEncoderConfig::VideoStreamFactoryInterface {
3012 public:
3013 explicit CroppingVideoStreamFactory(size_t num_temporal_layers,
3014 int framerate)
3015 : num_temporal_layers_(num_temporal_layers), framerate_(framerate) {
3016 EXPECT_GT(num_temporal_layers, 0u);
3017 EXPECT_GT(framerate, 0);
3018 }
3019
3020 private:
3021 std::vector<VideoStream> CreateEncoderStreams(
3022 int width,
3023 int height,
3024 const VideoEncoderConfig& encoder_config) override {
3025 std::vector<VideoStream> streams =
3026 test::CreateVideoStreams(width - width % 4, height - height % 4,
3027 encoder_config);
3028 for (VideoStream& stream : streams) {
Sergey Silkina796a7e2018-03-01 15:11:29 +01003029 stream.num_temporal_layers = num_temporal_layers_;
ilnik6b826ef2017-06-16 06:53:48 -07003030 stream.max_framerate = framerate_;
3031 }
3032 return streams;
3033 }
3034
3035 const size_t num_temporal_layers_;
3036 const int framerate_;
3037 };
3038
3039 const int kFrameWidth = 1920;
3040 const int kFrameHeight = 1080;
3041 // 3/4 of 1920.
3042 const int kAdaptedFrameWidth = 1440;
3043 // 3/4 of 1080 rounded down to multiple of 4.
3044 const int kAdaptedFrameHeight = 808;
3045 const int kFramerate = 24;
3046
mflodmancc3d4422017-08-03 08:27:51 -07003047 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
ilnik6b826ef2017-06-16 06:53:48 -07003048 // Trigger reconfigure encoder (without resetting the entire instance).
3049 VideoEncoderConfig video_encoder_config;
Niels Möller259a4972018-04-05 15:36:51 +02003050 video_encoder_config.codec_type = kVideoCodecVP8;
ilnik6b826ef2017-06-16 06:53:48 -07003051 video_encoder_config.max_bitrate_bps = kTargetBitrateBps;
3052 video_encoder_config.number_of_streams = 1;
3053 video_encoder_config.video_stream_factory =
3054 new rtc::RefCountedObject<CroppingVideoStreamFactory>(1, kFramerate);
mflodmancc3d4422017-08-03 08:27:51 -07003055 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
3056 kMaxPayloadLength, false);
3057 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
ilnik6b826ef2017-06-16 06:53:48 -07003058
3059 video_source_.set_adaptation_enabled(true);
3060
3061 video_source_.IncomingCapturedFrame(
3062 CreateFrame(1, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07003063 WaitForEncodedFrame(kFrameWidth, kFrameHeight);
ilnik6b826ef2017-06-16 06:53:48 -07003064
3065 // Trigger CPU overuse, downscale by 3/4.
mflodmancc3d4422017-08-03 08:27:51 -07003066 video_stream_encoder_->TriggerCpuOveruse();
ilnik6b826ef2017-06-16 06:53:48 -07003067 video_source_.IncomingCapturedFrame(
3068 CreateFrame(2, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07003069 WaitForEncodedFrame(kAdaptedFrameWidth, kAdaptedFrameHeight);
ilnik6b826ef2017-06-16 06:53:48 -07003070
mflodmancc3d4422017-08-03 08:27:51 -07003071 video_stream_encoder_->Stop();
ilnik6b826ef2017-06-16 06:53:48 -07003072}
3073
mflodmancc3d4422017-08-03 08:27:51 -07003074TEST_F(VideoStreamEncoderTest, PeriodicallyUpdatesChannelParameters) {
sprang4847ae62017-06-27 07:06:52 -07003075 const int kFrameWidth = 1280;
3076 const int kFrameHeight = 720;
3077 const int kLowFps = 2;
3078 const int kHighFps = 30;
3079
mflodmancc3d4422017-08-03 08:27:51 -07003080 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
sprang4847ae62017-06-27 07:06:52 -07003081
3082 int64_t timestamp_ms = fake_clock_.TimeNanos() / rtc::kNumNanosecsPerMillisec;
3083 max_framerate_ = kLowFps;
3084
3085 // Insert 2 seconds of 2fps video.
3086 for (int i = 0; i < kLowFps * 2; ++i) {
3087 video_source_.IncomingCapturedFrame(
3088 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
3089 WaitForEncodedFrame(timestamp_ms);
3090 timestamp_ms += 1000 / kLowFps;
3091 }
3092
3093 // Make sure encoder is updated with new target.
mflodmancc3d4422017-08-03 08:27:51 -07003094 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
sprang4847ae62017-06-27 07:06:52 -07003095 video_source_.IncomingCapturedFrame(
3096 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
3097 WaitForEncodedFrame(timestamp_ms);
3098 timestamp_ms += 1000 / kLowFps;
3099
3100 EXPECT_EQ(kLowFps, fake_encoder_.GetConfiguredInputFramerate());
3101
3102 // Insert 30fps frames for just a little more than the forced update period.
3103 const int kVcmTimerIntervalFrames =
3104 (vcm::VCMProcessTimer::kDefaultProcessIntervalMs * kHighFps) / 1000;
3105 const int kFrameIntervalMs = 1000 / kHighFps;
3106 max_framerate_ = kHighFps;
3107 for (int i = 0; i < kVcmTimerIntervalFrames + 2; ++i) {
3108 video_source_.IncomingCapturedFrame(
3109 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
3110 // Wait for encoded frame, but skip ahead if it doesn't arrive as it might
3111 // be dropped if the encoder hans't been updated with the new higher target
3112 // framerate yet, causing it to overshoot the target bitrate and then
3113 // suffering the wrath of the media optimizer.
3114 TimedWaitForEncodedFrame(timestamp_ms, 2 * kFrameIntervalMs);
3115 timestamp_ms += kFrameIntervalMs;
3116 }
3117
3118 // Don expect correct measurement just yet, but it should be higher than
3119 // before.
3120 EXPECT_GT(fake_encoder_.GetConfiguredInputFramerate(), kLowFps);
3121
mflodmancc3d4422017-08-03 08:27:51 -07003122 video_stream_encoder_->Stop();
sprang4847ae62017-06-27 07:06:52 -07003123}
3124
mflodmancc3d4422017-08-03 08:27:51 -07003125TEST_F(VideoStreamEncoderTest, DoesNotUpdateBitrateAllocationWhenSuspended) {
sprang4847ae62017-06-27 07:06:52 -07003126 const int kFrameWidth = 1280;
3127 const int kFrameHeight = 720;
3128 const int kTargetBitrateBps = 1000000;
3129
3130 MockBitrateObserver bitrate_observer;
mflodmancc3d4422017-08-03 08:27:51 -07003131 video_stream_encoder_->SetBitrateObserver(&bitrate_observer);
sprang4847ae62017-06-27 07:06:52 -07003132
3133 EXPECT_CALL(bitrate_observer, OnBitrateAllocationUpdated(_)).Times(1);
3134 // Initial bitrate update.
mflodmancc3d4422017-08-03 08:27:51 -07003135 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
3136 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
sprang4847ae62017-06-27 07:06:52 -07003137
3138 // Insert a first video frame, causes another bitrate update.
3139 int64_t timestamp_ms = fake_clock_.TimeNanos() / rtc::kNumNanosecsPerMillisec;
3140 EXPECT_CALL(bitrate_observer, OnBitrateAllocationUpdated(_)).Times(1);
3141 video_source_.IncomingCapturedFrame(
3142 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
3143 WaitForEncodedFrame(timestamp_ms);
3144
3145 // Next, simulate video suspension due to pacer queue overrun.
mflodmancc3d4422017-08-03 08:27:51 -07003146 video_stream_encoder_->OnBitrateUpdated(0, 0, 1);
sprang4847ae62017-06-27 07:06:52 -07003147
3148 // Skip ahead until a new periodic parameter update should have occured.
3149 timestamp_ms += vcm::VCMProcessTimer::kDefaultProcessIntervalMs;
3150 fake_clock_.AdvanceTimeMicros(
3151 vcm::VCMProcessTimer::kDefaultProcessIntervalMs *
3152 rtc::kNumMicrosecsPerMillisec);
3153
3154 // Bitrate observer should not be called.
3155 EXPECT_CALL(bitrate_observer, OnBitrateAllocationUpdated(_)).Times(0);
3156 video_source_.IncomingCapturedFrame(
3157 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
3158 ExpectDroppedFrame();
3159
mflodmancc3d4422017-08-03 08:27:51 -07003160 video_stream_encoder_->Stop();
sprang4847ae62017-06-27 07:06:52 -07003161}
ilnik6b826ef2017-06-16 06:53:48 -07003162
Niels Möller4db138e2018-04-19 09:04:13 +02003163TEST_F(VideoStreamEncoderTest,
3164 DefaultCpuAdaptationThresholdsForSoftwareEncoder) {
3165 const int kFrameWidth = 1280;
3166 const int kFrameHeight = 720;
3167 const CpuOveruseOptions default_options;
3168 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
3169 video_source_.IncomingCapturedFrame(
3170 CreateFrame(1, kFrameWidth, kFrameHeight));
3171 WaitForEncodedFrame(1);
3172 EXPECT_EQ(video_stream_encoder_->overuse_detector_proxy_->GetOptions()
3173 .low_encode_usage_threshold_percent,
3174 default_options.low_encode_usage_threshold_percent);
3175 EXPECT_EQ(video_stream_encoder_->overuse_detector_proxy_->GetOptions()
3176 .high_encode_usage_threshold_percent,
3177 default_options.high_encode_usage_threshold_percent);
3178 video_stream_encoder_->Stop();
3179}
3180
3181TEST_F(VideoStreamEncoderTest,
3182 HigherCpuAdaptationThresholdsForHardwareEncoder) {
3183 const int kFrameWidth = 1280;
3184 const int kFrameHeight = 720;
3185 CpuOveruseOptions hardware_options;
3186 hardware_options.low_encode_usage_threshold_percent = 150;
3187 hardware_options.high_encode_usage_threshold_percent = 200;
3188 encoder_factory_.SetIsHardwareAccelerated(true);
3189
3190 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
3191 video_source_.IncomingCapturedFrame(
3192 CreateFrame(1, kFrameWidth, kFrameHeight));
3193 WaitForEncodedFrame(1);
3194 EXPECT_EQ(video_stream_encoder_->overuse_detector_proxy_->GetOptions()
3195 .low_encode_usage_threshold_percent,
3196 hardware_options.low_encode_usage_threshold_percent);
3197 EXPECT_EQ(video_stream_encoder_->overuse_detector_proxy_->GetOptions()
3198 .high_encode_usage_threshold_percent,
3199 hardware_options.high_encode_usage_threshold_percent);
3200 video_stream_encoder_->Stop();
3201}
3202
perkj26091b12016-09-01 01:17:40 -07003203} // namespace webrtc