blob: b97d2cf6216c158eebf2456194d0dc9f97a0549d [file] [log] [blame]
perkj26091b12016-09-01 01:17:40 -07001/*
2 * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved.
3 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
sprangfe627f32017-03-29 08:24:59 -070011#include <algorithm>
perkj803d97f2016-11-01 11:45:46 -070012#include <limits>
Per512ecb32016-09-23 15:52:06 +020013#include <utility>
14
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020015#include "api/video/i420_buffer.h"
16#include "media/base/videoadapter.h"
17#include "modules/video_coding/codecs/vp8/temporal_layers.h"
Sergey Silkin86684962018-03-28 19:32:37 +020018#include "modules/video_coding/codecs/vp9/include/vp9_globals.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020019#include "modules/video_coding/utility/default_video_bitrate_allocator.h"
20#include "rtc_base/fakeclock.h"
21#include "rtc_base/logging.h"
Stefan Holmerdbdb3a02018-07-17 16:03:46 +020022#include "rtc_base/refcountedobject.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020023#include "system_wrappers/include/metrics_default.h"
24#include "system_wrappers/include/sleep.h"
Niels Möller4db138e2018-04-19 09:04:13 +020025#include "test/encoder_proxy_factory.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020026#include "test/encoder_settings.h"
27#include "test/fake_encoder.h"
Kári Tristan Helgason639602a2018-08-02 10:51:40 +020028#include "test/field_trial.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020029#include "test/frame_generator.h"
30#include "test/gmock.h"
31#include "test/gtest.h"
32#include "video/send_statistics_proxy.h"
33#include "video/video_stream_encoder.h"
perkj26091b12016-09-01 01:17:40 -070034
35namespace webrtc {
36
sprangb1ca0732017-02-01 08:38:12 -080037using ScaleReason = AdaptationObserverInterface::AdaptReason;
sprang57c2fff2017-01-16 06:24:02 -080038using ::testing::_;
39using ::testing::Return;
kthelgason876222f2016-11-29 01:44:11 -080040
perkj803d97f2016-11-01 11:45:46 -070041namespace {
Åsa Persson8c1bf952018-09-13 10:42:19 +020042const int kMinPixelsPerFrame = 320 * 180;
43const int kMinFramerateFps = 2;
44const int kMinBalancedFramerateFps = 7;
45const int64_t kFrameTimeoutMs = 100;
asapersson5f7226f2016-11-25 04:37:00 -080046const size_t kMaxPayloadLength = 1440;
kthelgason2bc68642017-02-07 07:02:22 -080047const int kTargetBitrateBps = 1000000;
48const int kLowTargetBitrateBps = kTargetBitrateBps / 10;
49const int kMaxInitialFramedrop = 4;
sprangfda496a2017-06-15 04:21:07 -070050const int kDefaultFramerate = 30;
Åsa Persson8c1bf952018-09-13 10:42:19 +020051const int64_t kFrameIntervalMs = rtc::kNumMillisecsPerSec / kDefaultFramerate;
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öller213618e2018-07-24 09:29:58 +020094 VideoStreamEncoderUnderTest(SendStatisticsProxy* stats_proxy,
95 const VideoStreamEncoderSettings& settings)
Yves Gerey665174f2018-06-19 15:03:05 +020096 : VideoStreamEncoder(1 /* number_of_cores */,
97 stats_proxy,
98 settings,
99 nullptr /* pre_encode_callback */,
100 std::unique_ptr<OveruseFrameDetector>(
101 overuse_detector_proxy_ =
102 new CpuOveruseDetectorProxy(stats_proxy))) {}
perkj803d97f2016-11-01 11:45:46 -0700103
sprangb1ca0732017-02-01 08:38:12 -0800104 void PostTaskAndWait(bool down, AdaptReason reason) {
perkj803d97f2016-11-01 11:45:46 -0700105 rtc::Event event(false, false);
kthelgason876222f2016-11-29 01:44:11 -0800106 encoder_queue()->PostTask([this, &event, reason, down] {
sprangb1ca0732017-02-01 08:38:12 -0800107 down ? AdaptDown(reason) : AdaptUp(reason);
perkj803d97f2016-11-01 11:45:46 -0700108 event.Set();
109 });
perkj070ba852017-02-16 15:46:27 -0800110 ASSERT_TRUE(event.Wait(5000));
perkj803d97f2016-11-01 11:45:46 -0700111 }
112
kthelgason2fc52542017-03-03 00:24:41 -0800113 // This is used as a synchronisation mechanism, to make sure that the
114 // encoder queue is not blocked before we start sending it frames.
115 void WaitUntilTaskQueueIsIdle() {
116 rtc::Event event(false, false);
Yves Gerey665174f2018-06-19 15:03:05 +0200117 encoder_queue()->PostTask([&event] { event.Set(); });
kthelgason2fc52542017-03-03 00:24:41 -0800118 ASSERT_TRUE(event.Wait(5000));
119 }
120
sprangb1ca0732017-02-01 08:38:12 -0800121 void TriggerCpuOveruse() { PostTaskAndWait(true, AdaptReason::kCpu); }
kthelgason876222f2016-11-29 01:44:11 -0800122
sprangb1ca0732017-02-01 08:38:12 -0800123 void TriggerCpuNormalUsage() { PostTaskAndWait(false, AdaptReason::kCpu); }
kthelgason876222f2016-11-29 01:44:11 -0800124
sprangb1ca0732017-02-01 08:38:12 -0800125 void TriggerQualityLow() { PostTaskAndWait(true, AdaptReason::kQuality); }
kthelgason876222f2016-11-29 01:44:11 -0800126
sprangb1ca0732017-02-01 08:38:12 -0800127 void TriggerQualityHigh() { PostTaskAndWait(false, AdaptReason::kQuality); }
sprangfda496a2017-06-15 04:21:07 -0700128
Niels Möller7dc26b72017-12-06 10:27:48 +0100129 CpuOveruseDetectorProxy* overuse_detector_proxy_;
perkj803d97f2016-11-01 11:45:46 -0700130};
131
asapersson5f7226f2016-11-25 04:37:00 -0800132class VideoStreamFactory
133 : public VideoEncoderConfig::VideoStreamFactoryInterface {
134 public:
sprangfda496a2017-06-15 04:21:07 -0700135 explicit VideoStreamFactory(size_t num_temporal_layers, int framerate)
136 : num_temporal_layers_(num_temporal_layers), framerate_(framerate) {
asapersson5f7226f2016-11-25 04:37:00 -0800137 EXPECT_GT(num_temporal_layers, 0u);
sprangfda496a2017-06-15 04:21:07 -0700138 EXPECT_GT(framerate, 0);
asapersson5f7226f2016-11-25 04:37:00 -0800139 }
140
141 private:
142 std::vector<VideoStream> CreateEncoderStreams(
143 int width,
144 int height,
145 const VideoEncoderConfig& encoder_config) override {
146 std::vector<VideoStream> streams =
147 test::CreateVideoStreams(width, height, encoder_config);
148 for (VideoStream& stream : streams) {
Sergey Silkina796a7e2018-03-01 15:11:29 +0100149 stream.num_temporal_layers = num_temporal_layers_;
sprangfda496a2017-06-15 04:21:07 -0700150 stream.max_framerate = framerate_;
asapersson5f7226f2016-11-25 04:37:00 -0800151 }
152 return streams;
153 }
sprangfda496a2017-06-15 04:21:07 -0700154
asapersson5f7226f2016-11-25 04:37:00 -0800155 const size_t num_temporal_layers_;
sprangfda496a2017-06-15 04:21:07 -0700156 const int framerate_;
asapersson5f7226f2016-11-25 04:37:00 -0800157};
158
sprangb1ca0732017-02-01 08:38:12 -0800159class AdaptingFrameForwarder : public test::FrameForwarder {
160 public:
161 AdaptingFrameForwarder() : adaptation_enabled_(false) {}
asaperssonfab67072017-04-04 05:51:49 -0700162 ~AdaptingFrameForwarder() override {}
sprangb1ca0732017-02-01 08:38:12 -0800163
164 void set_adaptation_enabled(bool enabled) {
165 rtc::CritScope cs(&crit_);
166 adaptation_enabled_ = enabled;
167 }
168
asaperssonfab67072017-04-04 05:51:49 -0700169 bool adaption_enabled() const {
sprangb1ca0732017-02-01 08:38:12 -0800170 rtc::CritScope cs(&crit_);
171 return adaptation_enabled_;
172 }
173
asapersson09f05612017-05-15 23:40:18 -0700174 rtc::VideoSinkWants last_wants() const {
175 rtc::CritScope cs(&crit_);
176 return last_wants_;
177 }
178
Danil Chapovalovb9b146c2018-06-15 12:28:07 +0200179 absl::optional<int> last_sent_width() const { return last_width_; }
180 absl::optional<int> last_sent_height() const { return last_height_; }
Jonathan Yubc771b72017-12-08 17:04:29 -0800181
sprangb1ca0732017-02-01 08:38:12 -0800182 void IncomingCapturedFrame(const VideoFrame& video_frame) override {
183 int cropped_width = 0;
184 int cropped_height = 0;
185 int out_width = 0;
186 int out_height = 0;
sprangc5d62e22017-04-02 23:53:04 -0700187 if (adaption_enabled()) {
188 if (adapter_.AdaptFrameResolution(
189 video_frame.width(), video_frame.height(),
190 video_frame.timestamp_us() * 1000, &cropped_width,
191 &cropped_height, &out_width, &out_height)) {
192 VideoFrame adapted_frame(new rtc::RefCountedObject<TestBuffer>(
193 nullptr, out_width, out_height),
194 99, 99, kVideoRotation_0);
195 adapted_frame.set_ntp_time_ms(video_frame.ntp_time_ms());
196 test::FrameForwarder::IncomingCapturedFrame(adapted_frame);
Jonathan Yubc771b72017-12-08 17:04:29 -0800197 last_width_.emplace(adapted_frame.width());
198 last_height_.emplace(adapted_frame.height());
199 } else {
Danil Chapovalovb9b146c2018-06-15 12:28:07 +0200200 last_width_ = absl::nullopt;
201 last_height_ = absl::nullopt;
sprangc5d62e22017-04-02 23:53:04 -0700202 }
sprangb1ca0732017-02-01 08:38:12 -0800203 } else {
204 test::FrameForwarder::IncomingCapturedFrame(video_frame);
Jonathan Yubc771b72017-12-08 17:04:29 -0800205 last_width_.emplace(video_frame.width());
206 last_height_.emplace(video_frame.height());
sprangb1ca0732017-02-01 08:38:12 -0800207 }
208 }
209
210 void AddOrUpdateSink(rtc::VideoSinkInterface<VideoFrame>* sink,
211 const rtc::VideoSinkWants& wants) override {
212 rtc::CritScope cs(&crit_);
asapersson09f05612017-05-15 23:40:18 -0700213 last_wants_ = sink_wants();
sprangc5d62e22017-04-02 23:53:04 -0700214 adapter_.OnResolutionFramerateRequest(wants.target_pixel_count,
215 wants.max_pixel_count,
216 wants.max_framerate_fps);
sprangb1ca0732017-02-01 08:38:12 -0800217 test::FrameForwarder::AddOrUpdateSink(sink, wants);
218 }
sprangb1ca0732017-02-01 08:38:12 -0800219 cricket::VideoAdapter adapter_;
danilchapa37de392017-09-09 04:17:22 -0700220 bool adaptation_enabled_ RTC_GUARDED_BY(crit_);
221 rtc::VideoSinkWants last_wants_ RTC_GUARDED_BY(crit_);
Danil Chapovalovb9b146c2018-06-15 12:28:07 +0200222 absl::optional<int> last_width_;
223 absl::optional<int> last_height_;
sprangb1ca0732017-02-01 08:38:12 -0800224};
sprangc5d62e22017-04-02 23:53:04 -0700225
Niels Möller213618e2018-07-24 09:29:58 +0200226// TODO(nisse): Mock only VideoStreamEncoderObserver.
sprangc5d62e22017-04-02 23:53:04 -0700227class MockableSendStatisticsProxy : public SendStatisticsProxy {
228 public:
229 MockableSendStatisticsProxy(Clock* clock,
230 const VideoSendStream::Config& config,
231 VideoEncoderConfig::ContentType content_type)
232 : SendStatisticsProxy(clock, config, content_type) {}
233
234 VideoSendStream::Stats GetStats() override {
235 rtc::CritScope cs(&lock_);
236 if (mock_stats_)
237 return *mock_stats_;
238 return SendStatisticsProxy::GetStats();
239 }
240
Niels Möller213618e2018-07-24 09:29:58 +0200241 int GetInputFrameRate() const override {
242 rtc::CritScope cs(&lock_);
243 if (mock_stats_)
244 return mock_stats_->input_frame_rate;
245 return SendStatisticsProxy::GetInputFrameRate();
246 }
sprangc5d62e22017-04-02 23:53:04 -0700247 void SetMockStats(const VideoSendStream::Stats& stats) {
248 rtc::CritScope cs(&lock_);
249 mock_stats_.emplace(stats);
250 }
251
252 void ResetMockStats() {
253 rtc::CritScope cs(&lock_);
254 mock_stats_.reset();
255 }
256
257 private:
258 rtc::CriticalSection lock_;
Danil Chapovalovb9b146c2018-06-15 12:28:07 +0200259 absl::optional<VideoSendStream::Stats> mock_stats_ RTC_GUARDED_BY(lock_);
sprangc5d62e22017-04-02 23:53:04 -0700260};
261
sprang4847ae62017-06-27 07:06:52 -0700262class MockBitrateObserver : public VideoBitrateAllocationObserver {
263 public:
Erik Språng566124a2018-04-23 12:32:22 +0200264 MOCK_METHOD1(OnBitrateAllocationUpdated, void(const VideoBitrateAllocation&));
sprang4847ae62017-06-27 07:06:52 -0700265};
266
perkj803d97f2016-11-01 11:45:46 -0700267} // namespace
268
mflodmancc3d4422017-08-03 08:27:51 -0700269class VideoStreamEncoderTest : public ::testing::Test {
perkj26091b12016-09-01 01:17:40 -0700270 public:
271 static const int kDefaultTimeoutMs = 30 * 1000;
272
mflodmancc3d4422017-08-03 08:27:51 -0700273 VideoStreamEncoderTest()
perkj26091b12016-09-01 01:17:40 -0700274 : video_send_config_(VideoSendStream::Config(nullptr)),
perkjfa10b552016-10-02 23:45:26 -0700275 codec_width_(320),
276 codec_height_(240),
Åsa Persson8c1bf952018-09-13 10:42:19 +0200277 max_framerate_(kDefaultFramerate),
perkj26091b12016-09-01 01:17:40 -0700278 fake_encoder_(),
Niels Möller4db138e2018-04-19 09:04:13 +0200279 encoder_factory_(&fake_encoder_),
sprangc5d62e22017-04-02 23:53:04 -0700280 stats_proxy_(new MockableSendStatisticsProxy(
perkj803d97f2016-11-01 11:45:46 -0700281 Clock::GetRealTimeClock(),
282 video_send_config_,
283 webrtc::VideoEncoderConfig::ContentType::kRealtimeVideo)),
perkj26091b12016-09-01 01:17:40 -0700284 sink_(&fake_encoder_) {}
285
286 void SetUp() override {
perkj803d97f2016-11-01 11:45:46 -0700287 metrics::Reset();
perkj26091b12016-09-01 01:17:40 -0700288 video_send_config_ = VideoSendStream::Config(nullptr);
Niels Möller4db138e2018-04-19 09:04:13 +0200289 video_send_config_.encoder_settings.encoder_factory = &encoder_factory_;
Niels Möller259a4972018-04-05 15:36:51 +0200290 video_send_config_.rtp.payload_name = "FAKE";
291 video_send_config_.rtp.payload_type = 125;
perkj26091b12016-09-01 01:17:40 -0700292
Per512ecb32016-09-23 15:52:06 +0200293 VideoEncoderConfig video_encoder_config;
Niels Möller259a4972018-04-05 15:36:51 +0200294 test::FillEncoderConfiguration(kVideoCodecVP8, 1, &video_encoder_config);
sprang4847ae62017-06-27 07:06:52 -0700295 video_encoder_config.video_stream_factory =
296 new rtc::RefCountedObject<VideoStreamFactory>(1, max_framerate_);
Erik Språng08127a92016-11-16 16:41:30 +0100297 video_encoder_config_ = video_encoder_config.Copy();
sprang4847ae62017-06-27 07:06:52 -0700298
299 // Framerate limit is specified by the VideoStreamFactory.
300 std::vector<VideoStream> streams =
301 video_encoder_config.video_stream_factory->CreateEncoderStreams(
302 codec_width_, codec_height_, video_encoder_config);
303 max_framerate_ = streams[0].max_framerate;
304 fake_clock_.SetTimeMicros(1234);
305
Niels Möllerf1338562018-04-26 09:51:47 +0200306 ConfigureEncoder(std::move(video_encoder_config));
asapersson5f7226f2016-11-25 04:37:00 -0800307 }
308
Niels Möllerf1338562018-04-26 09:51:47 +0200309 void ConfigureEncoder(VideoEncoderConfig video_encoder_config) {
mflodmancc3d4422017-08-03 08:27:51 -0700310 if (video_stream_encoder_)
311 video_stream_encoder_->Stop();
312 video_stream_encoder_.reset(new VideoStreamEncoderUnderTest(
perkj803d97f2016-11-01 11:45:46 -0700313 stats_proxy_.get(), video_send_config_.encoder_settings));
mflodmancc3d4422017-08-03 08:27:51 -0700314 video_stream_encoder_->SetSink(&sink_, false /* rotation_applied */);
315 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -0700316 &video_source_, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
mflodmancc3d4422017-08-03 08:27:51 -0700317 video_stream_encoder_->SetStartBitrate(kTargetBitrateBps);
318 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
Niels Möllerf1338562018-04-26 09:51:47 +0200319 kMaxPayloadLength);
mflodmancc3d4422017-08-03 08:27:51 -0700320 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
asapersson5f7226f2016-11-25 04:37:00 -0800321 }
322
323 void ResetEncoder(const std::string& payload_name,
324 size_t num_streams,
325 size_t num_temporal_layers,
emircanbbcc3562017-08-18 00:28:40 -0700326 unsigned char num_spatial_layers,
sprang4847ae62017-06-27 07:06:52 -0700327 bool screenshare) {
Niels Möller259a4972018-04-05 15:36:51 +0200328 video_send_config_.rtp.payload_name = payload_name;
asapersson5f7226f2016-11-25 04:37:00 -0800329
330 VideoEncoderConfig video_encoder_config;
Niels Möller259a4972018-04-05 15:36:51 +0200331 video_encoder_config.codec_type = PayloadStringToCodecType(payload_name);
asapersson5f7226f2016-11-25 04:37:00 -0800332 video_encoder_config.number_of_streams = num_streams;
kthelgason2bc68642017-02-07 07:02:22 -0800333 video_encoder_config.max_bitrate_bps = kTargetBitrateBps;
asapersson5f7226f2016-11-25 04:37:00 -0800334 video_encoder_config.video_stream_factory =
sprangfda496a2017-06-15 04:21:07 -0700335 new rtc::RefCountedObject<VideoStreamFactory>(num_temporal_layers,
336 kDefaultFramerate);
sprang4847ae62017-06-27 07:06:52 -0700337 video_encoder_config.content_type =
338 screenshare ? VideoEncoderConfig::ContentType::kScreen
339 : VideoEncoderConfig::ContentType::kRealtimeVideo;
emircanbbcc3562017-08-18 00:28:40 -0700340 if (payload_name == "VP9") {
341 VideoCodecVP9 vp9_settings = VideoEncoder::GetDefaultVp9Settings();
342 vp9_settings.numberOfSpatialLayers = num_spatial_layers;
343 video_encoder_config.encoder_specific_settings =
344 new rtc::RefCountedObject<
345 VideoEncoderConfig::Vp9EncoderSpecificSettings>(vp9_settings);
346 }
Niels Möllerf1338562018-04-26 09:51:47 +0200347 ConfigureEncoder(std::move(video_encoder_config));
perkj26091b12016-09-01 01:17:40 -0700348 }
349
sprang57c2fff2017-01-16 06:24:02 -0800350 VideoFrame CreateFrame(int64_t ntp_time_ms,
351 rtc::Event* destruction_event) const {
Per512ecb32016-09-23 15:52:06 +0200352 VideoFrame frame(new rtc::RefCountedObject<TestBuffer>(
353 destruction_event, codec_width_, codec_height_),
354 99, 99, kVideoRotation_0);
sprang57c2fff2017-01-16 06:24:02 -0800355 frame.set_ntp_time_ms(ntp_time_ms);
perkj26091b12016-09-01 01:17:40 -0700356 return frame;
357 }
358
sprang57c2fff2017-01-16 06:24:02 -0800359 VideoFrame CreateFrame(int64_t ntp_time_ms, int width, int height) const {
perkj803d97f2016-11-01 11:45:46 -0700360 VideoFrame frame(
361 new rtc::RefCountedObject<TestBuffer>(nullptr, width, height), 99, 99,
362 kVideoRotation_0);
sprang57c2fff2017-01-16 06:24:02 -0800363 frame.set_ntp_time_ms(ntp_time_ms);
sprangc5d62e22017-04-02 23:53:04 -0700364 frame.set_timestamp_us(ntp_time_ms * 1000);
perkj803d97f2016-11-01 11:45:46 -0700365 return frame;
366 }
367
asapersson02465b82017-04-10 01:12:52 -0700368 void VerifyNoLimitation(const rtc::VideoSinkWants& wants) {
asapersson02465b82017-04-10 01:12:52 -0700369 EXPECT_EQ(std::numeric_limits<int>::max(), wants.max_framerate_fps);
asapersson09f05612017-05-15 23:40:18 -0700370 EXPECT_EQ(std::numeric_limits<int>::max(), wants.max_pixel_count);
371 EXPECT_FALSE(wants.target_pixel_count);
asapersson02465b82017-04-10 01:12:52 -0700372 }
373
asapersson09f05612017-05-15 23:40:18 -0700374 void VerifyFpsEqResolutionEq(const rtc::VideoSinkWants& wants1,
375 const rtc::VideoSinkWants& wants2) {
376 EXPECT_EQ(wants1.max_framerate_fps, wants2.max_framerate_fps);
377 EXPECT_EQ(wants1.max_pixel_count, wants2.max_pixel_count);
378 }
379
Åsa Persson8c1bf952018-09-13 10:42:19 +0200380 void VerifyFpsMaxResolutionMax(const rtc::VideoSinkWants& wants) {
381 EXPECT_EQ(kDefaultFramerate, wants.max_framerate_fps);
382 EXPECT_EQ(std::numeric_limits<int>::max(), wants.max_pixel_count);
383 EXPECT_FALSE(wants.target_pixel_count);
384 }
385
asapersson09f05612017-05-15 23:40:18 -0700386 void VerifyFpsMaxResolutionLt(const rtc::VideoSinkWants& wants1,
387 const rtc::VideoSinkWants& wants2) {
Åsa Persson8c1bf952018-09-13 10:42:19 +0200388 EXPECT_EQ(kDefaultFramerate, wants1.max_framerate_fps);
asapersson09f05612017-05-15 23:40:18 -0700389 EXPECT_LT(wants1.max_pixel_count, wants2.max_pixel_count);
390 EXPECT_GT(wants1.max_pixel_count, 0);
391 }
392
393 void VerifyFpsMaxResolutionGt(const rtc::VideoSinkWants& wants1,
394 const rtc::VideoSinkWants& wants2) {
Åsa Persson8c1bf952018-09-13 10:42:19 +0200395 EXPECT_EQ(kDefaultFramerate, wants1.max_framerate_fps);
asapersson09f05612017-05-15 23:40:18 -0700396 EXPECT_GT(wants1.max_pixel_count, wants2.max_pixel_count);
397 }
398
asaperssonf7e294d2017-06-13 23:25:22 -0700399 void VerifyFpsMaxResolutionEq(const rtc::VideoSinkWants& wants1,
400 const rtc::VideoSinkWants& wants2) {
Åsa Persson8c1bf952018-09-13 10:42:19 +0200401 EXPECT_EQ(kDefaultFramerate, wants1.max_framerate_fps);
asaperssonf7e294d2017-06-13 23:25:22 -0700402 EXPECT_EQ(wants1.max_pixel_count, wants2.max_pixel_count);
403 }
404
405 void VerifyFpsLtResolutionEq(const rtc::VideoSinkWants& wants1,
406 const rtc::VideoSinkWants& wants2) {
407 EXPECT_LT(wants1.max_framerate_fps, wants2.max_framerate_fps);
408 EXPECT_EQ(wants1.max_pixel_count, wants2.max_pixel_count);
409 }
410
411 void VerifyFpsGtResolutionEq(const rtc::VideoSinkWants& wants1,
412 const rtc::VideoSinkWants& wants2) {
413 EXPECT_GT(wants1.max_framerate_fps, wants2.max_framerate_fps);
414 EXPECT_EQ(wants1.max_pixel_count, wants2.max_pixel_count);
415 }
416
417 void VerifyFpsEqResolutionLt(const rtc::VideoSinkWants& wants1,
418 const rtc::VideoSinkWants& wants2) {
419 EXPECT_EQ(wants1.max_framerate_fps, wants2.max_framerate_fps);
420 EXPECT_LT(wants1.max_pixel_count, wants2.max_pixel_count);
421 EXPECT_GT(wants1.max_pixel_count, 0);
422 }
423
424 void VerifyFpsEqResolutionGt(const rtc::VideoSinkWants& wants1,
425 const rtc::VideoSinkWants& wants2) {
426 EXPECT_EQ(wants1.max_framerate_fps, wants2.max_framerate_fps);
427 EXPECT_GT(wants1.max_pixel_count, wants2.max_pixel_count);
428 }
429
asapersson09f05612017-05-15 23:40:18 -0700430 void VerifyFpsMaxResolutionLt(const rtc::VideoSinkWants& wants,
431 int pixel_count) {
Åsa Persson8c1bf952018-09-13 10:42:19 +0200432 EXPECT_EQ(kDefaultFramerate, wants.max_framerate_fps);
asapersson02465b82017-04-10 01:12:52 -0700433 EXPECT_LT(wants.max_pixel_count, pixel_count);
434 EXPECT_GT(wants.max_pixel_count, 0);
asapersson09f05612017-05-15 23:40:18 -0700435 }
436
437 void VerifyFpsLtResolutionMax(const rtc::VideoSinkWants& wants, int fps) {
438 EXPECT_LT(wants.max_framerate_fps, fps);
439 EXPECT_EQ(std::numeric_limits<int>::max(), wants.max_pixel_count);
440 EXPECT_FALSE(wants.target_pixel_count);
asapersson02465b82017-04-10 01:12:52 -0700441 }
442
asaperssonf7e294d2017-06-13 23:25:22 -0700443 void VerifyFpsEqResolutionMax(const rtc::VideoSinkWants& wants,
444 int expected_fps) {
445 EXPECT_EQ(expected_fps, wants.max_framerate_fps);
446 EXPECT_EQ(std::numeric_limits<int>::max(), wants.max_pixel_count);
447 EXPECT_FALSE(wants.target_pixel_count);
448 }
449
Jonathan Yubc771b72017-12-08 17:04:29 -0800450 void VerifyBalancedModeFpsRange(const rtc::VideoSinkWants& wants,
451 int last_frame_pixels) {
452 // Balanced mode should always scale FPS to the desired range before
453 // attempting to scale resolution.
454 int fps_limit = wants.max_framerate_fps;
455 if (last_frame_pixels <= 320 * 240) {
456 EXPECT_TRUE(7 <= fps_limit && fps_limit <= 10);
457 } else if (last_frame_pixels <= 480 * 270) {
458 EXPECT_TRUE(10 <= fps_limit && fps_limit <= 15);
459 } else if (last_frame_pixels <= 640 * 480) {
460 EXPECT_LE(15, fps_limit);
461 } else {
Åsa Persson8c1bf952018-09-13 10:42:19 +0200462 EXPECT_EQ(kDefaultFramerate, fps_limit);
Jonathan Yubc771b72017-12-08 17:04:29 -0800463 }
464 }
465
sprang4847ae62017-06-27 07:06:52 -0700466 void WaitForEncodedFrame(int64_t expected_ntp_time) {
467 sink_.WaitForEncodedFrame(expected_ntp_time);
468 fake_clock_.AdvanceTimeMicros(rtc::kNumMicrosecsPerSec / max_framerate_);
469 }
470
471 bool TimedWaitForEncodedFrame(int64_t expected_ntp_time, int64_t timeout_ms) {
472 bool ok = sink_.TimedWaitForEncodedFrame(expected_ntp_time, timeout_ms);
473 fake_clock_.AdvanceTimeMicros(rtc::kNumMicrosecsPerSec / max_framerate_);
474 return ok;
475 }
476
477 void WaitForEncodedFrame(uint32_t expected_width, uint32_t expected_height) {
478 sink_.WaitForEncodedFrame(expected_width, expected_height);
479 fake_clock_.AdvanceTimeMicros(rtc::kNumMicrosecsPerSec / max_framerate_);
480 }
481
482 void ExpectDroppedFrame() {
483 sink_.ExpectDroppedFrame();
484 fake_clock_.AdvanceTimeMicros(rtc::kNumMicrosecsPerSec / max_framerate_);
485 }
486
487 bool WaitForFrame(int64_t timeout_ms) {
488 bool ok = sink_.WaitForFrame(timeout_ms);
489 fake_clock_.AdvanceTimeMicros(rtc::kNumMicrosecsPerSec / max_framerate_);
490 return ok;
491 }
492
perkj26091b12016-09-01 01:17:40 -0700493 class TestEncoder : public test::FakeEncoder {
494 public:
495 TestEncoder()
496 : FakeEncoder(Clock::GetRealTimeClock()),
497 continue_encode_event_(false, false) {}
498
asaperssonfab67072017-04-04 05:51:49 -0700499 VideoCodec codec_config() const {
brandtre78d2662017-01-16 05:57:16 -0800500 rtc::CritScope lock(&crit_sect_);
perkjfa10b552016-10-02 23:45:26 -0700501 return config_;
502 }
503
504 void BlockNextEncode() {
brandtre78d2662017-01-16 05:57:16 -0800505 rtc::CritScope lock(&local_crit_sect_);
perkjfa10b552016-10-02 23:45:26 -0700506 block_next_encode_ = true;
507 }
508
kthelgason876222f2016-11-29 01:44:11 -0800509 VideoEncoder::ScalingSettings GetScalingSettings() const override {
kthelgason2fc52542017-03-03 00:24:41 -0800510 rtc::CritScope lock(&local_crit_sect_);
kthelgasonad9010c2017-02-14 00:46:51 -0800511 if (quality_scaling_)
Niels Möller225c7872018-02-22 15:03:53 +0100512 return VideoEncoder::ScalingSettings(1, 2, kMinPixelsPerFrame);
513 return VideoEncoder::ScalingSettings::kOff;
kthelgason876222f2016-11-29 01:44:11 -0800514 }
515
perkjfa10b552016-10-02 23:45:26 -0700516 void ContinueEncode() { continue_encode_event_.Set(); }
517
518 void CheckLastTimeStampsMatch(int64_t ntp_time_ms,
519 uint32_t timestamp) const {
brandtre78d2662017-01-16 05:57:16 -0800520 rtc::CritScope lock(&local_crit_sect_);
perkjfa10b552016-10-02 23:45:26 -0700521 EXPECT_EQ(timestamp_, timestamp);
522 EXPECT_EQ(ntp_time_ms_, ntp_time_ms);
523 }
524
kthelgason2fc52542017-03-03 00:24:41 -0800525 void SetQualityScaling(bool b) {
526 rtc::CritScope lock(&local_crit_sect_);
527 quality_scaling_ = b;
528 }
kthelgasonad9010c2017-02-14 00:46:51 -0800529
sprangfe627f32017-03-29 08:24:59 -0700530 void ForceInitEncodeFailure(bool force_failure) {
531 rtc::CritScope lock(&local_crit_sect_);
532 force_init_encode_failed_ = force_failure;
533 }
534
perkjfa10b552016-10-02 23:45:26 -0700535 private:
perkj26091b12016-09-01 01:17:40 -0700536 int32_t Encode(const VideoFrame& input_image,
537 const CodecSpecificInfo* codec_specific_info,
538 const std::vector<FrameType>* frame_types) override {
539 bool block_encode;
540 {
brandtre78d2662017-01-16 05:57:16 -0800541 rtc::CritScope lock(&local_crit_sect_);
perkj26091b12016-09-01 01:17:40 -0700542 EXPECT_GT(input_image.timestamp(), timestamp_);
543 EXPECT_GT(input_image.ntp_time_ms(), ntp_time_ms_);
544 EXPECT_EQ(input_image.timestamp(), input_image.ntp_time_ms() * 90);
545
546 timestamp_ = input_image.timestamp();
547 ntp_time_ms_ = input_image.ntp_time_ms();
perkj803d97f2016-11-01 11:45:46 -0700548 last_input_width_ = input_image.width();
549 last_input_height_ = input_image.height();
perkj26091b12016-09-01 01:17:40 -0700550 block_encode = block_next_encode_;
551 block_next_encode_ = false;
552 }
553 int32_t result =
554 FakeEncoder::Encode(input_image, codec_specific_info, frame_types);
555 if (block_encode)
perkja49cbd32016-09-16 07:53:41 -0700556 EXPECT_TRUE(continue_encode_event_.Wait(kDefaultTimeoutMs));
perkj26091b12016-09-01 01:17:40 -0700557 return result;
558 }
559
sprangfe627f32017-03-29 08:24:59 -0700560 int32_t InitEncode(const VideoCodec* config,
561 int32_t number_of_cores,
562 size_t max_payload_size) override {
563 int res =
564 FakeEncoder::InitEncode(config, number_of_cores, max_payload_size);
565 rtc::CritScope lock(&local_crit_sect_);
Erik Språng82fad3d2018-03-21 09:57:23 +0100566 if (config->codecType == kVideoCodecVP8) {
sprangfe627f32017-03-29 08:24:59 -0700567 // Simulate setting up temporal layers, in order to validate the life
568 // cycle of these objects.
569 int num_streams = std::max<int>(1, config->numberOfSimulcastStreams);
sprangfe627f32017-03-29 08:24:59 -0700570 for (int i = 0; i < num_streams; ++i) {
571 allocated_temporal_layers_.emplace_back(
Niels Möller150dcb02018-03-27 14:16:55 +0200572 TemporalLayers::CreateTemporalLayers(*config, i));
sprangfe627f32017-03-29 08:24:59 -0700573 }
574 }
575 if (force_init_encode_failed_)
576 return -1;
577 return res;
578 }
579
brandtre78d2662017-01-16 05:57:16 -0800580 rtc::CriticalSection local_crit_sect_;
danilchapa37de392017-09-09 04:17:22 -0700581 bool block_next_encode_ RTC_GUARDED_BY(local_crit_sect_) = false;
perkj26091b12016-09-01 01:17:40 -0700582 rtc::Event continue_encode_event_;
danilchapa37de392017-09-09 04:17:22 -0700583 uint32_t timestamp_ RTC_GUARDED_BY(local_crit_sect_) = 0;
584 int64_t ntp_time_ms_ RTC_GUARDED_BY(local_crit_sect_) = 0;
585 int last_input_width_ RTC_GUARDED_BY(local_crit_sect_) = 0;
586 int last_input_height_ RTC_GUARDED_BY(local_crit_sect_) = 0;
587 bool quality_scaling_ RTC_GUARDED_BY(local_crit_sect_) = true;
sprangfe627f32017-03-29 08:24:59 -0700588 std::vector<std::unique_ptr<TemporalLayers>> allocated_temporal_layers_
danilchapa37de392017-09-09 04:17:22 -0700589 RTC_GUARDED_BY(local_crit_sect_);
590 bool force_init_encode_failed_ RTC_GUARDED_BY(local_crit_sect_) = false;
perkj26091b12016-09-01 01:17:40 -0700591 };
592
mflodmancc3d4422017-08-03 08:27:51 -0700593 class TestSink : public VideoStreamEncoder::EncoderSink {
perkj26091b12016-09-01 01:17:40 -0700594 public:
595 explicit TestSink(TestEncoder* test_encoder)
596 : test_encoder_(test_encoder), encoded_frame_event_(false, false) {}
597
perkj26091b12016-09-01 01:17:40 -0700598 void WaitForEncodedFrame(int64_t expected_ntp_time) {
sprang4847ae62017-06-27 07:06:52 -0700599 EXPECT_TRUE(
600 TimedWaitForEncodedFrame(expected_ntp_time, kDefaultTimeoutMs));
601 }
602
603 bool TimedWaitForEncodedFrame(int64_t expected_ntp_time,
604 int64_t timeout_ms) {
perkj26091b12016-09-01 01:17:40 -0700605 uint32_t timestamp = 0;
sprang4847ae62017-06-27 07:06:52 -0700606 if (!encoded_frame_event_.Wait(timeout_ms))
607 return false;
perkj26091b12016-09-01 01:17:40 -0700608 {
609 rtc::CritScope lock(&crit_);
sprangb1ca0732017-02-01 08:38:12 -0800610 timestamp = last_timestamp_;
perkj26091b12016-09-01 01:17:40 -0700611 }
612 test_encoder_->CheckLastTimeStampsMatch(expected_ntp_time, timestamp);
sprang4847ae62017-06-27 07:06:52 -0700613 return true;
perkj26091b12016-09-01 01:17:40 -0700614 }
615
sprangb1ca0732017-02-01 08:38:12 -0800616 void WaitForEncodedFrame(uint32_t expected_width,
617 uint32_t expected_height) {
sprangc5d62e22017-04-02 23:53:04 -0700618 EXPECT_TRUE(encoded_frame_event_.Wait(kDefaultTimeoutMs));
Åsa Perssonc74d8da2017-12-04 14:13:56 +0100619 CheckLastFrameSizeMatches(expected_width, expected_height);
sprangc5d62e22017-04-02 23:53:04 -0700620 }
621
Åsa Perssonc74d8da2017-12-04 14:13:56 +0100622 void CheckLastFrameSizeMatches(uint32_t expected_width,
sprangc5d62e22017-04-02 23:53:04 -0700623 uint32_t expected_height) {
sprangb1ca0732017-02-01 08:38:12 -0800624 uint32_t width = 0;
625 uint32_t height = 0;
sprangb1ca0732017-02-01 08:38:12 -0800626 {
627 rtc::CritScope lock(&crit_);
628 width = last_width_;
629 height = last_height_;
630 }
631 EXPECT_EQ(expected_height, height);
632 EXPECT_EQ(expected_width, width);
633 }
634
kthelgason2fc52542017-03-03 00:24:41 -0800635 void ExpectDroppedFrame() { EXPECT_FALSE(encoded_frame_event_.Wait(100)); }
kthelgason2bc68642017-02-07 07:02:22 -0800636
sprangc5d62e22017-04-02 23:53:04 -0700637 bool WaitForFrame(int64_t timeout_ms) {
638 return encoded_frame_event_.Wait(timeout_ms);
639 }
640
perkj26091b12016-09-01 01:17:40 -0700641 void SetExpectNoFrames() {
642 rtc::CritScope lock(&crit_);
643 expect_frames_ = false;
644 }
645
asaperssonfab67072017-04-04 05:51:49 -0700646 int number_of_reconfigurations() const {
Per512ecb32016-09-23 15:52:06 +0200647 rtc::CritScope lock(&crit_);
648 return number_of_reconfigurations_;
649 }
650
asaperssonfab67072017-04-04 05:51:49 -0700651 int last_min_transmit_bitrate() const {
Per512ecb32016-09-23 15:52:06 +0200652 rtc::CritScope lock(&crit_);
653 return min_transmit_bitrate_bps_;
654 }
655
perkj26091b12016-09-01 01:17:40 -0700656 private:
sergeyu2cb155a2016-11-04 11:39:29 -0700657 Result OnEncodedImage(
658 const EncodedImage& encoded_image,
659 const CodecSpecificInfo* codec_specific_info,
660 const RTPFragmentationHeader* fragmentation) override {
Per512ecb32016-09-23 15:52:06 +0200661 rtc::CritScope lock(&crit_);
662 EXPECT_TRUE(expect_frames_);
Niels Möller23775882018-08-16 10:24:12 +0200663 last_timestamp_ = encoded_image.Timestamp();
sprangb1ca0732017-02-01 08:38:12 -0800664 last_width_ = encoded_image._encodedWidth;
665 last_height_ = encoded_image._encodedHeight;
Per512ecb32016-09-23 15:52:06 +0200666 encoded_frame_event_.Set();
sprangb1ca0732017-02-01 08:38:12 -0800667 return Result(Result::OK, last_timestamp_);
Per512ecb32016-09-23 15:52:06 +0200668 }
669
670 void OnEncoderConfigurationChanged(std::vector<VideoStream> streams,
671 int min_transmit_bitrate_bps) override {
672 rtc::CriticalSection crit_;
673 ++number_of_reconfigurations_;
674 min_transmit_bitrate_bps_ = min_transmit_bitrate_bps;
675 }
676
perkj26091b12016-09-01 01:17:40 -0700677 rtc::CriticalSection crit_;
678 TestEncoder* test_encoder_;
679 rtc::Event encoded_frame_event_;
sprangb1ca0732017-02-01 08:38:12 -0800680 uint32_t last_timestamp_ = 0;
681 uint32_t last_height_ = 0;
682 uint32_t last_width_ = 0;
perkj26091b12016-09-01 01:17:40 -0700683 bool expect_frames_ = true;
Per512ecb32016-09-23 15:52:06 +0200684 int number_of_reconfigurations_ = 0;
685 int min_transmit_bitrate_bps_ = 0;
perkj26091b12016-09-01 01:17:40 -0700686 };
687
688 VideoSendStream::Config video_send_config_;
Erik Språng08127a92016-11-16 16:41:30 +0100689 VideoEncoderConfig video_encoder_config_;
Per512ecb32016-09-23 15:52:06 +0200690 int codec_width_;
691 int codec_height_;
sprang4847ae62017-06-27 07:06:52 -0700692 int max_framerate_;
perkj26091b12016-09-01 01:17:40 -0700693 TestEncoder fake_encoder_;
Niels Möller4db138e2018-04-19 09:04:13 +0200694 test::EncoderProxyFactory encoder_factory_;
sprangc5d62e22017-04-02 23:53:04 -0700695 std::unique_ptr<MockableSendStatisticsProxy> stats_proxy_;
perkj26091b12016-09-01 01:17:40 -0700696 TestSink sink_;
sprangb1ca0732017-02-01 08:38:12 -0800697 AdaptingFrameForwarder video_source_;
mflodmancc3d4422017-08-03 08:27:51 -0700698 std::unique_ptr<VideoStreamEncoderUnderTest> video_stream_encoder_;
sprang4847ae62017-06-27 07:06:52 -0700699 rtc::ScopedFakeClock fake_clock_;
perkj26091b12016-09-01 01:17:40 -0700700};
701
mflodmancc3d4422017-08-03 08:27:51 -0700702TEST_F(VideoStreamEncoderTest, EncodeOneFrame) {
703 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkj26091b12016-09-01 01:17:40 -0700704 rtc::Event frame_destroyed_event(false, false);
perkja49cbd32016-09-16 07:53:41 -0700705 video_source_.IncomingCapturedFrame(CreateFrame(1, &frame_destroyed_event));
sprang4847ae62017-06-27 07:06:52 -0700706 WaitForEncodedFrame(1);
perkja49cbd32016-09-16 07:53:41 -0700707 EXPECT_TRUE(frame_destroyed_event.Wait(kDefaultTimeoutMs));
mflodmancc3d4422017-08-03 08:27:51 -0700708 video_stream_encoder_->Stop();
perkj26091b12016-09-01 01:17:40 -0700709}
710
mflodmancc3d4422017-08-03 08:27:51 -0700711TEST_F(VideoStreamEncoderTest, DropsFramesBeforeFirstOnBitrateUpdated) {
perkj26091b12016-09-01 01:17:40 -0700712 // Dropped since no target bitrate has been set.
713 rtc::Event frame_destroyed_event(false, false);
Sebastian Janssona3177052018-04-10 13:05:49 +0200714 // The encoder will cache up to one frame for a short duration. Adding two
715 // frames means that the first frame will be dropped and the second frame will
716 // be sent when the encoder is enabled.
perkja49cbd32016-09-16 07:53:41 -0700717 video_source_.IncomingCapturedFrame(CreateFrame(1, &frame_destroyed_event));
Sebastian Janssona3177052018-04-10 13:05:49 +0200718 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
perkja49cbd32016-09-16 07:53:41 -0700719 EXPECT_TRUE(frame_destroyed_event.Wait(kDefaultTimeoutMs));
perkj26091b12016-09-01 01:17:40 -0700720
mflodmancc3d4422017-08-03 08:27:51 -0700721 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkj26091b12016-09-01 01:17:40 -0700722
Sebastian Janssona3177052018-04-10 13:05:49 +0200723 // The pending frame should be received.
sprang4847ae62017-06-27 07:06:52 -0700724 WaitForEncodedFrame(2);
Sebastian Janssona3177052018-04-10 13:05:49 +0200725 video_source_.IncomingCapturedFrame(CreateFrame(3, nullptr));
726
727 WaitForEncodedFrame(3);
mflodmancc3d4422017-08-03 08:27:51 -0700728 video_stream_encoder_->Stop();
perkj26091b12016-09-01 01:17:40 -0700729}
730
mflodmancc3d4422017-08-03 08:27:51 -0700731TEST_F(VideoStreamEncoderTest, DropsFramesWhenRateSetToZero) {
732 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkja49cbd32016-09-16 07:53:41 -0700733 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700734 WaitForEncodedFrame(1);
perkj26091b12016-09-01 01:17:40 -0700735
mflodmancc3d4422017-08-03 08:27:51 -0700736 video_stream_encoder_->OnBitrateUpdated(0, 0, 0);
Sebastian Janssona3177052018-04-10 13:05:49 +0200737 // The encoder will cache up to one frame for a short duration. Adding two
738 // frames means that the first frame will be dropped and the second frame will
739 // be sent when the encoder is resumed.
perkja49cbd32016-09-16 07:53:41 -0700740 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
Sebastian Janssona3177052018-04-10 13:05:49 +0200741 video_source_.IncomingCapturedFrame(CreateFrame(3, nullptr));
perkj26091b12016-09-01 01:17:40 -0700742
mflodmancc3d4422017-08-03 08:27:51 -0700743 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
sprang4847ae62017-06-27 07:06:52 -0700744 WaitForEncodedFrame(3);
Sebastian Janssona3177052018-04-10 13:05:49 +0200745 video_source_.IncomingCapturedFrame(CreateFrame(4, nullptr));
746 WaitForEncodedFrame(4);
mflodmancc3d4422017-08-03 08:27:51 -0700747 video_stream_encoder_->Stop();
perkj26091b12016-09-01 01:17:40 -0700748}
749
mflodmancc3d4422017-08-03 08:27:51 -0700750TEST_F(VideoStreamEncoderTest, DropsFramesWithSameOrOldNtpTimestamp) {
751 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkja49cbd32016-09-16 07:53:41 -0700752 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700753 WaitForEncodedFrame(1);
perkj26091b12016-09-01 01:17:40 -0700754
755 // This frame will be dropped since it has the same ntp timestamp.
perkja49cbd32016-09-16 07:53:41 -0700756 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
perkj26091b12016-09-01 01:17:40 -0700757
perkja49cbd32016-09-16 07:53:41 -0700758 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700759 WaitForEncodedFrame(2);
mflodmancc3d4422017-08-03 08:27:51 -0700760 video_stream_encoder_->Stop();
perkj26091b12016-09-01 01:17:40 -0700761}
762
mflodmancc3d4422017-08-03 08:27:51 -0700763TEST_F(VideoStreamEncoderTest, DropsFrameAfterStop) {
764 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkj26091b12016-09-01 01:17:40 -0700765
perkja49cbd32016-09-16 07:53:41 -0700766 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700767 WaitForEncodedFrame(1);
perkj26091b12016-09-01 01:17:40 -0700768
mflodmancc3d4422017-08-03 08:27:51 -0700769 video_stream_encoder_->Stop();
perkj26091b12016-09-01 01:17:40 -0700770 sink_.SetExpectNoFrames();
771 rtc::Event frame_destroyed_event(false, false);
perkja49cbd32016-09-16 07:53:41 -0700772 video_source_.IncomingCapturedFrame(CreateFrame(2, &frame_destroyed_event));
773 EXPECT_TRUE(frame_destroyed_event.Wait(kDefaultTimeoutMs));
perkj26091b12016-09-01 01:17:40 -0700774}
775
mflodmancc3d4422017-08-03 08:27:51 -0700776TEST_F(VideoStreamEncoderTest, DropsPendingFramesOnSlowEncode) {
777 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkj26091b12016-09-01 01:17:40 -0700778
779 fake_encoder_.BlockNextEncode();
perkja49cbd32016-09-16 07:53:41 -0700780 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700781 WaitForEncodedFrame(1);
perkj26091b12016-09-01 01:17:40 -0700782 // Here, the encoder thread will be blocked in the TestEncoder waiting for a
783 // call to ContinueEncode.
perkja49cbd32016-09-16 07:53:41 -0700784 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
785 video_source_.IncomingCapturedFrame(CreateFrame(3, nullptr));
perkj26091b12016-09-01 01:17:40 -0700786 fake_encoder_.ContinueEncode();
sprang4847ae62017-06-27 07:06:52 -0700787 WaitForEncodedFrame(3);
perkj26091b12016-09-01 01:17:40 -0700788
mflodmancc3d4422017-08-03 08:27:51 -0700789 video_stream_encoder_->Stop();
perkj26091b12016-09-01 01:17:40 -0700790}
791
mflodmancc3d4422017-08-03 08:27:51 -0700792TEST_F(VideoStreamEncoderTest,
793 ConfigureEncoderTriggersOnEncoderConfigurationChanged) {
794 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
Per21d45d22016-10-30 21:37:57 +0100795 EXPECT_EQ(0, sink_.number_of_reconfigurations());
Per512ecb32016-09-23 15:52:06 +0200796
797 // Capture a frame and wait for it to synchronize with the encoder thread.
Perf8c5f2b2016-09-23 16:24:55 +0200798 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700799 WaitForEncodedFrame(1);
Per21d45d22016-10-30 21:37:57 +0100800 // The encoder will have been configured once when the first frame is
801 // received.
802 EXPECT_EQ(1, sink_.number_of_reconfigurations());
Per512ecb32016-09-23 15:52:06 +0200803
804 VideoEncoderConfig video_encoder_config;
Niels Möller259a4972018-04-05 15:36:51 +0200805 test::FillEncoderConfiguration(kVideoCodecVP8, 1, &video_encoder_config);
Per512ecb32016-09-23 15:52:06 +0200806 video_encoder_config.min_transmit_bitrate_bps = 9999;
mflodmancc3d4422017-08-03 08:27:51 -0700807 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
Niels Möllerf1338562018-04-26 09:51:47 +0200808 kMaxPayloadLength);
Per512ecb32016-09-23 15:52:06 +0200809
810 // Capture a frame and wait for it to synchronize with the encoder thread.
Perf8c5f2b2016-09-23 16:24:55 +0200811 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700812 WaitForEncodedFrame(2);
Per21d45d22016-10-30 21:37:57 +0100813 EXPECT_EQ(2, sink_.number_of_reconfigurations());
perkj3b703ed2016-09-29 23:25:40 -0700814 EXPECT_EQ(9999, sink_.last_min_transmit_bitrate());
perkj26105b42016-09-29 22:39:10 -0700815
mflodmancc3d4422017-08-03 08:27:51 -0700816 video_stream_encoder_->Stop();
perkj26105b42016-09-29 22:39:10 -0700817}
818
mflodmancc3d4422017-08-03 08:27:51 -0700819TEST_F(VideoStreamEncoderTest, FrameResolutionChangeReconfigureEncoder) {
820 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkjfa10b552016-10-02 23:45:26 -0700821
822 // Capture a frame and wait for it to synchronize with the encoder thread.
823 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700824 WaitForEncodedFrame(1);
Per21d45d22016-10-30 21:37:57 +0100825 // The encoder will have been configured once.
826 EXPECT_EQ(1, sink_.number_of_reconfigurations());
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);
829
830 codec_width_ *= 2;
831 codec_height_ *= 2;
832 // Capture a frame with a higher resolution and wait for it to synchronize
833 // with the encoder thread.
834 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700835 WaitForEncodedFrame(2);
perkjfa10b552016-10-02 23:45:26 -0700836 EXPECT_EQ(codec_width_, fake_encoder_.codec_config().width);
837 EXPECT_EQ(codec_height_, fake_encoder_.codec_config().height);
Per21d45d22016-10-30 21:37:57 +0100838 EXPECT_EQ(2, sink_.number_of_reconfigurations());
perkjfa10b552016-10-02 23:45:26 -0700839
mflodmancc3d4422017-08-03 08:27:51 -0700840 video_stream_encoder_->Stop();
perkjfa10b552016-10-02 23:45:26 -0700841}
842
mflodmancc3d4422017-08-03 08:27:51 -0700843TEST_F(VideoStreamEncoderTest, SwitchSourceDeregisterEncoderAsSink) {
perkj803d97f2016-11-01 11:45:46 -0700844 EXPECT_TRUE(video_source_.has_sinks());
845 test::FrameForwarder new_video_source;
mflodmancc3d4422017-08-03 08:27:51 -0700846 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -0700847 &new_video_source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
perkj803d97f2016-11-01 11:45:46 -0700848 EXPECT_FALSE(video_source_.has_sinks());
849 EXPECT_TRUE(new_video_source.has_sinks());
850
mflodmancc3d4422017-08-03 08:27:51 -0700851 video_stream_encoder_->Stop();
perkj803d97f2016-11-01 11:45:46 -0700852}
853
mflodmancc3d4422017-08-03 08:27:51 -0700854TEST_F(VideoStreamEncoderTest, SinkWantsRotationApplied) {
perkj803d97f2016-11-01 11:45:46 -0700855 EXPECT_FALSE(video_source_.sink_wants().rotation_applied);
mflodmancc3d4422017-08-03 08:27:51 -0700856 video_stream_encoder_->SetSink(&sink_, true /*rotation_applied*/);
perkj803d97f2016-11-01 11:45:46 -0700857 EXPECT_TRUE(video_source_.sink_wants().rotation_applied);
mflodmancc3d4422017-08-03 08:27:51 -0700858 video_stream_encoder_->Stop();
perkj803d97f2016-11-01 11:45:46 -0700859}
860
Jonathan Yubc771b72017-12-08 17:04:29 -0800861TEST_F(VideoStreamEncoderTest, TestCpuDowngrades_BalancedMode) {
862 const int kFramerateFps = 30;
asaperssonf7e294d2017-06-13 23:25:22 -0700863 const int kWidth = 1280;
864 const int kHeight = 720;
Jonathan Yubc771b72017-12-08 17:04:29 -0800865
866 // We rely on the automatic resolution adaptation, but we handle framerate
867 // adaptation manually by mocking the stats proxy.
868 video_source_.set_adaptation_enabled(true);
asaperssonf7e294d2017-06-13 23:25:22 -0700869
Taylor Brandstetter49fcc102018-05-16 14:20:41 -0700870 // Enable BALANCED preference, no initial limitation.
Jonathan Yubc771b72017-12-08 17:04:29 -0800871 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
Taylor Brandstetter49fcc102018-05-16 14:20:41 -0700872 video_stream_encoder_->SetSource(&video_source_,
873 webrtc::DegradationPreference::BALANCED);
Jonathan Yubc771b72017-12-08 17:04:29 -0800874 VerifyNoLimitation(video_source_.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -0700875 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
Jonathan Yubc771b72017-12-08 17:04:29 -0800876 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
asaperssonf7e294d2017-06-13 23:25:22 -0700877 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
878
Jonathan Yubc771b72017-12-08 17:04:29 -0800879 // Adapt down as far as possible.
880 rtc::VideoSinkWants last_wants;
881 int64_t t = 1;
882 int loop_count = 0;
883 do {
884 ++loop_count;
885 last_wants = video_source_.sink_wants();
886
887 // Simulate the framerate we've been asked to adapt to.
888 const int fps = std::min(kFramerateFps, last_wants.max_framerate_fps);
889 const int frame_interval_ms = rtc::kNumMillisecsPerSec / fps;
890 VideoSendStream::Stats mock_stats = stats_proxy_->GetStats();
891 mock_stats.input_frame_rate = fps;
892 stats_proxy_->SetMockStats(mock_stats);
893
894 video_source_.IncomingCapturedFrame(CreateFrame(t, kWidth, kHeight));
895 sink_.WaitForEncodedFrame(t);
896 t += frame_interval_ms;
897
mflodmancc3d4422017-08-03 08:27:51 -0700898 video_stream_encoder_->TriggerCpuOveruse();
Jonathan Yubc771b72017-12-08 17:04:29 -0800899 VerifyBalancedModeFpsRange(
900 video_source_.sink_wants(),
901 *video_source_.last_sent_width() * *video_source_.last_sent_height());
902 } while (video_source_.sink_wants().max_pixel_count <
903 last_wants.max_pixel_count ||
904 video_source_.sink_wants().max_framerate_fps <
905 last_wants.max_framerate_fps);
asaperssonf7e294d2017-06-13 23:25:22 -0700906
Jonathan Yubc771b72017-12-08 17:04:29 -0800907 // Verify that we've adapted all the way down.
908 stats_proxy_->ResetMockStats();
asaperssonf7e294d2017-06-13 23:25:22 -0700909 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
Jonathan Yubc771b72017-12-08 17:04:29 -0800910 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_framerate);
911 EXPECT_EQ(loop_count - 1,
asaperssonf7e294d2017-06-13 23:25:22 -0700912 stats_proxy_->GetStats().number_of_cpu_adapt_changes);
Jonathan Yubc771b72017-12-08 17:04:29 -0800913 EXPECT_EQ(kMinPixelsPerFrame, *video_source_.last_sent_width() *
914 *video_source_.last_sent_height());
915 EXPECT_EQ(kMinBalancedFramerateFps,
916 video_source_.sink_wants().max_framerate_fps);
asaperssonf7e294d2017-06-13 23:25:22 -0700917
Jonathan Yubc771b72017-12-08 17:04:29 -0800918 // Adapt back up the same number of times we adapted down.
919 for (int i = 0; i < loop_count - 1; ++i) {
920 last_wants = video_source_.sink_wants();
921
922 // Simulate the framerate we've been asked to adapt to.
923 const int fps = std::min(kFramerateFps, last_wants.max_framerate_fps);
924 const int frame_interval_ms = rtc::kNumMillisecsPerSec / fps;
925 VideoSendStream::Stats mock_stats = stats_proxy_->GetStats();
926 mock_stats.input_frame_rate = fps;
927 stats_proxy_->SetMockStats(mock_stats);
928
929 video_source_.IncomingCapturedFrame(CreateFrame(t, kWidth, kHeight));
930 sink_.WaitForEncodedFrame(t);
931 t += frame_interval_ms;
932
mflodmancc3d4422017-08-03 08:27:51 -0700933 video_stream_encoder_->TriggerCpuNormalUsage();
Jonathan Yubc771b72017-12-08 17:04:29 -0800934 VerifyBalancedModeFpsRange(
935 video_source_.sink_wants(),
936 *video_source_.last_sent_width() * *video_source_.last_sent_height());
937 EXPECT_TRUE(video_source_.sink_wants().max_pixel_count >
938 last_wants.max_pixel_count ||
939 video_source_.sink_wants().max_framerate_fps >
940 last_wants.max_framerate_fps);
asaperssonf7e294d2017-06-13 23:25:22 -0700941 }
942
Åsa Persson8c1bf952018-09-13 10:42:19 +0200943 VerifyFpsMaxResolutionMax(video_source_.sink_wants());
Jonathan Yubc771b72017-12-08 17:04:29 -0800944 stats_proxy_->ResetMockStats();
asaperssonf7e294d2017-06-13 23:25:22 -0700945 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
Jonathan Yubc771b72017-12-08 17:04:29 -0800946 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
947 EXPECT_EQ((loop_count - 1) * 2,
948 stats_proxy_->GetStats().number_of_cpu_adapt_changes);
asaperssonf7e294d2017-06-13 23:25:22 -0700949
mflodmancc3d4422017-08-03 08:27:51 -0700950 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -0700951}
mflodmancc3d4422017-08-03 08:27:51 -0700952TEST_F(VideoStreamEncoderTest, SinkWantsStoredByDegradationPreference) {
953 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson02465b82017-04-10 01:12:52 -0700954 VerifyNoLimitation(video_source_.sink_wants());
perkj803d97f2016-11-01 11:45:46 -0700955
sprangc5d62e22017-04-02 23:53:04 -0700956 const int kFrameWidth = 1280;
957 const int kFrameHeight = 720;
sprangc5d62e22017-04-02 23:53:04 -0700958
Åsa Persson8c1bf952018-09-13 10:42:19 +0200959 int64_t frame_timestamp = 1;
perkj803d97f2016-11-01 11:45:46 -0700960
kthelgason5e13d412016-12-01 03:59:51 -0800961 video_source_.IncomingCapturedFrame(
sprangc5d62e22017-04-02 23:53:04 -0700962 CreateFrame(frame_timestamp, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -0700963 WaitForEncodedFrame(frame_timestamp);
sprangc5d62e22017-04-02 23:53:04 -0700964 frame_timestamp += kFrameIntervalMs;
965
perkj803d97f2016-11-01 11:45:46 -0700966 // Trigger CPU overuse.
mflodmancc3d4422017-08-03 08:27:51 -0700967 video_stream_encoder_->TriggerCpuOveruse();
perkj803d97f2016-11-01 11:45:46 -0700968 video_source_.IncomingCapturedFrame(
sprangc5d62e22017-04-02 23:53:04 -0700969 CreateFrame(frame_timestamp, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -0700970 WaitForEncodedFrame(frame_timestamp);
sprangc5d62e22017-04-02 23:53:04 -0700971 frame_timestamp += kFrameIntervalMs;
sprang3ea3c772017-03-30 07:23:48 -0700972
asapersson0944a802017-04-07 00:57:58 -0700973 // Default degradation preference is maintain-framerate, so will lower max
sprangc5d62e22017-04-02 23:53:04 -0700974 // wanted resolution.
975 EXPECT_FALSE(video_source_.sink_wants().target_pixel_count);
976 EXPECT_LT(video_source_.sink_wants().max_pixel_count,
977 kFrameWidth * kFrameHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +0200978 EXPECT_EQ(kDefaultFramerate, video_source_.sink_wants().max_framerate_fps);
sprangc5d62e22017-04-02 23:53:04 -0700979
980 // Set new source, switch to maintain-resolution.
perkj803d97f2016-11-01 11:45:46 -0700981 test::FrameForwarder new_video_source;
mflodmancc3d4422017-08-03 08:27:51 -0700982 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -0700983 &new_video_source, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
perkj803d97f2016-11-01 11:45:46 -0700984
sprangc5d62e22017-04-02 23:53:04 -0700985 // Initially no degradation registered.
Åsa Persson8c1bf952018-09-13 10:42:19 +0200986 VerifyFpsMaxResolutionMax(new_video_source.sink_wants());
perkj803d97f2016-11-01 11:45:46 -0700987
sprangc5d62e22017-04-02 23:53:04 -0700988 // Force an input frame rate to be available, or the adaptation call won't
989 // know what framerate to adapt form.
asapersson02465b82017-04-10 01:12:52 -0700990 const int kInputFps = 30;
sprangc5d62e22017-04-02 23:53:04 -0700991 VideoSendStream::Stats stats = stats_proxy_->GetStats();
asapersson02465b82017-04-10 01:12:52 -0700992 stats.input_frame_rate = kInputFps;
sprangc5d62e22017-04-02 23:53:04 -0700993 stats_proxy_->SetMockStats(stats);
994
mflodmancc3d4422017-08-03 08:27:51 -0700995 video_stream_encoder_->TriggerCpuOveruse();
perkj803d97f2016-11-01 11:45:46 -0700996 new_video_source.IncomingCapturedFrame(
sprangc5d62e22017-04-02 23:53:04 -0700997 CreateFrame(frame_timestamp, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -0700998 WaitForEncodedFrame(frame_timestamp);
sprangc5d62e22017-04-02 23:53:04 -0700999 frame_timestamp += kFrameIntervalMs;
1000
1001 // Some framerate constraint should be set.
sprang84a37592017-02-10 07:04:27 -08001002 EXPECT_FALSE(new_video_source.sink_wants().target_pixel_count);
sprangc5d62e22017-04-02 23:53:04 -07001003 EXPECT_EQ(std::numeric_limits<int>::max(),
1004 new_video_source.sink_wants().max_pixel_count);
asapersson02465b82017-04-10 01:12:52 -07001005 EXPECT_LT(new_video_source.sink_wants().max_framerate_fps, kInputFps);
sprangc5d62e22017-04-02 23:53:04 -07001006
asapersson02465b82017-04-10 01:12:52 -07001007 // Turn off degradation completely.
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001008 video_stream_encoder_->SetSource(&new_video_source,
1009 webrtc::DegradationPreference::DISABLED);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001010 VerifyFpsMaxResolutionMax(new_video_source.sink_wants());
sprangc5d62e22017-04-02 23:53:04 -07001011
mflodmancc3d4422017-08-03 08:27:51 -07001012 video_stream_encoder_->TriggerCpuOveruse();
sprangc5d62e22017-04-02 23:53:04 -07001013 new_video_source.IncomingCapturedFrame(
1014 CreateFrame(frame_timestamp, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07001015 WaitForEncodedFrame(frame_timestamp);
sprangc5d62e22017-04-02 23:53:04 -07001016 frame_timestamp += kFrameIntervalMs;
1017
1018 // Still no degradation.
Åsa Persson8c1bf952018-09-13 10:42:19 +02001019 VerifyFpsMaxResolutionMax(new_video_source.sink_wants());
perkj803d97f2016-11-01 11:45:46 -07001020
1021 // Calling SetSource with resolution scaling enabled apply the old SinkWants.
mflodmancc3d4422017-08-03 08:27:51 -07001022 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001023 &new_video_source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
sprangc5d62e22017-04-02 23:53:04 -07001024 EXPECT_LT(new_video_source.sink_wants().max_pixel_count,
1025 kFrameWidth * kFrameHeight);
sprang84a37592017-02-10 07:04:27 -08001026 EXPECT_FALSE(new_video_source.sink_wants().target_pixel_count);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001027 EXPECT_EQ(kDefaultFramerate, new_video_source.sink_wants().max_framerate_fps);
sprangc5d62e22017-04-02 23:53:04 -07001028
1029 // Calling SetSource with framerate scaling enabled apply the old SinkWants.
mflodmancc3d4422017-08-03 08:27:51 -07001030 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001031 &new_video_source, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
sprangc5d62e22017-04-02 23:53:04 -07001032 EXPECT_FALSE(new_video_source.sink_wants().target_pixel_count);
1033 EXPECT_EQ(std::numeric_limits<int>::max(),
1034 new_video_source.sink_wants().max_pixel_count);
asapersson02465b82017-04-10 01:12:52 -07001035 EXPECT_LT(new_video_source.sink_wants().max_framerate_fps, kInputFps);
perkj803d97f2016-11-01 11:45:46 -07001036
mflodmancc3d4422017-08-03 08:27:51 -07001037 video_stream_encoder_->Stop();
perkj803d97f2016-11-01 11:45:46 -07001038}
1039
mflodmancc3d4422017-08-03 08:27:51 -07001040TEST_F(VideoStreamEncoderTest, StatsTracksQualityAdaptationStats) {
1041 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkj803d97f2016-11-01 11:45:46 -07001042
asaperssonfab67072017-04-04 05:51:49 -07001043 const int kWidth = 1280;
1044 const int kHeight = 720;
asaperssonfab67072017-04-04 05:51:49 -07001045 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001046 WaitForEncodedFrame(1);
asaperssonfab67072017-04-04 05:51:49 -07001047 VideoSendStream::Stats stats = stats_proxy_->GetStats();
1048 EXPECT_FALSE(stats.bw_limited_resolution);
1049 EXPECT_EQ(0, stats.number_of_quality_adapt_changes);
1050
1051 // Trigger adapt down.
mflodmancc3d4422017-08-03 08:27:51 -07001052 video_stream_encoder_->TriggerQualityLow();
asaperssonfab67072017-04-04 05:51:49 -07001053 video_source_.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001054 WaitForEncodedFrame(2);
asaperssonfab67072017-04-04 05:51:49 -07001055
1056 stats = stats_proxy_->GetStats();
1057 EXPECT_TRUE(stats.bw_limited_resolution);
1058 EXPECT_EQ(1, stats.number_of_quality_adapt_changes);
1059
1060 // Trigger adapt up.
mflodmancc3d4422017-08-03 08:27:51 -07001061 video_stream_encoder_->TriggerQualityHigh();
asaperssonfab67072017-04-04 05:51:49 -07001062 video_source_.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001063 WaitForEncodedFrame(3);
asaperssonfab67072017-04-04 05:51:49 -07001064
1065 stats = stats_proxy_->GetStats();
1066 EXPECT_FALSE(stats.bw_limited_resolution);
1067 EXPECT_EQ(2, stats.number_of_quality_adapt_changes);
1068 EXPECT_EQ(0, stats.number_of_cpu_adapt_changes);
1069
mflodmancc3d4422017-08-03 08:27:51 -07001070 video_stream_encoder_->Stop();
asaperssonfab67072017-04-04 05:51:49 -07001071}
1072
mflodmancc3d4422017-08-03 08:27:51 -07001073TEST_F(VideoStreamEncoderTest, StatsTracksCpuAdaptationStats) {
1074 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonfab67072017-04-04 05:51:49 -07001075
1076 const int kWidth = 1280;
1077 const int kHeight = 720;
asaperssonfab67072017-04-04 05:51:49 -07001078 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001079 WaitForEncodedFrame(1);
perkj803d97f2016-11-01 11:45:46 -07001080 VideoSendStream::Stats stats = stats_proxy_->GetStats();
1081 EXPECT_FALSE(stats.cpu_limited_resolution);
1082 EXPECT_EQ(0, stats.number_of_cpu_adapt_changes);
1083
1084 // Trigger CPU overuse.
mflodmancc3d4422017-08-03 08:27:51 -07001085 video_stream_encoder_->TriggerCpuOveruse();
asaperssonfab67072017-04-04 05:51:49 -07001086 video_source_.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001087 WaitForEncodedFrame(2);
perkj803d97f2016-11-01 11:45:46 -07001088
1089 stats = stats_proxy_->GetStats();
1090 EXPECT_TRUE(stats.cpu_limited_resolution);
1091 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1092
1093 // Trigger CPU normal use.
mflodmancc3d4422017-08-03 08:27:51 -07001094 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssonfab67072017-04-04 05:51:49 -07001095 video_source_.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001096 WaitForEncodedFrame(3);
perkj803d97f2016-11-01 11:45:46 -07001097
1098 stats = stats_proxy_->GetStats();
1099 EXPECT_FALSE(stats.cpu_limited_resolution);
1100 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
asaperssonfab67072017-04-04 05:51:49 -07001101 EXPECT_EQ(0, stats.number_of_quality_adapt_changes);
perkj803d97f2016-11-01 11:45:46 -07001102
mflodmancc3d4422017-08-03 08:27:51 -07001103 video_stream_encoder_->Stop();
perkj803d97f2016-11-01 11:45:46 -07001104}
1105
mflodmancc3d4422017-08-03 08:27:51 -07001106TEST_F(VideoStreamEncoderTest, SwitchingSourceKeepsCpuAdaptation) {
1107 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
kthelgason876222f2016-11-29 01:44:11 -08001108
asaperssonfab67072017-04-04 05:51:49 -07001109 const int kWidth = 1280;
1110 const int kHeight = 720;
1111 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001112 WaitForEncodedFrame(1);
kthelgason876222f2016-11-29 01:44:11 -08001113 VideoSendStream::Stats stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001114 EXPECT_FALSE(stats.bw_limited_resolution);
kthelgason876222f2016-11-29 01:44:11 -08001115 EXPECT_FALSE(stats.cpu_limited_resolution);
1116 EXPECT_EQ(0, stats.number_of_cpu_adapt_changes);
1117
asaperssonfab67072017-04-04 05:51:49 -07001118 // Trigger CPU overuse.
mflodmancc3d4422017-08-03 08:27:51 -07001119 video_stream_encoder_->TriggerCpuOveruse();
asaperssonfab67072017-04-04 05:51:49 -07001120 video_source_.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001121 WaitForEncodedFrame(2);
kthelgason876222f2016-11-29 01:44:11 -08001122 stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001123 EXPECT_FALSE(stats.bw_limited_resolution);
kthelgason876222f2016-11-29 01:44:11 -08001124 EXPECT_TRUE(stats.cpu_limited_resolution);
1125 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1126
1127 // Set new source with adaptation still enabled.
1128 test::FrameForwarder new_video_source;
mflodmancc3d4422017-08-03 08:27:51 -07001129 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001130 &new_video_source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
kthelgason876222f2016-11-29 01:44:11 -08001131
asaperssonfab67072017-04-04 05:51:49 -07001132 new_video_source.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001133 WaitForEncodedFrame(3);
kthelgason876222f2016-11-29 01:44:11 -08001134 stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001135 EXPECT_FALSE(stats.bw_limited_resolution);
kthelgason876222f2016-11-29 01:44:11 -08001136 EXPECT_TRUE(stats.cpu_limited_resolution);
1137 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1138
1139 // Set adaptation disabled.
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001140 video_stream_encoder_->SetSource(&new_video_source,
1141 webrtc::DegradationPreference::DISABLED);
kthelgason876222f2016-11-29 01:44:11 -08001142
asaperssonfab67072017-04-04 05:51:49 -07001143 new_video_source.IncomingCapturedFrame(CreateFrame(4, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001144 WaitForEncodedFrame(4);
kthelgason876222f2016-11-29 01:44:11 -08001145 stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001146 EXPECT_FALSE(stats.bw_limited_resolution);
kthelgason876222f2016-11-29 01:44:11 -08001147 EXPECT_FALSE(stats.cpu_limited_resolution);
1148 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1149
1150 // Set adaptation back to enabled.
mflodmancc3d4422017-08-03 08:27:51 -07001151 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001152 &new_video_source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
kthelgason876222f2016-11-29 01:44:11 -08001153
asaperssonfab67072017-04-04 05:51:49 -07001154 new_video_source.IncomingCapturedFrame(CreateFrame(5, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001155 WaitForEncodedFrame(5);
kthelgason876222f2016-11-29 01:44:11 -08001156 stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001157 EXPECT_FALSE(stats.bw_limited_resolution);
kthelgason876222f2016-11-29 01:44:11 -08001158 EXPECT_TRUE(stats.cpu_limited_resolution);
1159 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1160
asaperssonfab67072017-04-04 05:51:49 -07001161 // Trigger CPU normal use.
mflodmancc3d4422017-08-03 08:27:51 -07001162 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssonfab67072017-04-04 05:51:49 -07001163 new_video_source.IncomingCapturedFrame(CreateFrame(6, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001164 WaitForEncodedFrame(6);
kthelgason876222f2016-11-29 01:44:11 -08001165 stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001166 EXPECT_FALSE(stats.bw_limited_resolution);
kthelgason876222f2016-11-29 01:44:11 -08001167 EXPECT_FALSE(stats.cpu_limited_resolution);
1168 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
asapersson02465b82017-04-10 01:12:52 -07001169 EXPECT_EQ(0, stats.number_of_quality_adapt_changes);
kthelgason876222f2016-11-29 01:44:11 -08001170
mflodmancc3d4422017-08-03 08:27:51 -07001171 video_stream_encoder_->Stop();
kthelgason876222f2016-11-29 01:44:11 -08001172}
1173
mflodmancc3d4422017-08-03 08:27:51 -07001174TEST_F(VideoStreamEncoderTest, SwitchingSourceKeepsQualityAdaptation) {
1175 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
kthelgason876222f2016-11-29 01:44:11 -08001176
asaperssonfab67072017-04-04 05:51:49 -07001177 const int kWidth = 1280;
1178 const int kHeight = 720;
1179 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001180 WaitForEncodedFrame(1);
kthelgason876222f2016-11-29 01:44:11 -08001181 VideoSendStream::Stats stats = stats_proxy_->GetStats();
kthelgason876222f2016-11-29 01:44:11 -08001182 EXPECT_FALSE(stats.bw_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001183 EXPECT_FALSE(stats.bw_limited_framerate);
asaperssonfab67072017-04-04 05:51:49 -07001184 EXPECT_EQ(0, stats.number_of_quality_adapt_changes);
kthelgason876222f2016-11-29 01:44:11 -08001185
1186 // Set new source with adaptation still enabled.
1187 test::FrameForwarder new_video_source;
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001188 video_stream_encoder_->SetSource(&new_video_source,
1189 webrtc::DegradationPreference::BALANCED);
kthelgason876222f2016-11-29 01:44:11 -08001190
asaperssonfab67072017-04-04 05:51:49 -07001191 new_video_source.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001192 WaitForEncodedFrame(2);
kthelgason876222f2016-11-29 01:44:11 -08001193 stats = stats_proxy_->GetStats();
kthelgason876222f2016-11-29 01:44:11 -08001194 EXPECT_FALSE(stats.bw_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001195 EXPECT_FALSE(stats.bw_limited_framerate);
asaperssonfab67072017-04-04 05:51:49 -07001196 EXPECT_EQ(0, stats.number_of_quality_adapt_changes);
kthelgason876222f2016-11-29 01:44:11 -08001197
asaperssonfab67072017-04-04 05:51:49 -07001198 // Trigger adapt down.
mflodmancc3d4422017-08-03 08:27:51 -07001199 video_stream_encoder_->TriggerQualityLow();
asaperssonfab67072017-04-04 05:51:49 -07001200 new_video_source.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001201 WaitForEncodedFrame(3);
kthelgason876222f2016-11-29 01:44:11 -08001202 stats = stats_proxy_->GetStats();
kthelgason876222f2016-11-29 01:44:11 -08001203 EXPECT_TRUE(stats.bw_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001204 EXPECT_FALSE(stats.bw_limited_framerate);
asaperssonfab67072017-04-04 05:51:49 -07001205 EXPECT_EQ(1, stats.number_of_quality_adapt_changes);
kthelgason876222f2016-11-29 01:44:11 -08001206
asaperssonfab67072017-04-04 05:51:49 -07001207 // Set new source with adaptation still enabled.
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001208 video_stream_encoder_->SetSource(&new_video_source,
1209 webrtc::DegradationPreference::BALANCED);
kthelgason876222f2016-11-29 01:44:11 -08001210
asaperssonfab67072017-04-04 05:51:49 -07001211 new_video_source.IncomingCapturedFrame(CreateFrame(4, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001212 WaitForEncodedFrame(4);
kthelgason876222f2016-11-29 01:44:11 -08001213 stats = stats_proxy_->GetStats();
kthelgason876222f2016-11-29 01:44:11 -08001214 EXPECT_TRUE(stats.bw_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001215 EXPECT_FALSE(stats.bw_limited_framerate);
asaperssonfab67072017-04-04 05:51:49 -07001216 EXPECT_EQ(1, stats.number_of_quality_adapt_changes);
kthelgason876222f2016-11-29 01:44:11 -08001217
asapersson02465b82017-04-10 01:12:52 -07001218 // Disable resolution scaling.
mflodmancc3d4422017-08-03 08:27:51 -07001219 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001220 &new_video_source, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
kthelgason876222f2016-11-29 01:44:11 -08001221
asaperssonfab67072017-04-04 05:51:49 -07001222 new_video_source.IncomingCapturedFrame(CreateFrame(5, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001223 WaitForEncodedFrame(5);
kthelgason876222f2016-11-29 01:44:11 -08001224 stats = stats_proxy_->GetStats();
kthelgason876222f2016-11-29 01:44:11 -08001225 EXPECT_FALSE(stats.bw_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001226 EXPECT_FALSE(stats.bw_limited_framerate);
asaperssonfab67072017-04-04 05:51:49 -07001227 EXPECT_EQ(1, stats.number_of_quality_adapt_changes);
1228 EXPECT_EQ(0, stats.number_of_cpu_adapt_changes);
kthelgason876222f2016-11-29 01:44:11 -08001229
mflodmancc3d4422017-08-03 08:27:51 -07001230 video_stream_encoder_->Stop();
kthelgason876222f2016-11-29 01:44:11 -08001231}
1232
mflodmancc3d4422017-08-03 08:27:51 -07001233TEST_F(VideoStreamEncoderTest,
1234 QualityAdaptationStatsAreResetWhenScalerIsDisabled) {
1235 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson36e9eb42017-03-31 05:29:12 -07001236
1237 const int kWidth = 1280;
1238 const int kHeight = 720;
Åsa Persson8c1bf952018-09-13 10:42:19 +02001239 int64_t timestamp_ms = kFrameIntervalMs;
asapersson36e9eb42017-03-31 05:29:12 -07001240 video_source_.set_adaptation_enabled(true);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001241 video_source_.IncomingCapturedFrame(
1242 CreateFrame(timestamp_ms, kWidth, kHeight));
1243 WaitForEncodedFrame(timestamp_ms);
asapersson36e9eb42017-03-31 05:29:12 -07001244 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1245 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1246 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1247
1248 // Trigger adapt down.
mflodmancc3d4422017-08-03 08:27:51 -07001249 video_stream_encoder_->TriggerQualityLow();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001250 timestamp_ms += kFrameIntervalMs;
1251 video_source_.IncomingCapturedFrame(
1252 CreateFrame(timestamp_ms, kWidth, kHeight));
1253 WaitForEncodedFrame(timestamp_ms);
asapersson36e9eb42017-03-31 05:29:12 -07001254 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1255 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1256 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1257
1258 // Trigger overuse.
mflodmancc3d4422017-08-03 08:27:51 -07001259 video_stream_encoder_->TriggerCpuOveruse();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001260 timestamp_ms += kFrameIntervalMs;
1261 video_source_.IncomingCapturedFrame(
1262 CreateFrame(timestamp_ms, kWidth, kHeight));
1263 WaitForEncodedFrame(timestamp_ms);
asapersson36e9eb42017-03-31 05:29:12 -07001264 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1265 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1266 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1267
Niels Möller4db138e2018-04-19 09:04:13 +02001268 // Leave source unchanged, but disable quality scaler.
asapersson36e9eb42017-03-31 05:29:12 -07001269 fake_encoder_.SetQualityScaling(false);
Niels Möller4db138e2018-04-19 09:04:13 +02001270
1271 VideoEncoderConfig video_encoder_config;
1272 test::FillEncoderConfiguration(kVideoCodecVP8, 1, &video_encoder_config);
1273 // Make format different, to force recreation of encoder.
1274 video_encoder_config.video_format.parameters["foo"] = "foo";
1275 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
Niels Möllerf1338562018-04-26 09:51:47 +02001276 kMaxPayloadLength);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001277 timestamp_ms += kFrameIntervalMs;
1278 video_source_.IncomingCapturedFrame(
1279 CreateFrame(timestamp_ms, kWidth, kHeight));
1280 WaitForEncodedFrame(timestamp_ms);
asapersson36e9eb42017-03-31 05:29:12 -07001281 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1282 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1283 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1284
mflodmancc3d4422017-08-03 08:27:51 -07001285 video_stream_encoder_->Stop();
asapersson36e9eb42017-03-31 05:29:12 -07001286}
1287
mflodmancc3d4422017-08-03 08:27:51 -07001288TEST_F(VideoStreamEncoderTest,
1289 StatsTracksCpuAdaptationStatsWhenSwitchingSource) {
1290 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkj803d97f2016-11-01 11:45:46 -07001291
asapersson0944a802017-04-07 00:57:58 -07001292 const int kWidth = 1280;
1293 const int kHeight = 720;
sprang84a37592017-02-10 07:04:27 -08001294 int sequence = 1;
perkj803d97f2016-11-01 11:45:46 -07001295
asaperssonfab67072017-04-04 05:51:49 -07001296 video_source_.IncomingCapturedFrame(CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001297 WaitForEncodedFrame(sequence++);
perkj803d97f2016-11-01 11:45:46 -07001298 VideoSendStream::Stats stats = stats_proxy_->GetStats();
sprang84a37592017-02-10 07:04:27 -08001299 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001300 EXPECT_FALSE(stats.cpu_limited_framerate);
sprang84a37592017-02-10 07:04:27 -08001301 EXPECT_EQ(0, stats.number_of_cpu_adapt_changes);
1302
asapersson02465b82017-04-10 01:12:52 -07001303 // Trigger CPU overuse, should now adapt down.
mflodmancc3d4422017-08-03 08:27:51 -07001304 video_stream_encoder_->TriggerCpuOveruse();
asaperssonfab67072017-04-04 05:51:49 -07001305 video_source_.IncomingCapturedFrame(CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001306 WaitForEncodedFrame(sequence++);
sprang84a37592017-02-10 07:04:27 -08001307 stats = stats_proxy_->GetStats();
perkj803d97f2016-11-01 11:45:46 -07001308 EXPECT_TRUE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001309 EXPECT_FALSE(stats.cpu_limited_framerate);
perkj803d97f2016-11-01 11:45:46 -07001310 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1311
1312 // Set new source with adaptation still enabled.
1313 test::FrameForwarder new_video_source;
mflodmancc3d4422017-08-03 08:27:51 -07001314 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001315 &new_video_source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
perkj803d97f2016-11-01 11:45:46 -07001316
1317 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001318 CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001319 WaitForEncodedFrame(sequence++);
perkj803d97f2016-11-01 11:45:46 -07001320 stats = stats_proxy_->GetStats();
1321 EXPECT_TRUE(stats.cpu_limited_resolution);
asapersson09f05612017-05-15 23:40:18 -07001322 EXPECT_FALSE(stats.cpu_limited_framerate);
perkj803d97f2016-11-01 11:45:46 -07001323 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1324
sprangc5d62e22017-04-02 23:53:04 -07001325 // Set cpu adaptation by frame dropping.
mflodmancc3d4422017-08-03 08:27:51 -07001326 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001327 &new_video_source, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
perkj803d97f2016-11-01 11:45:46 -07001328 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001329 CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001330 WaitForEncodedFrame(sequence++);
perkj803d97f2016-11-01 11:45:46 -07001331 stats = stats_proxy_->GetStats();
sprangc5d62e22017-04-02 23:53:04 -07001332 // Not adapted at first.
perkj803d97f2016-11-01 11:45:46 -07001333 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson09f05612017-05-15 23:40:18 -07001334 EXPECT_FALSE(stats.cpu_limited_framerate);
perkj803d97f2016-11-01 11:45:46 -07001335 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1336
sprangc5d62e22017-04-02 23:53:04 -07001337 // Force an input frame rate to be available, or the adaptation call won't
asapersson09f05612017-05-15 23:40:18 -07001338 // know what framerate to adapt from.
sprangc5d62e22017-04-02 23:53:04 -07001339 VideoSendStream::Stats mock_stats = stats_proxy_->GetStats();
1340 mock_stats.input_frame_rate = 30;
1341 stats_proxy_->SetMockStats(mock_stats);
mflodmancc3d4422017-08-03 08:27:51 -07001342 video_stream_encoder_->TriggerCpuOveruse();
sprangc5d62e22017-04-02 23:53:04 -07001343 stats_proxy_->ResetMockStats();
1344
1345 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 // Framerate now adapted.
1350 stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001351 EXPECT_FALSE(stats.cpu_limited_resolution);
1352 EXPECT_TRUE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001353 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
1354
1355 // Disable CPU adaptation.
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001356 video_stream_encoder_->SetSource(&new_video_source,
1357 webrtc::DegradationPreference::DISABLED);
sprangc5d62e22017-04-02 23:53:04 -07001358 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001359 CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001360 WaitForEncodedFrame(sequence++);
sprangc5d62e22017-04-02 23:53:04 -07001361
1362 stats = stats_proxy_->GetStats();
1363 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001364 EXPECT_FALSE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001365 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
1366
1367 // Try to trigger overuse. Should not succeed.
1368 stats_proxy_->SetMockStats(mock_stats);
mflodmancc3d4422017-08-03 08:27:51 -07001369 video_stream_encoder_->TriggerCpuOveruse();
sprangc5d62e22017-04-02 23:53:04 -07001370 stats_proxy_->ResetMockStats();
1371
1372 stats = stats_proxy_->GetStats();
1373 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001374 EXPECT_FALSE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001375 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
1376
1377 // Switch back the source with resolution adaptation enabled.
mflodmancc3d4422017-08-03 08:27:51 -07001378 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001379 &video_source_, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
asaperssonfab67072017-04-04 05:51:49 -07001380 video_source_.IncomingCapturedFrame(CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001381 WaitForEncodedFrame(sequence++);
perkj803d97f2016-11-01 11:45:46 -07001382 stats = stats_proxy_->GetStats();
1383 EXPECT_TRUE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001384 EXPECT_FALSE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001385 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
perkj803d97f2016-11-01 11:45:46 -07001386
1387 // Trigger CPU normal usage.
mflodmancc3d4422017-08-03 08:27:51 -07001388 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssonfab67072017-04-04 05:51:49 -07001389 video_source_.IncomingCapturedFrame(CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001390 WaitForEncodedFrame(sequence++);
perkj803d97f2016-11-01 11:45:46 -07001391 stats = stats_proxy_->GetStats();
1392 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001393 EXPECT_FALSE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001394 EXPECT_EQ(3, stats.number_of_cpu_adapt_changes);
1395
1396 // Back to the source with adaptation off, set it back to maintain-resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001397 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001398 &new_video_source, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
sprangc5d62e22017-04-02 23:53:04 -07001399 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001400 CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001401 WaitForEncodedFrame(sequence++);
sprangc5d62e22017-04-02 23:53:04 -07001402 stats = stats_proxy_->GetStats();
asapersson13874762017-06-07 00:01:02 -07001403 // Disabled, since we previously switched the source to disabled.
sprangc5d62e22017-04-02 23:53:04 -07001404 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001405 EXPECT_TRUE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001406 EXPECT_EQ(3, stats.number_of_cpu_adapt_changes);
1407
1408 // Trigger CPU normal usage.
mflodmancc3d4422017-08-03 08:27:51 -07001409 video_stream_encoder_->TriggerCpuNormalUsage();
sprangc5d62e22017-04-02 23:53:04 -07001410 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001411 CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001412 WaitForEncodedFrame(sequence++);
sprangc5d62e22017-04-02 23:53:04 -07001413 stats = stats_proxy_->GetStats();
1414 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001415 EXPECT_FALSE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001416 EXPECT_EQ(4, stats.number_of_cpu_adapt_changes);
asapersson02465b82017-04-10 01:12:52 -07001417 EXPECT_EQ(0, stats.number_of_quality_adapt_changes);
perkj803d97f2016-11-01 11:45:46 -07001418
mflodmancc3d4422017-08-03 08:27:51 -07001419 video_stream_encoder_->Stop();
perkj803d97f2016-11-01 11:45:46 -07001420}
1421
mflodmancc3d4422017-08-03 08:27:51 -07001422TEST_F(VideoStreamEncoderTest,
1423 ScalingUpAndDownDoesNothingWithMaintainResolution) {
asaperssonfab67072017-04-04 05:51:49 -07001424 const int kWidth = 1280;
1425 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001426 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
kthelgason876222f2016-11-29 01:44:11 -08001427
asaperssonfab67072017-04-04 05:51:49 -07001428 // Expect no scaling to begin with.
asapersson02465b82017-04-10 01:12:52 -07001429 VerifyNoLimitation(video_source_.sink_wants());
kthelgason876222f2016-11-29 01:44:11 -08001430
asaperssonfab67072017-04-04 05:51:49 -07001431 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001432 WaitForEncodedFrame(1);
kthelgason876222f2016-11-29 01:44:11 -08001433
asaperssonfab67072017-04-04 05:51:49 -07001434 // Trigger scale down.
mflodmancc3d4422017-08-03 08:27:51 -07001435 video_stream_encoder_->TriggerQualityLow();
kthelgason5e13d412016-12-01 03:59:51 -08001436
asaperssonfab67072017-04-04 05:51:49 -07001437 video_source_.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001438 WaitForEncodedFrame(2);
kthelgason5e13d412016-12-01 03:59:51 -08001439
kthelgason876222f2016-11-29 01:44:11 -08001440 // Expect a scale down.
1441 EXPECT_TRUE(video_source_.sink_wants().max_pixel_count);
asaperssonfab67072017-04-04 05:51:49 -07001442 EXPECT_LT(video_source_.sink_wants().max_pixel_count, kWidth * kHeight);
kthelgason876222f2016-11-29 01:44:11 -08001443
asapersson02465b82017-04-10 01:12:52 -07001444 // Set resolution scaling disabled.
kthelgason876222f2016-11-29 01:44:11 -08001445 test::FrameForwarder new_video_source;
mflodmancc3d4422017-08-03 08:27:51 -07001446 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001447 &new_video_source, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
kthelgason876222f2016-11-29 01:44:11 -08001448
asaperssonfab67072017-04-04 05:51:49 -07001449 // Trigger scale down.
mflodmancc3d4422017-08-03 08:27:51 -07001450 video_stream_encoder_->TriggerQualityLow();
asaperssonfab67072017-04-04 05:51:49 -07001451 new_video_source.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001452 WaitForEncodedFrame(3);
kthelgason876222f2016-11-29 01:44:11 -08001453
asaperssonfab67072017-04-04 05:51:49 -07001454 // Expect no scaling.
sprangc5d62e22017-04-02 23:53:04 -07001455 EXPECT_EQ(std::numeric_limits<int>::max(),
1456 new_video_source.sink_wants().max_pixel_count);
kthelgason876222f2016-11-29 01:44:11 -08001457
asaperssonfab67072017-04-04 05:51:49 -07001458 // Trigger scale up.
mflodmancc3d4422017-08-03 08:27:51 -07001459 video_stream_encoder_->TriggerQualityHigh();
asaperssonfab67072017-04-04 05:51:49 -07001460 new_video_source.IncomingCapturedFrame(CreateFrame(4, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001461 WaitForEncodedFrame(4);
kthelgason876222f2016-11-29 01:44:11 -08001462
asapersson02465b82017-04-10 01:12:52 -07001463 // Expect nothing to change, still no scaling.
sprangc5d62e22017-04-02 23:53:04 -07001464 EXPECT_EQ(std::numeric_limits<int>::max(),
1465 new_video_source.sink_wants().max_pixel_count);
kthelgason876222f2016-11-29 01:44:11 -08001466
mflodmancc3d4422017-08-03 08:27:51 -07001467 video_stream_encoder_->Stop();
kthelgason876222f2016-11-29 01:44:11 -08001468}
1469
mflodmancc3d4422017-08-03 08:27:51 -07001470TEST_F(VideoStreamEncoderTest,
1471 SkipsSameAdaptDownRequest_MaintainFramerateMode) {
asapersson02465b82017-04-10 01:12:52 -07001472 const int kWidth = 1280;
1473 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001474 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson02465b82017-04-10 01:12:52 -07001475
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001476 // Enable MAINTAIN_FRAMERATE preference, no initial limitation.
asapersson02465b82017-04-10 01:12:52 -07001477 test::FrameForwarder source;
mflodmancc3d4422017-08-03 08:27:51 -07001478 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001479 &source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
asapersson02465b82017-04-10 01:12:52 -07001480
1481 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001482 WaitForEncodedFrame(1);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001483 VerifyFpsMaxResolutionMax(source.sink_wants());
asapersson02465b82017-04-10 01:12:52 -07001484 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1485 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1486
1487 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001488 video_stream_encoder_->TriggerCpuOveruse();
asapersson09f05612017-05-15 23:40:18 -07001489 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
asapersson02465b82017-04-10 01:12:52 -07001490 const int kLastMaxPixelCount = source.sink_wants().max_pixel_count;
1491 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1492 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1493
1494 // Trigger adapt down for same input resolution, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07001495 video_stream_encoder_->TriggerCpuOveruse();
asapersson02465b82017-04-10 01:12:52 -07001496 EXPECT_EQ(kLastMaxPixelCount, source.sink_wants().max_pixel_count);
1497 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1498 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1499
mflodmancc3d4422017-08-03 08:27:51 -07001500 video_stream_encoder_->Stop();
asapersson02465b82017-04-10 01:12:52 -07001501}
1502
mflodmancc3d4422017-08-03 08:27:51 -07001503TEST_F(VideoStreamEncoderTest, SkipsSameOrLargerAdaptDownRequest_BalancedMode) {
asaperssonf7e294d2017-06-13 23:25:22 -07001504 const int kWidth = 1280;
1505 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001506 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -07001507
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001508 // Enable BALANCED preference, no initial limitation.
asaperssonf7e294d2017-06-13 23:25:22 -07001509 test::FrameForwarder source;
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001510 video_stream_encoder_->SetSource(&source,
1511 webrtc::DegradationPreference::BALANCED);
asaperssonf7e294d2017-06-13 23:25:22 -07001512 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
1513 sink_.WaitForEncodedFrame(1);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001514 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07001515
1516 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001517 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07001518 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
1519 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1520 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1521 const int kLastMaxPixelCount = source.sink_wants().max_pixel_count;
1522
1523 // Trigger adapt down for same input resolution, expect no change.
1524 source.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
1525 sink_.WaitForEncodedFrame(2);
mflodmancc3d4422017-08-03 08:27:51 -07001526 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07001527 EXPECT_EQ(kLastMaxPixelCount, source.sink_wants().max_pixel_count);
1528 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1529 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1530
1531 // Trigger adapt down for larger input resolution, expect no change.
1532 source.IncomingCapturedFrame(CreateFrame(3, kWidth + 1, kHeight + 1));
1533 sink_.WaitForEncodedFrame(3);
mflodmancc3d4422017-08-03 08:27:51 -07001534 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07001535 EXPECT_EQ(kLastMaxPixelCount, source.sink_wants().max_pixel_count);
1536 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1537 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1538
mflodmancc3d4422017-08-03 08:27:51 -07001539 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07001540}
1541
mflodmancc3d4422017-08-03 08:27:51 -07001542TEST_F(VideoStreamEncoderTest,
1543 NoChangeForInitialNormalUsage_MaintainFramerateMode) {
asapersson02465b82017-04-10 01:12:52 -07001544 const int kWidth = 1280;
1545 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001546 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson02465b82017-04-10 01:12:52 -07001547
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001548 // Enable MAINTAIN_FRAMERATE preference, no initial limitation.
asapersson02465b82017-04-10 01:12:52 -07001549 test::FrameForwarder source;
mflodmancc3d4422017-08-03 08:27:51 -07001550 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001551 &source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
asapersson02465b82017-04-10 01:12:52 -07001552
1553 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001554 WaitForEncodedFrame(kWidth, kHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001555 VerifyFpsMaxResolutionMax(source.sink_wants());
asapersson02465b82017-04-10 01:12:52 -07001556 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1557 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1558
1559 // Trigger adapt up, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07001560 video_stream_encoder_->TriggerCpuNormalUsage();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001561 VerifyFpsMaxResolutionMax(source.sink_wants());
asapersson02465b82017-04-10 01:12:52 -07001562 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1563 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1564
mflodmancc3d4422017-08-03 08:27:51 -07001565 video_stream_encoder_->Stop();
asapersson02465b82017-04-10 01:12:52 -07001566}
1567
mflodmancc3d4422017-08-03 08:27:51 -07001568TEST_F(VideoStreamEncoderTest,
1569 NoChangeForInitialNormalUsage_MaintainResolutionMode) {
asapersson02465b82017-04-10 01:12:52 -07001570 const int kWidth = 1280;
1571 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001572 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson02465b82017-04-10 01:12:52 -07001573
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001574 // Enable MAINTAIN_RESOLUTION preference, no initial limitation.
asapersson02465b82017-04-10 01:12:52 -07001575 test::FrameForwarder source;
mflodmancc3d4422017-08-03 08:27:51 -07001576 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001577 &source, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
asapersson02465b82017-04-10 01:12:52 -07001578
1579 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001580 WaitForEncodedFrame(kWidth, kHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001581 VerifyFpsMaxResolutionMax(source.sink_wants());
asapersson09f05612017-05-15 23:40:18 -07001582 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
asapersson02465b82017-04-10 01:12:52 -07001583 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1584
1585 // Trigger adapt up, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07001586 video_stream_encoder_->TriggerCpuNormalUsage();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001587 VerifyFpsMaxResolutionMax(source.sink_wants());
asapersson09f05612017-05-15 23:40:18 -07001588 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
asapersson02465b82017-04-10 01:12:52 -07001589 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1590
mflodmancc3d4422017-08-03 08:27:51 -07001591 video_stream_encoder_->Stop();
asapersson02465b82017-04-10 01:12:52 -07001592}
1593
mflodmancc3d4422017-08-03 08:27:51 -07001594TEST_F(VideoStreamEncoderTest, NoChangeForInitialNormalUsage_BalancedMode) {
asaperssonf7e294d2017-06-13 23:25:22 -07001595 const int kWidth = 1280;
1596 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001597 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -07001598
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001599 // Enable BALANCED preference, no initial limitation.
asaperssonf7e294d2017-06-13 23:25:22 -07001600 test::FrameForwarder source;
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001601 video_stream_encoder_->SetSource(&source,
1602 webrtc::DegradationPreference::BALANCED);
asaperssonf7e294d2017-06-13 23:25:22 -07001603
1604 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
1605 sink_.WaitForEncodedFrame(kWidth, kHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001606 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07001607 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1608 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
1609 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1610
1611 // Trigger adapt up, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07001612 video_stream_encoder_->TriggerQualityHigh();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001613 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07001614 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1615 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
1616 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1617
mflodmancc3d4422017-08-03 08:27:51 -07001618 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07001619}
1620
mflodmancc3d4422017-08-03 08:27:51 -07001621TEST_F(VideoStreamEncoderTest, NoChangeForInitialNormalUsage_DisabledMode) {
asapersson09f05612017-05-15 23:40:18 -07001622 const int kWidth = 1280;
1623 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001624 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson09f05612017-05-15 23:40:18 -07001625
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001626 // Enable DISABLED preference, no initial limitation.
asapersson09f05612017-05-15 23:40:18 -07001627 test::FrameForwarder source;
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001628 video_stream_encoder_->SetSource(&source,
1629 webrtc::DegradationPreference::DISABLED);
asapersson09f05612017-05-15 23:40:18 -07001630
1631 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
1632 sink_.WaitForEncodedFrame(kWidth, kHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001633 VerifyFpsMaxResolutionMax(source.sink_wants());
asapersson09f05612017-05-15 23:40:18 -07001634 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1635 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
1636 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1637
1638 // Trigger adapt up, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07001639 video_stream_encoder_->TriggerQualityHigh();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001640 VerifyFpsMaxResolutionMax(source.sink_wants());
asapersson09f05612017-05-15 23:40:18 -07001641 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1642 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
1643 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1644
mflodmancc3d4422017-08-03 08:27:51 -07001645 video_stream_encoder_->Stop();
asapersson09f05612017-05-15 23:40:18 -07001646}
1647
mflodmancc3d4422017-08-03 08:27:51 -07001648TEST_F(VideoStreamEncoderTest,
1649 AdaptsResolutionForLowQuality_MaintainFramerateMode) {
asapersson02465b82017-04-10 01:12:52 -07001650 const int kWidth = 1280;
1651 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001652 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson02465b82017-04-10 01:12:52 -07001653
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001654 // Enable MAINTAIN_FRAMERATE preference, no initial limitation.
asapersson02465b82017-04-10 01:12:52 -07001655 AdaptingFrameForwarder source;
1656 source.set_adaptation_enabled(true);
mflodmancc3d4422017-08-03 08:27:51 -07001657 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001658 &source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
asapersson02465b82017-04-10 01:12:52 -07001659
1660 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001661 WaitForEncodedFrame(1);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001662 VerifyFpsMaxResolutionMax(source.sink_wants());
asapersson02465b82017-04-10 01:12:52 -07001663 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1664 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1665
1666 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001667 video_stream_encoder_->TriggerQualityLow();
asapersson02465b82017-04-10 01:12:52 -07001668 source.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001669 WaitForEncodedFrame(2);
asapersson09f05612017-05-15 23:40:18 -07001670 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
asapersson02465b82017-04-10 01:12:52 -07001671 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1672 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1673
1674 // Trigger adapt up, expect no restriction.
mflodmancc3d4422017-08-03 08:27:51 -07001675 video_stream_encoder_->TriggerQualityHigh();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001676 VerifyFpsMaxResolutionMax(source.sink_wants());
asapersson02465b82017-04-10 01:12:52 -07001677 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1678 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1679 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1680
mflodmancc3d4422017-08-03 08:27:51 -07001681 video_stream_encoder_->Stop();
asapersson02465b82017-04-10 01:12:52 -07001682}
1683
mflodmancc3d4422017-08-03 08:27:51 -07001684TEST_F(VideoStreamEncoderTest,
1685 AdaptsFramerateForLowQuality_MaintainResolutionMode) {
asapersson09f05612017-05-15 23:40:18 -07001686 const int kWidth = 1280;
1687 const int kHeight = 720;
1688 const int kInputFps = 30;
mflodmancc3d4422017-08-03 08:27:51 -07001689 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson09f05612017-05-15 23:40:18 -07001690
1691 VideoSendStream::Stats stats = stats_proxy_->GetStats();
1692 stats.input_frame_rate = kInputFps;
1693 stats_proxy_->SetMockStats(stats);
1694
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001695 // Expect no scaling to begin with (preference: MAINTAIN_FRAMERATE).
asapersson09f05612017-05-15 23:40:18 -07001696 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
1697 sink_.WaitForEncodedFrame(1);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001698 VerifyFpsMaxResolutionMax(video_source_.sink_wants());
asapersson09f05612017-05-15 23:40:18 -07001699
1700 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001701 video_stream_encoder_->TriggerQualityLow();
asapersson09f05612017-05-15 23:40:18 -07001702 video_source_.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
1703 sink_.WaitForEncodedFrame(2);
1704 VerifyFpsMaxResolutionLt(video_source_.sink_wants(), kWidth * kHeight);
1705
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001706 // Enable MAINTAIN_RESOLUTION preference.
asapersson09f05612017-05-15 23:40:18 -07001707 test::FrameForwarder new_video_source;
mflodmancc3d4422017-08-03 08:27:51 -07001708 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001709 &new_video_source, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001710 VerifyFpsMaxResolutionMax(new_video_source.sink_wants());
asapersson09f05612017-05-15 23:40:18 -07001711
1712 // Trigger adapt down, expect reduced framerate.
mflodmancc3d4422017-08-03 08:27:51 -07001713 video_stream_encoder_->TriggerQualityLow();
asapersson09f05612017-05-15 23:40:18 -07001714 new_video_source.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
1715 sink_.WaitForEncodedFrame(3);
1716 VerifyFpsLtResolutionMax(new_video_source.sink_wants(), kInputFps);
1717
1718 // Trigger adapt up, expect no restriction.
mflodmancc3d4422017-08-03 08:27:51 -07001719 video_stream_encoder_->TriggerQualityHigh();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001720 VerifyFpsMaxResolutionMax(new_video_source.sink_wants());
asapersson09f05612017-05-15 23:40:18 -07001721
mflodmancc3d4422017-08-03 08:27:51 -07001722 video_stream_encoder_->Stop();
asapersson09f05612017-05-15 23:40:18 -07001723}
1724
mflodmancc3d4422017-08-03 08:27:51 -07001725TEST_F(VideoStreamEncoderTest, DoesNotScaleBelowSetResolutionLimit) {
asaperssond0de2952017-04-21 01:47:31 -07001726 const int kWidth = 1280;
1727 const int kHeight = 720;
1728 const size_t kNumFrames = 10;
1729
mflodmancc3d4422017-08-03 08:27:51 -07001730 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
kthelgason5e13d412016-12-01 03:59:51 -08001731
asaperssond0de2952017-04-21 01:47:31 -07001732 // Enable adapter, expected input resolutions when downscaling:
asapersson142fcc92017-08-17 08:58:54 -07001733 // 1280x720 -> 960x540 -> 640x360 -> 480x270 -> 320x180 (kMinPixelsPerFrame)
asaperssond0de2952017-04-21 01:47:31 -07001734 video_source_.set_adaptation_enabled(true);
1735
1736 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1737 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1738
1739 int downscales = 0;
1740 for (size_t i = 1; i <= kNumFrames; i++) {
Åsa Persson8c1bf952018-09-13 10:42:19 +02001741 video_source_.IncomingCapturedFrame(
1742 CreateFrame(i * kFrameIntervalMs, kWidth, kHeight));
1743 WaitForEncodedFrame(i * kFrameIntervalMs);
asaperssond0de2952017-04-21 01:47:31 -07001744
asaperssonfab67072017-04-04 05:51:49 -07001745 // Trigger scale down.
asaperssond0de2952017-04-21 01:47:31 -07001746 rtc::VideoSinkWants last_wants = video_source_.sink_wants();
mflodmancc3d4422017-08-03 08:27:51 -07001747 video_stream_encoder_->TriggerQualityLow();
sprangc5d62e22017-04-02 23:53:04 -07001748 EXPECT_GE(video_source_.sink_wants().max_pixel_count, kMinPixelsPerFrame);
asaperssond0de2952017-04-21 01:47:31 -07001749
1750 if (video_source_.sink_wants().max_pixel_count < last_wants.max_pixel_count)
1751 ++downscales;
1752
1753 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1754 EXPECT_EQ(downscales,
1755 stats_proxy_->GetStats().number_of_quality_adapt_changes);
1756 EXPECT_GT(downscales, 0);
kthelgason5e13d412016-12-01 03:59:51 -08001757 }
mflodmancc3d4422017-08-03 08:27:51 -07001758 video_stream_encoder_->Stop();
asaperssond0de2952017-04-21 01:47:31 -07001759}
1760
mflodmancc3d4422017-08-03 08:27:51 -07001761TEST_F(VideoStreamEncoderTest,
asaperssond0de2952017-04-21 01:47:31 -07001762 AdaptsResolutionUpAndDownTwiceOnOveruse_MaintainFramerateMode) {
1763 const int kWidth = 1280;
1764 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001765 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssond0de2952017-04-21 01:47:31 -07001766
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001767 // Enable MAINTAIN_FRAMERATE preference, no initial limitation.
asaperssond0de2952017-04-21 01:47:31 -07001768 AdaptingFrameForwarder source;
1769 source.set_adaptation_enabled(true);
mflodmancc3d4422017-08-03 08:27:51 -07001770 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001771 &source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
asaperssond0de2952017-04-21 01:47:31 -07001772
Åsa Persson8c1bf952018-09-13 10:42:19 +02001773 int64_t timestamp_ms = kFrameIntervalMs;
1774 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001775 WaitForEncodedFrame(kWidth, kHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001776 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssond0de2952017-04-21 01:47:31 -07001777 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1778 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1779
1780 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001781 video_stream_encoder_->TriggerCpuOveruse();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001782 timestamp_ms += kFrameIntervalMs;
1783 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
1784 WaitForEncodedFrame(timestamp_ms);
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(1, 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();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001791 timestamp_ms += kFrameIntervalMs;
1792 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001793 WaitForEncodedFrame(kWidth, kHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001794 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssond0de2952017-04-21 01:47:31 -07001795 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1796 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1797
1798 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001799 video_stream_encoder_->TriggerCpuOveruse();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001800 timestamp_ms += kFrameIntervalMs;
1801 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
1802 WaitForEncodedFrame(timestamp_ms);
asapersson09f05612017-05-15 23:40:18 -07001803 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
asaperssond0de2952017-04-21 01:47:31 -07001804 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1805 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1806
1807 // Trigger adapt up, expect no restriction.
mflodmancc3d4422017-08-03 08:27:51 -07001808 video_stream_encoder_->TriggerCpuNormalUsage();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001809 timestamp_ms += kFrameIntervalMs;
1810 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
asapersson09f05612017-05-15 23:40:18 -07001811 sink_.WaitForEncodedFrame(kWidth, kHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001812 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssond0de2952017-04-21 01:47:31 -07001813 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1814 EXPECT_EQ(4, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1815
mflodmancc3d4422017-08-03 08:27:51 -07001816 video_stream_encoder_->Stop();
asaperssond0de2952017-04-21 01:47:31 -07001817}
1818
mflodmancc3d4422017-08-03 08:27:51 -07001819TEST_F(VideoStreamEncoderTest,
asaperssonf7e294d2017-06-13 23:25:22 -07001820 AdaptsResolutionUpAndDownTwiceForLowQuality_BalancedMode_NoFpsLimit) {
1821 const int kWidth = 1280;
1822 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001823 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -07001824
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001825 // Enable BALANCED preference, no initial limitation.
asaperssonf7e294d2017-06-13 23:25:22 -07001826 AdaptingFrameForwarder source;
1827 source.set_adaptation_enabled(true);
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001828 video_stream_encoder_->SetSource(&source,
1829 webrtc::DegradationPreference::BALANCED);
asaperssonf7e294d2017-06-13 23:25:22 -07001830
Åsa Persson8c1bf952018-09-13 10:42:19 +02001831 int64_t timestamp_ms = kFrameIntervalMs;
1832 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
asaperssonf7e294d2017-06-13 23:25:22 -07001833 sink_.WaitForEncodedFrame(kWidth, kHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001834 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07001835 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1836 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1837
1838 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001839 video_stream_encoder_->TriggerQualityLow();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001840 timestamp_ms += kFrameIntervalMs;
1841 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
1842 sink_.WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07001843 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
1844 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1845 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1846
1847 // Trigger adapt up, expect no restriction.
mflodmancc3d4422017-08-03 08:27:51 -07001848 video_stream_encoder_->TriggerQualityHigh();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001849 timestamp_ms += kFrameIntervalMs;
1850 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
asaperssonf7e294d2017-06-13 23:25:22 -07001851 sink_.WaitForEncodedFrame(kWidth, kHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001852 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07001853 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1854 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1855
1856 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001857 video_stream_encoder_->TriggerQualityLow();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001858 timestamp_ms += kFrameIntervalMs;
1859 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
1860 sink_.WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07001861 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
1862 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1863 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1864
1865 // Trigger adapt up, expect no restriction.
mflodmancc3d4422017-08-03 08:27:51 -07001866 video_stream_encoder_->TriggerQualityHigh();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001867 timestamp_ms += kFrameIntervalMs;
1868 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
asaperssonf7e294d2017-06-13 23:25:22 -07001869 sink_.WaitForEncodedFrame(kWidth, kHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001870 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07001871 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1872 EXPECT_EQ(4, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1873
mflodmancc3d4422017-08-03 08:27:51 -07001874 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07001875}
1876
mflodmancc3d4422017-08-03 08:27:51 -07001877TEST_F(VideoStreamEncoderTest,
asaperssond0de2952017-04-21 01:47:31 -07001878 AdaptsResolutionOnOveruseAndLowQuality_MaintainFramerateMode) {
1879 const int kWidth = 1280;
1880 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001881 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssond0de2952017-04-21 01:47:31 -07001882
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001883 // Enable MAINTAIN_FRAMERATE preference, no initial limitation.
asaperssond0de2952017-04-21 01:47:31 -07001884 AdaptingFrameForwarder source;
1885 source.set_adaptation_enabled(true);
mflodmancc3d4422017-08-03 08:27:51 -07001886 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001887 &source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
asaperssond0de2952017-04-21 01:47:31 -07001888
Åsa Persson8c1bf952018-09-13 10:42:19 +02001889 int64_t timestamp_ms = kFrameIntervalMs;
1890 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001891 WaitForEncodedFrame(kWidth, kHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001892 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssond0de2952017-04-21 01:47:31 -07001893 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1894 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1895 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1896 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1897
1898 // Trigger cpu adapt down, expect scaled down resolution (960x540).
mflodmancc3d4422017-08-03 08:27:51 -07001899 video_stream_encoder_->TriggerCpuOveruse();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001900 timestamp_ms += kFrameIntervalMs;
1901 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
1902 WaitForEncodedFrame(timestamp_ms);
asapersson09f05612017-05-15 23:40:18 -07001903 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
asaperssond0de2952017-04-21 01:47:31 -07001904 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1905 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1906 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1907 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1908
1909 // Trigger cpu adapt down, expect scaled down resolution (640x360).
mflodmancc3d4422017-08-03 08:27:51 -07001910 video_stream_encoder_->TriggerCpuOveruse();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001911 timestamp_ms += kFrameIntervalMs;
1912 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
1913 WaitForEncodedFrame(timestamp_ms);
asapersson09f05612017-05-15 23:40:18 -07001914 VerifyFpsMaxResolutionLt(source.sink_wants(), source.last_wants());
asaperssond0de2952017-04-21 01:47:31 -07001915 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1916 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1917 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1918 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1919
Jonathan Yubc771b72017-12-08 17:04:29 -08001920 // Trigger cpu adapt down, expect scaled down resolution (480x270).
mflodmancc3d4422017-08-03 08:27:51 -07001921 video_stream_encoder_->TriggerCpuOveruse();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001922 timestamp_ms += kFrameIntervalMs;
1923 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
1924 WaitForEncodedFrame(timestamp_ms);
Jonathan Yubc771b72017-12-08 17:04:29 -08001925 VerifyFpsMaxResolutionLt(source.sink_wants(), source.last_wants());
asaperssond0de2952017-04-21 01:47:31 -07001926 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1927 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
Jonathan Yubc771b72017-12-08 17:04:29 -08001928 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
asaperssond0de2952017-04-21 01:47:31 -07001929 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1930
Jonathan Yubc771b72017-12-08 17:04:29 -08001931 // Trigger quality adapt down, expect scaled down resolution (320x180).
mflodmancc3d4422017-08-03 08:27:51 -07001932 video_stream_encoder_->TriggerQualityLow();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001933 timestamp_ms += kFrameIntervalMs;
1934 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
1935 WaitForEncodedFrame(timestamp_ms);
asapersson09f05612017-05-15 23:40:18 -07001936 VerifyFpsMaxResolutionLt(source.sink_wants(), source.last_wants());
Jonathan Yubc771b72017-12-08 17:04:29 -08001937 rtc::VideoSinkWants last_wants = source.sink_wants();
asaperssond0de2952017-04-21 01:47:31 -07001938 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1939 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1940 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1941 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1942
Jonathan Yubc771b72017-12-08 17:04:29 -08001943 // Trigger quality adapt down, expect no change (min resolution reached).
1944 video_stream_encoder_->TriggerQualityLow();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001945 timestamp_ms += kFrameIntervalMs;
1946 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
1947 WaitForEncodedFrame(timestamp_ms);
Jonathan Yubc771b72017-12-08 17:04:29 -08001948 VerifyFpsMaxResolutionEq(source.sink_wants(), last_wants);
1949 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1950 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1951 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1952 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1953
1954 // Trigger cpu adapt up, expect upscaled resolution (480x270).
mflodmancc3d4422017-08-03 08:27:51 -07001955 video_stream_encoder_->TriggerCpuNormalUsage();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001956 timestamp_ms += kFrameIntervalMs;
1957 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
1958 WaitForEncodedFrame(timestamp_ms);
asapersson09f05612017-05-15 23:40:18 -07001959 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
Jonathan Yubc771b72017-12-08 17:04:29 -08001960 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1961 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1962 EXPECT_EQ(4, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1963 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1964
1965 // Trigger cpu adapt up, expect upscaled resolution (640x360).
1966 video_stream_encoder_->TriggerCpuNormalUsage();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001967 timestamp_ms += kFrameIntervalMs;
1968 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
1969 WaitForEncodedFrame(timestamp_ms);
Jonathan Yubc771b72017-12-08 17:04:29 -08001970 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
1971 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1972 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1973 EXPECT_EQ(5, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1974 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1975
1976 // Trigger cpu adapt up, expect upscaled resolution (960x540).
1977 video_stream_encoder_->TriggerCpuNormalUsage();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001978 timestamp_ms += kFrameIntervalMs;
1979 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
1980 WaitForEncodedFrame(timestamp_ms);
Jonathan Yubc771b72017-12-08 17:04:29 -08001981 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
asaperssond0de2952017-04-21 01:47:31 -07001982 last_wants = source.sink_wants();
1983 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1984 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
Jonathan Yubc771b72017-12-08 17:04:29 -08001985 EXPECT_EQ(6, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
asaperssond0de2952017-04-21 01:47:31 -07001986 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1987
1988 // Trigger cpu adapt up, no cpu downgrades, expect no change (960x540).
mflodmancc3d4422017-08-03 08:27:51 -07001989 video_stream_encoder_->TriggerCpuNormalUsage();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001990 timestamp_ms += kFrameIntervalMs;
1991 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
1992 WaitForEncodedFrame(timestamp_ms);
asapersson09f05612017-05-15 23:40:18 -07001993 VerifyFpsEqResolutionEq(source.sink_wants(), last_wants);
asaperssond0de2952017-04-21 01:47:31 -07001994 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1995 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
Jonathan Yubc771b72017-12-08 17:04:29 -08001996 EXPECT_EQ(6, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
asaperssond0de2952017-04-21 01:47:31 -07001997 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1998
1999 // Trigger quality adapt up, expect no restriction (1280x720).
mflodmancc3d4422017-08-03 08:27:51 -07002000 video_stream_encoder_->TriggerQualityHigh();
Åsa Persson8c1bf952018-09-13 10:42:19 +02002001 timestamp_ms += kFrameIntervalMs;
2002 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002003 WaitForEncodedFrame(kWidth, kHeight);
asapersson09f05612017-05-15 23:40:18 -07002004 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
Åsa Persson8c1bf952018-09-13 10:42:19 +02002005 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssond0de2952017-04-21 01:47:31 -07002006 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2007 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
Jonathan Yubc771b72017-12-08 17:04:29 -08002008 EXPECT_EQ(6, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
asaperssond0de2952017-04-21 01:47:31 -07002009 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
kthelgason5e13d412016-12-01 03:59:51 -08002010
mflodmancc3d4422017-08-03 08:27:51 -07002011 video_stream_encoder_->Stop();
kthelgason5e13d412016-12-01 03:59:51 -08002012}
2013
mflodmancc3d4422017-08-03 08:27:51 -07002014TEST_F(VideoStreamEncoderTest, CpuLimitedHistogramIsReported) {
asaperssonfab67072017-04-04 05:51:49 -07002015 const int kWidth = 640;
2016 const int kHeight = 360;
perkj803d97f2016-11-01 11:45:46 -07002017
mflodmancc3d4422017-08-03 08:27:51 -07002018 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
sprang4847ae62017-06-27 07:06:52 -07002019
perkj803d97f2016-11-01 11:45:46 -07002020 for (int i = 1; i <= SendStatisticsProxy::kMinRequiredMetricsSamples; ++i) {
asaperssonfab67072017-04-04 05:51:49 -07002021 video_source_.IncomingCapturedFrame(CreateFrame(i, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002022 WaitForEncodedFrame(i);
perkj803d97f2016-11-01 11:45:46 -07002023 }
2024
mflodmancc3d4422017-08-03 08:27:51 -07002025 video_stream_encoder_->TriggerCpuOveruse();
perkj803d97f2016-11-01 11:45:46 -07002026 for (int i = 1; i <= SendStatisticsProxy::kMinRequiredMetricsSamples; ++i) {
asaperssonfab67072017-04-04 05:51:49 -07002027 video_source_.IncomingCapturedFrame(CreateFrame(
2028 SendStatisticsProxy::kMinRequiredMetricsSamples + i, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002029 WaitForEncodedFrame(SendStatisticsProxy::kMinRequiredMetricsSamples + i);
perkj803d97f2016-11-01 11:45:46 -07002030 }
2031
mflodmancc3d4422017-08-03 08:27:51 -07002032 video_stream_encoder_->Stop();
2033 video_stream_encoder_.reset();
perkj803d97f2016-11-01 11:45:46 -07002034 stats_proxy_.reset();
sprangf8ee65e2017-02-28 08:49:33 -08002035
perkj803d97f2016-11-01 11:45:46 -07002036 EXPECT_EQ(1,
2037 metrics::NumSamples("WebRTC.Video.CpuLimitedResolutionInPercent"));
2038 EXPECT_EQ(
2039 1, metrics::NumEvents("WebRTC.Video.CpuLimitedResolutionInPercent", 50));
2040}
2041
mflodmancc3d4422017-08-03 08:27:51 -07002042TEST_F(VideoStreamEncoderTest,
2043 CpuLimitedHistogramIsNotReportedForDisabledDegradation) {
2044 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonf4e44af2017-04-19 02:01:06 -07002045 const int kWidth = 640;
2046 const int kHeight = 360;
2047
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002048 video_stream_encoder_->SetSource(&video_source_,
2049 webrtc::DegradationPreference::DISABLED);
asaperssonf4e44af2017-04-19 02:01:06 -07002050
2051 for (int i = 1; i <= SendStatisticsProxy::kMinRequiredMetricsSamples; ++i) {
2052 video_source_.IncomingCapturedFrame(CreateFrame(i, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002053 WaitForEncodedFrame(i);
asaperssonf4e44af2017-04-19 02:01:06 -07002054 }
2055
mflodmancc3d4422017-08-03 08:27:51 -07002056 video_stream_encoder_->Stop();
2057 video_stream_encoder_.reset();
asaperssonf4e44af2017-04-19 02:01:06 -07002058 stats_proxy_.reset();
2059
2060 EXPECT_EQ(0,
2061 metrics::NumSamples("WebRTC.Video.CpuLimitedResolutionInPercent"));
2062}
2063
mflodmancc3d4422017-08-03 08:27:51 -07002064TEST_F(VideoStreamEncoderTest, CallsBitrateObserver) {
sprang4847ae62017-06-27 07:06:52 -07002065 MockBitrateObserver bitrate_observer;
Niels Möller0327c2d2018-05-21 14:09:31 +02002066 video_stream_encoder_->SetBitrateAllocationObserver(&bitrate_observer);
sprang57c2fff2017-01-16 06:24:02 -08002067
2068 const int kDefaultFps = 30;
Erik Språng566124a2018-04-23 12:32:22 +02002069 const VideoBitrateAllocation expected_bitrate =
sprang57c2fff2017-01-16 06:24:02 -08002070 DefaultVideoBitrateAllocator(fake_encoder_.codec_config())
kthelgason2bc68642017-02-07 07:02:22 -08002071 .GetAllocation(kLowTargetBitrateBps, kDefaultFps);
sprang57c2fff2017-01-16 06:24:02 -08002072
2073 // First called on bitrate updated, then again on first frame.
2074 EXPECT_CALL(bitrate_observer, OnBitrateAllocationUpdated(expected_bitrate))
2075 .Times(2);
mflodmancc3d4422017-08-03 08:27:51 -07002076 video_stream_encoder_->OnBitrateUpdated(kLowTargetBitrateBps, 0, 0);
sprang57c2fff2017-01-16 06:24:02 -08002077
2078 const int64_t kStartTimeMs = 1;
2079 video_source_.IncomingCapturedFrame(
2080 CreateFrame(kStartTimeMs, codec_width_, codec_height_));
sprang4847ae62017-06-27 07:06:52 -07002081 WaitForEncodedFrame(kStartTimeMs);
sprang57c2fff2017-01-16 06:24:02 -08002082
2083 // Not called on second frame.
2084 EXPECT_CALL(bitrate_observer, OnBitrateAllocationUpdated(expected_bitrate))
2085 .Times(0);
2086 video_source_.IncomingCapturedFrame(
2087 CreateFrame(kStartTimeMs + 1, codec_width_, codec_height_));
sprang4847ae62017-06-27 07:06:52 -07002088 WaitForEncodedFrame(kStartTimeMs + 1);
sprang57c2fff2017-01-16 06:24:02 -08002089
2090 // Called after a process interval.
2091 const int64_t kProcessIntervalMs =
2092 vcm::VCMProcessTimer::kDefaultProcessIntervalMs;
sprang4847ae62017-06-27 07:06:52 -07002093 fake_clock_.AdvanceTimeMicros(rtc::kNumMicrosecsPerMillisec *
2094 (kProcessIntervalMs + (1000 / kDefaultFps)));
sprang57c2fff2017-01-16 06:24:02 -08002095 EXPECT_CALL(bitrate_observer, OnBitrateAllocationUpdated(expected_bitrate))
2096 .Times(1);
2097 video_source_.IncomingCapturedFrame(CreateFrame(
2098 kStartTimeMs + kProcessIntervalMs, codec_width_, codec_height_));
sprang4847ae62017-06-27 07:06:52 -07002099 WaitForEncodedFrame(kStartTimeMs + kProcessIntervalMs);
sprang57c2fff2017-01-16 06:24:02 -08002100
mflodmancc3d4422017-08-03 08:27:51 -07002101 video_stream_encoder_->Stop();
sprang57c2fff2017-01-16 06:24:02 -08002102}
2103
Niels Möller7dc26b72017-12-06 10:27:48 +01002104TEST_F(VideoStreamEncoderTest, OveruseDetectorUpdatedOnReconfigureAndAdaption) {
2105 const int kFrameWidth = 1280;
2106 const int kFrameHeight = 720;
2107 const int kFramerate = 24;
2108
2109 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
2110 test::FrameForwarder source;
2111 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002112 &source, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
Niels Möller7dc26b72017-12-06 10:27:48 +01002113
2114 // Insert a single frame, triggering initial configuration.
2115 source.IncomingCapturedFrame(CreateFrame(1, kFrameWidth, kFrameHeight));
2116 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2117
2118 EXPECT_EQ(
2119 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2120 kDefaultFramerate);
2121
2122 // Trigger reconfigure encoder (without resetting the entire instance).
2123 VideoEncoderConfig video_encoder_config;
Niels Möller259a4972018-04-05 15:36:51 +02002124 video_encoder_config.codec_type = kVideoCodecVP8;
Niels Möller7dc26b72017-12-06 10:27:48 +01002125 video_encoder_config.max_bitrate_bps = kTargetBitrateBps;
2126 video_encoder_config.number_of_streams = 1;
2127 video_encoder_config.video_stream_factory =
2128 new rtc::RefCountedObject<VideoStreamFactory>(1, kFramerate);
2129 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
Niels Möllerf1338562018-04-26 09:51:47 +02002130 kMaxPayloadLength);
Niels Möller7dc26b72017-12-06 10:27:48 +01002131 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2132
2133 // Detector should be updated with fps limit from codec config.
2134 EXPECT_EQ(
2135 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2136 kFramerate);
2137
2138 // Trigger overuse, max framerate should be reduced.
2139 VideoSendStream::Stats stats = stats_proxy_->GetStats();
2140 stats.input_frame_rate = kFramerate;
2141 stats_proxy_->SetMockStats(stats);
2142 video_stream_encoder_->TriggerCpuOveruse();
2143 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2144 int adapted_framerate =
2145 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate();
2146 EXPECT_LT(adapted_framerate, kFramerate);
2147
2148 // Trigger underuse, max framerate should go back to codec configured fps.
2149 // Set extra low fps, to make sure it's actually reset, not just incremented.
2150 stats = stats_proxy_->GetStats();
2151 stats.input_frame_rate = adapted_framerate / 2;
2152 stats_proxy_->SetMockStats(stats);
2153 video_stream_encoder_->TriggerCpuNormalUsage();
2154 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2155 EXPECT_EQ(
2156 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2157 kFramerate);
2158
2159 video_stream_encoder_->Stop();
2160}
2161
2162TEST_F(VideoStreamEncoderTest,
2163 OveruseDetectorUpdatedRespectsFramerateAfterUnderuse) {
2164 const int kFrameWidth = 1280;
2165 const int kFrameHeight = 720;
2166 const int kLowFramerate = 15;
2167 const int kHighFramerate = 25;
2168
2169 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
2170 test::FrameForwarder source;
2171 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002172 &source, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
Niels Möller7dc26b72017-12-06 10:27:48 +01002173
2174 // Trigger initial configuration.
2175 VideoEncoderConfig video_encoder_config;
Niels Möller259a4972018-04-05 15:36:51 +02002176 video_encoder_config.codec_type = kVideoCodecVP8;
Niels Möller7dc26b72017-12-06 10:27:48 +01002177 video_encoder_config.max_bitrate_bps = kTargetBitrateBps;
2178 video_encoder_config.number_of_streams = 1;
2179 video_encoder_config.video_stream_factory =
2180 new rtc::RefCountedObject<VideoStreamFactory>(1, kLowFramerate);
2181 source.IncomingCapturedFrame(CreateFrame(1, kFrameWidth, kFrameHeight));
2182 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
Niels Möllerf1338562018-04-26 09:51:47 +02002183 kMaxPayloadLength);
Niels Möller7dc26b72017-12-06 10:27:48 +01002184 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2185
2186 EXPECT_EQ(
2187 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2188 kLowFramerate);
2189
2190 // Trigger overuse, max framerate should be reduced.
2191 VideoSendStream::Stats stats = stats_proxy_->GetStats();
2192 stats.input_frame_rate = kLowFramerate;
2193 stats_proxy_->SetMockStats(stats);
2194 video_stream_encoder_->TriggerCpuOveruse();
2195 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2196 int adapted_framerate =
2197 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate();
2198 EXPECT_LT(adapted_framerate, kLowFramerate);
2199
2200 // Reconfigure the encoder with a new (higher max framerate), max fps should
2201 // still respect the adaptation.
2202 video_encoder_config.video_stream_factory =
2203 new rtc::RefCountedObject<VideoStreamFactory>(1, kHighFramerate);
2204 source.IncomingCapturedFrame(CreateFrame(1, kFrameWidth, kFrameHeight));
2205 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
Niels Möllerf1338562018-04-26 09:51:47 +02002206 kMaxPayloadLength);
Niels Möller7dc26b72017-12-06 10:27:48 +01002207 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2208
2209 EXPECT_EQ(
2210 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2211 adapted_framerate);
2212
2213 // Trigger underuse, max framerate should go back to codec configured fps.
2214 stats = stats_proxy_->GetStats();
2215 stats.input_frame_rate = adapted_framerate;
2216 stats_proxy_->SetMockStats(stats);
2217 video_stream_encoder_->TriggerCpuNormalUsage();
2218 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2219 EXPECT_EQ(
2220 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2221 kHighFramerate);
2222
2223 video_stream_encoder_->Stop();
2224}
2225
mflodmancc3d4422017-08-03 08:27:51 -07002226TEST_F(VideoStreamEncoderTest,
2227 OveruseDetectorUpdatedOnDegradationPreferenceChange) {
sprangfda496a2017-06-15 04:21:07 -07002228 const int kFrameWidth = 1280;
2229 const int kFrameHeight = 720;
2230 const int kFramerate = 24;
2231
mflodmancc3d4422017-08-03 08:27:51 -07002232 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
sprangfda496a2017-06-15 04:21:07 -07002233 test::FrameForwarder source;
mflodmancc3d4422017-08-03 08:27:51 -07002234 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002235 &source, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
sprangfda496a2017-06-15 04:21:07 -07002236
2237 // Trigger initial configuration.
2238 VideoEncoderConfig video_encoder_config;
Niels Möller259a4972018-04-05 15:36:51 +02002239 video_encoder_config.codec_type = kVideoCodecVP8;
sprangfda496a2017-06-15 04:21:07 -07002240 video_encoder_config.max_bitrate_bps = kTargetBitrateBps;
2241 video_encoder_config.number_of_streams = 1;
2242 video_encoder_config.video_stream_factory =
2243 new rtc::RefCountedObject<VideoStreamFactory>(1, kFramerate);
2244 source.IncomingCapturedFrame(CreateFrame(1, kFrameWidth, kFrameHeight));
mflodmancc3d4422017-08-03 08:27:51 -07002245 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
Niels Möllerf1338562018-04-26 09:51:47 +02002246 kMaxPayloadLength);
mflodmancc3d4422017-08-03 08:27:51 -07002247 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
sprangfda496a2017-06-15 04:21:07 -07002248
Niels Möller7dc26b72017-12-06 10:27:48 +01002249 EXPECT_EQ(
2250 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2251 kFramerate);
sprangfda496a2017-06-15 04:21:07 -07002252
2253 // Trigger overuse, max framerate should be reduced.
2254 VideoSendStream::Stats stats = stats_proxy_->GetStats();
2255 stats.input_frame_rate = kFramerate;
2256 stats_proxy_->SetMockStats(stats);
mflodmancc3d4422017-08-03 08:27:51 -07002257 video_stream_encoder_->TriggerCpuOveruse();
2258 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
Niels Möller7dc26b72017-12-06 10:27:48 +01002259 int adapted_framerate =
2260 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate();
sprangfda496a2017-06-15 04:21:07 -07002261 EXPECT_LT(adapted_framerate, kFramerate);
2262
2263 // Change degradation preference to not enable framerate scaling. Target
2264 // framerate should be changed to codec defined limit.
mflodmancc3d4422017-08-03 08:27:51 -07002265 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002266 &source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
mflodmancc3d4422017-08-03 08:27:51 -07002267 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
Niels Möller7dc26b72017-12-06 10:27:48 +01002268 EXPECT_EQ(
2269 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2270 kFramerate);
sprangfda496a2017-06-15 04:21:07 -07002271
mflodmancc3d4422017-08-03 08:27:51 -07002272 video_stream_encoder_->Stop();
sprangfda496a2017-06-15 04:21:07 -07002273}
2274
mflodmancc3d4422017-08-03 08:27:51 -07002275TEST_F(VideoStreamEncoderTest, DropsFramesAndScalesWhenBitrateIsTooLow) {
asaperssonfab67072017-04-04 05:51:49 -07002276 const int kTooLowBitrateForFrameSizeBps = 10000;
mflodmancc3d4422017-08-03 08:27:51 -07002277 video_stream_encoder_->OnBitrateUpdated(kTooLowBitrateForFrameSizeBps, 0, 0);
asaperssonfab67072017-04-04 05:51:49 -07002278 const int kWidth = 640;
2279 const int kHeight = 360;
kthelgason2bc68642017-02-07 07:02:22 -08002280
asaperssonfab67072017-04-04 05:51:49 -07002281 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
kthelgason2bc68642017-02-07 07:02:22 -08002282
2283 // Expect to drop this frame, the wait should time out.
sprang4847ae62017-06-27 07:06:52 -07002284 ExpectDroppedFrame();
kthelgason2bc68642017-02-07 07:02:22 -08002285
2286 // Expect the sink_wants to specify a scaled frame.
asapersson0944a802017-04-07 00:57:58 -07002287 EXPECT_LT(video_source_.sink_wants().max_pixel_count, kWidth * kHeight);
kthelgason2bc68642017-02-07 07:02:22 -08002288
sprangc5d62e22017-04-02 23:53:04 -07002289 int last_pixel_count = video_source_.sink_wants().max_pixel_count;
kthelgason2bc68642017-02-07 07:02:22 -08002290
asaperssonfab67072017-04-04 05:51:49 -07002291 // Next frame is scaled.
kthelgason2bc68642017-02-07 07:02:22 -08002292 video_source_.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07002293 CreateFrame(2, kWidth * 3 / 4, kHeight * 3 / 4));
kthelgason2bc68642017-02-07 07:02:22 -08002294
2295 // Expect to drop this frame, the wait should time out.
sprang4847ae62017-06-27 07:06:52 -07002296 ExpectDroppedFrame();
kthelgason2bc68642017-02-07 07:02:22 -08002297
sprangc5d62e22017-04-02 23:53:04 -07002298 EXPECT_LT(video_source_.sink_wants().max_pixel_count, last_pixel_count);
kthelgason2bc68642017-02-07 07:02:22 -08002299
mflodmancc3d4422017-08-03 08:27:51 -07002300 video_stream_encoder_->Stop();
kthelgason2bc68642017-02-07 07:02:22 -08002301}
2302
mflodmancc3d4422017-08-03 08:27:51 -07002303TEST_F(VideoStreamEncoderTest,
2304 NumberOfDroppedFramesLimitedWhenBitrateIsTooLow) {
asaperssonfab67072017-04-04 05:51:49 -07002305 const int kTooLowBitrateForFrameSizeBps = 10000;
mflodmancc3d4422017-08-03 08:27:51 -07002306 video_stream_encoder_->OnBitrateUpdated(kTooLowBitrateForFrameSizeBps, 0, 0);
asaperssonfab67072017-04-04 05:51:49 -07002307 const int kWidth = 640;
2308 const int kHeight = 360;
kthelgason2bc68642017-02-07 07:02:22 -08002309
2310 // We expect the n initial frames to get dropped.
2311 int i;
2312 for (i = 1; i <= kMaxInitialFramedrop; ++i) {
asaperssonfab67072017-04-04 05:51:49 -07002313 video_source_.IncomingCapturedFrame(CreateFrame(i, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002314 ExpectDroppedFrame();
kthelgason2bc68642017-02-07 07:02:22 -08002315 }
2316 // The n+1th frame should not be dropped, even though it's size is too large.
asaperssonfab67072017-04-04 05:51:49 -07002317 video_source_.IncomingCapturedFrame(CreateFrame(i, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002318 WaitForEncodedFrame(i);
kthelgason2bc68642017-02-07 07:02:22 -08002319
2320 // Expect the sink_wants to specify a scaled frame.
asaperssonfab67072017-04-04 05:51:49 -07002321 EXPECT_LT(video_source_.sink_wants().max_pixel_count, kWidth * kHeight);
kthelgason2bc68642017-02-07 07:02:22 -08002322
mflodmancc3d4422017-08-03 08:27:51 -07002323 video_stream_encoder_->Stop();
kthelgason2bc68642017-02-07 07:02:22 -08002324}
2325
mflodmancc3d4422017-08-03 08:27:51 -07002326TEST_F(VideoStreamEncoderTest,
2327 InitialFrameDropOffWithMaintainResolutionPreference) {
asaperssonfab67072017-04-04 05:51:49 -07002328 const int kWidth = 640;
2329 const int kHeight = 360;
mflodmancc3d4422017-08-03 08:27:51 -07002330 video_stream_encoder_->OnBitrateUpdated(kLowTargetBitrateBps, 0, 0);
kthelgason2bc68642017-02-07 07:02:22 -08002331
2332 // Set degradation preference.
mflodmancc3d4422017-08-03 08:27:51 -07002333 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002334 &video_source_, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
kthelgason2bc68642017-02-07 07:02:22 -08002335
asaperssonfab67072017-04-04 05:51:49 -07002336 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
kthelgason2bc68642017-02-07 07:02:22 -08002337 // Frame should not be dropped, even if it's too large.
sprang4847ae62017-06-27 07:06:52 -07002338 WaitForEncodedFrame(1);
kthelgason2bc68642017-02-07 07:02:22 -08002339
mflodmancc3d4422017-08-03 08:27:51 -07002340 video_stream_encoder_->Stop();
kthelgason2bc68642017-02-07 07:02:22 -08002341}
2342
mflodmancc3d4422017-08-03 08:27:51 -07002343TEST_F(VideoStreamEncoderTest, InitialFrameDropOffWhenEncoderDisabledScaling) {
asaperssonfab67072017-04-04 05:51:49 -07002344 const int kWidth = 640;
2345 const int kHeight = 360;
kthelgasonad9010c2017-02-14 00:46:51 -08002346 fake_encoder_.SetQualityScaling(false);
Niels Möller4db138e2018-04-19 09:04:13 +02002347
2348 VideoEncoderConfig video_encoder_config;
2349 test::FillEncoderConfiguration(kVideoCodecVP8, 1, &video_encoder_config);
2350 // Make format different, to force recreation of encoder.
2351 video_encoder_config.video_format.parameters["foo"] = "foo";
2352 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
Niels Möllerf1338562018-04-26 09:51:47 +02002353 kMaxPayloadLength);
mflodmancc3d4422017-08-03 08:27:51 -07002354 video_stream_encoder_->OnBitrateUpdated(kLowTargetBitrateBps, 0, 0);
asapersson09f05612017-05-15 23:40:18 -07002355
kthelgasonb83797b2017-02-14 11:57:25 -08002356 // Force quality scaler reconfiguration by resetting the source.
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002357 video_stream_encoder_->SetSource(&video_source_,
2358 webrtc::DegradationPreference::BALANCED);
kthelgasonad9010c2017-02-14 00:46:51 -08002359
asaperssonfab67072017-04-04 05:51:49 -07002360 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
kthelgasonad9010c2017-02-14 00:46:51 -08002361 // Frame should not be dropped, even if it's too large.
sprang4847ae62017-06-27 07:06:52 -07002362 WaitForEncodedFrame(1);
kthelgasonad9010c2017-02-14 00:46:51 -08002363
mflodmancc3d4422017-08-03 08:27:51 -07002364 video_stream_encoder_->Stop();
kthelgasonad9010c2017-02-14 00:46:51 -08002365 fake_encoder_.SetQualityScaling(true);
2366}
2367
Kári Tristan Helgason639602a2018-08-02 10:51:40 +02002368TEST_F(VideoStreamEncoderTest, InitialFrameDropActivatesWhenBWEstimateReady) {
2369 webrtc::test::ScopedFieldTrials field_trials(
2370 "WebRTC-InitialFramedrop/Enabled/");
2371 // Reset encoder for field trials to take effect.
2372 ConfigureEncoder(video_encoder_config_.Copy());
2373 const int kTooLowBitrateForFrameSizeBps = 10000;
2374 const int kWidth = 640;
2375 const int kHeight = 360;
2376
2377 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
2378 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
2379 // Frame should not be dropped.
2380 WaitForEncodedFrame(1);
2381
2382 video_stream_encoder_->OnBitrateUpdated(kTooLowBitrateForFrameSizeBps, 0, 0);
2383 video_source_.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
2384 // Expect to drop this frame, the wait should time out.
2385 ExpectDroppedFrame();
2386
2387 // Expect the sink_wants to specify a scaled frame.
2388 EXPECT_LT(video_source_.sink_wants().max_pixel_count, kWidth * kHeight);
2389 video_stream_encoder_->Stop();
2390}
2391
mflodmancc3d4422017-08-03 08:27:51 -07002392TEST_F(VideoStreamEncoderTest,
asaperssond0de2952017-04-21 01:47:31 -07002393 ResolutionNotAdaptedForTooSmallFrame_MaintainFramerateMode) {
2394 const int kTooSmallWidth = 10;
2395 const int kTooSmallHeight = 10;
mflodmancc3d4422017-08-03 08:27:51 -07002396 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssond0de2952017-04-21 01:47:31 -07002397
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002398 // Enable MAINTAIN_FRAMERATE preference, no initial limitation.
asaperssond0de2952017-04-21 01:47:31 -07002399 test::FrameForwarder source;
mflodmancc3d4422017-08-03 08:27:51 -07002400 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002401 &source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
asaperssond0de2952017-04-21 01:47:31 -07002402 VerifyNoLimitation(source.sink_wants());
2403 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2404
2405 // Trigger adapt down, too small frame, expect no change.
2406 source.IncomingCapturedFrame(CreateFrame(1, kTooSmallWidth, kTooSmallHeight));
sprang4847ae62017-06-27 07:06:52 -07002407 WaitForEncodedFrame(1);
mflodmancc3d4422017-08-03 08:27:51 -07002408 video_stream_encoder_->TriggerCpuOveruse();
Åsa Persson8c1bf952018-09-13 10:42:19 +02002409 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssond0de2952017-04-21 01:47:31 -07002410 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2411 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2412
mflodmancc3d4422017-08-03 08:27:51 -07002413 video_stream_encoder_->Stop();
asaperssond0de2952017-04-21 01:47:31 -07002414}
2415
mflodmancc3d4422017-08-03 08:27:51 -07002416TEST_F(VideoStreamEncoderTest,
2417 ResolutionNotAdaptedForTooSmallFrame_BalancedMode) {
asaperssonf7e294d2017-06-13 23:25:22 -07002418 const int kTooSmallWidth = 10;
2419 const int kTooSmallHeight = 10;
2420 const int kFpsLimit = 7;
mflodmancc3d4422017-08-03 08:27:51 -07002421 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -07002422
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002423 // Enable BALANCED preference, no initial limitation.
asaperssonf7e294d2017-06-13 23:25:22 -07002424 test::FrameForwarder source;
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002425 video_stream_encoder_->SetSource(&source,
2426 webrtc::DegradationPreference::BALANCED);
asaperssonf7e294d2017-06-13 23:25:22 -07002427 VerifyNoLimitation(source.sink_wants());
2428 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2429 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2430
2431 // Trigger adapt down, expect limited framerate.
2432 source.IncomingCapturedFrame(CreateFrame(1, kTooSmallWidth, kTooSmallHeight));
sprang4847ae62017-06-27 07:06:52 -07002433 WaitForEncodedFrame(1);
mflodmancc3d4422017-08-03 08:27:51 -07002434 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002435 VerifyFpsEqResolutionMax(source.sink_wants(), kFpsLimit);
2436 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2437 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2438 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2439
2440 // Trigger adapt down, too small frame, expect no change.
2441 source.IncomingCapturedFrame(CreateFrame(2, kTooSmallWidth, kTooSmallHeight));
sprang4847ae62017-06-27 07:06:52 -07002442 WaitForEncodedFrame(2);
mflodmancc3d4422017-08-03 08:27:51 -07002443 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002444 VerifyFpsEqResolutionMax(source.sink_wants(), kFpsLimit);
2445 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2446 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2447 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2448
mflodmancc3d4422017-08-03 08:27:51 -07002449 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07002450}
2451
mflodmancc3d4422017-08-03 08:27:51 -07002452TEST_F(VideoStreamEncoderTest, FailingInitEncodeDoesntCauseCrash) {
asapersson02465b82017-04-10 01:12:52 -07002453 fake_encoder_.ForceInitEncodeFailure(true);
mflodmancc3d4422017-08-03 08:27:51 -07002454 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
Niels Möllerf1338562018-04-26 09:51:47 +02002455 ResetEncoder("VP8", 2, 1, 1, false);
asapersson02465b82017-04-10 01:12:52 -07002456 const int kFrameWidth = 1280;
2457 const int kFrameHeight = 720;
2458 video_source_.IncomingCapturedFrame(
2459 CreateFrame(1, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002460 ExpectDroppedFrame();
mflodmancc3d4422017-08-03 08:27:51 -07002461 video_stream_encoder_->Stop();
asapersson02465b82017-04-10 01:12:52 -07002462}
2463
sprangb1ca0732017-02-01 08:38:12 -08002464// TODO(sprang): Extend this with fps throttling and any "balanced" extensions.
mflodmancc3d4422017-08-03 08:27:51 -07002465TEST_F(VideoStreamEncoderTest,
2466 AdaptsResolutionOnOveruse_MaintainFramerateMode) {
2467 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
sprangb1ca0732017-02-01 08:38:12 -08002468
2469 const int kFrameWidth = 1280;
2470 const int kFrameHeight = 720;
2471 // Enabled default VideoAdapter downscaling. First step is 3/4, not 3/5 as
mflodmancc3d4422017-08-03 08:27:51 -07002472 // requested by
2473 // VideoStreamEncoder::VideoSourceProxy::RequestResolutionLowerThan().
sprangb1ca0732017-02-01 08:38:12 -08002474 video_source_.set_adaptation_enabled(true);
2475
2476 video_source_.IncomingCapturedFrame(
Åsa Persson8c1bf952018-09-13 10:42:19 +02002477 CreateFrame(1 * kFrameIntervalMs, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002478 WaitForEncodedFrame(kFrameWidth, kFrameHeight);
sprangb1ca0732017-02-01 08:38:12 -08002479
2480 // Trigger CPU overuse, downscale by 3/4.
mflodmancc3d4422017-08-03 08:27:51 -07002481 video_stream_encoder_->TriggerCpuOveruse();
sprangb1ca0732017-02-01 08:38:12 -08002482 video_source_.IncomingCapturedFrame(
Åsa Persson8c1bf952018-09-13 10:42:19 +02002483 CreateFrame(2 * kFrameIntervalMs, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002484 WaitForEncodedFrame((kFrameWidth * 3) / 4, (kFrameHeight * 3) / 4);
sprangb1ca0732017-02-01 08:38:12 -08002485
asaperssonfab67072017-04-04 05:51:49 -07002486 // Trigger CPU normal use, return to original resolution.
mflodmancc3d4422017-08-03 08:27:51 -07002487 video_stream_encoder_->TriggerCpuNormalUsage();
sprangb1ca0732017-02-01 08:38:12 -08002488 video_source_.IncomingCapturedFrame(
Åsa Persson8c1bf952018-09-13 10:42:19 +02002489 CreateFrame(3 * kFrameIntervalMs, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002490 WaitForEncodedFrame(kFrameWidth, kFrameHeight);
sprangb1ca0732017-02-01 08:38:12 -08002491
mflodmancc3d4422017-08-03 08:27:51 -07002492 video_stream_encoder_->Stop();
sprangb1ca0732017-02-01 08:38:12 -08002493}
sprangfe627f32017-03-29 08:24:59 -07002494
mflodmancc3d4422017-08-03 08:27:51 -07002495TEST_F(VideoStreamEncoderTest,
2496 AdaptsFramerateOnOveruse_MaintainResolutionMode) {
sprangc5d62e22017-04-02 23:53:04 -07002497 const int kFrameWidth = 1280;
2498 const int kFrameHeight = 720;
sprangc5d62e22017-04-02 23:53:04 -07002499
mflodmancc3d4422017-08-03 08:27:51 -07002500 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
2501 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002502 &video_source_, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
sprangc5d62e22017-04-02 23:53:04 -07002503 video_source_.set_adaptation_enabled(true);
2504
sprang4847ae62017-06-27 07:06:52 -07002505 int64_t timestamp_ms = fake_clock_.TimeNanos() / rtc::kNumNanosecsPerMillisec;
sprangc5d62e22017-04-02 23:53:04 -07002506
2507 video_source_.IncomingCapturedFrame(
2508 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002509 WaitForEncodedFrame(timestamp_ms);
sprangc5d62e22017-04-02 23:53:04 -07002510
2511 // Try to trigger overuse. No fps estimate available => no effect.
mflodmancc3d4422017-08-03 08:27:51 -07002512 video_stream_encoder_->TriggerCpuOveruse();
sprangc5d62e22017-04-02 23:53:04 -07002513
2514 // Insert frames for one second to get a stable estimate.
sprang4847ae62017-06-27 07:06:52 -07002515 for (int i = 0; i < max_framerate_; ++i) {
sprangc5d62e22017-04-02 23:53:04 -07002516 timestamp_ms += kFrameIntervalMs;
sprangc5d62e22017-04-02 23:53:04 -07002517 video_source_.IncomingCapturedFrame(
2518 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002519 WaitForEncodedFrame(timestamp_ms);
sprangc5d62e22017-04-02 23:53:04 -07002520 }
2521
2522 // Trigger CPU overuse, reduce framerate by 2/3.
mflodmancc3d4422017-08-03 08:27:51 -07002523 video_stream_encoder_->TriggerCpuOveruse();
sprangc5d62e22017-04-02 23:53:04 -07002524 int num_frames_dropped = 0;
sprang4847ae62017-06-27 07:06:52 -07002525 for (int i = 0; i < max_framerate_; ++i) {
sprangc5d62e22017-04-02 23:53:04 -07002526 timestamp_ms += kFrameIntervalMs;
sprangc5d62e22017-04-02 23:53:04 -07002527 video_source_.IncomingCapturedFrame(
2528 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002529 if (!WaitForFrame(kFrameTimeoutMs)) {
sprangc5d62e22017-04-02 23:53:04 -07002530 ++num_frames_dropped;
2531 } else {
Åsa Perssonc74d8da2017-12-04 14:13:56 +01002532 sink_.CheckLastFrameSizeMatches(kFrameWidth, kFrameHeight);
sprangc5d62e22017-04-02 23:53:04 -07002533 }
2534 }
2535
sprang4847ae62017-06-27 07:06:52 -07002536 // Add some slack to account for frames dropped by the frame dropper.
2537 const int kErrorMargin = 1;
2538 EXPECT_NEAR(num_frames_dropped, max_framerate_ - (max_framerate_ * 2 / 3),
sprangc5d62e22017-04-02 23:53:04 -07002539 kErrorMargin);
2540
2541 // Trigger CPU overuse, reduce framerate by 2/3 again.
mflodmancc3d4422017-08-03 08:27:51 -07002542 video_stream_encoder_->TriggerCpuOveruse();
sprangc5d62e22017-04-02 23:53:04 -07002543 num_frames_dropped = 0;
Åsa Persson8c1bf952018-09-13 10:42:19 +02002544 for (int i = 0; i <= max_framerate_; ++i) {
sprangc5d62e22017-04-02 23:53:04 -07002545 timestamp_ms += kFrameIntervalMs;
sprangc5d62e22017-04-02 23:53:04 -07002546 video_source_.IncomingCapturedFrame(
2547 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002548 if (!WaitForFrame(kFrameTimeoutMs)) {
sprangc5d62e22017-04-02 23:53:04 -07002549 ++num_frames_dropped;
2550 } else {
Åsa Perssonc74d8da2017-12-04 14:13:56 +01002551 sink_.CheckLastFrameSizeMatches(kFrameWidth, kFrameHeight);
sprangc5d62e22017-04-02 23:53:04 -07002552 }
2553 }
sprang4847ae62017-06-27 07:06:52 -07002554 EXPECT_NEAR(num_frames_dropped, max_framerate_ - (max_framerate_ * 4 / 9),
sprangc5d62e22017-04-02 23:53:04 -07002555 kErrorMargin);
2556
2557 // Go back up one step.
mflodmancc3d4422017-08-03 08:27:51 -07002558 video_stream_encoder_->TriggerCpuNormalUsage();
sprangc5d62e22017-04-02 23:53:04 -07002559 num_frames_dropped = 0;
sprang4847ae62017-06-27 07:06:52 -07002560 for (int i = 0; i < max_framerate_; ++i) {
sprangc5d62e22017-04-02 23:53:04 -07002561 timestamp_ms += kFrameIntervalMs;
sprangc5d62e22017-04-02 23:53:04 -07002562 video_source_.IncomingCapturedFrame(
2563 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002564 if (!WaitForFrame(kFrameTimeoutMs)) {
sprangc5d62e22017-04-02 23:53:04 -07002565 ++num_frames_dropped;
2566 } else {
Åsa Perssonc74d8da2017-12-04 14:13:56 +01002567 sink_.CheckLastFrameSizeMatches(kFrameWidth, kFrameHeight);
sprangc5d62e22017-04-02 23:53:04 -07002568 }
2569 }
sprang4847ae62017-06-27 07:06:52 -07002570 EXPECT_NEAR(num_frames_dropped, max_framerate_ - (max_framerate_ * 2 / 3),
sprangc5d62e22017-04-02 23:53:04 -07002571 kErrorMargin);
2572
2573 // Go back up to original mode.
mflodmancc3d4422017-08-03 08:27:51 -07002574 video_stream_encoder_->TriggerCpuNormalUsage();
sprangc5d62e22017-04-02 23:53:04 -07002575 num_frames_dropped = 0;
sprang4847ae62017-06-27 07:06:52 -07002576 for (int i = 0; i < max_framerate_; ++i) {
sprangc5d62e22017-04-02 23:53:04 -07002577 timestamp_ms += kFrameIntervalMs;
sprangc5d62e22017-04-02 23:53:04 -07002578 video_source_.IncomingCapturedFrame(
2579 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002580 if (!WaitForFrame(kFrameTimeoutMs)) {
sprangc5d62e22017-04-02 23:53:04 -07002581 ++num_frames_dropped;
2582 } else {
Åsa Perssonc74d8da2017-12-04 14:13:56 +01002583 sink_.CheckLastFrameSizeMatches(kFrameWidth, kFrameHeight);
sprangc5d62e22017-04-02 23:53:04 -07002584 }
2585 }
2586 EXPECT_NEAR(num_frames_dropped, 0, kErrorMargin);
2587
mflodmancc3d4422017-08-03 08:27:51 -07002588 video_stream_encoder_->Stop();
sprangc5d62e22017-04-02 23:53:04 -07002589}
2590
mflodmancc3d4422017-08-03 08:27:51 -07002591TEST_F(VideoStreamEncoderTest, DoesntAdaptDownPastMinFramerate) {
sprangc5d62e22017-04-02 23:53:04 -07002592 const int kFramerateFps = 5;
2593 const int kFrameIntervalMs = rtc::kNumMillisecsPerSec / kFramerateFps;
sprangc5d62e22017-04-02 23:53:04 -07002594 const int kFrameWidth = 1280;
2595 const int kFrameHeight = 720;
2596
sprang4847ae62017-06-27 07:06:52 -07002597 // Reconfigure encoder with two temporal layers and screensharing, which will
2598 // disable frame dropping and make testing easier.
Niels Möllerf1338562018-04-26 09:51:47 +02002599 ResetEncoder("VP8", 1, 2, 1, true);
sprang4847ae62017-06-27 07:06:52 -07002600
mflodmancc3d4422017-08-03 08:27:51 -07002601 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
2602 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002603 &video_source_, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
sprangc5d62e22017-04-02 23:53:04 -07002604 video_source_.set_adaptation_enabled(true);
2605
sprang4847ae62017-06-27 07:06:52 -07002606 int64_t timestamp_ms = fake_clock_.TimeNanos() / rtc::kNumNanosecsPerMillisec;
sprangc5d62e22017-04-02 23:53:04 -07002607
2608 // Trigger overuse as much as we can.
Jonathan Yubc771b72017-12-08 17:04:29 -08002609 rtc::VideoSinkWants last_wants;
2610 do {
2611 last_wants = video_source_.sink_wants();
2612
sprangc5d62e22017-04-02 23:53:04 -07002613 // Insert frames to get a new fps estimate...
2614 for (int j = 0; j < kFramerateFps; ++j) {
2615 video_source_.IncomingCapturedFrame(
2616 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
Jonathan Yubc771b72017-12-08 17:04:29 -08002617 if (video_source_.last_sent_width()) {
2618 sink_.WaitForEncodedFrame(timestamp_ms);
2619 }
sprangc5d62e22017-04-02 23:53:04 -07002620 timestamp_ms += kFrameIntervalMs;
Yves Gerey665174f2018-06-19 15:03:05 +02002621 fake_clock_.AdvanceTimeMicros(kFrameIntervalMs *
2622 rtc::kNumMicrosecsPerMillisec);
sprangc5d62e22017-04-02 23:53:04 -07002623 }
2624 // ...and then try to adapt again.
mflodmancc3d4422017-08-03 08:27:51 -07002625 video_stream_encoder_->TriggerCpuOveruse();
Jonathan Yubc771b72017-12-08 17:04:29 -08002626 } while (video_source_.sink_wants().max_framerate_fps <
2627 last_wants.max_framerate_fps);
sprangc5d62e22017-04-02 23:53:04 -07002628
Jonathan Yubc771b72017-12-08 17:04:29 -08002629 VerifyFpsEqResolutionMax(video_source_.sink_wants(), kMinFramerateFps);
asaperssonf7e294d2017-06-13 23:25:22 -07002630
mflodmancc3d4422017-08-03 08:27:51 -07002631 video_stream_encoder_->Stop();
sprangc5d62e22017-04-02 23:53:04 -07002632}
asaperssonf7e294d2017-06-13 23:25:22 -07002633
mflodmancc3d4422017-08-03 08:27:51 -07002634TEST_F(VideoStreamEncoderTest,
2635 AdaptsResolutionAndFramerateForLowQuality_BalancedMode) {
asaperssonf7e294d2017-06-13 23:25:22 -07002636 const int kWidth = 1280;
2637 const int kHeight = 720;
2638 const int64_t kFrameIntervalMs = 150;
2639 int64_t timestamp_ms = kFrameIntervalMs;
mflodmancc3d4422017-08-03 08:27:51 -07002640 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -07002641
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002642 // Enable BALANCED preference, no initial limitation.
asaperssonf7e294d2017-06-13 23:25:22 -07002643 AdaptingFrameForwarder source;
2644 source.set_adaptation_enabled(true);
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002645 video_stream_encoder_->SetSource(&source,
2646 webrtc::DegradationPreference::BALANCED);
asaperssonf7e294d2017-06-13 23:25:22 -07002647 timestamp_ms += kFrameIntervalMs;
2648 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002649 WaitForEncodedFrame(kWidth, kHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +02002650 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07002651 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2652 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2653 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2654
2655 // Trigger adapt down, expect scaled down resolution (960x540@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002656 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002657 timestamp_ms += kFrameIntervalMs;
2658 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002659 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002660 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
2661 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2662 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2663 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2664
2665 // Trigger adapt down, expect scaled down resolution (640x360@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002666 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002667 timestamp_ms += kFrameIntervalMs;
2668 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002669 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002670 VerifyFpsMaxResolutionLt(source.sink_wants(), source.last_wants());
2671 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2672 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2673 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2674
2675 // Trigger adapt down, expect reduced fps (640x360@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07002676 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002677 timestamp_ms += kFrameIntervalMs;
2678 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002679 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002680 VerifyFpsLtResolutionEq(source.sink_wants(), source.last_wants());
2681 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2682 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2683 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2684
2685 // Trigger adapt down, expect scaled down resolution (480x270@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07002686 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002687 timestamp_ms += kFrameIntervalMs;
2688 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002689 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002690 VerifyFpsEqResolutionLt(source.sink_wants(), source.last_wants());
2691 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2692 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2693 EXPECT_EQ(4, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2694
2695 // Restrict bitrate, trigger adapt down, expect reduced fps (480x270@10fps).
mflodmancc3d4422017-08-03 08:27:51 -07002696 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002697 timestamp_ms += kFrameIntervalMs;
2698 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002699 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002700 VerifyFpsLtResolutionEq(source.sink_wants(), source.last_wants());
2701 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2702 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2703 EXPECT_EQ(5, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2704
2705 // Trigger adapt down, expect scaled down resolution (320x180@10fps).
mflodmancc3d4422017-08-03 08:27:51 -07002706 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002707 timestamp_ms += kFrameIntervalMs;
2708 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002709 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002710 VerifyFpsEqResolutionLt(source.sink_wants(), source.last_wants());
2711 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2712 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2713 EXPECT_EQ(6, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2714
2715 // Trigger adapt down, expect reduced fps (320x180@7fps).
mflodmancc3d4422017-08-03 08:27:51 -07002716 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002717 timestamp_ms += kFrameIntervalMs;
2718 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002719 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002720 VerifyFpsLtResolutionEq(source.sink_wants(), source.last_wants());
2721 rtc::VideoSinkWants last_wants = source.sink_wants();
2722 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2723 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2724 EXPECT_EQ(7, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2725
2726 // Trigger adapt down, min resolution reached, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07002727 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002728 timestamp_ms += kFrameIntervalMs;
2729 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002730 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002731 VerifyFpsEqResolutionEq(source.sink_wants(), last_wants);
2732 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2733 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2734 EXPECT_EQ(7, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2735
2736 // Trigger adapt down, expect expect increased fps (320x180@10fps).
mflodmancc3d4422017-08-03 08:27:51 -07002737 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002738 timestamp_ms += kFrameIntervalMs;
2739 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002740 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002741 VerifyFpsGtResolutionEq(source.sink_wants(), source.last_wants());
2742 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2743 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2744 EXPECT_EQ(8, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2745
2746 // Trigger adapt up, expect upscaled resolution (480x270@10fps).
mflodmancc3d4422017-08-03 08:27:51 -07002747 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002748 timestamp_ms += kFrameIntervalMs;
2749 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002750 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002751 VerifyFpsEqResolutionGt(source.sink_wants(), source.last_wants());
2752 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2753 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2754 EXPECT_EQ(9, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2755
2756 // Increase bitrate, trigger adapt up, expect increased fps (480x270@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07002757 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002758 timestamp_ms += kFrameIntervalMs;
2759 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002760 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002761 VerifyFpsGtResolutionEq(source.sink_wants(), source.last_wants());
2762 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2763 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2764 EXPECT_EQ(10, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2765
2766 // Trigger adapt up, expect upscaled resolution (640x360@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07002767 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002768 timestamp_ms += kFrameIntervalMs;
2769 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002770 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002771 VerifyFpsEqResolutionGt(source.sink_wants(), source.last_wants());
2772 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2773 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2774 EXPECT_EQ(11, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2775
2776 // Trigger adapt up, expect increased fps (640x360@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002777 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002778 timestamp_ms += kFrameIntervalMs;
2779 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002780 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002781 VerifyFpsMaxResolutionEq(source.sink_wants(), source.last_wants());
2782 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2783 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2784 EXPECT_EQ(12, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2785
2786 // Trigger adapt up, expect upscaled resolution (960x540@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002787 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002788 timestamp_ms += kFrameIntervalMs;
2789 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002790 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002791 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
2792 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2793 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2794 EXPECT_EQ(13, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2795
2796 // Trigger adapt up, expect no restriction (1280x720fps@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002797 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002798 timestamp_ms += kFrameIntervalMs;
2799 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002800 WaitForEncodedFrame(kWidth, kHeight);
asaperssonf7e294d2017-06-13 23:25:22 -07002801 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
Åsa Persson8c1bf952018-09-13 10:42:19 +02002802 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07002803 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2804 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2805 EXPECT_EQ(14, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2806
2807 // Trigger adapt up, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07002808 video_stream_encoder_->TriggerQualityHigh();
Åsa Persson8c1bf952018-09-13 10:42:19 +02002809 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07002810 EXPECT_EQ(14, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2811
mflodmancc3d4422017-08-03 08:27:51 -07002812 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07002813}
2814
mflodmancc3d4422017-08-03 08:27:51 -07002815TEST_F(VideoStreamEncoderTest, AdaptWithTwoReasonsAndDifferentOrder_Framerate) {
asaperssonf7e294d2017-06-13 23:25:22 -07002816 const int kWidth = 1280;
2817 const int kHeight = 720;
2818 const int64_t kFrameIntervalMs = 150;
2819 int64_t timestamp_ms = kFrameIntervalMs;
mflodmancc3d4422017-08-03 08:27:51 -07002820 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -07002821
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002822 // Enable BALANCED preference, no initial limitation.
asaperssonf7e294d2017-06-13 23:25:22 -07002823 AdaptingFrameForwarder source;
2824 source.set_adaptation_enabled(true);
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002825 video_stream_encoder_->SetSource(&source,
2826 webrtc::DegradationPreference::BALANCED);
asaperssonf7e294d2017-06-13 23:25:22 -07002827 timestamp_ms += kFrameIntervalMs;
2828 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002829 WaitForEncodedFrame(kWidth, kHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +02002830 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07002831 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2832 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2833 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2834 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
2835 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2836 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2837
2838 // Trigger cpu adapt down, expect scaled down resolution (960x540@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002839 video_stream_encoder_->TriggerCpuOveruse();
asaperssonf7e294d2017-06-13 23:25:22 -07002840 timestamp_ms += kFrameIntervalMs;
2841 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002842 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002843 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
2844 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2845 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2846 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2847 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
2848 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2849 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2850
2851 // Trigger cpu adapt down, expect scaled down resolution (640x360@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002852 video_stream_encoder_->TriggerCpuOveruse();
asaperssonf7e294d2017-06-13 23:25:22 -07002853 timestamp_ms += kFrameIntervalMs;
2854 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002855 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002856 VerifyFpsMaxResolutionLt(source.sink_wants(), source.last_wants());
2857 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2858 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2859 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2860 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
2861 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2862 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2863
2864 // Trigger quality adapt down, expect reduced fps (640x360@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07002865 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002866 timestamp_ms += kFrameIntervalMs;
2867 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002868 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002869 VerifyFpsLtResolutionEq(source.sink_wants(), source.last_wants());
2870 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2871 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2872 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2873 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
2874 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2875 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2876
2877 // Trigger cpu adapt up, expect increased fps (640x360@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002878 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssonf7e294d2017-06-13 23:25:22 -07002879 timestamp_ms += kFrameIntervalMs;
2880 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002881 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002882 VerifyFpsMaxResolutionEq(source.sink_wants(), source.last_wants());
2883 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2884 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2885 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2886 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
2887 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2888 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2889
2890 // Trigger quality adapt up, expect upscaled resolution (960x540@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002891 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002892 timestamp_ms += kFrameIntervalMs;
2893 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002894 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002895 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
2896 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2897 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2898 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2899 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
2900 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2901 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2902
2903 // Trigger cpu adapt up, expect no restriction (1280x720fps@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002904 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssonf7e294d2017-06-13 23:25:22 -07002905 timestamp_ms += kFrameIntervalMs;
2906 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002907 WaitForEncodedFrame(kWidth, kHeight);
asaperssonf7e294d2017-06-13 23:25:22 -07002908 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
Åsa Persson8c1bf952018-09-13 10:42:19 +02002909 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07002910 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2911 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2912 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2913 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
2914 EXPECT_EQ(4, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2915 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2916
2917 // Trigger adapt up, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07002918 video_stream_encoder_->TriggerQualityHigh();
Åsa Persson8c1bf952018-09-13 10:42:19 +02002919 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07002920 EXPECT_EQ(4, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2921 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2922
mflodmancc3d4422017-08-03 08:27:51 -07002923 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07002924}
2925
mflodmancc3d4422017-08-03 08:27:51 -07002926TEST_F(VideoStreamEncoderTest,
2927 AdaptWithTwoReasonsAndDifferentOrder_Resolution) {
asaperssonf7e294d2017-06-13 23:25:22 -07002928 const int kWidth = 640;
2929 const int kHeight = 360;
2930 const int kFpsLimit = 15;
2931 const int64_t kFrameIntervalMs = 150;
2932 int64_t timestamp_ms = kFrameIntervalMs;
mflodmancc3d4422017-08-03 08:27:51 -07002933 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -07002934
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002935 // Enable BALANCED preference, no initial limitation.
asaperssonf7e294d2017-06-13 23:25:22 -07002936 AdaptingFrameForwarder source;
2937 source.set_adaptation_enabled(true);
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002938 video_stream_encoder_->SetSource(&source,
2939 webrtc::DegradationPreference::BALANCED);
asaperssonf7e294d2017-06-13 23:25:22 -07002940 timestamp_ms += kFrameIntervalMs;
2941 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002942 WaitForEncodedFrame(kWidth, kHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +02002943 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07002944 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2945 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2946 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2947 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
2948 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2949 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2950
2951 // Trigger cpu adapt down, expect scaled down framerate (640x360@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07002952 video_stream_encoder_->TriggerCpuOveruse();
asaperssonf7e294d2017-06-13 23:25:22 -07002953 timestamp_ms += kFrameIntervalMs;
2954 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002955 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002956 VerifyFpsEqResolutionMax(source.sink_wants(), kFpsLimit);
2957 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2958 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2959 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2960 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_framerate);
2961 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2962 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2963
2964 // Trigger quality adapt down, expect scaled down resolution (480x270@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07002965 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002966 timestamp_ms += kFrameIntervalMs;
2967 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002968 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002969 VerifyFpsEqResolutionLt(source.sink_wants(), source.last_wants());
2970 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2971 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2972 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2973 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_framerate);
2974 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2975 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2976
2977 // Trigger cpu adapt up, expect upscaled resolution (640x360@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07002978 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssonf7e294d2017-06-13 23:25:22 -07002979 timestamp_ms += kFrameIntervalMs;
2980 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002981 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002982 VerifyFpsEqResolutionGt(source.sink_wants(), source.last_wants());
2983 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2984 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2985 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2986 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
2987 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2988 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2989
2990 // Trigger quality adapt up, expect increased fps (640x360@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002991 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002992 timestamp_ms += kFrameIntervalMs;
2993 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002994 WaitForEncodedFrame(timestamp_ms);
Åsa Persson8c1bf952018-09-13 10:42:19 +02002995 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07002996 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2997 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2998 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2999 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
3000 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
3001 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3002
3003 // Trigger adapt up, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07003004 video_stream_encoder_->TriggerQualityHigh();
Åsa Persson8c1bf952018-09-13 10:42:19 +02003005 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07003006 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
3007 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3008
mflodmancc3d4422017-08-03 08:27:51 -07003009 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07003010}
3011
mflodmancc3d4422017-08-03 08:27:51 -07003012TEST_F(VideoStreamEncoderTest, AcceptsFullHdAdaptedDownSimulcastFrames) {
ilnik6b826ef2017-06-16 06:53:48 -07003013 // Simulates simulcast behavior and makes highest stream resolutions divisible
3014 // by 4.
3015 class CroppingVideoStreamFactory
3016 : public VideoEncoderConfig::VideoStreamFactoryInterface {
3017 public:
3018 explicit CroppingVideoStreamFactory(size_t num_temporal_layers,
3019 int framerate)
3020 : num_temporal_layers_(num_temporal_layers), framerate_(framerate) {
3021 EXPECT_GT(num_temporal_layers, 0u);
3022 EXPECT_GT(framerate, 0);
3023 }
3024
3025 private:
3026 std::vector<VideoStream> CreateEncoderStreams(
3027 int width,
3028 int height,
3029 const VideoEncoderConfig& encoder_config) override {
Yves Gerey665174f2018-06-19 15:03:05 +02003030 std::vector<VideoStream> streams = test::CreateVideoStreams(
3031 width - width % 4, height - height % 4, encoder_config);
ilnik6b826ef2017-06-16 06:53:48 -07003032 for (VideoStream& stream : streams) {
Sergey Silkina796a7e2018-03-01 15:11:29 +01003033 stream.num_temporal_layers = num_temporal_layers_;
ilnik6b826ef2017-06-16 06:53:48 -07003034 stream.max_framerate = framerate_;
3035 }
3036 return streams;
3037 }
3038
3039 const size_t num_temporal_layers_;
3040 const int framerate_;
3041 };
3042
3043 const int kFrameWidth = 1920;
3044 const int kFrameHeight = 1080;
3045 // 3/4 of 1920.
3046 const int kAdaptedFrameWidth = 1440;
3047 // 3/4 of 1080 rounded down to multiple of 4.
3048 const int kAdaptedFrameHeight = 808;
3049 const int kFramerate = 24;
3050
mflodmancc3d4422017-08-03 08:27:51 -07003051 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
ilnik6b826ef2017-06-16 06:53:48 -07003052 // Trigger reconfigure encoder (without resetting the entire instance).
3053 VideoEncoderConfig video_encoder_config;
Niels Möller259a4972018-04-05 15:36:51 +02003054 video_encoder_config.codec_type = kVideoCodecVP8;
ilnik6b826ef2017-06-16 06:53:48 -07003055 video_encoder_config.max_bitrate_bps = kTargetBitrateBps;
3056 video_encoder_config.number_of_streams = 1;
3057 video_encoder_config.video_stream_factory =
3058 new rtc::RefCountedObject<CroppingVideoStreamFactory>(1, kFramerate);
mflodmancc3d4422017-08-03 08:27:51 -07003059 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
Niels Möllerf1338562018-04-26 09:51:47 +02003060 kMaxPayloadLength);
mflodmancc3d4422017-08-03 08:27:51 -07003061 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
ilnik6b826ef2017-06-16 06:53:48 -07003062
3063 video_source_.set_adaptation_enabled(true);
3064
3065 video_source_.IncomingCapturedFrame(
3066 CreateFrame(1, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07003067 WaitForEncodedFrame(kFrameWidth, kFrameHeight);
ilnik6b826ef2017-06-16 06:53:48 -07003068
3069 // Trigger CPU overuse, downscale by 3/4.
mflodmancc3d4422017-08-03 08:27:51 -07003070 video_stream_encoder_->TriggerCpuOveruse();
ilnik6b826ef2017-06-16 06:53:48 -07003071 video_source_.IncomingCapturedFrame(
3072 CreateFrame(2, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07003073 WaitForEncodedFrame(kAdaptedFrameWidth, kAdaptedFrameHeight);
ilnik6b826ef2017-06-16 06:53:48 -07003074
mflodmancc3d4422017-08-03 08:27:51 -07003075 video_stream_encoder_->Stop();
ilnik6b826ef2017-06-16 06:53:48 -07003076}
3077
mflodmancc3d4422017-08-03 08:27:51 -07003078TEST_F(VideoStreamEncoderTest, PeriodicallyUpdatesChannelParameters) {
sprang4847ae62017-06-27 07:06:52 -07003079 const int kFrameWidth = 1280;
3080 const int kFrameHeight = 720;
3081 const int kLowFps = 2;
3082 const int kHighFps = 30;
3083
mflodmancc3d4422017-08-03 08:27:51 -07003084 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
sprang4847ae62017-06-27 07:06:52 -07003085
3086 int64_t timestamp_ms = fake_clock_.TimeNanos() / rtc::kNumNanosecsPerMillisec;
3087 max_framerate_ = kLowFps;
3088
3089 // Insert 2 seconds of 2fps video.
3090 for (int i = 0; i < kLowFps * 2; ++i) {
3091 video_source_.IncomingCapturedFrame(
3092 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
3093 WaitForEncodedFrame(timestamp_ms);
3094 timestamp_ms += 1000 / kLowFps;
3095 }
3096
3097 // Make sure encoder is updated with new target.
mflodmancc3d4422017-08-03 08:27:51 -07003098 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
sprang4847ae62017-06-27 07:06:52 -07003099 video_source_.IncomingCapturedFrame(
3100 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
3101 WaitForEncodedFrame(timestamp_ms);
3102 timestamp_ms += 1000 / kLowFps;
3103
3104 EXPECT_EQ(kLowFps, fake_encoder_.GetConfiguredInputFramerate());
3105
3106 // Insert 30fps frames for just a little more than the forced update period.
3107 const int kVcmTimerIntervalFrames =
3108 (vcm::VCMProcessTimer::kDefaultProcessIntervalMs * kHighFps) / 1000;
3109 const int kFrameIntervalMs = 1000 / kHighFps;
3110 max_framerate_ = kHighFps;
3111 for (int i = 0; i < kVcmTimerIntervalFrames + 2; ++i) {
3112 video_source_.IncomingCapturedFrame(
3113 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
3114 // Wait for encoded frame, but skip ahead if it doesn't arrive as it might
3115 // be dropped if the encoder hans't been updated with the new higher target
3116 // framerate yet, causing it to overshoot the target bitrate and then
3117 // suffering the wrath of the media optimizer.
3118 TimedWaitForEncodedFrame(timestamp_ms, 2 * kFrameIntervalMs);
3119 timestamp_ms += kFrameIntervalMs;
3120 }
3121
3122 // Don expect correct measurement just yet, but it should be higher than
3123 // before.
3124 EXPECT_GT(fake_encoder_.GetConfiguredInputFramerate(), kLowFps);
3125
mflodmancc3d4422017-08-03 08:27:51 -07003126 video_stream_encoder_->Stop();
sprang4847ae62017-06-27 07:06:52 -07003127}
3128
mflodmancc3d4422017-08-03 08:27:51 -07003129TEST_F(VideoStreamEncoderTest, DoesNotUpdateBitrateAllocationWhenSuspended) {
sprang4847ae62017-06-27 07:06:52 -07003130 const int kFrameWidth = 1280;
3131 const int kFrameHeight = 720;
3132 const int kTargetBitrateBps = 1000000;
3133
3134 MockBitrateObserver bitrate_observer;
Niels Möller0327c2d2018-05-21 14:09:31 +02003135 video_stream_encoder_->SetBitrateAllocationObserver(&bitrate_observer);
sprang4847ae62017-06-27 07:06:52 -07003136
3137 EXPECT_CALL(bitrate_observer, OnBitrateAllocationUpdated(_)).Times(1);
3138 // Initial bitrate update.
mflodmancc3d4422017-08-03 08:27:51 -07003139 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
3140 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
sprang4847ae62017-06-27 07:06:52 -07003141
3142 // Insert a first video frame, causes another bitrate update.
3143 int64_t timestamp_ms = fake_clock_.TimeNanos() / rtc::kNumNanosecsPerMillisec;
3144 EXPECT_CALL(bitrate_observer, OnBitrateAllocationUpdated(_)).Times(1);
3145 video_source_.IncomingCapturedFrame(
3146 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
3147 WaitForEncodedFrame(timestamp_ms);
3148
3149 // Next, simulate video suspension due to pacer queue overrun.
mflodmancc3d4422017-08-03 08:27:51 -07003150 video_stream_encoder_->OnBitrateUpdated(0, 0, 1);
sprang4847ae62017-06-27 07:06:52 -07003151
3152 // Skip ahead until a new periodic parameter update should have occured.
3153 timestamp_ms += vcm::VCMProcessTimer::kDefaultProcessIntervalMs;
3154 fake_clock_.AdvanceTimeMicros(
3155 vcm::VCMProcessTimer::kDefaultProcessIntervalMs *
3156 rtc::kNumMicrosecsPerMillisec);
3157
3158 // Bitrate observer should not be called.
3159 EXPECT_CALL(bitrate_observer, OnBitrateAllocationUpdated(_)).Times(0);
3160 video_source_.IncomingCapturedFrame(
3161 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
3162 ExpectDroppedFrame();
3163
mflodmancc3d4422017-08-03 08:27:51 -07003164 video_stream_encoder_->Stop();
sprang4847ae62017-06-27 07:06:52 -07003165}
ilnik6b826ef2017-06-16 06:53:48 -07003166
Niels Möller4db138e2018-04-19 09:04:13 +02003167TEST_F(VideoStreamEncoderTest,
3168 DefaultCpuAdaptationThresholdsForSoftwareEncoder) {
3169 const int kFrameWidth = 1280;
3170 const int kFrameHeight = 720;
3171 const CpuOveruseOptions default_options;
3172 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
3173 video_source_.IncomingCapturedFrame(
3174 CreateFrame(1, kFrameWidth, kFrameHeight));
3175 WaitForEncodedFrame(1);
3176 EXPECT_EQ(video_stream_encoder_->overuse_detector_proxy_->GetOptions()
3177 .low_encode_usage_threshold_percent,
3178 default_options.low_encode_usage_threshold_percent);
3179 EXPECT_EQ(video_stream_encoder_->overuse_detector_proxy_->GetOptions()
3180 .high_encode_usage_threshold_percent,
3181 default_options.high_encode_usage_threshold_percent);
3182 video_stream_encoder_->Stop();
3183}
3184
3185TEST_F(VideoStreamEncoderTest,
3186 HigherCpuAdaptationThresholdsForHardwareEncoder) {
3187 const int kFrameWidth = 1280;
3188 const int kFrameHeight = 720;
3189 CpuOveruseOptions hardware_options;
3190 hardware_options.low_encode_usage_threshold_percent = 150;
3191 hardware_options.high_encode_usage_threshold_percent = 200;
3192 encoder_factory_.SetIsHardwareAccelerated(true);
3193
3194 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
3195 video_source_.IncomingCapturedFrame(
3196 CreateFrame(1, kFrameWidth, kFrameHeight));
3197 WaitForEncodedFrame(1);
3198 EXPECT_EQ(video_stream_encoder_->overuse_detector_proxy_->GetOptions()
3199 .low_encode_usage_threshold_percent,
3200 hardware_options.low_encode_usage_threshold_percent);
3201 EXPECT_EQ(video_stream_encoder_->overuse_detector_proxy_->GetOptions()
3202 .high_encode_usage_threshold_percent,
3203 hardware_options.high_encode_usage_threshold_percent);
3204 video_stream_encoder_->Stop();
3205}
3206
perkj26091b12016-09-01 01:17:40 -07003207} // namespace webrtc