blob: d83322deff6a0af97fcb7b599f80794467a8af23 [file] [log] [blame]
perkj26091b12016-09-01 01:17:40 -07001/*
2 * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved.
3 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
sprangfe627f32017-03-29 08:24:59 -070011#include <algorithm>
perkj803d97f2016-11-01 11:45:46 -070012#include <limits>
Per512ecb32016-09-23 15:52:06 +020013#include <utility>
14
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020015#include "api/video/i420_buffer.h"
16#include "media/base/videoadapter.h"
17#include "modules/video_coding/codecs/vp8/temporal_layers.h"
Sergey Silkin86684962018-03-28 19:32:37 +020018#include "modules/video_coding/codecs/vp9/include/vp9_globals.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020019#include "modules/video_coding/utility/default_video_bitrate_allocator.h"
20#include "rtc_base/fakeclock.h"
21#include "rtc_base/logging.h"
22#include "system_wrappers/include/metrics_default.h"
23#include "system_wrappers/include/sleep.h"
Niels Möller4db138e2018-04-19 09:04:13 +020024#include "test/encoder_proxy_factory.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020025#include "test/encoder_settings.h"
26#include "test/fake_encoder.h"
27#include "test/frame_generator.h"
28#include "test/gmock.h"
29#include "test/gtest.h"
30#include "video/send_statistics_proxy.h"
31#include "video/video_stream_encoder.h"
perkj26091b12016-09-01 01:17:40 -070032
kthelgason33ce8892016-12-09 03:53:59 -080033namespace {
kthelgason33ce8892016-12-09 03:53:59 -080034const int kMinPixelsPerFrame = 320 * 180;
sprangc5d62e22017-04-02 23:53:04 -070035const int kMinFramerateFps = 2;
Jonathan Yubc771b72017-12-08 17:04:29 -080036const int kMinBalancedFramerateFps = 7;
sprangc5d62e22017-04-02 23:53:04 -070037const int64_t kFrameTimeoutMs = 100;
38} // namespace
kthelgason33ce8892016-12-09 03:53:59 -080039
perkj26091b12016-09-01 01:17:40 -070040namespace webrtc {
41
sprangb1ca0732017-02-01 08:38:12 -080042using ScaleReason = AdaptationObserverInterface::AdaptReason;
sprang57c2fff2017-01-16 06:24:02 -080043using ::testing::_;
44using ::testing::Return;
kthelgason876222f2016-11-29 01:44:11 -080045
perkj803d97f2016-11-01 11:45:46 -070046namespace {
asapersson5f7226f2016-11-25 04:37:00 -080047const size_t kMaxPayloadLength = 1440;
kthelgason2bc68642017-02-07 07:02:22 -080048const int kTargetBitrateBps = 1000000;
49const int kLowTargetBitrateBps = kTargetBitrateBps / 10;
50const int kMaxInitialFramedrop = 4;
sprangfda496a2017-06-15 04:21:07 -070051const int kDefaultFramerate = 30;
asapersson5f7226f2016-11-25 04:37:00 -080052
perkj803d97f2016-11-01 11:45:46 -070053class TestBuffer : public webrtc::I420Buffer {
54 public:
55 TestBuffer(rtc::Event* event, int width, int height)
56 : I420Buffer(width, height), event_(event) {}
57
58 private:
59 friend class rtc::RefCountedObject<TestBuffer>;
60 ~TestBuffer() override {
61 if (event_)
62 event_->Set();
63 }
64 rtc::Event* const event_;
65};
66
Niels Möller7dc26b72017-12-06 10:27:48 +010067class CpuOveruseDetectorProxy : public OveruseFrameDetector {
68 public:
Niels Möllerd1f7eb62018-03-28 16:40:58 +020069 explicit CpuOveruseDetectorProxy(CpuOveruseMetricsObserver* metrics_observer)
70 : OveruseFrameDetector(metrics_observer),
Niels Möller7dc26b72017-12-06 10:27:48 +010071 last_target_framerate_fps_(-1) {}
72 virtual ~CpuOveruseDetectorProxy() {}
73
74 void OnTargetFramerateUpdated(int framerate_fps) override {
75 rtc::CritScope cs(&lock_);
76 last_target_framerate_fps_ = framerate_fps;
77 OveruseFrameDetector::OnTargetFramerateUpdated(framerate_fps);
78 }
79
80 int GetLastTargetFramerate() {
81 rtc::CritScope cs(&lock_);
82 return last_target_framerate_fps_;
83 }
84
Niels Möller4db138e2018-04-19 09:04:13 +020085 CpuOveruseOptions GetOptions() { return options_; }
86
Niels Möller7dc26b72017-12-06 10:27:48 +010087 private:
88 rtc::CriticalSection lock_;
89 int last_target_framerate_fps_ RTC_GUARDED_BY(lock_);
90};
91
mflodmancc3d4422017-08-03 08:27:51 -070092class VideoStreamEncoderUnderTest : public VideoStreamEncoder {
perkj803d97f2016-11-01 11:45:46 -070093 public:
Niels Möller7dc26b72017-12-06 10:27:48 +010094 VideoStreamEncoderUnderTest(SendStatisticsProxy* stats_proxy,
95 const VideoSendStream::Config::EncoderSettings& settings)
mflodmancc3d4422017-08-03 08:27:51 -070096 : VideoStreamEncoder(
97 1 /* number_of_cores */,
98 stats_proxy,
99 settings,
100 nullptr /* pre_encode_callback */,
mflodmancc3d4422017-08-03 08:27:51 -0700101 std::unique_ptr<OveruseFrameDetector>(
Niels Möller7dc26b72017-12-06 10:27:48 +0100102 overuse_detector_proxy_ = new CpuOveruseDetectorProxy(
mflodmancc3d4422017-08-03 08:27:51 -0700103 stats_proxy))) {}
perkj803d97f2016-11-01 11:45:46 -0700104
sprangb1ca0732017-02-01 08:38:12 -0800105 void PostTaskAndWait(bool down, AdaptReason reason) {
perkj803d97f2016-11-01 11:45:46 -0700106 rtc::Event event(false, false);
kthelgason876222f2016-11-29 01:44:11 -0800107 encoder_queue()->PostTask([this, &event, reason, down] {
sprangb1ca0732017-02-01 08:38:12 -0800108 down ? AdaptDown(reason) : AdaptUp(reason);
perkj803d97f2016-11-01 11:45:46 -0700109 event.Set();
110 });
perkj070ba852017-02-16 15:46:27 -0800111 ASSERT_TRUE(event.Wait(5000));
perkj803d97f2016-11-01 11:45:46 -0700112 }
113
kthelgason2fc52542017-03-03 00:24:41 -0800114 // This is used as a synchronisation mechanism, to make sure that the
115 // encoder queue is not blocked before we start sending it frames.
116 void WaitUntilTaskQueueIsIdle() {
117 rtc::Event event(false, false);
118 encoder_queue()->PostTask([&event] {
119 event.Set();
120 });
121 ASSERT_TRUE(event.Wait(5000));
122 }
123
sprangb1ca0732017-02-01 08:38:12 -0800124 void TriggerCpuOveruse() { PostTaskAndWait(true, AdaptReason::kCpu); }
kthelgason876222f2016-11-29 01:44:11 -0800125
sprangb1ca0732017-02-01 08:38:12 -0800126 void TriggerCpuNormalUsage() { PostTaskAndWait(false, AdaptReason::kCpu); }
kthelgason876222f2016-11-29 01:44:11 -0800127
sprangb1ca0732017-02-01 08:38:12 -0800128 void TriggerQualityLow() { PostTaskAndWait(true, AdaptReason::kQuality); }
kthelgason876222f2016-11-29 01:44:11 -0800129
sprangb1ca0732017-02-01 08:38:12 -0800130 void TriggerQualityHigh() { PostTaskAndWait(false, AdaptReason::kQuality); }
sprangfda496a2017-06-15 04:21:07 -0700131
Niels Möller7dc26b72017-12-06 10:27:48 +0100132 CpuOveruseDetectorProxy* overuse_detector_proxy_;
perkj803d97f2016-11-01 11:45:46 -0700133};
134
asapersson5f7226f2016-11-25 04:37:00 -0800135class VideoStreamFactory
136 : public VideoEncoderConfig::VideoStreamFactoryInterface {
137 public:
sprangfda496a2017-06-15 04:21:07 -0700138 explicit VideoStreamFactory(size_t num_temporal_layers, int framerate)
139 : num_temporal_layers_(num_temporal_layers), framerate_(framerate) {
asapersson5f7226f2016-11-25 04:37:00 -0800140 EXPECT_GT(num_temporal_layers, 0u);
sprangfda496a2017-06-15 04:21:07 -0700141 EXPECT_GT(framerate, 0);
asapersson5f7226f2016-11-25 04:37:00 -0800142 }
143
144 private:
145 std::vector<VideoStream> CreateEncoderStreams(
146 int width,
147 int height,
148 const VideoEncoderConfig& encoder_config) override {
149 std::vector<VideoStream> streams =
150 test::CreateVideoStreams(width, height, encoder_config);
151 for (VideoStream& stream : streams) {
Sergey Silkina796a7e2018-03-01 15:11:29 +0100152 stream.num_temporal_layers = num_temporal_layers_;
sprangfda496a2017-06-15 04:21:07 -0700153 stream.max_framerate = framerate_;
asapersson5f7226f2016-11-25 04:37:00 -0800154 }
155 return streams;
156 }
sprangfda496a2017-06-15 04:21:07 -0700157
asapersson5f7226f2016-11-25 04:37:00 -0800158 const size_t num_temporal_layers_;
sprangfda496a2017-06-15 04:21:07 -0700159 const int framerate_;
asapersson5f7226f2016-11-25 04:37:00 -0800160};
161
ilnik6b826ef2017-06-16 06:53:48 -0700162
sprangb1ca0732017-02-01 08:38:12 -0800163class AdaptingFrameForwarder : public test::FrameForwarder {
164 public:
165 AdaptingFrameForwarder() : adaptation_enabled_(false) {}
asaperssonfab67072017-04-04 05:51:49 -0700166 ~AdaptingFrameForwarder() override {}
sprangb1ca0732017-02-01 08:38:12 -0800167
168 void set_adaptation_enabled(bool enabled) {
169 rtc::CritScope cs(&crit_);
170 adaptation_enabled_ = enabled;
171 }
172
asaperssonfab67072017-04-04 05:51:49 -0700173 bool adaption_enabled() const {
sprangb1ca0732017-02-01 08:38:12 -0800174 rtc::CritScope cs(&crit_);
175 return adaptation_enabled_;
176 }
177
asapersson09f05612017-05-15 23:40:18 -0700178 rtc::VideoSinkWants last_wants() const {
179 rtc::CritScope cs(&crit_);
180 return last_wants_;
181 }
182
Danil Chapovalovb9b146c2018-06-15 12:28:07 +0200183 absl::optional<int> last_sent_width() const { return last_width_; }
184 absl::optional<int> last_sent_height() const { return last_height_; }
Jonathan Yubc771b72017-12-08 17:04:29 -0800185
sprangb1ca0732017-02-01 08:38:12 -0800186 void IncomingCapturedFrame(const VideoFrame& video_frame) override {
187 int cropped_width = 0;
188 int cropped_height = 0;
189 int out_width = 0;
190 int out_height = 0;
sprangc5d62e22017-04-02 23:53:04 -0700191 if (adaption_enabled()) {
192 if (adapter_.AdaptFrameResolution(
193 video_frame.width(), video_frame.height(),
194 video_frame.timestamp_us() * 1000, &cropped_width,
195 &cropped_height, &out_width, &out_height)) {
196 VideoFrame adapted_frame(new rtc::RefCountedObject<TestBuffer>(
197 nullptr, out_width, out_height),
198 99, 99, kVideoRotation_0);
199 adapted_frame.set_ntp_time_ms(video_frame.ntp_time_ms());
200 test::FrameForwarder::IncomingCapturedFrame(adapted_frame);
Jonathan Yubc771b72017-12-08 17:04:29 -0800201 last_width_.emplace(adapted_frame.width());
202 last_height_.emplace(adapted_frame.height());
203 } else {
Danil Chapovalovb9b146c2018-06-15 12:28:07 +0200204 last_width_ = absl::nullopt;
205 last_height_ = absl::nullopt;
sprangc5d62e22017-04-02 23:53:04 -0700206 }
sprangb1ca0732017-02-01 08:38:12 -0800207 } else {
208 test::FrameForwarder::IncomingCapturedFrame(video_frame);
Jonathan Yubc771b72017-12-08 17:04:29 -0800209 last_width_.emplace(video_frame.width());
210 last_height_.emplace(video_frame.height());
sprangb1ca0732017-02-01 08:38:12 -0800211 }
212 }
213
214 void AddOrUpdateSink(rtc::VideoSinkInterface<VideoFrame>* sink,
215 const rtc::VideoSinkWants& wants) override {
216 rtc::CritScope cs(&crit_);
asapersson09f05612017-05-15 23:40:18 -0700217 last_wants_ = sink_wants();
sprangc5d62e22017-04-02 23:53:04 -0700218 adapter_.OnResolutionFramerateRequest(wants.target_pixel_count,
219 wants.max_pixel_count,
220 wants.max_framerate_fps);
sprangb1ca0732017-02-01 08:38:12 -0800221 test::FrameForwarder::AddOrUpdateSink(sink, wants);
222 }
sprangb1ca0732017-02-01 08:38:12 -0800223 cricket::VideoAdapter adapter_;
danilchapa37de392017-09-09 04:17:22 -0700224 bool adaptation_enabled_ RTC_GUARDED_BY(crit_);
225 rtc::VideoSinkWants last_wants_ RTC_GUARDED_BY(crit_);
Danil Chapovalovb9b146c2018-06-15 12:28:07 +0200226 absl::optional<int> last_width_;
227 absl::optional<int> last_height_;
sprangb1ca0732017-02-01 08:38:12 -0800228};
sprangc5d62e22017-04-02 23:53:04 -0700229
230class MockableSendStatisticsProxy : public SendStatisticsProxy {
231 public:
232 MockableSendStatisticsProxy(Clock* clock,
233 const VideoSendStream::Config& config,
234 VideoEncoderConfig::ContentType content_type)
235 : SendStatisticsProxy(clock, config, content_type) {}
236
237 VideoSendStream::Stats GetStats() override {
238 rtc::CritScope cs(&lock_);
239 if (mock_stats_)
240 return *mock_stats_;
241 return SendStatisticsProxy::GetStats();
242 }
243
244 void SetMockStats(const VideoSendStream::Stats& stats) {
245 rtc::CritScope cs(&lock_);
246 mock_stats_.emplace(stats);
247 }
248
249 void ResetMockStats() {
250 rtc::CritScope cs(&lock_);
251 mock_stats_.reset();
252 }
253
254 private:
255 rtc::CriticalSection lock_;
Danil Chapovalovb9b146c2018-06-15 12:28:07 +0200256 absl::optional<VideoSendStream::Stats> mock_stats_ RTC_GUARDED_BY(lock_);
sprangc5d62e22017-04-02 23:53:04 -0700257};
258
sprang4847ae62017-06-27 07:06:52 -0700259class MockBitrateObserver : public VideoBitrateAllocationObserver {
260 public:
Erik Språng566124a2018-04-23 12:32:22 +0200261 MOCK_METHOD1(OnBitrateAllocationUpdated, void(const VideoBitrateAllocation&));
sprang4847ae62017-06-27 07:06:52 -0700262};
263
perkj803d97f2016-11-01 11:45:46 -0700264} // namespace
265
mflodmancc3d4422017-08-03 08:27:51 -0700266class VideoStreamEncoderTest : public ::testing::Test {
perkj26091b12016-09-01 01:17:40 -0700267 public:
268 static const int kDefaultTimeoutMs = 30 * 1000;
269
mflodmancc3d4422017-08-03 08:27:51 -0700270 VideoStreamEncoderTest()
perkj26091b12016-09-01 01:17:40 -0700271 : video_send_config_(VideoSendStream::Config(nullptr)),
perkjfa10b552016-10-02 23:45:26 -0700272 codec_width_(320),
273 codec_height_(240),
sprang4847ae62017-06-27 07:06:52 -0700274 max_framerate_(30),
perkj26091b12016-09-01 01:17:40 -0700275 fake_encoder_(),
Niels Möller4db138e2018-04-19 09:04:13 +0200276 encoder_factory_(&fake_encoder_),
sprangc5d62e22017-04-02 23:53:04 -0700277 stats_proxy_(new MockableSendStatisticsProxy(
perkj803d97f2016-11-01 11:45:46 -0700278 Clock::GetRealTimeClock(),
279 video_send_config_,
280 webrtc::VideoEncoderConfig::ContentType::kRealtimeVideo)),
perkj26091b12016-09-01 01:17:40 -0700281 sink_(&fake_encoder_) {}
282
283 void SetUp() override {
perkj803d97f2016-11-01 11:45:46 -0700284 metrics::Reset();
perkj26091b12016-09-01 01:17:40 -0700285 video_send_config_ = VideoSendStream::Config(nullptr);
Niels Möller4db138e2018-04-19 09:04:13 +0200286 video_send_config_.encoder_settings.encoder_factory = &encoder_factory_;
Niels Möller259a4972018-04-05 15:36:51 +0200287 video_send_config_.rtp.payload_name = "FAKE";
288 video_send_config_.rtp.payload_type = 125;
perkj26091b12016-09-01 01:17:40 -0700289
Per512ecb32016-09-23 15:52:06 +0200290 VideoEncoderConfig video_encoder_config;
Niels Möller259a4972018-04-05 15:36:51 +0200291 test::FillEncoderConfiguration(kVideoCodecVP8, 1, &video_encoder_config);
sprang4847ae62017-06-27 07:06:52 -0700292 video_encoder_config.video_stream_factory =
293 new rtc::RefCountedObject<VideoStreamFactory>(1, max_framerate_);
Erik Språng08127a92016-11-16 16:41:30 +0100294 video_encoder_config_ = video_encoder_config.Copy();
sprang4847ae62017-06-27 07:06:52 -0700295
296 // Framerate limit is specified by the VideoStreamFactory.
297 std::vector<VideoStream> streams =
298 video_encoder_config.video_stream_factory->CreateEncoderStreams(
299 codec_width_, codec_height_, video_encoder_config);
300 max_framerate_ = streams[0].max_framerate;
301 fake_clock_.SetTimeMicros(1234);
302
Niels Möllerf1338562018-04-26 09:51:47 +0200303 ConfigureEncoder(std::move(video_encoder_config));
asapersson5f7226f2016-11-25 04:37:00 -0800304 }
305
Niels Möllerf1338562018-04-26 09:51:47 +0200306 void ConfigureEncoder(VideoEncoderConfig video_encoder_config) {
mflodmancc3d4422017-08-03 08:27:51 -0700307 if (video_stream_encoder_)
308 video_stream_encoder_->Stop();
309 video_stream_encoder_.reset(new VideoStreamEncoderUnderTest(
perkj803d97f2016-11-01 11:45:46 -0700310 stats_proxy_.get(), video_send_config_.encoder_settings));
mflodmancc3d4422017-08-03 08:27:51 -0700311 video_stream_encoder_->SetSink(&sink_, false /* rotation_applied */);
312 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -0700313 &video_source_, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
mflodmancc3d4422017-08-03 08:27:51 -0700314 video_stream_encoder_->SetStartBitrate(kTargetBitrateBps);
315 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
Niels Möllerf1338562018-04-26 09:51:47 +0200316 kMaxPayloadLength);
mflodmancc3d4422017-08-03 08:27:51 -0700317 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
asapersson5f7226f2016-11-25 04:37:00 -0800318 }
319
320 void ResetEncoder(const std::string& payload_name,
321 size_t num_streams,
322 size_t num_temporal_layers,
emircanbbcc3562017-08-18 00:28:40 -0700323 unsigned char num_spatial_layers,
sprang4847ae62017-06-27 07:06:52 -0700324 bool screenshare) {
Niels Möller259a4972018-04-05 15:36:51 +0200325 video_send_config_.rtp.payload_name = payload_name;
asapersson5f7226f2016-11-25 04:37:00 -0800326
327 VideoEncoderConfig video_encoder_config;
Niels Möller259a4972018-04-05 15:36:51 +0200328 video_encoder_config.codec_type = PayloadStringToCodecType(payload_name);
asapersson5f7226f2016-11-25 04:37:00 -0800329 video_encoder_config.number_of_streams = num_streams;
kthelgason2bc68642017-02-07 07:02:22 -0800330 video_encoder_config.max_bitrate_bps = kTargetBitrateBps;
asapersson5f7226f2016-11-25 04:37:00 -0800331 video_encoder_config.video_stream_factory =
sprangfda496a2017-06-15 04:21:07 -0700332 new rtc::RefCountedObject<VideoStreamFactory>(num_temporal_layers,
333 kDefaultFramerate);
sprang4847ae62017-06-27 07:06:52 -0700334 video_encoder_config.content_type =
335 screenshare ? VideoEncoderConfig::ContentType::kScreen
336 : VideoEncoderConfig::ContentType::kRealtimeVideo;
emircanbbcc3562017-08-18 00:28:40 -0700337 if (payload_name == "VP9") {
338 VideoCodecVP9 vp9_settings = VideoEncoder::GetDefaultVp9Settings();
339 vp9_settings.numberOfSpatialLayers = num_spatial_layers;
340 video_encoder_config.encoder_specific_settings =
341 new rtc::RefCountedObject<
342 VideoEncoderConfig::Vp9EncoderSpecificSettings>(vp9_settings);
343 }
Niels Möllerf1338562018-04-26 09:51:47 +0200344 ConfigureEncoder(std::move(video_encoder_config));
perkj26091b12016-09-01 01:17:40 -0700345 }
346
sprang57c2fff2017-01-16 06:24:02 -0800347 VideoFrame CreateFrame(int64_t ntp_time_ms,
348 rtc::Event* destruction_event) const {
Per512ecb32016-09-23 15:52:06 +0200349 VideoFrame frame(new rtc::RefCountedObject<TestBuffer>(
350 destruction_event, codec_width_, codec_height_),
351 99, 99, kVideoRotation_0);
sprang57c2fff2017-01-16 06:24:02 -0800352 frame.set_ntp_time_ms(ntp_time_ms);
perkj26091b12016-09-01 01:17:40 -0700353 return frame;
354 }
355
sprang57c2fff2017-01-16 06:24:02 -0800356 VideoFrame CreateFrame(int64_t ntp_time_ms, int width, int height) const {
perkj803d97f2016-11-01 11:45:46 -0700357 VideoFrame frame(
358 new rtc::RefCountedObject<TestBuffer>(nullptr, width, height), 99, 99,
359 kVideoRotation_0);
sprang57c2fff2017-01-16 06:24:02 -0800360 frame.set_ntp_time_ms(ntp_time_ms);
sprangc5d62e22017-04-02 23:53:04 -0700361 frame.set_timestamp_us(ntp_time_ms * 1000);
perkj803d97f2016-11-01 11:45:46 -0700362 return frame;
363 }
364
asapersson02465b82017-04-10 01:12:52 -0700365 void VerifyNoLimitation(const rtc::VideoSinkWants& wants) {
asapersson02465b82017-04-10 01:12:52 -0700366 EXPECT_EQ(std::numeric_limits<int>::max(), wants.max_framerate_fps);
asapersson09f05612017-05-15 23:40:18 -0700367 EXPECT_EQ(std::numeric_limits<int>::max(), wants.max_pixel_count);
368 EXPECT_FALSE(wants.target_pixel_count);
asapersson02465b82017-04-10 01:12:52 -0700369 }
370
asapersson09f05612017-05-15 23:40:18 -0700371 void VerifyFpsEqResolutionEq(const rtc::VideoSinkWants& wants1,
372 const rtc::VideoSinkWants& wants2) {
373 EXPECT_EQ(wants1.max_framerate_fps, wants2.max_framerate_fps);
374 EXPECT_EQ(wants1.max_pixel_count, wants2.max_pixel_count);
375 }
376
377 void VerifyFpsMaxResolutionLt(const rtc::VideoSinkWants& wants1,
378 const rtc::VideoSinkWants& wants2) {
379 EXPECT_EQ(std::numeric_limits<int>::max(), wants1.max_framerate_fps);
380 EXPECT_LT(wants1.max_pixel_count, wants2.max_pixel_count);
381 EXPECT_GT(wants1.max_pixel_count, 0);
382 }
383
384 void VerifyFpsMaxResolutionGt(const rtc::VideoSinkWants& wants1,
385 const rtc::VideoSinkWants& wants2) {
386 EXPECT_EQ(std::numeric_limits<int>::max(), wants1.max_framerate_fps);
387 EXPECT_GT(wants1.max_pixel_count, wants2.max_pixel_count);
388 }
389
asaperssonf7e294d2017-06-13 23:25:22 -0700390 void VerifyFpsMaxResolutionEq(const rtc::VideoSinkWants& wants1,
391 const rtc::VideoSinkWants& wants2) {
392 EXPECT_EQ(std::numeric_limits<int>::max(), wants1.max_framerate_fps);
393 EXPECT_EQ(wants1.max_pixel_count, wants2.max_pixel_count);
394 }
395
396 void VerifyFpsLtResolutionEq(const rtc::VideoSinkWants& wants1,
397 const rtc::VideoSinkWants& wants2) {
398 EXPECT_LT(wants1.max_framerate_fps, wants2.max_framerate_fps);
399 EXPECT_EQ(wants1.max_pixel_count, wants2.max_pixel_count);
400 }
401
402 void VerifyFpsGtResolutionEq(const rtc::VideoSinkWants& wants1,
403 const rtc::VideoSinkWants& wants2) {
404 EXPECT_GT(wants1.max_framerate_fps, wants2.max_framerate_fps);
405 EXPECT_EQ(wants1.max_pixel_count, wants2.max_pixel_count);
406 }
407
408 void VerifyFpsEqResolutionLt(const rtc::VideoSinkWants& wants1,
409 const rtc::VideoSinkWants& wants2) {
410 EXPECT_EQ(wants1.max_framerate_fps, wants2.max_framerate_fps);
411 EXPECT_LT(wants1.max_pixel_count, wants2.max_pixel_count);
412 EXPECT_GT(wants1.max_pixel_count, 0);
413 }
414
415 void VerifyFpsEqResolutionGt(const rtc::VideoSinkWants& wants1,
416 const rtc::VideoSinkWants& wants2) {
417 EXPECT_EQ(wants1.max_framerate_fps, wants2.max_framerate_fps);
418 EXPECT_GT(wants1.max_pixel_count, wants2.max_pixel_count);
419 }
420
asapersson09f05612017-05-15 23:40:18 -0700421 void VerifyFpsMaxResolutionLt(const rtc::VideoSinkWants& wants,
422 int pixel_count) {
423 EXPECT_EQ(std::numeric_limits<int>::max(), wants.max_framerate_fps);
asapersson02465b82017-04-10 01:12:52 -0700424 EXPECT_LT(wants.max_pixel_count, pixel_count);
425 EXPECT_GT(wants.max_pixel_count, 0);
asapersson09f05612017-05-15 23:40:18 -0700426 }
427
428 void VerifyFpsLtResolutionMax(const rtc::VideoSinkWants& wants, int fps) {
429 EXPECT_LT(wants.max_framerate_fps, fps);
430 EXPECT_EQ(std::numeric_limits<int>::max(), wants.max_pixel_count);
431 EXPECT_FALSE(wants.target_pixel_count);
asapersson02465b82017-04-10 01:12:52 -0700432 }
433
asaperssonf7e294d2017-06-13 23:25:22 -0700434 void VerifyFpsEqResolutionMax(const rtc::VideoSinkWants& wants,
435 int expected_fps) {
436 EXPECT_EQ(expected_fps, wants.max_framerate_fps);
437 EXPECT_EQ(std::numeric_limits<int>::max(), wants.max_pixel_count);
438 EXPECT_FALSE(wants.target_pixel_count);
439 }
440
Jonathan Yubc771b72017-12-08 17:04:29 -0800441 void VerifyBalancedModeFpsRange(const rtc::VideoSinkWants& wants,
442 int last_frame_pixels) {
443 // Balanced mode should always scale FPS to the desired range before
444 // attempting to scale resolution.
445 int fps_limit = wants.max_framerate_fps;
446 if (last_frame_pixels <= 320 * 240) {
447 EXPECT_TRUE(7 <= fps_limit && fps_limit <= 10);
448 } else if (last_frame_pixels <= 480 * 270) {
449 EXPECT_TRUE(10 <= fps_limit && fps_limit <= 15);
450 } else if (last_frame_pixels <= 640 * 480) {
451 EXPECT_LE(15, fps_limit);
452 } else {
453 EXPECT_EQ(std::numeric_limits<int>::max(), fps_limit);
454 }
455 }
456
sprang4847ae62017-06-27 07:06:52 -0700457 void WaitForEncodedFrame(int64_t expected_ntp_time) {
458 sink_.WaitForEncodedFrame(expected_ntp_time);
459 fake_clock_.AdvanceTimeMicros(rtc::kNumMicrosecsPerSec / max_framerate_);
460 }
461
462 bool TimedWaitForEncodedFrame(int64_t expected_ntp_time, int64_t timeout_ms) {
463 bool ok = sink_.TimedWaitForEncodedFrame(expected_ntp_time, timeout_ms);
464 fake_clock_.AdvanceTimeMicros(rtc::kNumMicrosecsPerSec / max_framerate_);
465 return ok;
466 }
467
468 void WaitForEncodedFrame(uint32_t expected_width, uint32_t expected_height) {
469 sink_.WaitForEncodedFrame(expected_width, expected_height);
470 fake_clock_.AdvanceTimeMicros(rtc::kNumMicrosecsPerSec / max_framerate_);
471 }
472
473 void ExpectDroppedFrame() {
474 sink_.ExpectDroppedFrame();
475 fake_clock_.AdvanceTimeMicros(rtc::kNumMicrosecsPerSec / max_framerate_);
476 }
477
478 bool WaitForFrame(int64_t timeout_ms) {
479 bool ok = sink_.WaitForFrame(timeout_ms);
480 fake_clock_.AdvanceTimeMicros(rtc::kNumMicrosecsPerSec / max_framerate_);
481 return ok;
482 }
483
perkj26091b12016-09-01 01:17:40 -0700484 class TestEncoder : public test::FakeEncoder {
485 public:
486 TestEncoder()
487 : FakeEncoder(Clock::GetRealTimeClock()),
488 continue_encode_event_(false, false) {}
489
asaperssonfab67072017-04-04 05:51:49 -0700490 VideoCodec codec_config() const {
brandtre78d2662017-01-16 05:57:16 -0800491 rtc::CritScope lock(&crit_sect_);
perkjfa10b552016-10-02 23:45:26 -0700492 return config_;
493 }
494
495 void BlockNextEncode() {
brandtre78d2662017-01-16 05:57:16 -0800496 rtc::CritScope lock(&local_crit_sect_);
perkjfa10b552016-10-02 23:45:26 -0700497 block_next_encode_ = true;
498 }
499
kthelgason876222f2016-11-29 01:44:11 -0800500 VideoEncoder::ScalingSettings GetScalingSettings() const override {
kthelgason2fc52542017-03-03 00:24:41 -0800501 rtc::CritScope lock(&local_crit_sect_);
kthelgasonad9010c2017-02-14 00:46:51 -0800502 if (quality_scaling_)
Niels Möller225c7872018-02-22 15:03:53 +0100503 return VideoEncoder::ScalingSettings(1, 2, kMinPixelsPerFrame);
504 return VideoEncoder::ScalingSettings::kOff;
kthelgason876222f2016-11-29 01:44:11 -0800505 }
506
perkjfa10b552016-10-02 23:45:26 -0700507 void ContinueEncode() { continue_encode_event_.Set(); }
508
509 void CheckLastTimeStampsMatch(int64_t ntp_time_ms,
510 uint32_t timestamp) const {
brandtre78d2662017-01-16 05:57:16 -0800511 rtc::CritScope lock(&local_crit_sect_);
perkjfa10b552016-10-02 23:45:26 -0700512 EXPECT_EQ(timestamp_, timestamp);
513 EXPECT_EQ(ntp_time_ms_, ntp_time_ms);
514 }
515
kthelgason2fc52542017-03-03 00:24:41 -0800516 void SetQualityScaling(bool b) {
517 rtc::CritScope lock(&local_crit_sect_);
518 quality_scaling_ = b;
519 }
kthelgasonad9010c2017-02-14 00:46:51 -0800520
sprangfe627f32017-03-29 08:24:59 -0700521 void ForceInitEncodeFailure(bool force_failure) {
522 rtc::CritScope lock(&local_crit_sect_);
523 force_init_encode_failed_ = force_failure;
524 }
525
perkjfa10b552016-10-02 23:45:26 -0700526 private:
perkj26091b12016-09-01 01:17:40 -0700527 int32_t Encode(const VideoFrame& input_image,
528 const CodecSpecificInfo* codec_specific_info,
529 const std::vector<FrameType>* frame_types) override {
530 bool block_encode;
531 {
brandtre78d2662017-01-16 05:57:16 -0800532 rtc::CritScope lock(&local_crit_sect_);
perkj26091b12016-09-01 01:17:40 -0700533 EXPECT_GT(input_image.timestamp(), timestamp_);
534 EXPECT_GT(input_image.ntp_time_ms(), ntp_time_ms_);
535 EXPECT_EQ(input_image.timestamp(), input_image.ntp_time_ms() * 90);
536
537 timestamp_ = input_image.timestamp();
538 ntp_time_ms_ = input_image.ntp_time_ms();
perkj803d97f2016-11-01 11:45:46 -0700539 last_input_width_ = input_image.width();
540 last_input_height_ = input_image.height();
perkj26091b12016-09-01 01:17:40 -0700541 block_encode = block_next_encode_;
542 block_next_encode_ = false;
543 }
544 int32_t result =
545 FakeEncoder::Encode(input_image, codec_specific_info, frame_types);
546 if (block_encode)
perkja49cbd32016-09-16 07:53:41 -0700547 EXPECT_TRUE(continue_encode_event_.Wait(kDefaultTimeoutMs));
perkj26091b12016-09-01 01:17:40 -0700548 return result;
549 }
550
sprangfe627f32017-03-29 08:24:59 -0700551 int32_t InitEncode(const VideoCodec* config,
552 int32_t number_of_cores,
553 size_t max_payload_size) override {
554 int res =
555 FakeEncoder::InitEncode(config, number_of_cores, max_payload_size);
556 rtc::CritScope lock(&local_crit_sect_);
Erik Språng82fad3d2018-03-21 09:57:23 +0100557 if (config->codecType == kVideoCodecVP8) {
sprangfe627f32017-03-29 08:24:59 -0700558 // Simulate setting up temporal layers, in order to validate the life
559 // cycle of these objects.
560 int num_streams = std::max<int>(1, config->numberOfSimulcastStreams);
sprangfe627f32017-03-29 08:24:59 -0700561 for (int i = 0; i < num_streams; ++i) {
562 allocated_temporal_layers_.emplace_back(
Niels Möller150dcb02018-03-27 14:16:55 +0200563 TemporalLayers::CreateTemporalLayers(*config, i));
sprangfe627f32017-03-29 08:24:59 -0700564 }
565 }
566 if (force_init_encode_failed_)
567 return -1;
568 return res;
569 }
570
brandtre78d2662017-01-16 05:57:16 -0800571 rtc::CriticalSection local_crit_sect_;
danilchapa37de392017-09-09 04:17:22 -0700572 bool block_next_encode_ RTC_GUARDED_BY(local_crit_sect_) = false;
perkj26091b12016-09-01 01:17:40 -0700573 rtc::Event continue_encode_event_;
danilchapa37de392017-09-09 04:17:22 -0700574 uint32_t timestamp_ RTC_GUARDED_BY(local_crit_sect_) = 0;
575 int64_t ntp_time_ms_ RTC_GUARDED_BY(local_crit_sect_) = 0;
576 int last_input_width_ RTC_GUARDED_BY(local_crit_sect_) = 0;
577 int last_input_height_ RTC_GUARDED_BY(local_crit_sect_) = 0;
578 bool quality_scaling_ RTC_GUARDED_BY(local_crit_sect_) = true;
sprangfe627f32017-03-29 08:24:59 -0700579 std::vector<std::unique_ptr<TemporalLayers>> allocated_temporal_layers_
danilchapa37de392017-09-09 04:17:22 -0700580 RTC_GUARDED_BY(local_crit_sect_);
581 bool force_init_encode_failed_ RTC_GUARDED_BY(local_crit_sect_) = false;
perkj26091b12016-09-01 01:17:40 -0700582 };
583
mflodmancc3d4422017-08-03 08:27:51 -0700584 class TestSink : public VideoStreamEncoder::EncoderSink {
perkj26091b12016-09-01 01:17:40 -0700585 public:
586 explicit TestSink(TestEncoder* test_encoder)
587 : test_encoder_(test_encoder), encoded_frame_event_(false, false) {}
588
perkj26091b12016-09-01 01:17:40 -0700589 void WaitForEncodedFrame(int64_t expected_ntp_time) {
sprang4847ae62017-06-27 07:06:52 -0700590 EXPECT_TRUE(
591 TimedWaitForEncodedFrame(expected_ntp_time, kDefaultTimeoutMs));
592 }
593
594 bool TimedWaitForEncodedFrame(int64_t expected_ntp_time,
595 int64_t timeout_ms) {
perkj26091b12016-09-01 01:17:40 -0700596 uint32_t timestamp = 0;
sprang4847ae62017-06-27 07:06:52 -0700597 if (!encoded_frame_event_.Wait(timeout_ms))
598 return false;
perkj26091b12016-09-01 01:17:40 -0700599 {
600 rtc::CritScope lock(&crit_);
sprangb1ca0732017-02-01 08:38:12 -0800601 timestamp = last_timestamp_;
perkj26091b12016-09-01 01:17:40 -0700602 }
603 test_encoder_->CheckLastTimeStampsMatch(expected_ntp_time, timestamp);
sprang4847ae62017-06-27 07:06:52 -0700604 return true;
perkj26091b12016-09-01 01:17:40 -0700605 }
606
sprangb1ca0732017-02-01 08:38:12 -0800607 void WaitForEncodedFrame(uint32_t expected_width,
608 uint32_t expected_height) {
sprangc5d62e22017-04-02 23:53:04 -0700609 EXPECT_TRUE(encoded_frame_event_.Wait(kDefaultTimeoutMs));
Åsa Perssonc74d8da2017-12-04 14:13:56 +0100610 CheckLastFrameSizeMatches(expected_width, expected_height);
sprangc5d62e22017-04-02 23:53:04 -0700611 }
612
Åsa Perssonc74d8da2017-12-04 14:13:56 +0100613 void CheckLastFrameSizeMatches(uint32_t expected_width,
sprangc5d62e22017-04-02 23:53:04 -0700614 uint32_t expected_height) {
sprangb1ca0732017-02-01 08:38:12 -0800615 uint32_t width = 0;
616 uint32_t height = 0;
sprangb1ca0732017-02-01 08:38:12 -0800617 {
618 rtc::CritScope lock(&crit_);
619 width = last_width_;
620 height = last_height_;
621 }
622 EXPECT_EQ(expected_height, height);
623 EXPECT_EQ(expected_width, width);
624 }
625
kthelgason2fc52542017-03-03 00:24:41 -0800626 void ExpectDroppedFrame() { EXPECT_FALSE(encoded_frame_event_.Wait(100)); }
kthelgason2bc68642017-02-07 07:02:22 -0800627
sprangc5d62e22017-04-02 23:53:04 -0700628 bool WaitForFrame(int64_t timeout_ms) {
629 return encoded_frame_event_.Wait(timeout_ms);
630 }
631
perkj26091b12016-09-01 01:17:40 -0700632 void SetExpectNoFrames() {
633 rtc::CritScope lock(&crit_);
634 expect_frames_ = false;
635 }
636
asaperssonfab67072017-04-04 05:51:49 -0700637 int number_of_reconfigurations() const {
Per512ecb32016-09-23 15:52:06 +0200638 rtc::CritScope lock(&crit_);
639 return number_of_reconfigurations_;
640 }
641
asaperssonfab67072017-04-04 05:51:49 -0700642 int last_min_transmit_bitrate() const {
Per512ecb32016-09-23 15:52:06 +0200643 rtc::CritScope lock(&crit_);
644 return min_transmit_bitrate_bps_;
645 }
646
perkj26091b12016-09-01 01:17:40 -0700647 private:
sergeyu2cb155a2016-11-04 11:39:29 -0700648 Result OnEncodedImage(
649 const EncodedImage& encoded_image,
650 const CodecSpecificInfo* codec_specific_info,
651 const RTPFragmentationHeader* fragmentation) override {
Per512ecb32016-09-23 15:52:06 +0200652 rtc::CritScope lock(&crit_);
653 EXPECT_TRUE(expect_frames_);
sprangb1ca0732017-02-01 08:38:12 -0800654 last_timestamp_ = encoded_image._timeStamp;
655 last_width_ = encoded_image._encodedWidth;
656 last_height_ = encoded_image._encodedHeight;
Per512ecb32016-09-23 15:52:06 +0200657 encoded_frame_event_.Set();
sprangb1ca0732017-02-01 08:38:12 -0800658 return Result(Result::OK, last_timestamp_);
Per512ecb32016-09-23 15:52:06 +0200659 }
660
661 void OnEncoderConfigurationChanged(std::vector<VideoStream> streams,
662 int min_transmit_bitrate_bps) override {
663 rtc::CriticalSection crit_;
664 ++number_of_reconfigurations_;
665 min_transmit_bitrate_bps_ = min_transmit_bitrate_bps;
666 }
667
perkj26091b12016-09-01 01:17:40 -0700668 rtc::CriticalSection crit_;
669 TestEncoder* test_encoder_;
670 rtc::Event encoded_frame_event_;
sprangb1ca0732017-02-01 08:38:12 -0800671 uint32_t last_timestamp_ = 0;
672 uint32_t last_height_ = 0;
673 uint32_t last_width_ = 0;
perkj26091b12016-09-01 01:17:40 -0700674 bool expect_frames_ = true;
Per512ecb32016-09-23 15:52:06 +0200675 int number_of_reconfigurations_ = 0;
676 int min_transmit_bitrate_bps_ = 0;
perkj26091b12016-09-01 01:17:40 -0700677 };
678
679 VideoSendStream::Config video_send_config_;
Erik Språng08127a92016-11-16 16:41:30 +0100680 VideoEncoderConfig video_encoder_config_;
Per512ecb32016-09-23 15:52:06 +0200681 int codec_width_;
682 int codec_height_;
sprang4847ae62017-06-27 07:06:52 -0700683 int max_framerate_;
perkj26091b12016-09-01 01:17:40 -0700684 TestEncoder fake_encoder_;
Niels Möller4db138e2018-04-19 09:04:13 +0200685 test::EncoderProxyFactory encoder_factory_;
sprangc5d62e22017-04-02 23:53:04 -0700686 std::unique_ptr<MockableSendStatisticsProxy> stats_proxy_;
perkj26091b12016-09-01 01:17:40 -0700687 TestSink sink_;
sprangb1ca0732017-02-01 08:38:12 -0800688 AdaptingFrameForwarder video_source_;
mflodmancc3d4422017-08-03 08:27:51 -0700689 std::unique_ptr<VideoStreamEncoderUnderTest> video_stream_encoder_;
sprang4847ae62017-06-27 07:06:52 -0700690 rtc::ScopedFakeClock fake_clock_;
perkj26091b12016-09-01 01:17:40 -0700691};
692
mflodmancc3d4422017-08-03 08:27:51 -0700693TEST_F(VideoStreamEncoderTest, EncodeOneFrame) {
694 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkj26091b12016-09-01 01:17:40 -0700695 rtc::Event frame_destroyed_event(false, false);
perkja49cbd32016-09-16 07:53:41 -0700696 video_source_.IncomingCapturedFrame(CreateFrame(1, &frame_destroyed_event));
sprang4847ae62017-06-27 07:06:52 -0700697 WaitForEncodedFrame(1);
perkja49cbd32016-09-16 07:53:41 -0700698 EXPECT_TRUE(frame_destroyed_event.Wait(kDefaultTimeoutMs));
mflodmancc3d4422017-08-03 08:27:51 -0700699 video_stream_encoder_->Stop();
perkj26091b12016-09-01 01:17:40 -0700700}
701
mflodmancc3d4422017-08-03 08:27:51 -0700702TEST_F(VideoStreamEncoderTest, DropsFramesBeforeFirstOnBitrateUpdated) {
perkj26091b12016-09-01 01:17:40 -0700703 // Dropped since no target bitrate has been set.
704 rtc::Event frame_destroyed_event(false, false);
Sebastian Janssona3177052018-04-10 13:05:49 +0200705 // The encoder will cache up to one frame for a short duration. Adding two
706 // frames means that the first frame will be dropped and the second frame will
707 // be sent when the encoder is enabled.
perkja49cbd32016-09-16 07:53:41 -0700708 video_source_.IncomingCapturedFrame(CreateFrame(1, &frame_destroyed_event));
Sebastian Janssona3177052018-04-10 13:05:49 +0200709 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
perkja49cbd32016-09-16 07:53:41 -0700710 EXPECT_TRUE(frame_destroyed_event.Wait(kDefaultTimeoutMs));
perkj26091b12016-09-01 01:17:40 -0700711
mflodmancc3d4422017-08-03 08:27:51 -0700712 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkj26091b12016-09-01 01:17:40 -0700713
Sebastian Janssona3177052018-04-10 13:05:49 +0200714 // The pending frame should be received.
sprang4847ae62017-06-27 07:06:52 -0700715 WaitForEncodedFrame(2);
Sebastian Janssona3177052018-04-10 13:05:49 +0200716 video_source_.IncomingCapturedFrame(CreateFrame(3, nullptr));
717
718 WaitForEncodedFrame(3);
mflodmancc3d4422017-08-03 08:27:51 -0700719 video_stream_encoder_->Stop();
perkj26091b12016-09-01 01:17:40 -0700720}
721
mflodmancc3d4422017-08-03 08:27:51 -0700722TEST_F(VideoStreamEncoderTest, DropsFramesWhenRateSetToZero) {
723 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkja49cbd32016-09-16 07:53:41 -0700724 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700725 WaitForEncodedFrame(1);
perkj26091b12016-09-01 01:17:40 -0700726
mflodmancc3d4422017-08-03 08:27:51 -0700727 video_stream_encoder_->OnBitrateUpdated(0, 0, 0);
Sebastian Janssona3177052018-04-10 13:05:49 +0200728 // The encoder will cache up to one frame for a short duration. Adding two
729 // frames means that the first frame will be dropped and the second frame will
730 // be sent when the encoder is resumed.
perkja49cbd32016-09-16 07:53:41 -0700731 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
Sebastian Janssona3177052018-04-10 13:05:49 +0200732 video_source_.IncomingCapturedFrame(CreateFrame(3, nullptr));
perkj26091b12016-09-01 01:17:40 -0700733
mflodmancc3d4422017-08-03 08:27:51 -0700734 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
sprang4847ae62017-06-27 07:06:52 -0700735 WaitForEncodedFrame(3);
Sebastian Janssona3177052018-04-10 13:05:49 +0200736 video_source_.IncomingCapturedFrame(CreateFrame(4, nullptr));
737 WaitForEncodedFrame(4);
mflodmancc3d4422017-08-03 08:27:51 -0700738 video_stream_encoder_->Stop();
perkj26091b12016-09-01 01:17:40 -0700739}
740
mflodmancc3d4422017-08-03 08:27:51 -0700741TEST_F(VideoStreamEncoderTest, DropsFramesWithSameOrOldNtpTimestamp) {
742 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkja49cbd32016-09-16 07:53:41 -0700743 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700744 WaitForEncodedFrame(1);
perkj26091b12016-09-01 01:17:40 -0700745
746 // This frame will be dropped since it has the same ntp timestamp.
perkja49cbd32016-09-16 07:53:41 -0700747 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
perkj26091b12016-09-01 01:17:40 -0700748
perkja49cbd32016-09-16 07:53:41 -0700749 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700750 WaitForEncodedFrame(2);
mflodmancc3d4422017-08-03 08:27:51 -0700751 video_stream_encoder_->Stop();
perkj26091b12016-09-01 01:17:40 -0700752}
753
mflodmancc3d4422017-08-03 08:27:51 -0700754TEST_F(VideoStreamEncoderTest, DropsFrameAfterStop) {
755 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkj26091b12016-09-01 01:17:40 -0700756
perkja49cbd32016-09-16 07:53:41 -0700757 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700758 WaitForEncodedFrame(1);
perkj26091b12016-09-01 01:17:40 -0700759
mflodmancc3d4422017-08-03 08:27:51 -0700760 video_stream_encoder_->Stop();
perkj26091b12016-09-01 01:17:40 -0700761 sink_.SetExpectNoFrames();
762 rtc::Event frame_destroyed_event(false, false);
perkja49cbd32016-09-16 07:53:41 -0700763 video_source_.IncomingCapturedFrame(CreateFrame(2, &frame_destroyed_event));
764 EXPECT_TRUE(frame_destroyed_event.Wait(kDefaultTimeoutMs));
perkj26091b12016-09-01 01:17:40 -0700765}
766
mflodmancc3d4422017-08-03 08:27:51 -0700767TEST_F(VideoStreamEncoderTest, DropsPendingFramesOnSlowEncode) {
768 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkj26091b12016-09-01 01:17:40 -0700769
770 fake_encoder_.BlockNextEncode();
perkja49cbd32016-09-16 07:53:41 -0700771 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700772 WaitForEncodedFrame(1);
perkj26091b12016-09-01 01:17:40 -0700773 // Here, the encoder thread will be blocked in the TestEncoder waiting for a
774 // call to ContinueEncode.
perkja49cbd32016-09-16 07:53:41 -0700775 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
776 video_source_.IncomingCapturedFrame(CreateFrame(3, nullptr));
perkj26091b12016-09-01 01:17:40 -0700777 fake_encoder_.ContinueEncode();
sprang4847ae62017-06-27 07:06:52 -0700778 WaitForEncodedFrame(3);
perkj26091b12016-09-01 01:17:40 -0700779
mflodmancc3d4422017-08-03 08:27:51 -0700780 video_stream_encoder_->Stop();
perkj26091b12016-09-01 01:17:40 -0700781}
782
mflodmancc3d4422017-08-03 08:27:51 -0700783TEST_F(VideoStreamEncoderTest,
784 ConfigureEncoderTriggersOnEncoderConfigurationChanged) {
785 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
Per21d45d22016-10-30 21:37:57 +0100786 EXPECT_EQ(0, sink_.number_of_reconfigurations());
Per512ecb32016-09-23 15:52:06 +0200787
788 // Capture a frame and wait for it to synchronize with the encoder thread.
Perf8c5f2b2016-09-23 16:24:55 +0200789 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700790 WaitForEncodedFrame(1);
Per21d45d22016-10-30 21:37:57 +0100791 // The encoder will have been configured once when the first frame is
792 // received.
793 EXPECT_EQ(1, sink_.number_of_reconfigurations());
Per512ecb32016-09-23 15:52:06 +0200794
795 VideoEncoderConfig video_encoder_config;
Niels Möller259a4972018-04-05 15:36:51 +0200796 test::FillEncoderConfiguration(kVideoCodecVP8, 1, &video_encoder_config);
Per512ecb32016-09-23 15:52:06 +0200797 video_encoder_config.min_transmit_bitrate_bps = 9999;
mflodmancc3d4422017-08-03 08:27:51 -0700798 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
Niels Möllerf1338562018-04-26 09:51:47 +0200799 kMaxPayloadLength);
Per512ecb32016-09-23 15:52:06 +0200800
801 // Capture a frame and wait for it to synchronize with the encoder thread.
Perf8c5f2b2016-09-23 16:24:55 +0200802 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700803 WaitForEncodedFrame(2);
Per21d45d22016-10-30 21:37:57 +0100804 EXPECT_EQ(2, sink_.number_of_reconfigurations());
perkj3b703ed2016-09-29 23:25:40 -0700805 EXPECT_EQ(9999, sink_.last_min_transmit_bitrate());
perkj26105b42016-09-29 22:39:10 -0700806
mflodmancc3d4422017-08-03 08:27:51 -0700807 video_stream_encoder_->Stop();
perkj26105b42016-09-29 22:39:10 -0700808}
809
mflodmancc3d4422017-08-03 08:27:51 -0700810TEST_F(VideoStreamEncoderTest, FrameResolutionChangeReconfigureEncoder) {
811 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkjfa10b552016-10-02 23:45:26 -0700812
813 // Capture a frame and wait for it to synchronize with the encoder thread.
814 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700815 WaitForEncodedFrame(1);
Per21d45d22016-10-30 21:37:57 +0100816 // The encoder will have been configured once.
817 EXPECT_EQ(1, sink_.number_of_reconfigurations());
perkjfa10b552016-10-02 23:45:26 -0700818 EXPECT_EQ(codec_width_, fake_encoder_.codec_config().width);
819 EXPECT_EQ(codec_height_, fake_encoder_.codec_config().height);
820
821 codec_width_ *= 2;
822 codec_height_ *= 2;
823 // Capture a frame with a higher resolution and wait for it to synchronize
824 // with the encoder thread.
825 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700826 WaitForEncodedFrame(2);
perkjfa10b552016-10-02 23:45:26 -0700827 EXPECT_EQ(codec_width_, fake_encoder_.codec_config().width);
828 EXPECT_EQ(codec_height_, fake_encoder_.codec_config().height);
Per21d45d22016-10-30 21:37:57 +0100829 EXPECT_EQ(2, sink_.number_of_reconfigurations());
perkjfa10b552016-10-02 23:45:26 -0700830
mflodmancc3d4422017-08-03 08:27:51 -0700831 video_stream_encoder_->Stop();
perkjfa10b552016-10-02 23:45:26 -0700832}
833
mflodmancc3d4422017-08-03 08:27:51 -0700834TEST_F(VideoStreamEncoderTest, SwitchSourceDeregisterEncoderAsSink) {
perkj803d97f2016-11-01 11:45:46 -0700835 EXPECT_TRUE(video_source_.has_sinks());
836 test::FrameForwarder new_video_source;
mflodmancc3d4422017-08-03 08:27:51 -0700837 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -0700838 &new_video_source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
perkj803d97f2016-11-01 11:45:46 -0700839 EXPECT_FALSE(video_source_.has_sinks());
840 EXPECT_TRUE(new_video_source.has_sinks());
841
mflodmancc3d4422017-08-03 08:27:51 -0700842 video_stream_encoder_->Stop();
perkj803d97f2016-11-01 11:45:46 -0700843}
844
mflodmancc3d4422017-08-03 08:27:51 -0700845TEST_F(VideoStreamEncoderTest, SinkWantsRotationApplied) {
perkj803d97f2016-11-01 11:45:46 -0700846 EXPECT_FALSE(video_source_.sink_wants().rotation_applied);
mflodmancc3d4422017-08-03 08:27:51 -0700847 video_stream_encoder_->SetSink(&sink_, true /*rotation_applied*/);
perkj803d97f2016-11-01 11:45:46 -0700848 EXPECT_TRUE(video_source_.sink_wants().rotation_applied);
mflodmancc3d4422017-08-03 08:27:51 -0700849 video_stream_encoder_->Stop();
perkj803d97f2016-11-01 11:45:46 -0700850}
851
Jonathan Yubc771b72017-12-08 17:04:29 -0800852TEST_F(VideoStreamEncoderTest, TestCpuDowngrades_BalancedMode) {
853 const int kFramerateFps = 30;
asaperssonf7e294d2017-06-13 23:25:22 -0700854 const int kWidth = 1280;
855 const int kHeight = 720;
Jonathan Yubc771b72017-12-08 17:04:29 -0800856
857 // We rely on the automatic resolution adaptation, but we handle framerate
858 // adaptation manually by mocking the stats proxy.
859 video_source_.set_adaptation_enabled(true);
asaperssonf7e294d2017-06-13 23:25:22 -0700860
Taylor Brandstetter49fcc102018-05-16 14:20:41 -0700861 // Enable BALANCED preference, no initial limitation.
Jonathan Yubc771b72017-12-08 17:04:29 -0800862 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
Taylor Brandstetter49fcc102018-05-16 14:20:41 -0700863 video_stream_encoder_->SetSource(&video_source_,
864 webrtc::DegradationPreference::BALANCED);
Jonathan Yubc771b72017-12-08 17:04:29 -0800865 VerifyNoLimitation(video_source_.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -0700866 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
Jonathan Yubc771b72017-12-08 17:04:29 -0800867 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
asaperssonf7e294d2017-06-13 23:25:22 -0700868 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
869
Jonathan Yubc771b72017-12-08 17:04:29 -0800870 // Adapt down as far as possible.
871 rtc::VideoSinkWants last_wants;
872 int64_t t = 1;
873 int loop_count = 0;
874 do {
875 ++loop_count;
876 last_wants = video_source_.sink_wants();
877
878 // Simulate the framerate we've been asked to adapt to.
879 const int fps = std::min(kFramerateFps, last_wants.max_framerate_fps);
880 const int frame_interval_ms = rtc::kNumMillisecsPerSec / fps;
881 VideoSendStream::Stats mock_stats = stats_proxy_->GetStats();
882 mock_stats.input_frame_rate = fps;
883 stats_proxy_->SetMockStats(mock_stats);
884
885 video_source_.IncomingCapturedFrame(CreateFrame(t, kWidth, kHeight));
886 sink_.WaitForEncodedFrame(t);
887 t += frame_interval_ms;
888
mflodmancc3d4422017-08-03 08:27:51 -0700889 video_stream_encoder_->TriggerCpuOveruse();
Jonathan Yubc771b72017-12-08 17:04:29 -0800890 VerifyBalancedModeFpsRange(
891 video_source_.sink_wants(),
892 *video_source_.last_sent_width() * *video_source_.last_sent_height());
893 } while (video_source_.sink_wants().max_pixel_count <
894 last_wants.max_pixel_count ||
895 video_source_.sink_wants().max_framerate_fps <
896 last_wants.max_framerate_fps);
asaperssonf7e294d2017-06-13 23:25:22 -0700897
Jonathan Yubc771b72017-12-08 17:04:29 -0800898 // Verify that we've adapted all the way down.
899 stats_proxy_->ResetMockStats();
asaperssonf7e294d2017-06-13 23:25:22 -0700900 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
Jonathan Yubc771b72017-12-08 17:04:29 -0800901 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_framerate);
902 EXPECT_EQ(loop_count - 1,
asaperssonf7e294d2017-06-13 23:25:22 -0700903 stats_proxy_->GetStats().number_of_cpu_adapt_changes);
Jonathan Yubc771b72017-12-08 17:04:29 -0800904 EXPECT_EQ(kMinPixelsPerFrame, *video_source_.last_sent_width() *
905 *video_source_.last_sent_height());
906 EXPECT_EQ(kMinBalancedFramerateFps,
907 video_source_.sink_wants().max_framerate_fps);
asaperssonf7e294d2017-06-13 23:25:22 -0700908
Jonathan Yubc771b72017-12-08 17:04:29 -0800909 // Adapt back up the same number of times we adapted down.
910 for (int i = 0; i < loop_count - 1; ++i) {
911 last_wants = video_source_.sink_wants();
912
913 // Simulate the framerate we've been asked to adapt to.
914 const int fps = std::min(kFramerateFps, last_wants.max_framerate_fps);
915 const int frame_interval_ms = rtc::kNumMillisecsPerSec / fps;
916 VideoSendStream::Stats mock_stats = stats_proxy_->GetStats();
917 mock_stats.input_frame_rate = fps;
918 stats_proxy_->SetMockStats(mock_stats);
919
920 video_source_.IncomingCapturedFrame(CreateFrame(t, kWidth, kHeight));
921 sink_.WaitForEncodedFrame(t);
922 t += frame_interval_ms;
923
mflodmancc3d4422017-08-03 08:27:51 -0700924 video_stream_encoder_->TriggerCpuNormalUsage();
Jonathan Yubc771b72017-12-08 17:04:29 -0800925 VerifyBalancedModeFpsRange(
926 video_source_.sink_wants(),
927 *video_source_.last_sent_width() * *video_source_.last_sent_height());
928 EXPECT_TRUE(video_source_.sink_wants().max_pixel_count >
929 last_wants.max_pixel_count ||
930 video_source_.sink_wants().max_framerate_fps >
931 last_wants.max_framerate_fps);
asaperssonf7e294d2017-06-13 23:25:22 -0700932 }
933
Jonathan Yubc771b72017-12-08 17:04:29 -0800934 VerifyNoLimitation(video_source_.sink_wants());
935 stats_proxy_->ResetMockStats();
asaperssonf7e294d2017-06-13 23:25:22 -0700936 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
Jonathan Yubc771b72017-12-08 17:04:29 -0800937 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
938 EXPECT_EQ((loop_count - 1) * 2,
939 stats_proxy_->GetStats().number_of_cpu_adapt_changes);
asaperssonf7e294d2017-06-13 23:25:22 -0700940
mflodmancc3d4422017-08-03 08:27:51 -0700941 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -0700942}
mflodmancc3d4422017-08-03 08:27:51 -0700943TEST_F(VideoStreamEncoderTest, SinkWantsStoredByDegradationPreference) {
944 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson02465b82017-04-10 01:12:52 -0700945 VerifyNoLimitation(video_source_.sink_wants());
perkj803d97f2016-11-01 11:45:46 -0700946
sprangc5d62e22017-04-02 23:53:04 -0700947 const int kFrameWidth = 1280;
948 const int kFrameHeight = 720;
949 const int kFrameIntervalMs = 1000 / 30;
950
951 int frame_timestamp = 1;
perkj803d97f2016-11-01 11:45:46 -0700952
kthelgason5e13d412016-12-01 03:59:51 -0800953 video_source_.IncomingCapturedFrame(
sprangc5d62e22017-04-02 23:53:04 -0700954 CreateFrame(frame_timestamp, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -0700955 WaitForEncodedFrame(frame_timestamp);
sprangc5d62e22017-04-02 23:53:04 -0700956 frame_timestamp += kFrameIntervalMs;
957
perkj803d97f2016-11-01 11:45:46 -0700958 // Trigger CPU overuse.
mflodmancc3d4422017-08-03 08:27:51 -0700959 video_stream_encoder_->TriggerCpuOveruse();
perkj803d97f2016-11-01 11:45:46 -0700960 video_source_.IncomingCapturedFrame(
sprangc5d62e22017-04-02 23:53:04 -0700961 CreateFrame(frame_timestamp, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -0700962 WaitForEncodedFrame(frame_timestamp);
sprangc5d62e22017-04-02 23:53:04 -0700963 frame_timestamp += kFrameIntervalMs;
sprang3ea3c772017-03-30 07:23:48 -0700964
asapersson0944a802017-04-07 00:57:58 -0700965 // Default degradation preference is maintain-framerate, so will lower max
sprangc5d62e22017-04-02 23:53:04 -0700966 // wanted resolution.
967 EXPECT_FALSE(video_source_.sink_wants().target_pixel_count);
968 EXPECT_LT(video_source_.sink_wants().max_pixel_count,
969 kFrameWidth * kFrameHeight);
970 EXPECT_EQ(std::numeric_limits<int>::max(),
971 video_source_.sink_wants().max_framerate_fps);
972
973 // Set new source, switch to maintain-resolution.
perkj803d97f2016-11-01 11:45:46 -0700974 test::FrameForwarder new_video_source;
mflodmancc3d4422017-08-03 08:27:51 -0700975 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -0700976 &new_video_source, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
perkj803d97f2016-11-01 11:45:46 -0700977
sprangc5d62e22017-04-02 23:53:04 -0700978 // Initially no degradation registered.
asapersson02465b82017-04-10 01:12:52 -0700979 VerifyNoLimitation(new_video_source.sink_wants());
perkj803d97f2016-11-01 11:45:46 -0700980
sprangc5d62e22017-04-02 23:53:04 -0700981 // Force an input frame rate to be available, or the adaptation call won't
982 // know what framerate to adapt form.
asapersson02465b82017-04-10 01:12:52 -0700983 const int kInputFps = 30;
sprangc5d62e22017-04-02 23:53:04 -0700984 VideoSendStream::Stats stats = stats_proxy_->GetStats();
asapersson02465b82017-04-10 01:12:52 -0700985 stats.input_frame_rate = kInputFps;
sprangc5d62e22017-04-02 23:53:04 -0700986 stats_proxy_->SetMockStats(stats);
987
mflodmancc3d4422017-08-03 08:27:51 -0700988 video_stream_encoder_->TriggerCpuOveruse();
perkj803d97f2016-11-01 11:45:46 -0700989 new_video_source.IncomingCapturedFrame(
sprangc5d62e22017-04-02 23:53:04 -0700990 CreateFrame(frame_timestamp, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -0700991 WaitForEncodedFrame(frame_timestamp);
sprangc5d62e22017-04-02 23:53:04 -0700992 frame_timestamp += kFrameIntervalMs;
993
994 // Some framerate constraint should be set.
sprang84a37592017-02-10 07:04:27 -0800995 EXPECT_FALSE(new_video_source.sink_wants().target_pixel_count);
sprangc5d62e22017-04-02 23:53:04 -0700996 EXPECT_EQ(std::numeric_limits<int>::max(),
997 new_video_source.sink_wants().max_pixel_count);
asapersson02465b82017-04-10 01:12:52 -0700998 EXPECT_LT(new_video_source.sink_wants().max_framerate_fps, kInputFps);
sprangc5d62e22017-04-02 23:53:04 -0700999
asapersson02465b82017-04-10 01:12:52 -07001000 // Turn off degradation completely.
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001001 video_stream_encoder_->SetSource(&new_video_source,
1002 webrtc::DegradationPreference::DISABLED);
asapersson02465b82017-04-10 01:12:52 -07001003 VerifyNoLimitation(new_video_source.sink_wants());
sprangc5d62e22017-04-02 23:53:04 -07001004
mflodmancc3d4422017-08-03 08:27:51 -07001005 video_stream_encoder_->TriggerCpuOveruse();
sprangc5d62e22017-04-02 23:53:04 -07001006 new_video_source.IncomingCapturedFrame(
1007 CreateFrame(frame_timestamp, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07001008 WaitForEncodedFrame(frame_timestamp);
sprangc5d62e22017-04-02 23:53:04 -07001009 frame_timestamp += kFrameIntervalMs;
1010
1011 // Still no degradation.
asapersson02465b82017-04-10 01:12:52 -07001012 VerifyNoLimitation(new_video_source.sink_wants());
perkj803d97f2016-11-01 11:45:46 -07001013
1014 // Calling SetSource with resolution scaling enabled apply the old SinkWants.
mflodmancc3d4422017-08-03 08:27:51 -07001015 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001016 &new_video_source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
sprangc5d62e22017-04-02 23:53:04 -07001017 EXPECT_LT(new_video_source.sink_wants().max_pixel_count,
1018 kFrameWidth * kFrameHeight);
sprang84a37592017-02-10 07:04:27 -08001019 EXPECT_FALSE(new_video_source.sink_wants().target_pixel_count);
sprangc5d62e22017-04-02 23:53:04 -07001020 EXPECT_EQ(std::numeric_limits<int>::max(),
1021 new_video_source.sink_wants().max_framerate_fps);
1022
1023 // Calling SetSource with framerate scaling enabled apply the old SinkWants.
mflodmancc3d4422017-08-03 08:27:51 -07001024 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001025 &new_video_source, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
sprangc5d62e22017-04-02 23:53:04 -07001026 EXPECT_FALSE(new_video_source.sink_wants().target_pixel_count);
1027 EXPECT_EQ(std::numeric_limits<int>::max(),
1028 new_video_source.sink_wants().max_pixel_count);
asapersson02465b82017-04-10 01:12:52 -07001029 EXPECT_LT(new_video_source.sink_wants().max_framerate_fps, kInputFps);
perkj803d97f2016-11-01 11:45:46 -07001030
mflodmancc3d4422017-08-03 08:27:51 -07001031 video_stream_encoder_->Stop();
perkj803d97f2016-11-01 11:45:46 -07001032}
1033
mflodmancc3d4422017-08-03 08:27:51 -07001034TEST_F(VideoStreamEncoderTest, StatsTracksQualityAdaptationStats) {
1035 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkj803d97f2016-11-01 11:45:46 -07001036
asaperssonfab67072017-04-04 05:51:49 -07001037 const int kWidth = 1280;
1038 const int kHeight = 720;
asaperssonfab67072017-04-04 05:51:49 -07001039 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001040 WaitForEncodedFrame(1);
asaperssonfab67072017-04-04 05:51:49 -07001041 VideoSendStream::Stats stats = stats_proxy_->GetStats();
1042 EXPECT_FALSE(stats.bw_limited_resolution);
1043 EXPECT_EQ(0, stats.number_of_quality_adapt_changes);
1044
1045 // Trigger adapt down.
mflodmancc3d4422017-08-03 08:27:51 -07001046 video_stream_encoder_->TriggerQualityLow();
asaperssonfab67072017-04-04 05:51:49 -07001047 video_source_.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001048 WaitForEncodedFrame(2);
asaperssonfab67072017-04-04 05:51:49 -07001049
1050 stats = stats_proxy_->GetStats();
1051 EXPECT_TRUE(stats.bw_limited_resolution);
1052 EXPECT_EQ(1, stats.number_of_quality_adapt_changes);
1053
1054 // Trigger adapt up.
mflodmancc3d4422017-08-03 08:27:51 -07001055 video_stream_encoder_->TriggerQualityHigh();
asaperssonfab67072017-04-04 05:51:49 -07001056 video_source_.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001057 WaitForEncodedFrame(3);
asaperssonfab67072017-04-04 05:51:49 -07001058
1059 stats = stats_proxy_->GetStats();
1060 EXPECT_FALSE(stats.bw_limited_resolution);
1061 EXPECT_EQ(2, stats.number_of_quality_adapt_changes);
1062 EXPECT_EQ(0, stats.number_of_cpu_adapt_changes);
1063
mflodmancc3d4422017-08-03 08:27:51 -07001064 video_stream_encoder_->Stop();
asaperssonfab67072017-04-04 05:51:49 -07001065}
1066
mflodmancc3d4422017-08-03 08:27:51 -07001067TEST_F(VideoStreamEncoderTest, StatsTracksCpuAdaptationStats) {
1068 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonfab67072017-04-04 05:51:49 -07001069
1070 const int kWidth = 1280;
1071 const int kHeight = 720;
asaperssonfab67072017-04-04 05:51:49 -07001072 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001073 WaitForEncodedFrame(1);
perkj803d97f2016-11-01 11:45:46 -07001074 VideoSendStream::Stats stats = stats_proxy_->GetStats();
1075 EXPECT_FALSE(stats.cpu_limited_resolution);
1076 EXPECT_EQ(0, stats.number_of_cpu_adapt_changes);
1077
1078 // Trigger CPU overuse.
mflodmancc3d4422017-08-03 08:27:51 -07001079 video_stream_encoder_->TriggerCpuOveruse();
asaperssonfab67072017-04-04 05:51:49 -07001080 video_source_.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001081 WaitForEncodedFrame(2);
perkj803d97f2016-11-01 11:45:46 -07001082
1083 stats = stats_proxy_->GetStats();
1084 EXPECT_TRUE(stats.cpu_limited_resolution);
1085 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1086
1087 // Trigger CPU normal use.
mflodmancc3d4422017-08-03 08:27:51 -07001088 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssonfab67072017-04-04 05:51:49 -07001089 video_source_.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001090 WaitForEncodedFrame(3);
perkj803d97f2016-11-01 11:45:46 -07001091
1092 stats = stats_proxy_->GetStats();
1093 EXPECT_FALSE(stats.cpu_limited_resolution);
1094 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
asaperssonfab67072017-04-04 05:51:49 -07001095 EXPECT_EQ(0, stats.number_of_quality_adapt_changes);
perkj803d97f2016-11-01 11:45:46 -07001096
mflodmancc3d4422017-08-03 08:27:51 -07001097 video_stream_encoder_->Stop();
perkj803d97f2016-11-01 11:45:46 -07001098}
1099
mflodmancc3d4422017-08-03 08:27:51 -07001100TEST_F(VideoStreamEncoderTest, SwitchingSourceKeepsCpuAdaptation) {
1101 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
kthelgason876222f2016-11-29 01:44:11 -08001102
asaperssonfab67072017-04-04 05:51:49 -07001103 const int kWidth = 1280;
1104 const int kHeight = 720;
1105 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001106 WaitForEncodedFrame(1);
kthelgason876222f2016-11-29 01:44:11 -08001107 VideoSendStream::Stats stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001108 EXPECT_FALSE(stats.bw_limited_resolution);
kthelgason876222f2016-11-29 01:44:11 -08001109 EXPECT_FALSE(stats.cpu_limited_resolution);
1110 EXPECT_EQ(0, stats.number_of_cpu_adapt_changes);
1111
asaperssonfab67072017-04-04 05:51:49 -07001112 // Trigger CPU overuse.
mflodmancc3d4422017-08-03 08:27:51 -07001113 video_stream_encoder_->TriggerCpuOveruse();
asaperssonfab67072017-04-04 05:51:49 -07001114 video_source_.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001115 WaitForEncodedFrame(2);
kthelgason876222f2016-11-29 01:44:11 -08001116 stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001117 EXPECT_FALSE(stats.bw_limited_resolution);
kthelgason876222f2016-11-29 01:44:11 -08001118 EXPECT_TRUE(stats.cpu_limited_resolution);
1119 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1120
1121 // Set new source with adaptation still enabled.
1122 test::FrameForwarder new_video_source;
mflodmancc3d4422017-08-03 08:27:51 -07001123 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001124 &new_video_source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
kthelgason876222f2016-11-29 01:44:11 -08001125
asaperssonfab67072017-04-04 05:51:49 -07001126 new_video_source.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001127 WaitForEncodedFrame(3);
kthelgason876222f2016-11-29 01:44:11 -08001128 stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001129 EXPECT_FALSE(stats.bw_limited_resolution);
kthelgason876222f2016-11-29 01:44:11 -08001130 EXPECT_TRUE(stats.cpu_limited_resolution);
1131 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1132
1133 // Set adaptation disabled.
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001134 video_stream_encoder_->SetSource(&new_video_source,
1135 webrtc::DegradationPreference::DISABLED);
kthelgason876222f2016-11-29 01:44:11 -08001136
asaperssonfab67072017-04-04 05:51:49 -07001137 new_video_source.IncomingCapturedFrame(CreateFrame(4, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001138 WaitForEncodedFrame(4);
kthelgason876222f2016-11-29 01:44:11 -08001139 stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001140 EXPECT_FALSE(stats.bw_limited_resolution);
kthelgason876222f2016-11-29 01:44:11 -08001141 EXPECT_FALSE(stats.cpu_limited_resolution);
1142 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1143
1144 // Set adaptation back to enabled.
mflodmancc3d4422017-08-03 08:27:51 -07001145 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001146 &new_video_source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
kthelgason876222f2016-11-29 01:44:11 -08001147
asaperssonfab67072017-04-04 05:51:49 -07001148 new_video_source.IncomingCapturedFrame(CreateFrame(5, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001149 WaitForEncodedFrame(5);
kthelgason876222f2016-11-29 01:44:11 -08001150 stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001151 EXPECT_FALSE(stats.bw_limited_resolution);
kthelgason876222f2016-11-29 01:44:11 -08001152 EXPECT_TRUE(stats.cpu_limited_resolution);
1153 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1154
asaperssonfab67072017-04-04 05:51:49 -07001155 // Trigger CPU normal use.
mflodmancc3d4422017-08-03 08:27:51 -07001156 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssonfab67072017-04-04 05:51:49 -07001157 new_video_source.IncomingCapturedFrame(CreateFrame(6, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001158 WaitForEncodedFrame(6);
kthelgason876222f2016-11-29 01:44:11 -08001159 stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001160 EXPECT_FALSE(stats.bw_limited_resolution);
kthelgason876222f2016-11-29 01:44:11 -08001161 EXPECT_FALSE(stats.cpu_limited_resolution);
1162 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
asapersson02465b82017-04-10 01:12:52 -07001163 EXPECT_EQ(0, stats.number_of_quality_adapt_changes);
kthelgason876222f2016-11-29 01:44:11 -08001164
mflodmancc3d4422017-08-03 08:27:51 -07001165 video_stream_encoder_->Stop();
kthelgason876222f2016-11-29 01:44:11 -08001166}
1167
mflodmancc3d4422017-08-03 08:27:51 -07001168TEST_F(VideoStreamEncoderTest, SwitchingSourceKeepsQualityAdaptation) {
1169 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
kthelgason876222f2016-11-29 01:44:11 -08001170
asaperssonfab67072017-04-04 05:51:49 -07001171 const int kWidth = 1280;
1172 const int kHeight = 720;
1173 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001174 WaitForEncodedFrame(1);
kthelgason876222f2016-11-29 01:44:11 -08001175 VideoSendStream::Stats stats = stats_proxy_->GetStats();
kthelgason876222f2016-11-29 01:44:11 -08001176 EXPECT_FALSE(stats.bw_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001177 EXPECT_FALSE(stats.bw_limited_framerate);
asaperssonfab67072017-04-04 05:51:49 -07001178 EXPECT_EQ(0, stats.number_of_quality_adapt_changes);
kthelgason876222f2016-11-29 01:44:11 -08001179
1180 // Set new source with adaptation still enabled.
1181 test::FrameForwarder new_video_source;
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001182 video_stream_encoder_->SetSource(&new_video_source,
1183 webrtc::DegradationPreference::BALANCED);
kthelgason876222f2016-11-29 01:44:11 -08001184
asaperssonfab67072017-04-04 05:51:49 -07001185 new_video_source.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001186 WaitForEncodedFrame(2);
kthelgason876222f2016-11-29 01:44:11 -08001187 stats = stats_proxy_->GetStats();
kthelgason876222f2016-11-29 01:44:11 -08001188 EXPECT_FALSE(stats.bw_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001189 EXPECT_FALSE(stats.bw_limited_framerate);
asaperssonfab67072017-04-04 05:51:49 -07001190 EXPECT_EQ(0, stats.number_of_quality_adapt_changes);
kthelgason876222f2016-11-29 01:44:11 -08001191
asaperssonfab67072017-04-04 05:51:49 -07001192 // Trigger adapt down.
mflodmancc3d4422017-08-03 08:27:51 -07001193 video_stream_encoder_->TriggerQualityLow();
asaperssonfab67072017-04-04 05:51:49 -07001194 new_video_source.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001195 WaitForEncodedFrame(3);
kthelgason876222f2016-11-29 01:44:11 -08001196 stats = stats_proxy_->GetStats();
kthelgason876222f2016-11-29 01:44:11 -08001197 EXPECT_TRUE(stats.bw_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001198 EXPECT_FALSE(stats.bw_limited_framerate);
asaperssonfab67072017-04-04 05:51:49 -07001199 EXPECT_EQ(1, stats.number_of_quality_adapt_changes);
kthelgason876222f2016-11-29 01:44:11 -08001200
asaperssonfab67072017-04-04 05:51:49 -07001201 // Set new source with adaptation still enabled.
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001202 video_stream_encoder_->SetSource(&new_video_source,
1203 webrtc::DegradationPreference::BALANCED);
kthelgason876222f2016-11-29 01:44:11 -08001204
asaperssonfab67072017-04-04 05:51:49 -07001205 new_video_source.IncomingCapturedFrame(CreateFrame(4, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001206 WaitForEncodedFrame(4);
kthelgason876222f2016-11-29 01:44:11 -08001207 stats = stats_proxy_->GetStats();
kthelgason876222f2016-11-29 01:44:11 -08001208 EXPECT_TRUE(stats.bw_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001209 EXPECT_FALSE(stats.bw_limited_framerate);
asaperssonfab67072017-04-04 05:51:49 -07001210 EXPECT_EQ(1, stats.number_of_quality_adapt_changes);
kthelgason876222f2016-11-29 01:44:11 -08001211
asapersson02465b82017-04-10 01:12:52 -07001212 // Disable resolution scaling.
mflodmancc3d4422017-08-03 08:27:51 -07001213 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001214 &new_video_source, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
kthelgason876222f2016-11-29 01:44:11 -08001215
asaperssonfab67072017-04-04 05:51:49 -07001216 new_video_source.IncomingCapturedFrame(CreateFrame(5, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001217 WaitForEncodedFrame(5);
kthelgason876222f2016-11-29 01:44:11 -08001218 stats = stats_proxy_->GetStats();
kthelgason876222f2016-11-29 01:44:11 -08001219 EXPECT_FALSE(stats.bw_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001220 EXPECT_FALSE(stats.bw_limited_framerate);
asaperssonfab67072017-04-04 05:51:49 -07001221 EXPECT_EQ(1, stats.number_of_quality_adapt_changes);
1222 EXPECT_EQ(0, stats.number_of_cpu_adapt_changes);
kthelgason876222f2016-11-29 01:44:11 -08001223
mflodmancc3d4422017-08-03 08:27:51 -07001224 video_stream_encoder_->Stop();
kthelgason876222f2016-11-29 01:44:11 -08001225}
1226
mflodmancc3d4422017-08-03 08:27:51 -07001227TEST_F(VideoStreamEncoderTest,
1228 QualityAdaptationStatsAreResetWhenScalerIsDisabled) {
1229 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson36e9eb42017-03-31 05:29:12 -07001230
1231 const int kWidth = 1280;
1232 const int kHeight = 720;
1233 video_source_.set_adaptation_enabled(true);
1234 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001235 WaitForEncodedFrame(1);
asapersson36e9eb42017-03-31 05:29:12 -07001236 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1237 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1238 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1239
1240 // Trigger adapt down.
mflodmancc3d4422017-08-03 08:27:51 -07001241 video_stream_encoder_->TriggerQualityLow();
asapersson36e9eb42017-03-31 05:29:12 -07001242 video_source_.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001243 WaitForEncodedFrame(2);
asapersson36e9eb42017-03-31 05:29:12 -07001244 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1245 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1246 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1247
1248 // Trigger overuse.
mflodmancc3d4422017-08-03 08:27:51 -07001249 video_stream_encoder_->TriggerCpuOveruse();
asapersson36e9eb42017-03-31 05:29:12 -07001250 video_source_.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001251 WaitForEncodedFrame(3);
asapersson36e9eb42017-03-31 05:29:12 -07001252 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1253 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1254 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1255
Niels Möller4db138e2018-04-19 09:04:13 +02001256 // Leave source unchanged, but disable quality scaler.
asapersson36e9eb42017-03-31 05:29:12 -07001257 fake_encoder_.SetQualityScaling(false);
Niels Möller4db138e2018-04-19 09:04:13 +02001258
1259 VideoEncoderConfig video_encoder_config;
1260 test::FillEncoderConfiguration(kVideoCodecVP8, 1, &video_encoder_config);
1261 // Make format different, to force recreation of encoder.
1262 video_encoder_config.video_format.parameters["foo"] = "foo";
1263 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
Niels Möllerf1338562018-04-26 09:51:47 +02001264 kMaxPayloadLength);
asapersson36e9eb42017-03-31 05:29:12 -07001265
1266 video_source_.IncomingCapturedFrame(CreateFrame(4, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001267 WaitForEncodedFrame(4);
asapersson36e9eb42017-03-31 05:29:12 -07001268 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1269 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1270 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1271
mflodmancc3d4422017-08-03 08:27:51 -07001272 video_stream_encoder_->Stop();
asapersson36e9eb42017-03-31 05:29:12 -07001273}
1274
mflodmancc3d4422017-08-03 08:27:51 -07001275TEST_F(VideoStreamEncoderTest,
1276 StatsTracksCpuAdaptationStatsWhenSwitchingSource) {
1277 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkj803d97f2016-11-01 11:45:46 -07001278
asapersson0944a802017-04-07 00:57:58 -07001279 const int kWidth = 1280;
1280 const int kHeight = 720;
sprang84a37592017-02-10 07:04:27 -08001281 int sequence = 1;
perkj803d97f2016-11-01 11:45:46 -07001282
asaperssonfab67072017-04-04 05:51:49 -07001283 video_source_.IncomingCapturedFrame(CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001284 WaitForEncodedFrame(sequence++);
perkj803d97f2016-11-01 11:45:46 -07001285 VideoSendStream::Stats stats = stats_proxy_->GetStats();
sprang84a37592017-02-10 07:04:27 -08001286 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001287 EXPECT_FALSE(stats.cpu_limited_framerate);
sprang84a37592017-02-10 07:04:27 -08001288 EXPECT_EQ(0, stats.number_of_cpu_adapt_changes);
1289
asapersson02465b82017-04-10 01:12:52 -07001290 // Trigger CPU overuse, should now adapt down.
mflodmancc3d4422017-08-03 08:27:51 -07001291 video_stream_encoder_->TriggerCpuOveruse();
asaperssonfab67072017-04-04 05:51:49 -07001292 video_source_.IncomingCapturedFrame(CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001293 WaitForEncodedFrame(sequence++);
sprang84a37592017-02-10 07:04:27 -08001294 stats = stats_proxy_->GetStats();
perkj803d97f2016-11-01 11:45:46 -07001295 EXPECT_TRUE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001296 EXPECT_FALSE(stats.cpu_limited_framerate);
perkj803d97f2016-11-01 11:45:46 -07001297 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1298
1299 // Set new source with adaptation still enabled.
1300 test::FrameForwarder new_video_source;
mflodmancc3d4422017-08-03 08:27:51 -07001301 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001302 &new_video_source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
perkj803d97f2016-11-01 11:45:46 -07001303
1304 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001305 CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001306 WaitForEncodedFrame(sequence++);
perkj803d97f2016-11-01 11:45:46 -07001307 stats = stats_proxy_->GetStats();
1308 EXPECT_TRUE(stats.cpu_limited_resolution);
asapersson09f05612017-05-15 23:40:18 -07001309 EXPECT_FALSE(stats.cpu_limited_framerate);
perkj803d97f2016-11-01 11:45:46 -07001310 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1311
sprangc5d62e22017-04-02 23:53:04 -07001312 // Set cpu adaptation by frame dropping.
mflodmancc3d4422017-08-03 08:27:51 -07001313 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001314 &new_video_source, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
perkj803d97f2016-11-01 11:45:46 -07001315 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001316 CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001317 WaitForEncodedFrame(sequence++);
perkj803d97f2016-11-01 11:45:46 -07001318 stats = stats_proxy_->GetStats();
sprangc5d62e22017-04-02 23:53:04 -07001319 // Not adapted at first.
perkj803d97f2016-11-01 11:45:46 -07001320 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson09f05612017-05-15 23:40:18 -07001321 EXPECT_FALSE(stats.cpu_limited_framerate);
perkj803d97f2016-11-01 11:45:46 -07001322 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1323
sprangc5d62e22017-04-02 23:53:04 -07001324 // Force an input frame rate to be available, or the adaptation call won't
asapersson09f05612017-05-15 23:40:18 -07001325 // know what framerate to adapt from.
sprangc5d62e22017-04-02 23:53:04 -07001326 VideoSendStream::Stats mock_stats = stats_proxy_->GetStats();
1327 mock_stats.input_frame_rate = 30;
1328 stats_proxy_->SetMockStats(mock_stats);
mflodmancc3d4422017-08-03 08:27:51 -07001329 video_stream_encoder_->TriggerCpuOveruse();
sprangc5d62e22017-04-02 23:53:04 -07001330 stats_proxy_->ResetMockStats();
1331
1332 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001333 CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001334 WaitForEncodedFrame(sequence++);
sprangc5d62e22017-04-02 23:53:04 -07001335
1336 // Framerate now adapted.
1337 stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001338 EXPECT_FALSE(stats.cpu_limited_resolution);
1339 EXPECT_TRUE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001340 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
1341
1342 // Disable CPU adaptation.
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001343 video_stream_encoder_->SetSource(&new_video_source,
1344 webrtc::DegradationPreference::DISABLED);
sprangc5d62e22017-04-02 23:53:04 -07001345 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001346 CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001347 WaitForEncodedFrame(sequence++);
sprangc5d62e22017-04-02 23:53:04 -07001348
1349 stats = stats_proxy_->GetStats();
1350 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001351 EXPECT_FALSE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001352 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
1353
1354 // Try to trigger overuse. Should not succeed.
1355 stats_proxy_->SetMockStats(mock_stats);
mflodmancc3d4422017-08-03 08:27:51 -07001356 video_stream_encoder_->TriggerCpuOveruse();
sprangc5d62e22017-04-02 23:53:04 -07001357 stats_proxy_->ResetMockStats();
1358
1359 stats = stats_proxy_->GetStats();
1360 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001361 EXPECT_FALSE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001362 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
1363
1364 // Switch back the source with resolution adaptation enabled.
mflodmancc3d4422017-08-03 08:27:51 -07001365 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001366 &video_source_, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
asaperssonfab67072017-04-04 05:51:49 -07001367 video_source_.IncomingCapturedFrame(CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001368 WaitForEncodedFrame(sequence++);
perkj803d97f2016-11-01 11:45:46 -07001369 stats = stats_proxy_->GetStats();
1370 EXPECT_TRUE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001371 EXPECT_FALSE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001372 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
perkj803d97f2016-11-01 11:45:46 -07001373
1374 // Trigger CPU normal usage.
mflodmancc3d4422017-08-03 08:27:51 -07001375 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssonfab67072017-04-04 05:51:49 -07001376 video_source_.IncomingCapturedFrame(CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001377 WaitForEncodedFrame(sequence++);
perkj803d97f2016-11-01 11:45:46 -07001378 stats = stats_proxy_->GetStats();
1379 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001380 EXPECT_FALSE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001381 EXPECT_EQ(3, stats.number_of_cpu_adapt_changes);
1382
1383 // Back to the source with adaptation off, set it back to maintain-resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001384 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001385 &new_video_source, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
sprangc5d62e22017-04-02 23:53:04 -07001386 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001387 CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001388 WaitForEncodedFrame(sequence++);
sprangc5d62e22017-04-02 23:53:04 -07001389 stats = stats_proxy_->GetStats();
asapersson13874762017-06-07 00:01:02 -07001390 // Disabled, since we previously switched the source to disabled.
sprangc5d62e22017-04-02 23:53:04 -07001391 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001392 EXPECT_TRUE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001393 EXPECT_EQ(3, stats.number_of_cpu_adapt_changes);
1394
1395 // Trigger CPU normal usage.
mflodmancc3d4422017-08-03 08:27:51 -07001396 video_stream_encoder_->TriggerCpuNormalUsage();
sprangc5d62e22017-04-02 23:53:04 -07001397 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001398 CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001399 WaitForEncodedFrame(sequence++);
sprangc5d62e22017-04-02 23:53:04 -07001400 stats = stats_proxy_->GetStats();
1401 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001402 EXPECT_FALSE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001403 EXPECT_EQ(4, stats.number_of_cpu_adapt_changes);
asapersson02465b82017-04-10 01:12:52 -07001404 EXPECT_EQ(0, stats.number_of_quality_adapt_changes);
perkj803d97f2016-11-01 11:45:46 -07001405
mflodmancc3d4422017-08-03 08:27:51 -07001406 video_stream_encoder_->Stop();
perkj803d97f2016-11-01 11:45:46 -07001407}
1408
mflodmancc3d4422017-08-03 08:27:51 -07001409TEST_F(VideoStreamEncoderTest,
1410 ScalingUpAndDownDoesNothingWithMaintainResolution) {
asaperssonfab67072017-04-04 05:51:49 -07001411 const int kWidth = 1280;
1412 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001413 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
kthelgason876222f2016-11-29 01:44:11 -08001414
asaperssonfab67072017-04-04 05:51:49 -07001415 // Expect no scaling to begin with.
asapersson02465b82017-04-10 01:12:52 -07001416 VerifyNoLimitation(video_source_.sink_wants());
kthelgason876222f2016-11-29 01:44:11 -08001417
asaperssonfab67072017-04-04 05:51:49 -07001418 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001419 WaitForEncodedFrame(1);
kthelgason876222f2016-11-29 01:44:11 -08001420
asaperssonfab67072017-04-04 05:51:49 -07001421 // Trigger scale down.
mflodmancc3d4422017-08-03 08:27:51 -07001422 video_stream_encoder_->TriggerQualityLow();
kthelgason5e13d412016-12-01 03:59:51 -08001423
asaperssonfab67072017-04-04 05:51:49 -07001424 video_source_.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001425 WaitForEncodedFrame(2);
kthelgason5e13d412016-12-01 03:59:51 -08001426
kthelgason876222f2016-11-29 01:44:11 -08001427 // Expect a scale down.
1428 EXPECT_TRUE(video_source_.sink_wants().max_pixel_count);
asaperssonfab67072017-04-04 05:51:49 -07001429 EXPECT_LT(video_source_.sink_wants().max_pixel_count, kWidth * kHeight);
kthelgason876222f2016-11-29 01:44:11 -08001430
asapersson02465b82017-04-10 01:12:52 -07001431 // Set resolution scaling disabled.
kthelgason876222f2016-11-29 01:44:11 -08001432 test::FrameForwarder new_video_source;
mflodmancc3d4422017-08-03 08:27:51 -07001433 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001434 &new_video_source, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
kthelgason876222f2016-11-29 01:44:11 -08001435
asaperssonfab67072017-04-04 05:51:49 -07001436 // Trigger scale down.
mflodmancc3d4422017-08-03 08:27:51 -07001437 video_stream_encoder_->TriggerQualityLow();
asaperssonfab67072017-04-04 05:51:49 -07001438 new_video_source.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001439 WaitForEncodedFrame(3);
kthelgason876222f2016-11-29 01:44:11 -08001440
asaperssonfab67072017-04-04 05:51:49 -07001441 // Expect no scaling.
sprangc5d62e22017-04-02 23:53:04 -07001442 EXPECT_EQ(std::numeric_limits<int>::max(),
1443 new_video_source.sink_wants().max_pixel_count);
kthelgason876222f2016-11-29 01:44:11 -08001444
asaperssonfab67072017-04-04 05:51:49 -07001445 // Trigger scale up.
mflodmancc3d4422017-08-03 08:27:51 -07001446 video_stream_encoder_->TriggerQualityHigh();
asaperssonfab67072017-04-04 05:51:49 -07001447 new_video_source.IncomingCapturedFrame(CreateFrame(4, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001448 WaitForEncodedFrame(4);
kthelgason876222f2016-11-29 01:44:11 -08001449
asapersson02465b82017-04-10 01:12:52 -07001450 // Expect nothing to change, still no scaling.
sprangc5d62e22017-04-02 23:53:04 -07001451 EXPECT_EQ(std::numeric_limits<int>::max(),
1452 new_video_source.sink_wants().max_pixel_count);
kthelgason876222f2016-11-29 01:44:11 -08001453
mflodmancc3d4422017-08-03 08:27:51 -07001454 video_stream_encoder_->Stop();
kthelgason876222f2016-11-29 01:44:11 -08001455}
1456
mflodmancc3d4422017-08-03 08:27:51 -07001457TEST_F(VideoStreamEncoderTest,
1458 SkipsSameAdaptDownRequest_MaintainFramerateMode) {
asapersson02465b82017-04-10 01:12:52 -07001459 const int kWidth = 1280;
1460 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001461 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson02465b82017-04-10 01:12:52 -07001462
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001463 // Enable MAINTAIN_FRAMERATE preference, no initial limitation.
asapersson02465b82017-04-10 01:12:52 -07001464 test::FrameForwarder source;
mflodmancc3d4422017-08-03 08:27:51 -07001465 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001466 &source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
asapersson02465b82017-04-10 01:12:52 -07001467
1468 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001469 WaitForEncodedFrame(1);
asapersson02465b82017-04-10 01:12:52 -07001470 VerifyNoLimitation(source.sink_wants());
1471 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1472 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1473
1474 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001475 video_stream_encoder_->TriggerCpuOveruse();
asapersson09f05612017-05-15 23:40:18 -07001476 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
asapersson02465b82017-04-10 01:12:52 -07001477 const int kLastMaxPixelCount = source.sink_wants().max_pixel_count;
1478 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1479 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1480
1481 // Trigger adapt down for same input resolution, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07001482 video_stream_encoder_->TriggerCpuOveruse();
asapersson02465b82017-04-10 01:12:52 -07001483 EXPECT_EQ(kLastMaxPixelCount, source.sink_wants().max_pixel_count);
1484 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1485 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1486
mflodmancc3d4422017-08-03 08:27:51 -07001487 video_stream_encoder_->Stop();
asapersson02465b82017-04-10 01:12:52 -07001488}
1489
mflodmancc3d4422017-08-03 08:27:51 -07001490TEST_F(VideoStreamEncoderTest, SkipsSameOrLargerAdaptDownRequest_BalancedMode) {
asaperssonf7e294d2017-06-13 23:25:22 -07001491 const int kWidth = 1280;
1492 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001493 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -07001494
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001495 // Enable BALANCED preference, no initial limitation.
asaperssonf7e294d2017-06-13 23:25:22 -07001496 test::FrameForwarder source;
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001497 video_stream_encoder_->SetSource(&source,
1498 webrtc::DegradationPreference::BALANCED);
asaperssonf7e294d2017-06-13 23:25:22 -07001499 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
1500 sink_.WaitForEncodedFrame(1);
1501 VerifyNoLimitation(source.sink_wants());
1502
1503 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001504 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07001505 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
1506 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1507 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1508 const int kLastMaxPixelCount = source.sink_wants().max_pixel_count;
1509
1510 // Trigger adapt down for same input resolution, expect no change.
1511 source.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
1512 sink_.WaitForEncodedFrame(2);
mflodmancc3d4422017-08-03 08:27:51 -07001513 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07001514 EXPECT_EQ(kLastMaxPixelCount, source.sink_wants().max_pixel_count);
1515 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1516 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1517
1518 // Trigger adapt down for larger input resolution, expect no change.
1519 source.IncomingCapturedFrame(CreateFrame(3, kWidth + 1, kHeight + 1));
1520 sink_.WaitForEncodedFrame(3);
mflodmancc3d4422017-08-03 08:27:51 -07001521 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07001522 EXPECT_EQ(kLastMaxPixelCount, source.sink_wants().max_pixel_count);
1523 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1524 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1525
mflodmancc3d4422017-08-03 08:27:51 -07001526 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07001527}
1528
mflodmancc3d4422017-08-03 08:27:51 -07001529TEST_F(VideoStreamEncoderTest,
1530 NoChangeForInitialNormalUsage_MaintainFramerateMode) {
asapersson02465b82017-04-10 01:12:52 -07001531 const int kWidth = 1280;
1532 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001533 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson02465b82017-04-10 01:12:52 -07001534
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001535 // Enable MAINTAIN_FRAMERATE preference, no initial limitation.
asapersson02465b82017-04-10 01:12:52 -07001536 test::FrameForwarder source;
mflodmancc3d4422017-08-03 08:27:51 -07001537 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001538 &source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
asapersson02465b82017-04-10 01:12:52 -07001539
1540 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001541 WaitForEncodedFrame(kWidth, kHeight);
asapersson02465b82017-04-10 01:12:52 -07001542 VerifyNoLimitation(source.sink_wants());
1543 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1544 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1545
1546 // Trigger adapt up, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07001547 video_stream_encoder_->TriggerCpuNormalUsage();
asapersson02465b82017-04-10 01:12:52 -07001548 VerifyNoLimitation(source.sink_wants());
1549 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1550 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1551
mflodmancc3d4422017-08-03 08:27:51 -07001552 video_stream_encoder_->Stop();
asapersson02465b82017-04-10 01:12:52 -07001553}
1554
mflodmancc3d4422017-08-03 08:27:51 -07001555TEST_F(VideoStreamEncoderTest,
1556 NoChangeForInitialNormalUsage_MaintainResolutionMode) {
asapersson02465b82017-04-10 01:12:52 -07001557 const int kWidth = 1280;
1558 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001559 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson02465b82017-04-10 01:12:52 -07001560
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001561 // Enable MAINTAIN_RESOLUTION preference, no initial limitation.
asapersson02465b82017-04-10 01:12:52 -07001562 test::FrameForwarder source;
mflodmancc3d4422017-08-03 08:27:51 -07001563 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001564 &source, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
asapersson02465b82017-04-10 01:12:52 -07001565
1566 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001567 WaitForEncodedFrame(kWidth, kHeight);
asapersson02465b82017-04-10 01:12:52 -07001568 VerifyNoLimitation(source.sink_wants());
asapersson09f05612017-05-15 23:40:18 -07001569 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
asapersson02465b82017-04-10 01:12:52 -07001570 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1571
1572 // Trigger adapt up, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07001573 video_stream_encoder_->TriggerCpuNormalUsage();
asapersson02465b82017-04-10 01:12:52 -07001574 VerifyNoLimitation(source.sink_wants());
asapersson09f05612017-05-15 23:40:18 -07001575 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
asapersson02465b82017-04-10 01:12:52 -07001576 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1577
mflodmancc3d4422017-08-03 08:27:51 -07001578 video_stream_encoder_->Stop();
asapersson02465b82017-04-10 01:12:52 -07001579}
1580
mflodmancc3d4422017-08-03 08:27:51 -07001581TEST_F(VideoStreamEncoderTest, NoChangeForInitialNormalUsage_BalancedMode) {
asaperssonf7e294d2017-06-13 23:25:22 -07001582 const int kWidth = 1280;
1583 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001584 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -07001585
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001586 // Enable BALANCED preference, no initial limitation.
asaperssonf7e294d2017-06-13 23:25:22 -07001587 test::FrameForwarder source;
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001588 video_stream_encoder_->SetSource(&source,
1589 webrtc::DegradationPreference::BALANCED);
asaperssonf7e294d2017-06-13 23:25:22 -07001590
1591 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
1592 sink_.WaitForEncodedFrame(kWidth, kHeight);
1593 VerifyNoLimitation(source.sink_wants());
1594 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1595 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
1596 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1597
1598 // Trigger adapt up, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07001599 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07001600 VerifyNoLimitation(source.sink_wants());
1601 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1602 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
1603 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1604
mflodmancc3d4422017-08-03 08:27:51 -07001605 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07001606}
1607
mflodmancc3d4422017-08-03 08:27:51 -07001608TEST_F(VideoStreamEncoderTest, NoChangeForInitialNormalUsage_DisabledMode) {
asapersson09f05612017-05-15 23:40:18 -07001609 const int kWidth = 1280;
1610 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001611 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson09f05612017-05-15 23:40:18 -07001612
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001613 // Enable DISABLED preference, no initial limitation.
asapersson09f05612017-05-15 23:40:18 -07001614 test::FrameForwarder source;
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001615 video_stream_encoder_->SetSource(&source,
1616 webrtc::DegradationPreference::DISABLED);
asapersson09f05612017-05-15 23:40:18 -07001617
1618 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
1619 sink_.WaitForEncodedFrame(kWidth, kHeight);
1620 VerifyNoLimitation(source.sink_wants());
1621 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1622 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
1623 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1624
1625 // Trigger adapt up, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07001626 video_stream_encoder_->TriggerQualityHigh();
asapersson09f05612017-05-15 23:40:18 -07001627 VerifyNoLimitation(source.sink_wants());
1628 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1629 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
1630 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1631
mflodmancc3d4422017-08-03 08:27:51 -07001632 video_stream_encoder_->Stop();
asapersson09f05612017-05-15 23:40:18 -07001633}
1634
mflodmancc3d4422017-08-03 08:27:51 -07001635TEST_F(VideoStreamEncoderTest,
1636 AdaptsResolutionForLowQuality_MaintainFramerateMode) {
asapersson02465b82017-04-10 01:12:52 -07001637 const int kWidth = 1280;
1638 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001639 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson02465b82017-04-10 01:12:52 -07001640
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001641 // Enable MAINTAIN_FRAMERATE preference, no initial limitation.
asapersson02465b82017-04-10 01:12:52 -07001642 AdaptingFrameForwarder source;
1643 source.set_adaptation_enabled(true);
mflodmancc3d4422017-08-03 08:27:51 -07001644 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001645 &source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
asapersson02465b82017-04-10 01:12:52 -07001646
1647 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001648 WaitForEncodedFrame(1);
asapersson02465b82017-04-10 01:12:52 -07001649 VerifyNoLimitation(source.sink_wants());
1650 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1651 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1652
1653 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001654 video_stream_encoder_->TriggerQualityLow();
asapersson02465b82017-04-10 01:12:52 -07001655 source.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001656 WaitForEncodedFrame(2);
asapersson09f05612017-05-15 23:40:18 -07001657 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
asapersson02465b82017-04-10 01:12:52 -07001658 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1659 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1660
1661 // Trigger adapt up, expect no restriction.
mflodmancc3d4422017-08-03 08:27:51 -07001662 video_stream_encoder_->TriggerQualityHigh();
asapersson02465b82017-04-10 01:12:52 -07001663 VerifyNoLimitation(source.sink_wants());
1664 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1665 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1666 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1667
mflodmancc3d4422017-08-03 08:27:51 -07001668 video_stream_encoder_->Stop();
asapersson02465b82017-04-10 01:12:52 -07001669}
1670
mflodmancc3d4422017-08-03 08:27:51 -07001671TEST_F(VideoStreamEncoderTest,
1672 AdaptsFramerateForLowQuality_MaintainResolutionMode) {
asapersson09f05612017-05-15 23:40:18 -07001673 const int kWidth = 1280;
1674 const int kHeight = 720;
1675 const int kInputFps = 30;
mflodmancc3d4422017-08-03 08:27:51 -07001676 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson09f05612017-05-15 23:40:18 -07001677
1678 VideoSendStream::Stats stats = stats_proxy_->GetStats();
1679 stats.input_frame_rate = kInputFps;
1680 stats_proxy_->SetMockStats(stats);
1681
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001682 // Expect no scaling to begin with (preference: MAINTAIN_FRAMERATE).
asapersson09f05612017-05-15 23:40:18 -07001683 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
1684 sink_.WaitForEncodedFrame(1);
1685 VerifyNoLimitation(video_source_.sink_wants());
1686
1687 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001688 video_stream_encoder_->TriggerQualityLow();
asapersson09f05612017-05-15 23:40:18 -07001689 video_source_.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
1690 sink_.WaitForEncodedFrame(2);
1691 VerifyFpsMaxResolutionLt(video_source_.sink_wants(), kWidth * kHeight);
1692
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001693 // Enable MAINTAIN_RESOLUTION preference.
asapersson09f05612017-05-15 23:40:18 -07001694 test::FrameForwarder new_video_source;
mflodmancc3d4422017-08-03 08:27:51 -07001695 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001696 &new_video_source, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
asapersson09f05612017-05-15 23:40:18 -07001697 VerifyNoLimitation(new_video_source.sink_wants());
1698
1699 // Trigger adapt down, expect reduced framerate.
mflodmancc3d4422017-08-03 08:27:51 -07001700 video_stream_encoder_->TriggerQualityLow();
asapersson09f05612017-05-15 23:40:18 -07001701 new_video_source.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
1702 sink_.WaitForEncodedFrame(3);
1703 VerifyFpsLtResolutionMax(new_video_source.sink_wants(), kInputFps);
1704
1705 // Trigger adapt up, expect no restriction.
mflodmancc3d4422017-08-03 08:27:51 -07001706 video_stream_encoder_->TriggerQualityHigh();
asapersson09f05612017-05-15 23:40:18 -07001707 VerifyNoLimitation(new_video_source.sink_wants());
1708
mflodmancc3d4422017-08-03 08:27:51 -07001709 video_stream_encoder_->Stop();
asapersson09f05612017-05-15 23:40:18 -07001710}
1711
mflodmancc3d4422017-08-03 08:27:51 -07001712TEST_F(VideoStreamEncoderTest, DoesNotScaleBelowSetResolutionLimit) {
asaperssond0de2952017-04-21 01:47:31 -07001713 const int kWidth = 1280;
1714 const int kHeight = 720;
1715 const size_t kNumFrames = 10;
1716
mflodmancc3d4422017-08-03 08:27:51 -07001717 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
kthelgason5e13d412016-12-01 03:59:51 -08001718
asaperssond0de2952017-04-21 01:47:31 -07001719 // Enable adapter, expected input resolutions when downscaling:
asapersson142fcc92017-08-17 08:58:54 -07001720 // 1280x720 -> 960x540 -> 640x360 -> 480x270 -> 320x180 (kMinPixelsPerFrame)
asaperssond0de2952017-04-21 01:47:31 -07001721 video_source_.set_adaptation_enabled(true);
1722
1723 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1724 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1725
1726 int downscales = 0;
1727 for (size_t i = 1; i <= kNumFrames; i++) {
1728 video_source_.IncomingCapturedFrame(CreateFrame(i, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001729 WaitForEncodedFrame(i);
asaperssond0de2952017-04-21 01:47:31 -07001730
asaperssonfab67072017-04-04 05:51:49 -07001731 // Trigger scale down.
asaperssond0de2952017-04-21 01:47:31 -07001732 rtc::VideoSinkWants last_wants = video_source_.sink_wants();
mflodmancc3d4422017-08-03 08:27:51 -07001733 video_stream_encoder_->TriggerQualityLow();
sprangc5d62e22017-04-02 23:53:04 -07001734 EXPECT_GE(video_source_.sink_wants().max_pixel_count, kMinPixelsPerFrame);
asaperssond0de2952017-04-21 01:47:31 -07001735
1736 if (video_source_.sink_wants().max_pixel_count < last_wants.max_pixel_count)
1737 ++downscales;
1738
1739 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1740 EXPECT_EQ(downscales,
1741 stats_proxy_->GetStats().number_of_quality_adapt_changes);
1742 EXPECT_GT(downscales, 0);
kthelgason5e13d412016-12-01 03:59:51 -08001743 }
mflodmancc3d4422017-08-03 08:27:51 -07001744 video_stream_encoder_->Stop();
asaperssond0de2952017-04-21 01:47:31 -07001745}
1746
mflodmancc3d4422017-08-03 08:27:51 -07001747TEST_F(VideoStreamEncoderTest,
asaperssond0de2952017-04-21 01:47:31 -07001748 AdaptsResolutionUpAndDownTwiceOnOveruse_MaintainFramerateMode) {
1749 const int kWidth = 1280;
1750 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001751 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssond0de2952017-04-21 01:47:31 -07001752
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001753 // Enable MAINTAIN_FRAMERATE preference, no initial limitation.
asaperssond0de2952017-04-21 01:47:31 -07001754 AdaptingFrameForwarder source;
1755 source.set_adaptation_enabled(true);
mflodmancc3d4422017-08-03 08:27:51 -07001756 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001757 &source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
asaperssond0de2952017-04-21 01:47:31 -07001758
1759 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001760 WaitForEncodedFrame(kWidth, kHeight);
asaperssond0de2952017-04-21 01:47:31 -07001761 VerifyNoLimitation(source.sink_wants());
1762 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1763 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1764
1765 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001766 video_stream_encoder_->TriggerCpuOveruse();
asaperssond0de2952017-04-21 01:47:31 -07001767 source.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001768 WaitForEncodedFrame(2);
asapersson09f05612017-05-15 23:40:18 -07001769 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
asaperssond0de2952017-04-21 01:47:31 -07001770 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1771 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1772
1773 // Trigger adapt up, expect no restriction.
mflodmancc3d4422017-08-03 08:27:51 -07001774 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssond0de2952017-04-21 01:47:31 -07001775 source.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001776 WaitForEncodedFrame(kWidth, kHeight);
asaperssond0de2952017-04-21 01:47:31 -07001777 VerifyNoLimitation(source.sink_wants());
1778 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1779 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1780
1781 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001782 video_stream_encoder_->TriggerCpuOveruse();
asaperssond0de2952017-04-21 01:47:31 -07001783 source.IncomingCapturedFrame(CreateFrame(4, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001784 WaitForEncodedFrame(4);
asapersson09f05612017-05-15 23:40:18 -07001785 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
asaperssond0de2952017-04-21 01:47:31 -07001786 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1787 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1788
1789 // Trigger adapt up, expect no restriction.
mflodmancc3d4422017-08-03 08:27:51 -07001790 video_stream_encoder_->TriggerCpuNormalUsage();
asapersson09f05612017-05-15 23:40:18 -07001791 source.IncomingCapturedFrame(CreateFrame(5, kWidth, kHeight));
1792 sink_.WaitForEncodedFrame(kWidth, kHeight);
asaperssond0de2952017-04-21 01:47:31 -07001793 VerifyNoLimitation(source.sink_wants());
1794 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1795 EXPECT_EQ(4, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1796
mflodmancc3d4422017-08-03 08:27:51 -07001797 video_stream_encoder_->Stop();
asaperssond0de2952017-04-21 01:47:31 -07001798}
1799
mflodmancc3d4422017-08-03 08:27:51 -07001800TEST_F(VideoStreamEncoderTest,
asaperssonf7e294d2017-06-13 23:25:22 -07001801 AdaptsResolutionUpAndDownTwiceForLowQuality_BalancedMode_NoFpsLimit) {
1802 const int kWidth = 1280;
1803 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001804 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -07001805
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001806 // Enable BALANCED preference, no initial limitation.
asaperssonf7e294d2017-06-13 23:25:22 -07001807 AdaptingFrameForwarder source;
1808 source.set_adaptation_enabled(true);
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001809 video_stream_encoder_->SetSource(&source,
1810 webrtc::DegradationPreference::BALANCED);
asaperssonf7e294d2017-06-13 23:25:22 -07001811
1812 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
1813 sink_.WaitForEncodedFrame(kWidth, kHeight);
1814 VerifyNoLimitation(source.sink_wants());
1815 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1816 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1817
1818 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001819 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07001820 source.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
1821 sink_.WaitForEncodedFrame(2);
1822 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
1823 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1824 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1825
1826 // Trigger adapt up, expect no restriction.
mflodmancc3d4422017-08-03 08:27:51 -07001827 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07001828 source.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
1829 sink_.WaitForEncodedFrame(kWidth, kHeight);
1830 VerifyNoLimitation(source.sink_wants());
1831 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1832 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1833
1834 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001835 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07001836 source.IncomingCapturedFrame(CreateFrame(4, kWidth, kHeight));
1837 sink_.WaitForEncodedFrame(4);
1838 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
1839 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1840 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1841
1842 // Trigger adapt up, expect no restriction.
mflodmancc3d4422017-08-03 08:27:51 -07001843 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07001844 source.IncomingCapturedFrame(CreateFrame(5, kWidth, kHeight));
1845 sink_.WaitForEncodedFrame(kWidth, kHeight);
1846 VerifyNoLimitation(source.sink_wants());
1847 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1848 EXPECT_EQ(4, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1849
mflodmancc3d4422017-08-03 08:27:51 -07001850 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07001851}
1852
mflodmancc3d4422017-08-03 08:27:51 -07001853TEST_F(VideoStreamEncoderTest,
asaperssond0de2952017-04-21 01:47:31 -07001854 AdaptsResolutionOnOveruseAndLowQuality_MaintainFramerateMode) {
1855 const int kWidth = 1280;
1856 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001857 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssond0de2952017-04-21 01:47:31 -07001858
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001859 // Enable MAINTAIN_FRAMERATE preference, no initial limitation.
asaperssond0de2952017-04-21 01:47:31 -07001860 AdaptingFrameForwarder source;
1861 source.set_adaptation_enabled(true);
mflodmancc3d4422017-08-03 08:27:51 -07001862 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001863 &source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
asaperssond0de2952017-04-21 01:47:31 -07001864
1865 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001866 WaitForEncodedFrame(kWidth, kHeight);
asaperssond0de2952017-04-21 01:47:31 -07001867 VerifyNoLimitation(source.sink_wants());
1868 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1869 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1870 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1871 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1872
1873 // Trigger cpu adapt down, expect scaled down resolution (960x540).
mflodmancc3d4422017-08-03 08:27:51 -07001874 video_stream_encoder_->TriggerCpuOveruse();
asaperssond0de2952017-04-21 01:47:31 -07001875 source.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001876 WaitForEncodedFrame(2);
asapersson09f05612017-05-15 23:40:18 -07001877 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
asaperssond0de2952017-04-21 01:47:31 -07001878 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1879 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1880 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1881 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1882
1883 // Trigger cpu adapt down, expect scaled down resolution (640x360).
mflodmancc3d4422017-08-03 08:27:51 -07001884 video_stream_encoder_->TriggerCpuOveruse();
asaperssond0de2952017-04-21 01:47:31 -07001885 source.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001886 WaitForEncodedFrame(3);
asapersson09f05612017-05-15 23:40:18 -07001887 VerifyFpsMaxResolutionLt(source.sink_wants(), source.last_wants());
asaperssond0de2952017-04-21 01:47:31 -07001888 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1889 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1890 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1891 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1892
Jonathan Yubc771b72017-12-08 17:04:29 -08001893 // Trigger cpu adapt down, expect scaled down resolution (480x270).
mflodmancc3d4422017-08-03 08:27:51 -07001894 video_stream_encoder_->TriggerCpuOveruse();
asaperssond0de2952017-04-21 01:47:31 -07001895 source.IncomingCapturedFrame(CreateFrame(4, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001896 WaitForEncodedFrame(4);
Jonathan Yubc771b72017-12-08 17:04:29 -08001897 VerifyFpsMaxResolutionLt(source.sink_wants(), source.last_wants());
asaperssond0de2952017-04-21 01:47:31 -07001898 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1899 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
Jonathan Yubc771b72017-12-08 17:04:29 -08001900 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
asaperssond0de2952017-04-21 01:47:31 -07001901 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1902
Jonathan Yubc771b72017-12-08 17:04:29 -08001903 // Trigger quality adapt down, expect scaled down resolution (320x180).
mflodmancc3d4422017-08-03 08:27:51 -07001904 video_stream_encoder_->TriggerQualityLow();
asaperssond0de2952017-04-21 01:47:31 -07001905 source.IncomingCapturedFrame(CreateFrame(5, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001906 WaitForEncodedFrame(5);
asapersson09f05612017-05-15 23:40:18 -07001907 VerifyFpsMaxResolutionLt(source.sink_wants(), source.last_wants());
Jonathan Yubc771b72017-12-08 17:04:29 -08001908 rtc::VideoSinkWants last_wants = source.sink_wants();
asaperssond0de2952017-04-21 01:47:31 -07001909 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1910 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1911 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1912 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1913
Jonathan Yubc771b72017-12-08 17:04:29 -08001914 // Trigger quality adapt down, expect no change (min resolution reached).
1915 video_stream_encoder_->TriggerQualityLow();
1916 source.IncomingCapturedFrame(CreateFrame(6, kWidth, kHeight));
1917 WaitForEncodedFrame(6);
1918 VerifyFpsMaxResolutionEq(source.sink_wants(), last_wants);
1919 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1920 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1921 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1922 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1923
1924 // Trigger cpu adapt up, expect upscaled resolution (480x270).
mflodmancc3d4422017-08-03 08:27:51 -07001925 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssond0de2952017-04-21 01:47:31 -07001926 source.IncomingCapturedFrame(CreateFrame(7, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001927 WaitForEncodedFrame(7);
asapersson09f05612017-05-15 23:40:18 -07001928 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
Jonathan Yubc771b72017-12-08 17:04:29 -08001929 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1930 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1931 EXPECT_EQ(4, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1932 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1933
1934 // Trigger cpu adapt up, expect upscaled resolution (640x360).
1935 video_stream_encoder_->TriggerCpuNormalUsage();
1936 source.IncomingCapturedFrame(CreateFrame(8, kWidth, kHeight));
1937 WaitForEncodedFrame(8);
1938 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
1939 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1940 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1941 EXPECT_EQ(5, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1942 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1943
1944 // Trigger cpu adapt up, expect upscaled resolution (960x540).
1945 video_stream_encoder_->TriggerCpuNormalUsage();
1946 source.IncomingCapturedFrame(CreateFrame(9, kWidth, kHeight));
1947 WaitForEncodedFrame(9);
1948 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
asaperssond0de2952017-04-21 01:47:31 -07001949 last_wants = source.sink_wants();
1950 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1951 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
Jonathan Yubc771b72017-12-08 17:04:29 -08001952 EXPECT_EQ(6, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
asaperssond0de2952017-04-21 01:47:31 -07001953 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1954
1955 // Trigger cpu adapt up, no cpu downgrades, expect no change (960x540).
mflodmancc3d4422017-08-03 08:27:51 -07001956 video_stream_encoder_->TriggerCpuNormalUsage();
Jonathan Yubc771b72017-12-08 17:04:29 -08001957 source.IncomingCapturedFrame(CreateFrame(10, kWidth, kHeight));
1958 WaitForEncodedFrame(10);
asapersson09f05612017-05-15 23:40:18 -07001959 VerifyFpsEqResolutionEq(source.sink_wants(), last_wants);
asaperssond0de2952017-04-21 01:47:31 -07001960 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1961 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
Jonathan Yubc771b72017-12-08 17:04:29 -08001962 EXPECT_EQ(6, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
asaperssond0de2952017-04-21 01:47:31 -07001963 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1964
1965 // Trigger quality adapt up, expect no restriction (1280x720).
mflodmancc3d4422017-08-03 08:27:51 -07001966 video_stream_encoder_->TriggerQualityHigh();
Jonathan Yubc771b72017-12-08 17:04:29 -08001967 source.IncomingCapturedFrame(CreateFrame(11, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001968 WaitForEncodedFrame(kWidth, kHeight);
asapersson09f05612017-05-15 23:40:18 -07001969 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
asaperssond0de2952017-04-21 01:47:31 -07001970 VerifyNoLimitation(source.sink_wants());
1971 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1972 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
Jonathan Yubc771b72017-12-08 17:04:29 -08001973 EXPECT_EQ(6, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
asaperssond0de2952017-04-21 01:47:31 -07001974 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
kthelgason5e13d412016-12-01 03:59:51 -08001975
mflodmancc3d4422017-08-03 08:27:51 -07001976 video_stream_encoder_->Stop();
kthelgason5e13d412016-12-01 03:59:51 -08001977}
1978
mflodmancc3d4422017-08-03 08:27:51 -07001979TEST_F(VideoStreamEncoderTest, CpuLimitedHistogramIsReported) {
asaperssonfab67072017-04-04 05:51:49 -07001980 const int kWidth = 640;
1981 const int kHeight = 360;
perkj803d97f2016-11-01 11:45:46 -07001982
mflodmancc3d4422017-08-03 08:27:51 -07001983 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
sprang4847ae62017-06-27 07:06:52 -07001984
perkj803d97f2016-11-01 11:45:46 -07001985 for (int i = 1; i <= SendStatisticsProxy::kMinRequiredMetricsSamples; ++i) {
asaperssonfab67072017-04-04 05:51:49 -07001986 video_source_.IncomingCapturedFrame(CreateFrame(i, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001987 WaitForEncodedFrame(i);
perkj803d97f2016-11-01 11:45:46 -07001988 }
1989
mflodmancc3d4422017-08-03 08:27:51 -07001990 video_stream_encoder_->TriggerCpuOveruse();
perkj803d97f2016-11-01 11:45:46 -07001991 for (int i = 1; i <= SendStatisticsProxy::kMinRequiredMetricsSamples; ++i) {
asaperssonfab67072017-04-04 05:51:49 -07001992 video_source_.IncomingCapturedFrame(CreateFrame(
1993 SendStatisticsProxy::kMinRequiredMetricsSamples + i, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001994 WaitForEncodedFrame(SendStatisticsProxy::kMinRequiredMetricsSamples + i);
perkj803d97f2016-11-01 11:45:46 -07001995 }
1996
mflodmancc3d4422017-08-03 08:27:51 -07001997 video_stream_encoder_->Stop();
1998 video_stream_encoder_.reset();
perkj803d97f2016-11-01 11:45:46 -07001999 stats_proxy_.reset();
sprangf8ee65e2017-02-28 08:49:33 -08002000
perkj803d97f2016-11-01 11:45:46 -07002001 EXPECT_EQ(1,
2002 metrics::NumSamples("WebRTC.Video.CpuLimitedResolutionInPercent"));
2003 EXPECT_EQ(
2004 1, metrics::NumEvents("WebRTC.Video.CpuLimitedResolutionInPercent", 50));
2005}
2006
mflodmancc3d4422017-08-03 08:27:51 -07002007TEST_F(VideoStreamEncoderTest,
2008 CpuLimitedHistogramIsNotReportedForDisabledDegradation) {
2009 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonf4e44af2017-04-19 02:01:06 -07002010 const int kWidth = 640;
2011 const int kHeight = 360;
2012
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002013 video_stream_encoder_->SetSource(&video_source_,
2014 webrtc::DegradationPreference::DISABLED);
asaperssonf4e44af2017-04-19 02:01:06 -07002015
2016 for (int i = 1; i <= SendStatisticsProxy::kMinRequiredMetricsSamples; ++i) {
2017 video_source_.IncomingCapturedFrame(CreateFrame(i, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002018 WaitForEncodedFrame(i);
asaperssonf4e44af2017-04-19 02:01:06 -07002019 }
2020
mflodmancc3d4422017-08-03 08:27:51 -07002021 video_stream_encoder_->Stop();
2022 video_stream_encoder_.reset();
asaperssonf4e44af2017-04-19 02:01:06 -07002023 stats_proxy_.reset();
2024
2025 EXPECT_EQ(0,
2026 metrics::NumSamples("WebRTC.Video.CpuLimitedResolutionInPercent"));
2027}
2028
mflodmancc3d4422017-08-03 08:27:51 -07002029TEST_F(VideoStreamEncoderTest, CallsBitrateObserver) {
sprang4847ae62017-06-27 07:06:52 -07002030 MockBitrateObserver bitrate_observer;
Niels Möller0327c2d2018-05-21 14:09:31 +02002031 video_stream_encoder_->SetBitrateAllocationObserver(&bitrate_observer);
sprang57c2fff2017-01-16 06:24:02 -08002032
2033 const int kDefaultFps = 30;
Erik Språng566124a2018-04-23 12:32:22 +02002034 const VideoBitrateAllocation expected_bitrate =
sprang57c2fff2017-01-16 06:24:02 -08002035 DefaultVideoBitrateAllocator(fake_encoder_.codec_config())
kthelgason2bc68642017-02-07 07:02:22 -08002036 .GetAllocation(kLowTargetBitrateBps, kDefaultFps);
sprang57c2fff2017-01-16 06:24:02 -08002037
2038 // First called on bitrate updated, then again on first frame.
2039 EXPECT_CALL(bitrate_observer, OnBitrateAllocationUpdated(expected_bitrate))
2040 .Times(2);
mflodmancc3d4422017-08-03 08:27:51 -07002041 video_stream_encoder_->OnBitrateUpdated(kLowTargetBitrateBps, 0, 0);
sprang57c2fff2017-01-16 06:24:02 -08002042
2043 const int64_t kStartTimeMs = 1;
2044 video_source_.IncomingCapturedFrame(
2045 CreateFrame(kStartTimeMs, codec_width_, codec_height_));
sprang4847ae62017-06-27 07:06:52 -07002046 WaitForEncodedFrame(kStartTimeMs);
sprang57c2fff2017-01-16 06:24:02 -08002047
2048 // Not called on second frame.
2049 EXPECT_CALL(bitrate_observer, OnBitrateAllocationUpdated(expected_bitrate))
2050 .Times(0);
2051 video_source_.IncomingCapturedFrame(
2052 CreateFrame(kStartTimeMs + 1, codec_width_, codec_height_));
sprang4847ae62017-06-27 07:06:52 -07002053 WaitForEncodedFrame(kStartTimeMs + 1);
sprang57c2fff2017-01-16 06:24:02 -08002054
2055 // Called after a process interval.
2056 const int64_t kProcessIntervalMs =
2057 vcm::VCMProcessTimer::kDefaultProcessIntervalMs;
sprang4847ae62017-06-27 07:06:52 -07002058 fake_clock_.AdvanceTimeMicros(rtc::kNumMicrosecsPerMillisec *
2059 (kProcessIntervalMs + (1000 / kDefaultFps)));
sprang57c2fff2017-01-16 06:24:02 -08002060 EXPECT_CALL(bitrate_observer, OnBitrateAllocationUpdated(expected_bitrate))
2061 .Times(1);
2062 video_source_.IncomingCapturedFrame(CreateFrame(
2063 kStartTimeMs + kProcessIntervalMs, codec_width_, codec_height_));
sprang4847ae62017-06-27 07:06:52 -07002064 WaitForEncodedFrame(kStartTimeMs + kProcessIntervalMs);
sprang57c2fff2017-01-16 06:24:02 -08002065
mflodmancc3d4422017-08-03 08:27:51 -07002066 video_stream_encoder_->Stop();
sprang57c2fff2017-01-16 06:24:02 -08002067}
2068
Niels Möller7dc26b72017-12-06 10:27:48 +01002069TEST_F(VideoStreamEncoderTest, OveruseDetectorUpdatedOnReconfigureAndAdaption) {
2070 const int kFrameWidth = 1280;
2071 const int kFrameHeight = 720;
2072 const int kFramerate = 24;
2073
2074 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
2075 test::FrameForwarder source;
2076 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002077 &source, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
Niels Möller7dc26b72017-12-06 10:27:48 +01002078
2079 // Insert a single frame, triggering initial configuration.
2080 source.IncomingCapturedFrame(CreateFrame(1, kFrameWidth, kFrameHeight));
2081 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2082
2083 EXPECT_EQ(
2084 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2085 kDefaultFramerate);
2086
2087 // Trigger reconfigure encoder (without resetting the entire instance).
2088 VideoEncoderConfig video_encoder_config;
Niels Möller259a4972018-04-05 15:36:51 +02002089 video_encoder_config.codec_type = kVideoCodecVP8;
Niels Möller7dc26b72017-12-06 10:27:48 +01002090 video_encoder_config.max_bitrate_bps = kTargetBitrateBps;
2091 video_encoder_config.number_of_streams = 1;
2092 video_encoder_config.video_stream_factory =
2093 new rtc::RefCountedObject<VideoStreamFactory>(1, kFramerate);
2094 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
Niels Möllerf1338562018-04-26 09:51:47 +02002095 kMaxPayloadLength);
Niels Möller7dc26b72017-12-06 10:27:48 +01002096 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2097
2098 // Detector should be updated with fps limit from codec config.
2099 EXPECT_EQ(
2100 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2101 kFramerate);
2102
2103 // Trigger overuse, max framerate should be reduced.
2104 VideoSendStream::Stats stats = stats_proxy_->GetStats();
2105 stats.input_frame_rate = kFramerate;
2106 stats_proxy_->SetMockStats(stats);
2107 video_stream_encoder_->TriggerCpuOveruse();
2108 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2109 int adapted_framerate =
2110 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate();
2111 EXPECT_LT(adapted_framerate, kFramerate);
2112
2113 // Trigger underuse, max framerate should go back to codec configured fps.
2114 // Set extra low fps, to make sure it's actually reset, not just incremented.
2115 stats = stats_proxy_->GetStats();
2116 stats.input_frame_rate = adapted_framerate / 2;
2117 stats_proxy_->SetMockStats(stats);
2118 video_stream_encoder_->TriggerCpuNormalUsage();
2119 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2120 EXPECT_EQ(
2121 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2122 kFramerate);
2123
2124 video_stream_encoder_->Stop();
2125}
2126
2127TEST_F(VideoStreamEncoderTest,
2128 OveruseDetectorUpdatedRespectsFramerateAfterUnderuse) {
2129 const int kFrameWidth = 1280;
2130 const int kFrameHeight = 720;
2131 const int kLowFramerate = 15;
2132 const int kHighFramerate = 25;
2133
2134 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
2135 test::FrameForwarder source;
2136 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002137 &source, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
Niels Möller7dc26b72017-12-06 10:27:48 +01002138
2139 // Trigger initial configuration.
2140 VideoEncoderConfig video_encoder_config;
Niels Möller259a4972018-04-05 15:36:51 +02002141 video_encoder_config.codec_type = kVideoCodecVP8;
Niels Möller7dc26b72017-12-06 10:27:48 +01002142 video_encoder_config.max_bitrate_bps = kTargetBitrateBps;
2143 video_encoder_config.number_of_streams = 1;
2144 video_encoder_config.video_stream_factory =
2145 new rtc::RefCountedObject<VideoStreamFactory>(1, kLowFramerate);
2146 source.IncomingCapturedFrame(CreateFrame(1, kFrameWidth, kFrameHeight));
2147 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
Niels Möllerf1338562018-04-26 09:51:47 +02002148 kMaxPayloadLength);
Niels Möller7dc26b72017-12-06 10:27:48 +01002149 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2150
2151 EXPECT_EQ(
2152 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2153 kLowFramerate);
2154
2155 // Trigger overuse, max framerate should be reduced.
2156 VideoSendStream::Stats stats = stats_proxy_->GetStats();
2157 stats.input_frame_rate = kLowFramerate;
2158 stats_proxy_->SetMockStats(stats);
2159 video_stream_encoder_->TriggerCpuOveruse();
2160 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2161 int adapted_framerate =
2162 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate();
2163 EXPECT_LT(adapted_framerate, kLowFramerate);
2164
2165 // Reconfigure the encoder with a new (higher max framerate), max fps should
2166 // still respect the adaptation.
2167 video_encoder_config.video_stream_factory =
2168 new rtc::RefCountedObject<VideoStreamFactory>(1, kHighFramerate);
2169 source.IncomingCapturedFrame(CreateFrame(1, kFrameWidth, kFrameHeight));
2170 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
Niels Möllerf1338562018-04-26 09:51:47 +02002171 kMaxPayloadLength);
Niels Möller7dc26b72017-12-06 10:27:48 +01002172 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2173
2174 EXPECT_EQ(
2175 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2176 adapted_framerate);
2177
2178 // Trigger underuse, max framerate should go back to codec configured fps.
2179 stats = stats_proxy_->GetStats();
2180 stats.input_frame_rate = adapted_framerate;
2181 stats_proxy_->SetMockStats(stats);
2182 video_stream_encoder_->TriggerCpuNormalUsage();
2183 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2184 EXPECT_EQ(
2185 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2186 kHighFramerate);
2187
2188 video_stream_encoder_->Stop();
2189}
2190
mflodmancc3d4422017-08-03 08:27:51 -07002191TEST_F(VideoStreamEncoderTest,
2192 OveruseDetectorUpdatedOnDegradationPreferenceChange) {
sprangfda496a2017-06-15 04:21:07 -07002193 const int kFrameWidth = 1280;
2194 const int kFrameHeight = 720;
2195 const int kFramerate = 24;
2196
mflodmancc3d4422017-08-03 08:27:51 -07002197 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
sprangfda496a2017-06-15 04:21:07 -07002198 test::FrameForwarder source;
mflodmancc3d4422017-08-03 08:27:51 -07002199 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002200 &source, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
sprangfda496a2017-06-15 04:21:07 -07002201
2202 // Trigger initial configuration.
2203 VideoEncoderConfig video_encoder_config;
Niels Möller259a4972018-04-05 15:36:51 +02002204 video_encoder_config.codec_type = kVideoCodecVP8;
sprangfda496a2017-06-15 04:21:07 -07002205 video_encoder_config.max_bitrate_bps = kTargetBitrateBps;
2206 video_encoder_config.number_of_streams = 1;
2207 video_encoder_config.video_stream_factory =
2208 new rtc::RefCountedObject<VideoStreamFactory>(1, kFramerate);
2209 source.IncomingCapturedFrame(CreateFrame(1, kFrameWidth, kFrameHeight));
mflodmancc3d4422017-08-03 08:27:51 -07002210 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
Niels Möllerf1338562018-04-26 09:51:47 +02002211 kMaxPayloadLength);
mflodmancc3d4422017-08-03 08:27:51 -07002212 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
sprangfda496a2017-06-15 04:21:07 -07002213
Niels Möller7dc26b72017-12-06 10:27:48 +01002214 EXPECT_EQ(
2215 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2216 kFramerate);
sprangfda496a2017-06-15 04:21:07 -07002217
2218 // Trigger overuse, max framerate should be reduced.
2219 VideoSendStream::Stats stats = stats_proxy_->GetStats();
2220 stats.input_frame_rate = kFramerate;
2221 stats_proxy_->SetMockStats(stats);
mflodmancc3d4422017-08-03 08:27:51 -07002222 video_stream_encoder_->TriggerCpuOveruse();
2223 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
Niels Möller7dc26b72017-12-06 10:27:48 +01002224 int adapted_framerate =
2225 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate();
sprangfda496a2017-06-15 04:21:07 -07002226 EXPECT_LT(adapted_framerate, kFramerate);
2227
2228 // Change degradation preference to not enable framerate scaling. Target
2229 // framerate should be changed to codec defined limit.
mflodmancc3d4422017-08-03 08:27:51 -07002230 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002231 &source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
mflodmancc3d4422017-08-03 08:27:51 -07002232 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
Niels Möller7dc26b72017-12-06 10:27:48 +01002233 EXPECT_EQ(
2234 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2235 kFramerate);
sprangfda496a2017-06-15 04:21:07 -07002236
mflodmancc3d4422017-08-03 08:27:51 -07002237 video_stream_encoder_->Stop();
sprangfda496a2017-06-15 04:21:07 -07002238}
2239
mflodmancc3d4422017-08-03 08:27:51 -07002240TEST_F(VideoStreamEncoderTest, DropsFramesAndScalesWhenBitrateIsTooLow) {
asaperssonfab67072017-04-04 05:51:49 -07002241 const int kTooLowBitrateForFrameSizeBps = 10000;
mflodmancc3d4422017-08-03 08:27:51 -07002242 video_stream_encoder_->OnBitrateUpdated(kTooLowBitrateForFrameSizeBps, 0, 0);
asaperssonfab67072017-04-04 05:51:49 -07002243 const int kWidth = 640;
2244 const int kHeight = 360;
kthelgason2bc68642017-02-07 07:02:22 -08002245
asaperssonfab67072017-04-04 05:51:49 -07002246 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
kthelgason2bc68642017-02-07 07:02:22 -08002247
2248 // Expect to drop this frame, the wait should time out.
sprang4847ae62017-06-27 07:06:52 -07002249 ExpectDroppedFrame();
kthelgason2bc68642017-02-07 07:02:22 -08002250
2251 // Expect the sink_wants to specify a scaled frame.
asapersson0944a802017-04-07 00:57:58 -07002252 EXPECT_LT(video_source_.sink_wants().max_pixel_count, kWidth * kHeight);
kthelgason2bc68642017-02-07 07:02:22 -08002253
sprangc5d62e22017-04-02 23:53:04 -07002254 int last_pixel_count = video_source_.sink_wants().max_pixel_count;
kthelgason2bc68642017-02-07 07:02:22 -08002255
asaperssonfab67072017-04-04 05:51:49 -07002256 // Next frame is scaled.
kthelgason2bc68642017-02-07 07:02:22 -08002257 video_source_.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07002258 CreateFrame(2, kWidth * 3 / 4, kHeight * 3 / 4));
kthelgason2bc68642017-02-07 07:02:22 -08002259
2260 // Expect to drop this frame, the wait should time out.
sprang4847ae62017-06-27 07:06:52 -07002261 ExpectDroppedFrame();
kthelgason2bc68642017-02-07 07:02:22 -08002262
sprangc5d62e22017-04-02 23:53:04 -07002263 EXPECT_LT(video_source_.sink_wants().max_pixel_count, last_pixel_count);
kthelgason2bc68642017-02-07 07:02:22 -08002264
mflodmancc3d4422017-08-03 08:27:51 -07002265 video_stream_encoder_->Stop();
kthelgason2bc68642017-02-07 07:02:22 -08002266}
2267
mflodmancc3d4422017-08-03 08:27:51 -07002268TEST_F(VideoStreamEncoderTest,
2269 NumberOfDroppedFramesLimitedWhenBitrateIsTooLow) {
asaperssonfab67072017-04-04 05:51:49 -07002270 const int kTooLowBitrateForFrameSizeBps = 10000;
mflodmancc3d4422017-08-03 08:27:51 -07002271 video_stream_encoder_->OnBitrateUpdated(kTooLowBitrateForFrameSizeBps, 0, 0);
asaperssonfab67072017-04-04 05:51:49 -07002272 const int kWidth = 640;
2273 const int kHeight = 360;
kthelgason2bc68642017-02-07 07:02:22 -08002274
2275 // We expect the n initial frames to get dropped.
2276 int i;
2277 for (i = 1; i <= kMaxInitialFramedrop; ++i) {
asaperssonfab67072017-04-04 05:51:49 -07002278 video_source_.IncomingCapturedFrame(CreateFrame(i, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002279 ExpectDroppedFrame();
kthelgason2bc68642017-02-07 07:02:22 -08002280 }
2281 // The n+1th frame should not be dropped, even though it's size is too large.
asaperssonfab67072017-04-04 05:51:49 -07002282 video_source_.IncomingCapturedFrame(CreateFrame(i, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002283 WaitForEncodedFrame(i);
kthelgason2bc68642017-02-07 07:02:22 -08002284
2285 // Expect the sink_wants to specify a scaled frame.
asaperssonfab67072017-04-04 05:51:49 -07002286 EXPECT_LT(video_source_.sink_wants().max_pixel_count, kWidth * kHeight);
kthelgason2bc68642017-02-07 07:02:22 -08002287
mflodmancc3d4422017-08-03 08:27:51 -07002288 video_stream_encoder_->Stop();
kthelgason2bc68642017-02-07 07:02:22 -08002289}
2290
mflodmancc3d4422017-08-03 08:27:51 -07002291TEST_F(VideoStreamEncoderTest,
2292 InitialFrameDropOffWithMaintainResolutionPreference) {
asaperssonfab67072017-04-04 05:51:49 -07002293 const int kWidth = 640;
2294 const int kHeight = 360;
mflodmancc3d4422017-08-03 08:27:51 -07002295 video_stream_encoder_->OnBitrateUpdated(kLowTargetBitrateBps, 0, 0);
kthelgason2bc68642017-02-07 07:02:22 -08002296
2297 // Set degradation preference.
mflodmancc3d4422017-08-03 08:27:51 -07002298 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002299 &video_source_, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
kthelgason2bc68642017-02-07 07:02:22 -08002300
asaperssonfab67072017-04-04 05:51:49 -07002301 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
kthelgason2bc68642017-02-07 07:02:22 -08002302 // Frame should not be dropped, even if it's too large.
sprang4847ae62017-06-27 07:06:52 -07002303 WaitForEncodedFrame(1);
kthelgason2bc68642017-02-07 07:02:22 -08002304
mflodmancc3d4422017-08-03 08:27:51 -07002305 video_stream_encoder_->Stop();
kthelgason2bc68642017-02-07 07:02:22 -08002306}
2307
mflodmancc3d4422017-08-03 08:27:51 -07002308TEST_F(VideoStreamEncoderTest, InitialFrameDropOffWhenEncoderDisabledScaling) {
asaperssonfab67072017-04-04 05:51:49 -07002309 const int kWidth = 640;
2310 const int kHeight = 360;
kthelgasonad9010c2017-02-14 00:46:51 -08002311 fake_encoder_.SetQualityScaling(false);
Niels Möller4db138e2018-04-19 09:04:13 +02002312
2313 VideoEncoderConfig video_encoder_config;
2314 test::FillEncoderConfiguration(kVideoCodecVP8, 1, &video_encoder_config);
2315 // Make format different, to force recreation of encoder.
2316 video_encoder_config.video_format.parameters["foo"] = "foo";
2317 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
Niels Möllerf1338562018-04-26 09:51:47 +02002318 kMaxPayloadLength);
mflodmancc3d4422017-08-03 08:27:51 -07002319 video_stream_encoder_->OnBitrateUpdated(kLowTargetBitrateBps, 0, 0);
asapersson09f05612017-05-15 23:40:18 -07002320
kthelgasonb83797b2017-02-14 11:57:25 -08002321 // Force quality scaler reconfiguration by resetting the source.
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002322 video_stream_encoder_->SetSource(&video_source_,
2323 webrtc::DegradationPreference::BALANCED);
kthelgasonad9010c2017-02-14 00:46:51 -08002324
asaperssonfab67072017-04-04 05:51:49 -07002325 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
kthelgasonad9010c2017-02-14 00:46:51 -08002326 // Frame should not be dropped, even if it's too large.
sprang4847ae62017-06-27 07:06:52 -07002327 WaitForEncodedFrame(1);
kthelgasonad9010c2017-02-14 00:46:51 -08002328
mflodmancc3d4422017-08-03 08:27:51 -07002329 video_stream_encoder_->Stop();
kthelgasonad9010c2017-02-14 00:46:51 -08002330 fake_encoder_.SetQualityScaling(true);
2331}
2332
mflodmancc3d4422017-08-03 08:27:51 -07002333TEST_F(VideoStreamEncoderTest,
asaperssond0de2952017-04-21 01:47:31 -07002334 ResolutionNotAdaptedForTooSmallFrame_MaintainFramerateMode) {
2335 const int kTooSmallWidth = 10;
2336 const int kTooSmallHeight = 10;
mflodmancc3d4422017-08-03 08:27:51 -07002337 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssond0de2952017-04-21 01:47:31 -07002338
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002339 // Enable MAINTAIN_FRAMERATE preference, no initial limitation.
asaperssond0de2952017-04-21 01:47:31 -07002340 test::FrameForwarder source;
mflodmancc3d4422017-08-03 08:27:51 -07002341 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002342 &source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
asaperssond0de2952017-04-21 01:47:31 -07002343 VerifyNoLimitation(source.sink_wants());
2344 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2345
2346 // Trigger adapt down, too small frame, expect no change.
2347 source.IncomingCapturedFrame(CreateFrame(1, kTooSmallWidth, kTooSmallHeight));
sprang4847ae62017-06-27 07:06:52 -07002348 WaitForEncodedFrame(1);
mflodmancc3d4422017-08-03 08:27:51 -07002349 video_stream_encoder_->TriggerCpuOveruse();
asaperssond0de2952017-04-21 01:47:31 -07002350 VerifyNoLimitation(source.sink_wants());
2351 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2352 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2353
mflodmancc3d4422017-08-03 08:27:51 -07002354 video_stream_encoder_->Stop();
asaperssond0de2952017-04-21 01:47:31 -07002355}
2356
mflodmancc3d4422017-08-03 08:27:51 -07002357TEST_F(VideoStreamEncoderTest,
2358 ResolutionNotAdaptedForTooSmallFrame_BalancedMode) {
asaperssonf7e294d2017-06-13 23:25:22 -07002359 const int kTooSmallWidth = 10;
2360 const int kTooSmallHeight = 10;
2361 const int kFpsLimit = 7;
mflodmancc3d4422017-08-03 08:27:51 -07002362 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -07002363
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002364 // Enable BALANCED preference, no initial limitation.
asaperssonf7e294d2017-06-13 23:25:22 -07002365 test::FrameForwarder source;
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002366 video_stream_encoder_->SetSource(&source,
2367 webrtc::DegradationPreference::BALANCED);
asaperssonf7e294d2017-06-13 23:25:22 -07002368 VerifyNoLimitation(source.sink_wants());
2369 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2370 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2371
2372 // Trigger adapt down, expect limited framerate.
2373 source.IncomingCapturedFrame(CreateFrame(1, kTooSmallWidth, kTooSmallHeight));
sprang4847ae62017-06-27 07:06:52 -07002374 WaitForEncodedFrame(1);
mflodmancc3d4422017-08-03 08:27:51 -07002375 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002376 VerifyFpsEqResolutionMax(source.sink_wants(), kFpsLimit);
2377 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2378 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2379 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2380
2381 // Trigger adapt down, too small frame, expect no change.
2382 source.IncomingCapturedFrame(CreateFrame(2, kTooSmallWidth, kTooSmallHeight));
sprang4847ae62017-06-27 07:06:52 -07002383 WaitForEncodedFrame(2);
mflodmancc3d4422017-08-03 08:27:51 -07002384 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002385 VerifyFpsEqResolutionMax(source.sink_wants(), kFpsLimit);
2386 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2387 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2388 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2389
mflodmancc3d4422017-08-03 08:27:51 -07002390 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07002391}
2392
mflodmancc3d4422017-08-03 08:27:51 -07002393TEST_F(VideoStreamEncoderTest, FailingInitEncodeDoesntCauseCrash) {
asapersson02465b82017-04-10 01:12:52 -07002394 fake_encoder_.ForceInitEncodeFailure(true);
mflodmancc3d4422017-08-03 08:27:51 -07002395 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
Niels Möllerf1338562018-04-26 09:51:47 +02002396 ResetEncoder("VP8", 2, 1, 1, false);
asapersson02465b82017-04-10 01:12:52 -07002397 const int kFrameWidth = 1280;
2398 const int kFrameHeight = 720;
2399 video_source_.IncomingCapturedFrame(
2400 CreateFrame(1, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002401 ExpectDroppedFrame();
mflodmancc3d4422017-08-03 08:27:51 -07002402 video_stream_encoder_->Stop();
asapersson02465b82017-04-10 01:12:52 -07002403}
2404
sprangb1ca0732017-02-01 08:38:12 -08002405// TODO(sprang): Extend this with fps throttling and any "balanced" extensions.
mflodmancc3d4422017-08-03 08:27:51 -07002406TEST_F(VideoStreamEncoderTest,
2407 AdaptsResolutionOnOveruse_MaintainFramerateMode) {
2408 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
sprangb1ca0732017-02-01 08:38:12 -08002409
2410 const int kFrameWidth = 1280;
2411 const int kFrameHeight = 720;
2412 // Enabled default VideoAdapter downscaling. First step is 3/4, not 3/5 as
mflodmancc3d4422017-08-03 08:27:51 -07002413 // requested by
2414 // VideoStreamEncoder::VideoSourceProxy::RequestResolutionLowerThan().
sprangb1ca0732017-02-01 08:38:12 -08002415 video_source_.set_adaptation_enabled(true);
2416
2417 video_source_.IncomingCapturedFrame(
2418 CreateFrame(1, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002419 WaitForEncodedFrame(kFrameWidth, kFrameHeight);
sprangb1ca0732017-02-01 08:38:12 -08002420
2421 // Trigger CPU overuse, downscale by 3/4.
mflodmancc3d4422017-08-03 08:27:51 -07002422 video_stream_encoder_->TriggerCpuOveruse();
sprangb1ca0732017-02-01 08:38:12 -08002423 video_source_.IncomingCapturedFrame(
2424 CreateFrame(2, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002425 WaitForEncodedFrame((kFrameWidth * 3) / 4, (kFrameHeight * 3) / 4);
sprangb1ca0732017-02-01 08:38:12 -08002426
asaperssonfab67072017-04-04 05:51:49 -07002427 // Trigger CPU normal use, return to original resolution.
mflodmancc3d4422017-08-03 08:27:51 -07002428 video_stream_encoder_->TriggerCpuNormalUsage();
sprangb1ca0732017-02-01 08:38:12 -08002429 video_source_.IncomingCapturedFrame(
2430 CreateFrame(3, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002431 WaitForEncodedFrame(kFrameWidth, kFrameHeight);
sprangb1ca0732017-02-01 08:38:12 -08002432
mflodmancc3d4422017-08-03 08:27:51 -07002433 video_stream_encoder_->Stop();
sprangb1ca0732017-02-01 08:38:12 -08002434}
sprangfe627f32017-03-29 08:24:59 -07002435
mflodmancc3d4422017-08-03 08:27:51 -07002436TEST_F(VideoStreamEncoderTest,
2437 AdaptsFramerateOnOveruse_MaintainResolutionMode) {
sprangc5d62e22017-04-02 23:53:04 -07002438 const int kFrameWidth = 1280;
2439 const int kFrameHeight = 720;
sprang4847ae62017-06-27 07:06:52 -07002440 int kFrameIntervalMs = rtc::kNumMillisecsPerSec / max_framerate_;
sprangc5d62e22017-04-02 23:53:04 -07002441
mflodmancc3d4422017-08-03 08:27:51 -07002442 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
2443 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002444 &video_source_, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
sprangc5d62e22017-04-02 23:53:04 -07002445 video_source_.set_adaptation_enabled(true);
2446
sprang4847ae62017-06-27 07:06:52 -07002447 int64_t timestamp_ms = fake_clock_.TimeNanos() / rtc::kNumNanosecsPerMillisec;
sprangc5d62e22017-04-02 23:53:04 -07002448
2449 video_source_.IncomingCapturedFrame(
2450 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002451 WaitForEncodedFrame(timestamp_ms);
sprangc5d62e22017-04-02 23:53:04 -07002452
2453 // Try to trigger overuse. No fps estimate available => no effect.
mflodmancc3d4422017-08-03 08:27:51 -07002454 video_stream_encoder_->TriggerCpuOveruse();
sprangc5d62e22017-04-02 23:53:04 -07002455
2456 // Insert frames for one second to get a stable estimate.
sprang4847ae62017-06-27 07:06:52 -07002457 for (int i = 0; i < max_framerate_; ++i) {
sprangc5d62e22017-04-02 23:53:04 -07002458 timestamp_ms += kFrameIntervalMs;
sprangc5d62e22017-04-02 23:53:04 -07002459 video_source_.IncomingCapturedFrame(
2460 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002461 WaitForEncodedFrame(timestamp_ms);
sprangc5d62e22017-04-02 23:53:04 -07002462 }
2463
2464 // Trigger CPU overuse, reduce framerate by 2/3.
mflodmancc3d4422017-08-03 08:27:51 -07002465 video_stream_encoder_->TriggerCpuOveruse();
sprangc5d62e22017-04-02 23:53:04 -07002466 int num_frames_dropped = 0;
sprang4847ae62017-06-27 07:06:52 -07002467 for (int i = 0; i < max_framerate_; ++i) {
sprangc5d62e22017-04-02 23:53:04 -07002468 timestamp_ms += kFrameIntervalMs;
sprangc5d62e22017-04-02 23:53:04 -07002469 video_source_.IncomingCapturedFrame(
2470 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002471 if (!WaitForFrame(kFrameTimeoutMs)) {
sprangc5d62e22017-04-02 23:53:04 -07002472 ++num_frames_dropped;
2473 } else {
Åsa Perssonc74d8da2017-12-04 14:13:56 +01002474 sink_.CheckLastFrameSizeMatches(kFrameWidth, kFrameHeight);
sprangc5d62e22017-04-02 23:53:04 -07002475 }
2476 }
2477
sprang4847ae62017-06-27 07:06:52 -07002478 // Add some slack to account for frames dropped by the frame dropper.
2479 const int kErrorMargin = 1;
2480 EXPECT_NEAR(num_frames_dropped, max_framerate_ - (max_framerate_ * 2 / 3),
sprangc5d62e22017-04-02 23:53:04 -07002481 kErrorMargin);
2482
2483 // Trigger CPU overuse, reduce framerate by 2/3 again.
mflodmancc3d4422017-08-03 08:27:51 -07002484 video_stream_encoder_->TriggerCpuOveruse();
sprangc5d62e22017-04-02 23:53:04 -07002485 num_frames_dropped = 0;
sprang4847ae62017-06-27 07:06:52 -07002486 for (int i = 0; i < max_framerate_; ++i) {
sprangc5d62e22017-04-02 23:53:04 -07002487 timestamp_ms += kFrameIntervalMs;
sprangc5d62e22017-04-02 23:53:04 -07002488 video_source_.IncomingCapturedFrame(
2489 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002490 if (!WaitForFrame(kFrameTimeoutMs)) {
sprangc5d62e22017-04-02 23:53:04 -07002491 ++num_frames_dropped;
2492 } else {
Åsa Perssonc74d8da2017-12-04 14:13:56 +01002493 sink_.CheckLastFrameSizeMatches(kFrameWidth, kFrameHeight);
sprangc5d62e22017-04-02 23:53:04 -07002494 }
2495 }
sprang4847ae62017-06-27 07:06:52 -07002496 EXPECT_NEAR(num_frames_dropped, max_framerate_ - (max_framerate_ * 4 / 9),
sprangc5d62e22017-04-02 23:53:04 -07002497 kErrorMargin);
2498
2499 // Go back up one step.
mflodmancc3d4422017-08-03 08:27:51 -07002500 video_stream_encoder_->TriggerCpuNormalUsage();
sprangc5d62e22017-04-02 23:53:04 -07002501 num_frames_dropped = 0;
sprang4847ae62017-06-27 07:06:52 -07002502 for (int i = 0; i < max_framerate_; ++i) {
sprangc5d62e22017-04-02 23:53:04 -07002503 timestamp_ms += kFrameIntervalMs;
sprangc5d62e22017-04-02 23:53:04 -07002504 video_source_.IncomingCapturedFrame(
2505 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002506 if (!WaitForFrame(kFrameTimeoutMs)) {
sprangc5d62e22017-04-02 23:53:04 -07002507 ++num_frames_dropped;
2508 } else {
Åsa Perssonc74d8da2017-12-04 14:13:56 +01002509 sink_.CheckLastFrameSizeMatches(kFrameWidth, kFrameHeight);
sprangc5d62e22017-04-02 23:53:04 -07002510 }
2511 }
sprang4847ae62017-06-27 07:06:52 -07002512 EXPECT_NEAR(num_frames_dropped, max_framerate_ - (max_framerate_ * 2 / 3),
sprangc5d62e22017-04-02 23:53:04 -07002513 kErrorMargin);
2514
2515 // Go back up to original mode.
mflodmancc3d4422017-08-03 08:27:51 -07002516 video_stream_encoder_->TriggerCpuNormalUsage();
sprangc5d62e22017-04-02 23:53:04 -07002517 num_frames_dropped = 0;
sprang4847ae62017-06-27 07:06:52 -07002518 for (int i = 0; i < max_framerate_; ++i) {
sprangc5d62e22017-04-02 23:53:04 -07002519 timestamp_ms += kFrameIntervalMs;
sprangc5d62e22017-04-02 23:53:04 -07002520 video_source_.IncomingCapturedFrame(
2521 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002522 if (!WaitForFrame(kFrameTimeoutMs)) {
sprangc5d62e22017-04-02 23:53:04 -07002523 ++num_frames_dropped;
2524 } else {
Åsa Perssonc74d8da2017-12-04 14:13:56 +01002525 sink_.CheckLastFrameSizeMatches(kFrameWidth, kFrameHeight);
sprangc5d62e22017-04-02 23:53:04 -07002526 }
2527 }
2528 EXPECT_NEAR(num_frames_dropped, 0, kErrorMargin);
2529
mflodmancc3d4422017-08-03 08:27:51 -07002530 video_stream_encoder_->Stop();
sprangc5d62e22017-04-02 23:53:04 -07002531}
2532
mflodmancc3d4422017-08-03 08:27:51 -07002533TEST_F(VideoStreamEncoderTest, DoesntAdaptDownPastMinFramerate) {
sprangc5d62e22017-04-02 23:53:04 -07002534 const int kFramerateFps = 5;
2535 const int kFrameIntervalMs = rtc::kNumMillisecsPerSec / kFramerateFps;
sprangc5d62e22017-04-02 23:53:04 -07002536 const int kFrameWidth = 1280;
2537 const int kFrameHeight = 720;
2538
sprang4847ae62017-06-27 07:06:52 -07002539 // Reconfigure encoder with two temporal layers and screensharing, which will
2540 // disable frame dropping and make testing easier.
Niels Möllerf1338562018-04-26 09:51:47 +02002541 ResetEncoder("VP8", 1, 2, 1, true);
sprang4847ae62017-06-27 07:06:52 -07002542
mflodmancc3d4422017-08-03 08:27:51 -07002543 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
2544 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002545 &video_source_, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
sprangc5d62e22017-04-02 23:53:04 -07002546 video_source_.set_adaptation_enabled(true);
2547
sprang4847ae62017-06-27 07:06:52 -07002548 int64_t timestamp_ms = fake_clock_.TimeNanos() / rtc::kNumNanosecsPerMillisec;
sprangc5d62e22017-04-02 23:53:04 -07002549
2550 // Trigger overuse as much as we can.
Jonathan Yubc771b72017-12-08 17:04:29 -08002551 rtc::VideoSinkWants last_wants;
2552 do {
2553 last_wants = video_source_.sink_wants();
2554
sprangc5d62e22017-04-02 23:53:04 -07002555 // Insert frames to get a new fps estimate...
2556 for (int j = 0; j < kFramerateFps; ++j) {
2557 video_source_.IncomingCapturedFrame(
2558 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
Jonathan Yubc771b72017-12-08 17:04:29 -08002559 if (video_source_.last_sent_width()) {
2560 sink_.WaitForEncodedFrame(timestamp_ms);
2561 }
sprangc5d62e22017-04-02 23:53:04 -07002562 timestamp_ms += kFrameIntervalMs;
Jonathan Yubc771b72017-12-08 17:04:29 -08002563 fake_clock_.AdvanceTimeMicros(
2564 kFrameIntervalMs * rtc::kNumMicrosecsPerMillisec);
sprangc5d62e22017-04-02 23:53:04 -07002565 }
2566 // ...and then try to adapt again.
mflodmancc3d4422017-08-03 08:27:51 -07002567 video_stream_encoder_->TriggerCpuOveruse();
Jonathan Yubc771b72017-12-08 17:04:29 -08002568 } while (video_source_.sink_wants().max_framerate_fps <
2569 last_wants.max_framerate_fps);
sprangc5d62e22017-04-02 23:53:04 -07002570
Jonathan Yubc771b72017-12-08 17:04:29 -08002571 VerifyFpsEqResolutionMax(video_source_.sink_wants(), kMinFramerateFps);
asaperssonf7e294d2017-06-13 23:25:22 -07002572
mflodmancc3d4422017-08-03 08:27:51 -07002573 video_stream_encoder_->Stop();
sprangc5d62e22017-04-02 23:53:04 -07002574}
asaperssonf7e294d2017-06-13 23:25:22 -07002575
mflodmancc3d4422017-08-03 08:27:51 -07002576TEST_F(VideoStreamEncoderTest,
2577 AdaptsResolutionAndFramerateForLowQuality_BalancedMode) {
asaperssonf7e294d2017-06-13 23:25:22 -07002578 const int kWidth = 1280;
2579 const int kHeight = 720;
2580 const int64_t kFrameIntervalMs = 150;
2581 int64_t timestamp_ms = kFrameIntervalMs;
mflodmancc3d4422017-08-03 08:27:51 -07002582 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -07002583
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002584 // Enable BALANCED preference, no initial limitation.
asaperssonf7e294d2017-06-13 23:25:22 -07002585 AdaptingFrameForwarder source;
2586 source.set_adaptation_enabled(true);
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002587 video_stream_encoder_->SetSource(&source,
2588 webrtc::DegradationPreference::BALANCED);
asaperssonf7e294d2017-06-13 23:25:22 -07002589 timestamp_ms += kFrameIntervalMs;
2590 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002591 WaitForEncodedFrame(kWidth, kHeight);
asaperssonf7e294d2017-06-13 23:25:22 -07002592 VerifyNoLimitation(source.sink_wants());
2593 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2594 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2595 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2596
2597 // Trigger adapt down, expect scaled down resolution (960x540@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002598 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002599 timestamp_ms += kFrameIntervalMs;
2600 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002601 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002602 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
2603 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2604 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2605 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2606
2607 // Trigger adapt down, expect scaled down resolution (640x360@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002608 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002609 timestamp_ms += kFrameIntervalMs;
2610 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002611 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002612 VerifyFpsMaxResolutionLt(source.sink_wants(), source.last_wants());
2613 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2614 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2615 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2616
2617 // Trigger adapt down, expect reduced fps (640x360@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07002618 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002619 timestamp_ms += kFrameIntervalMs;
2620 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002621 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002622 VerifyFpsLtResolutionEq(source.sink_wants(), source.last_wants());
2623 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2624 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2625 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2626
2627 // Trigger adapt down, expect scaled down resolution (480x270@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07002628 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002629 timestamp_ms += kFrameIntervalMs;
2630 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002631 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002632 VerifyFpsEqResolutionLt(source.sink_wants(), source.last_wants());
2633 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2634 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2635 EXPECT_EQ(4, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2636
2637 // Restrict bitrate, trigger adapt down, expect reduced fps (480x270@10fps).
mflodmancc3d4422017-08-03 08:27:51 -07002638 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002639 timestamp_ms += kFrameIntervalMs;
2640 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002641 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002642 VerifyFpsLtResolutionEq(source.sink_wants(), source.last_wants());
2643 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2644 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2645 EXPECT_EQ(5, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2646
2647 // Trigger adapt down, expect scaled down resolution (320x180@10fps).
mflodmancc3d4422017-08-03 08:27:51 -07002648 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002649 timestamp_ms += kFrameIntervalMs;
2650 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002651 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002652 VerifyFpsEqResolutionLt(source.sink_wants(), source.last_wants());
2653 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2654 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2655 EXPECT_EQ(6, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2656
2657 // Trigger adapt down, expect reduced fps (320x180@7fps).
mflodmancc3d4422017-08-03 08:27:51 -07002658 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002659 timestamp_ms += kFrameIntervalMs;
2660 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002661 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002662 VerifyFpsLtResolutionEq(source.sink_wants(), source.last_wants());
2663 rtc::VideoSinkWants last_wants = source.sink_wants();
2664 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2665 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2666 EXPECT_EQ(7, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2667
2668 // Trigger adapt down, min resolution reached, expect no change.
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 VerifyFpsEqResolutionEq(source.sink_wants(), last_wants);
2674 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2675 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2676 EXPECT_EQ(7, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2677
2678 // Trigger adapt down, expect expect increased fps (320x180@10fps).
mflodmancc3d4422017-08-03 08:27:51 -07002679 video_stream_encoder_->TriggerQualityHigh();
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 VerifyFpsGtResolutionEq(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(8, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2687
2688 // Trigger adapt up, expect upscaled resolution (480x270@10fps).
mflodmancc3d4422017-08-03 08:27:51 -07002689 video_stream_encoder_->TriggerQualityHigh();
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 VerifyFpsEqResolutionGt(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(9, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2697
2698 // Increase bitrate, trigger adapt up, expect increased fps (480x270@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07002699 video_stream_encoder_->TriggerQualityHigh();
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 VerifyFpsGtResolutionEq(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(10, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2707
2708 // Trigger adapt up, expect upscaled resolution (640x360@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07002709 video_stream_encoder_->TriggerQualityHigh();
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 VerifyFpsEqResolutionGt(source.sink_wants(), source.last_wants());
2714 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2715 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2716 EXPECT_EQ(11, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2717
2718 // Trigger adapt up, expect increased fps (640x360@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002719 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002720 timestamp_ms += kFrameIntervalMs;
2721 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002722 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002723 VerifyFpsMaxResolutionEq(source.sink_wants(), source.last_wants());
2724 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2725 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2726 EXPECT_EQ(12, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2727
2728 // Trigger adapt up, expect upscaled resolution (960x540@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002729 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002730 timestamp_ms += kFrameIntervalMs;
2731 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002732 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002733 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
2734 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2735 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2736 EXPECT_EQ(13, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2737
2738 // Trigger adapt up, expect no restriction (1280x720fps@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002739 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002740 timestamp_ms += kFrameIntervalMs;
2741 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002742 WaitForEncodedFrame(kWidth, kHeight);
asaperssonf7e294d2017-06-13 23:25:22 -07002743 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
2744 VerifyNoLimitation(source.sink_wants());
2745 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2746 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2747 EXPECT_EQ(14, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2748
2749 // Trigger adapt up, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07002750 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002751 VerifyNoLimitation(source.sink_wants());
2752 EXPECT_EQ(14, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2753
mflodmancc3d4422017-08-03 08:27:51 -07002754 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07002755}
2756
mflodmancc3d4422017-08-03 08:27:51 -07002757TEST_F(VideoStreamEncoderTest, AdaptWithTwoReasonsAndDifferentOrder_Framerate) {
asaperssonf7e294d2017-06-13 23:25:22 -07002758 const int kWidth = 1280;
2759 const int kHeight = 720;
2760 const int64_t kFrameIntervalMs = 150;
2761 int64_t timestamp_ms = kFrameIntervalMs;
mflodmancc3d4422017-08-03 08:27:51 -07002762 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -07002763
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002764 // Enable BALANCED preference, no initial limitation.
asaperssonf7e294d2017-06-13 23:25:22 -07002765 AdaptingFrameForwarder source;
2766 source.set_adaptation_enabled(true);
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002767 video_stream_encoder_->SetSource(&source,
2768 webrtc::DegradationPreference::BALANCED);
asaperssonf7e294d2017-06-13 23:25:22 -07002769 timestamp_ms += kFrameIntervalMs;
2770 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002771 WaitForEncodedFrame(kWidth, kHeight);
asaperssonf7e294d2017-06-13 23:25:22 -07002772 VerifyNoLimitation(source.sink_wants());
2773 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2774 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2775 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2776 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
2777 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2778 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2779
2780 // Trigger cpu adapt down, expect scaled down resolution (960x540@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002781 video_stream_encoder_->TriggerCpuOveruse();
asaperssonf7e294d2017-06-13 23:25:22 -07002782 timestamp_ms += kFrameIntervalMs;
2783 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002784 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002785 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
2786 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2787 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2788 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2789 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
2790 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2791 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2792
2793 // Trigger cpu adapt down, expect scaled down resolution (640x360@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002794 video_stream_encoder_->TriggerCpuOveruse();
asaperssonf7e294d2017-06-13 23:25:22 -07002795 timestamp_ms += kFrameIntervalMs;
2796 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002797 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002798 VerifyFpsMaxResolutionLt(source.sink_wants(), source.last_wants());
2799 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2800 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2801 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2802 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
2803 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2804 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2805
2806 // Trigger quality adapt down, expect reduced fps (640x360@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07002807 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002808 timestamp_ms += kFrameIntervalMs;
2809 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002810 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002811 VerifyFpsLtResolutionEq(source.sink_wants(), source.last_wants());
2812 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2813 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2814 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2815 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
2816 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2817 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2818
2819 // Trigger cpu adapt up, expect increased fps (640x360@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002820 video_stream_encoder_->TriggerCpuNormalUsage();
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(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002824 VerifyFpsMaxResolutionEq(source.sink_wants(), source.last_wants());
2825 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2826 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2827 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2828 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
2829 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2830 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2831
2832 // Trigger quality adapt up, expect upscaled resolution (960x540@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002833 video_stream_encoder_->TriggerQualityHigh();
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 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
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(3, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2843 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2844
2845 // Trigger cpu adapt up, expect no restriction (1280x720fps@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002846 video_stream_encoder_->TriggerCpuNormalUsage();
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(kWidth, kHeight);
asaperssonf7e294d2017-06-13 23:25:22 -07002850 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
2851 VerifyNoLimitation(source.sink_wants());
2852 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2853 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2854 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2855 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
2856 EXPECT_EQ(4, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2857 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2858
2859 // Trigger adapt up, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07002860 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002861 VerifyNoLimitation(source.sink_wants());
2862 EXPECT_EQ(4, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2863 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2864
mflodmancc3d4422017-08-03 08:27:51 -07002865 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07002866}
2867
mflodmancc3d4422017-08-03 08:27:51 -07002868TEST_F(VideoStreamEncoderTest,
2869 AdaptWithTwoReasonsAndDifferentOrder_Resolution) {
asaperssonf7e294d2017-06-13 23:25:22 -07002870 const int kWidth = 640;
2871 const int kHeight = 360;
2872 const int kFpsLimit = 15;
2873 const int64_t kFrameIntervalMs = 150;
2874 int64_t timestamp_ms = kFrameIntervalMs;
mflodmancc3d4422017-08-03 08:27:51 -07002875 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -07002876
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002877 // Enable BALANCED preference, no initial limitation.
asaperssonf7e294d2017-06-13 23:25:22 -07002878 AdaptingFrameForwarder source;
2879 source.set_adaptation_enabled(true);
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002880 video_stream_encoder_->SetSource(&source,
2881 webrtc::DegradationPreference::BALANCED);
asaperssonf7e294d2017-06-13 23:25:22 -07002882 timestamp_ms += kFrameIntervalMs;
2883 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002884 WaitForEncodedFrame(kWidth, kHeight);
asaperssonf7e294d2017-06-13 23:25:22 -07002885 VerifyNoLimitation(source.sink_wants());
2886 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2887 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2888 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2889 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
2890 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2891 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2892
2893 // Trigger cpu adapt down, expect scaled down framerate (640x360@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07002894 video_stream_encoder_->TriggerCpuOveruse();
asaperssonf7e294d2017-06-13 23:25:22 -07002895 timestamp_ms += kFrameIntervalMs;
2896 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002897 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002898 VerifyFpsEqResolutionMax(source.sink_wants(), kFpsLimit);
2899 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2900 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2901 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2902 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_framerate);
2903 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2904 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2905
2906 // Trigger quality adapt down, expect scaled down resolution (480x270@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07002907 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002908 timestamp_ms += kFrameIntervalMs;
2909 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002910 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002911 VerifyFpsEqResolutionLt(source.sink_wants(), source.last_wants());
2912 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2913 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2914 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2915 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_framerate);
2916 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2917 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2918
2919 // Trigger cpu adapt up, expect upscaled resolution (640x360@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07002920 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssonf7e294d2017-06-13 23:25:22 -07002921 timestamp_ms += kFrameIntervalMs;
2922 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002923 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002924 VerifyFpsEqResolutionGt(source.sink_wants(), source.last_wants());
2925 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2926 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2927 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2928 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
2929 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2930 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2931
2932 // Trigger quality adapt up, expect increased fps (640x360@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002933 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002934 timestamp_ms += kFrameIntervalMs;
2935 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002936 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002937 VerifyNoLimitation(source.sink_wants());
2938 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2939 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2940 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2941 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
2942 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2943 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2944
2945 // Trigger adapt up, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07002946 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002947 VerifyNoLimitation(source.sink_wants());
2948 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2949 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2950
mflodmancc3d4422017-08-03 08:27:51 -07002951 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07002952}
2953
mflodmancc3d4422017-08-03 08:27:51 -07002954TEST_F(VideoStreamEncoderTest, AcceptsFullHdAdaptedDownSimulcastFrames) {
ilnik6b826ef2017-06-16 06:53:48 -07002955 // Simulates simulcast behavior and makes highest stream resolutions divisible
2956 // by 4.
2957 class CroppingVideoStreamFactory
2958 : public VideoEncoderConfig::VideoStreamFactoryInterface {
2959 public:
2960 explicit CroppingVideoStreamFactory(size_t num_temporal_layers,
2961 int framerate)
2962 : num_temporal_layers_(num_temporal_layers), framerate_(framerate) {
2963 EXPECT_GT(num_temporal_layers, 0u);
2964 EXPECT_GT(framerate, 0);
2965 }
2966
2967 private:
2968 std::vector<VideoStream> CreateEncoderStreams(
2969 int width,
2970 int height,
2971 const VideoEncoderConfig& encoder_config) override {
2972 std::vector<VideoStream> streams =
2973 test::CreateVideoStreams(width - width % 4, height - height % 4,
2974 encoder_config);
2975 for (VideoStream& stream : streams) {
Sergey Silkina796a7e2018-03-01 15:11:29 +01002976 stream.num_temporal_layers = num_temporal_layers_;
ilnik6b826ef2017-06-16 06:53:48 -07002977 stream.max_framerate = framerate_;
2978 }
2979 return streams;
2980 }
2981
2982 const size_t num_temporal_layers_;
2983 const int framerate_;
2984 };
2985
2986 const int kFrameWidth = 1920;
2987 const int kFrameHeight = 1080;
2988 // 3/4 of 1920.
2989 const int kAdaptedFrameWidth = 1440;
2990 // 3/4 of 1080 rounded down to multiple of 4.
2991 const int kAdaptedFrameHeight = 808;
2992 const int kFramerate = 24;
2993
mflodmancc3d4422017-08-03 08:27:51 -07002994 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
ilnik6b826ef2017-06-16 06:53:48 -07002995 // Trigger reconfigure encoder (without resetting the entire instance).
2996 VideoEncoderConfig video_encoder_config;
Niels Möller259a4972018-04-05 15:36:51 +02002997 video_encoder_config.codec_type = kVideoCodecVP8;
ilnik6b826ef2017-06-16 06:53:48 -07002998 video_encoder_config.max_bitrate_bps = kTargetBitrateBps;
2999 video_encoder_config.number_of_streams = 1;
3000 video_encoder_config.video_stream_factory =
3001 new rtc::RefCountedObject<CroppingVideoStreamFactory>(1, kFramerate);
mflodmancc3d4422017-08-03 08:27:51 -07003002 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
Niels Möllerf1338562018-04-26 09:51:47 +02003003 kMaxPayloadLength);
mflodmancc3d4422017-08-03 08:27:51 -07003004 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
ilnik6b826ef2017-06-16 06:53:48 -07003005
3006 video_source_.set_adaptation_enabled(true);
3007
3008 video_source_.IncomingCapturedFrame(
3009 CreateFrame(1, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07003010 WaitForEncodedFrame(kFrameWidth, kFrameHeight);
ilnik6b826ef2017-06-16 06:53:48 -07003011
3012 // Trigger CPU overuse, downscale by 3/4.
mflodmancc3d4422017-08-03 08:27:51 -07003013 video_stream_encoder_->TriggerCpuOveruse();
ilnik6b826ef2017-06-16 06:53:48 -07003014 video_source_.IncomingCapturedFrame(
3015 CreateFrame(2, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07003016 WaitForEncodedFrame(kAdaptedFrameWidth, kAdaptedFrameHeight);
ilnik6b826ef2017-06-16 06:53:48 -07003017
mflodmancc3d4422017-08-03 08:27:51 -07003018 video_stream_encoder_->Stop();
ilnik6b826ef2017-06-16 06:53:48 -07003019}
3020
mflodmancc3d4422017-08-03 08:27:51 -07003021TEST_F(VideoStreamEncoderTest, PeriodicallyUpdatesChannelParameters) {
sprang4847ae62017-06-27 07:06:52 -07003022 const int kFrameWidth = 1280;
3023 const int kFrameHeight = 720;
3024 const int kLowFps = 2;
3025 const int kHighFps = 30;
3026
mflodmancc3d4422017-08-03 08:27:51 -07003027 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
sprang4847ae62017-06-27 07:06:52 -07003028
3029 int64_t timestamp_ms = fake_clock_.TimeNanos() / rtc::kNumNanosecsPerMillisec;
3030 max_framerate_ = kLowFps;
3031
3032 // Insert 2 seconds of 2fps video.
3033 for (int i = 0; i < kLowFps * 2; ++i) {
3034 video_source_.IncomingCapturedFrame(
3035 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
3036 WaitForEncodedFrame(timestamp_ms);
3037 timestamp_ms += 1000 / kLowFps;
3038 }
3039
3040 // Make sure encoder is updated with new target.
mflodmancc3d4422017-08-03 08:27:51 -07003041 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
sprang4847ae62017-06-27 07:06:52 -07003042 video_source_.IncomingCapturedFrame(
3043 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
3044 WaitForEncodedFrame(timestamp_ms);
3045 timestamp_ms += 1000 / kLowFps;
3046
3047 EXPECT_EQ(kLowFps, fake_encoder_.GetConfiguredInputFramerate());
3048
3049 // Insert 30fps frames for just a little more than the forced update period.
3050 const int kVcmTimerIntervalFrames =
3051 (vcm::VCMProcessTimer::kDefaultProcessIntervalMs * kHighFps) / 1000;
3052 const int kFrameIntervalMs = 1000 / kHighFps;
3053 max_framerate_ = kHighFps;
3054 for (int i = 0; i < kVcmTimerIntervalFrames + 2; ++i) {
3055 video_source_.IncomingCapturedFrame(
3056 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
3057 // Wait for encoded frame, but skip ahead if it doesn't arrive as it might
3058 // be dropped if the encoder hans't been updated with the new higher target
3059 // framerate yet, causing it to overshoot the target bitrate and then
3060 // suffering the wrath of the media optimizer.
3061 TimedWaitForEncodedFrame(timestamp_ms, 2 * kFrameIntervalMs);
3062 timestamp_ms += kFrameIntervalMs;
3063 }
3064
3065 // Don expect correct measurement just yet, but it should be higher than
3066 // before.
3067 EXPECT_GT(fake_encoder_.GetConfiguredInputFramerate(), kLowFps);
3068
mflodmancc3d4422017-08-03 08:27:51 -07003069 video_stream_encoder_->Stop();
sprang4847ae62017-06-27 07:06:52 -07003070}
3071
mflodmancc3d4422017-08-03 08:27:51 -07003072TEST_F(VideoStreamEncoderTest, DoesNotUpdateBitrateAllocationWhenSuspended) {
sprang4847ae62017-06-27 07:06:52 -07003073 const int kFrameWidth = 1280;
3074 const int kFrameHeight = 720;
3075 const int kTargetBitrateBps = 1000000;
3076
3077 MockBitrateObserver bitrate_observer;
Niels Möller0327c2d2018-05-21 14:09:31 +02003078 video_stream_encoder_->SetBitrateAllocationObserver(&bitrate_observer);
sprang4847ae62017-06-27 07:06:52 -07003079
3080 EXPECT_CALL(bitrate_observer, OnBitrateAllocationUpdated(_)).Times(1);
3081 // Initial bitrate update.
mflodmancc3d4422017-08-03 08:27:51 -07003082 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
3083 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
sprang4847ae62017-06-27 07:06:52 -07003084
3085 // Insert a first video frame, causes another bitrate update.
3086 int64_t timestamp_ms = fake_clock_.TimeNanos() / rtc::kNumNanosecsPerMillisec;
3087 EXPECT_CALL(bitrate_observer, OnBitrateAllocationUpdated(_)).Times(1);
3088 video_source_.IncomingCapturedFrame(
3089 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
3090 WaitForEncodedFrame(timestamp_ms);
3091
3092 // Next, simulate video suspension due to pacer queue overrun.
mflodmancc3d4422017-08-03 08:27:51 -07003093 video_stream_encoder_->OnBitrateUpdated(0, 0, 1);
sprang4847ae62017-06-27 07:06:52 -07003094
3095 // Skip ahead until a new periodic parameter update should have occured.
3096 timestamp_ms += vcm::VCMProcessTimer::kDefaultProcessIntervalMs;
3097 fake_clock_.AdvanceTimeMicros(
3098 vcm::VCMProcessTimer::kDefaultProcessIntervalMs *
3099 rtc::kNumMicrosecsPerMillisec);
3100
3101 // Bitrate observer should not be called.
3102 EXPECT_CALL(bitrate_observer, OnBitrateAllocationUpdated(_)).Times(0);
3103 video_source_.IncomingCapturedFrame(
3104 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
3105 ExpectDroppedFrame();
3106
mflodmancc3d4422017-08-03 08:27:51 -07003107 video_stream_encoder_->Stop();
sprang4847ae62017-06-27 07:06:52 -07003108}
ilnik6b826ef2017-06-16 06:53:48 -07003109
Niels Möller4db138e2018-04-19 09:04:13 +02003110TEST_F(VideoStreamEncoderTest,
3111 DefaultCpuAdaptationThresholdsForSoftwareEncoder) {
3112 const int kFrameWidth = 1280;
3113 const int kFrameHeight = 720;
3114 const CpuOveruseOptions default_options;
3115 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
3116 video_source_.IncomingCapturedFrame(
3117 CreateFrame(1, kFrameWidth, kFrameHeight));
3118 WaitForEncodedFrame(1);
3119 EXPECT_EQ(video_stream_encoder_->overuse_detector_proxy_->GetOptions()
3120 .low_encode_usage_threshold_percent,
3121 default_options.low_encode_usage_threshold_percent);
3122 EXPECT_EQ(video_stream_encoder_->overuse_detector_proxy_->GetOptions()
3123 .high_encode_usage_threshold_percent,
3124 default_options.high_encode_usage_threshold_percent);
3125 video_stream_encoder_->Stop();
3126}
3127
3128TEST_F(VideoStreamEncoderTest,
3129 HigherCpuAdaptationThresholdsForHardwareEncoder) {
3130 const int kFrameWidth = 1280;
3131 const int kFrameHeight = 720;
3132 CpuOveruseOptions hardware_options;
3133 hardware_options.low_encode_usage_threshold_percent = 150;
3134 hardware_options.high_encode_usage_threshold_percent = 200;
3135 encoder_factory_.SetIsHardwareAccelerated(true);
3136
3137 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
3138 video_source_.IncomingCapturedFrame(
3139 CreateFrame(1, kFrameWidth, kFrameHeight));
3140 WaitForEncodedFrame(1);
3141 EXPECT_EQ(video_stream_encoder_->overuse_detector_proxy_->GetOptions()
3142 .low_encode_usage_threshold_percent,
3143 hardware_options.low_encode_usage_threshold_percent);
3144 EXPECT_EQ(video_stream_encoder_->overuse_detector_proxy_->GetOptions()
3145 .high_encode_usage_threshold_percent,
3146 hardware_options.high_encode_usage_threshold_percent);
3147 video_stream_encoder_->Stop();
3148}
3149
perkj26091b12016-09-01 01:17:40 -07003150} // namespace webrtc