blob: 58d140f6b9f30ef3a1b43462f1f6811729aff9f8 [file] [log] [blame]
perkj26091b12016-09-01 01:17:40 -07001/*
2 * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved.
3 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
sprangfe627f32017-03-29 08:24:59 -070011#include <algorithm>
perkj803d97f2016-11-01 11:45:46 -070012#include <limits>
Per512ecb32016-09-23 15:52:06 +020013#include <utility>
14
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020015#include "api/video/i420_buffer.h"
16#include "media/base/videoadapter.h"
17#include "modules/video_coding/codecs/vp8/temporal_layers.h"
Sergey Silkin86684962018-03-28 19:32:37 +020018#include "modules/video_coding/codecs/vp9/include/vp9_globals.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020019#include "modules/video_coding/utility/default_video_bitrate_allocator.h"
20#include "rtc_base/fakeclock.h"
21#include "rtc_base/logging.h"
Stefan Holmerdbdb3a02018-07-17 16:03:46 +020022#include "rtc_base/refcountedobject.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020023#include "system_wrappers/include/metrics_default.h"
24#include "system_wrappers/include/sleep.h"
Niels Möller4db138e2018-04-19 09:04:13 +020025#include "test/encoder_proxy_factory.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020026#include "test/encoder_settings.h"
27#include "test/fake_encoder.h"
28#include "test/frame_generator.h"
29#include "test/gmock.h"
30#include "test/gtest.h"
31#include "video/send_statistics_proxy.h"
32#include "video/video_stream_encoder.h"
perkj26091b12016-09-01 01:17:40 -070033
34namespace webrtc {
35
sprangb1ca0732017-02-01 08:38:12 -080036using ScaleReason = AdaptationObserverInterface::AdaptReason;
sprang57c2fff2017-01-16 06:24:02 -080037using ::testing::_;
38using ::testing::Return;
kthelgason876222f2016-11-29 01:44:11 -080039
perkj803d97f2016-11-01 11:45:46 -070040namespace {
Åsa Perssonced5cfd2018-08-10 16:16:43 +020041const int kMinPixelsPerFrame = 320 * 180;
42const int kMinFramerateFps = 2;
43const int kMinBalancedFramerateFps = 7;
44const int64_t kFrameTimeoutMs = 100;
asapersson5f7226f2016-11-25 04:37:00 -080045const size_t kMaxPayloadLength = 1440;
kthelgason2bc68642017-02-07 07:02:22 -080046const int kTargetBitrateBps = 1000000;
47const int kLowTargetBitrateBps = kTargetBitrateBps / 10;
48const int kMaxInitialFramedrop = 4;
sprangfda496a2017-06-15 04:21:07 -070049const int kDefaultFramerate = 30;
Åsa Perssonced5cfd2018-08-10 16:16:43 +020050const int64_t kFrameIntervalMs = rtc::kNumMillisecsPerSec / kDefaultFramerate;
asapersson5f7226f2016-11-25 04:37:00 -080051
perkj803d97f2016-11-01 11:45:46 -070052class TestBuffer : public webrtc::I420Buffer {
53 public:
54 TestBuffer(rtc::Event* event, int width, int height)
55 : I420Buffer(width, height), event_(event) {}
56
57 private:
58 friend class rtc::RefCountedObject<TestBuffer>;
59 ~TestBuffer() override {
60 if (event_)
61 event_->Set();
62 }
63 rtc::Event* const event_;
64};
65
Niels Möller7dc26b72017-12-06 10:27:48 +010066class CpuOveruseDetectorProxy : public OveruseFrameDetector {
67 public:
Niels Möllerd1f7eb62018-03-28 16:40:58 +020068 explicit CpuOveruseDetectorProxy(CpuOveruseMetricsObserver* metrics_observer)
69 : OveruseFrameDetector(metrics_observer),
Niels Möller7dc26b72017-12-06 10:27:48 +010070 last_target_framerate_fps_(-1) {}
71 virtual ~CpuOveruseDetectorProxy() {}
72
73 void OnTargetFramerateUpdated(int framerate_fps) override {
74 rtc::CritScope cs(&lock_);
75 last_target_framerate_fps_ = framerate_fps;
76 OveruseFrameDetector::OnTargetFramerateUpdated(framerate_fps);
77 }
78
79 int GetLastTargetFramerate() {
80 rtc::CritScope cs(&lock_);
81 return last_target_framerate_fps_;
82 }
83
Niels Möller4db138e2018-04-19 09:04:13 +020084 CpuOveruseOptions GetOptions() { return options_; }
85
Niels Möller7dc26b72017-12-06 10:27:48 +010086 private:
87 rtc::CriticalSection lock_;
88 int last_target_framerate_fps_ RTC_GUARDED_BY(lock_);
89};
90
mflodmancc3d4422017-08-03 08:27:51 -070091class VideoStreamEncoderUnderTest : public VideoStreamEncoder {
perkj803d97f2016-11-01 11:45:46 -070092 public:
Niels Möller213618e2018-07-24 09:29:58 +020093 VideoStreamEncoderUnderTest(SendStatisticsProxy* stats_proxy,
94 const VideoStreamEncoderSettings& settings)
Yves Gerey665174f2018-06-19 15:03:05 +020095 : VideoStreamEncoder(1 /* number_of_cores */,
96 stats_proxy,
97 settings,
98 nullptr /* pre_encode_callback */,
99 std::unique_ptr<OveruseFrameDetector>(
100 overuse_detector_proxy_ =
101 new CpuOveruseDetectorProxy(stats_proxy))) {}
perkj803d97f2016-11-01 11:45:46 -0700102
sprangb1ca0732017-02-01 08:38:12 -0800103 void PostTaskAndWait(bool down, AdaptReason reason) {
perkj803d97f2016-11-01 11:45:46 -0700104 rtc::Event event(false, false);
kthelgason876222f2016-11-29 01:44:11 -0800105 encoder_queue()->PostTask([this, &event, reason, down] {
sprangb1ca0732017-02-01 08:38:12 -0800106 down ? AdaptDown(reason) : AdaptUp(reason);
perkj803d97f2016-11-01 11:45:46 -0700107 event.Set();
108 });
perkj070ba852017-02-16 15:46:27 -0800109 ASSERT_TRUE(event.Wait(5000));
perkj803d97f2016-11-01 11:45:46 -0700110 }
111
kthelgason2fc52542017-03-03 00:24:41 -0800112 // This is used as a synchronisation mechanism, to make sure that the
113 // encoder queue is not blocked before we start sending it frames.
114 void WaitUntilTaskQueueIsIdle() {
115 rtc::Event event(false, false);
Yves Gerey665174f2018-06-19 15:03:05 +0200116 encoder_queue()->PostTask([&event] { event.Set(); });
kthelgason2fc52542017-03-03 00:24:41 -0800117 ASSERT_TRUE(event.Wait(5000));
118 }
119
sprangb1ca0732017-02-01 08:38:12 -0800120 void TriggerCpuOveruse() { PostTaskAndWait(true, AdaptReason::kCpu); }
kthelgason876222f2016-11-29 01:44:11 -0800121
sprangb1ca0732017-02-01 08:38:12 -0800122 void TriggerCpuNormalUsage() { PostTaskAndWait(false, AdaptReason::kCpu); }
kthelgason876222f2016-11-29 01:44:11 -0800123
sprangb1ca0732017-02-01 08:38:12 -0800124 void TriggerQualityLow() { PostTaskAndWait(true, AdaptReason::kQuality); }
kthelgason876222f2016-11-29 01:44:11 -0800125
sprangb1ca0732017-02-01 08:38:12 -0800126 void TriggerQualityHigh() { PostTaskAndWait(false, AdaptReason::kQuality); }
sprangfda496a2017-06-15 04:21:07 -0700127
Niels Möller7dc26b72017-12-06 10:27:48 +0100128 CpuOveruseDetectorProxy* overuse_detector_proxy_;
perkj803d97f2016-11-01 11:45:46 -0700129};
130
asapersson5f7226f2016-11-25 04:37:00 -0800131class VideoStreamFactory
132 : public VideoEncoderConfig::VideoStreamFactoryInterface {
133 public:
sprangfda496a2017-06-15 04:21:07 -0700134 explicit VideoStreamFactory(size_t num_temporal_layers, int framerate)
135 : num_temporal_layers_(num_temporal_layers), framerate_(framerate) {
asapersson5f7226f2016-11-25 04:37:00 -0800136 EXPECT_GT(num_temporal_layers, 0u);
sprangfda496a2017-06-15 04:21:07 -0700137 EXPECT_GT(framerate, 0);
asapersson5f7226f2016-11-25 04:37:00 -0800138 }
139
140 private:
141 std::vector<VideoStream> CreateEncoderStreams(
142 int width,
143 int height,
144 const VideoEncoderConfig& encoder_config) override {
145 std::vector<VideoStream> streams =
146 test::CreateVideoStreams(width, height, encoder_config);
147 for (VideoStream& stream : streams) {
Sergey Silkina796a7e2018-03-01 15:11:29 +0100148 stream.num_temporal_layers = num_temporal_layers_;
sprangfda496a2017-06-15 04:21:07 -0700149 stream.max_framerate = framerate_;
asapersson5f7226f2016-11-25 04:37:00 -0800150 }
151 return streams;
152 }
sprangfda496a2017-06-15 04:21:07 -0700153
asapersson5f7226f2016-11-25 04:37:00 -0800154 const size_t num_temporal_layers_;
sprangfda496a2017-06-15 04:21:07 -0700155 const int framerate_;
asapersson5f7226f2016-11-25 04:37:00 -0800156};
157
sprangb1ca0732017-02-01 08:38:12 -0800158class AdaptingFrameForwarder : public test::FrameForwarder {
159 public:
160 AdaptingFrameForwarder() : adaptation_enabled_(false) {}
asaperssonfab67072017-04-04 05:51:49 -0700161 ~AdaptingFrameForwarder() override {}
sprangb1ca0732017-02-01 08:38:12 -0800162
163 void set_adaptation_enabled(bool enabled) {
164 rtc::CritScope cs(&crit_);
165 adaptation_enabled_ = enabled;
166 }
167
asaperssonfab67072017-04-04 05:51:49 -0700168 bool adaption_enabled() const {
sprangb1ca0732017-02-01 08:38:12 -0800169 rtc::CritScope cs(&crit_);
170 return adaptation_enabled_;
171 }
172
asapersson09f05612017-05-15 23:40:18 -0700173 rtc::VideoSinkWants last_wants() const {
174 rtc::CritScope cs(&crit_);
175 return last_wants_;
176 }
177
Danil Chapovalovb9b146c2018-06-15 12:28:07 +0200178 absl::optional<int> last_sent_width() const { return last_width_; }
179 absl::optional<int> last_sent_height() const { return last_height_; }
Jonathan Yubc771b72017-12-08 17:04:29 -0800180
sprangb1ca0732017-02-01 08:38:12 -0800181 void IncomingCapturedFrame(const VideoFrame& video_frame) override {
182 int cropped_width = 0;
183 int cropped_height = 0;
184 int out_width = 0;
185 int out_height = 0;
sprangc5d62e22017-04-02 23:53:04 -0700186 if (adaption_enabled()) {
187 if (adapter_.AdaptFrameResolution(
188 video_frame.width(), video_frame.height(),
189 video_frame.timestamp_us() * 1000, &cropped_width,
190 &cropped_height, &out_width, &out_height)) {
191 VideoFrame adapted_frame(new rtc::RefCountedObject<TestBuffer>(
192 nullptr, out_width, out_height),
193 99, 99, kVideoRotation_0);
194 adapted_frame.set_ntp_time_ms(video_frame.ntp_time_ms());
195 test::FrameForwarder::IncomingCapturedFrame(adapted_frame);
Jonathan Yubc771b72017-12-08 17:04:29 -0800196 last_width_.emplace(adapted_frame.width());
197 last_height_.emplace(adapted_frame.height());
198 } else {
Danil Chapovalovb9b146c2018-06-15 12:28:07 +0200199 last_width_ = absl::nullopt;
200 last_height_ = absl::nullopt;
sprangc5d62e22017-04-02 23:53:04 -0700201 }
sprangb1ca0732017-02-01 08:38:12 -0800202 } else {
203 test::FrameForwarder::IncomingCapturedFrame(video_frame);
Jonathan Yubc771b72017-12-08 17:04:29 -0800204 last_width_.emplace(video_frame.width());
205 last_height_.emplace(video_frame.height());
sprangb1ca0732017-02-01 08:38:12 -0800206 }
207 }
208
209 void AddOrUpdateSink(rtc::VideoSinkInterface<VideoFrame>* sink,
210 const rtc::VideoSinkWants& wants) override {
211 rtc::CritScope cs(&crit_);
asapersson09f05612017-05-15 23:40:18 -0700212 last_wants_ = sink_wants();
sprangc5d62e22017-04-02 23:53:04 -0700213 adapter_.OnResolutionFramerateRequest(wants.target_pixel_count,
214 wants.max_pixel_count,
215 wants.max_framerate_fps);
sprangb1ca0732017-02-01 08:38:12 -0800216 test::FrameForwarder::AddOrUpdateSink(sink, wants);
217 }
sprangb1ca0732017-02-01 08:38:12 -0800218 cricket::VideoAdapter adapter_;
danilchapa37de392017-09-09 04:17:22 -0700219 bool adaptation_enabled_ RTC_GUARDED_BY(crit_);
220 rtc::VideoSinkWants last_wants_ RTC_GUARDED_BY(crit_);
Danil Chapovalovb9b146c2018-06-15 12:28:07 +0200221 absl::optional<int> last_width_;
222 absl::optional<int> last_height_;
sprangb1ca0732017-02-01 08:38:12 -0800223};
sprangc5d62e22017-04-02 23:53:04 -0700224
Niels Möller213618e2018-07-24 09:29:58 +0200225// TODO(nisse): Mock only VideoStreamEncoderObserver.
sprangc5d62e22017-04-02 23:53:04 -0700226class MockableSendStatisticsProxy : public SendStatisticsProxy {
227 public:
228 MockableSendStatisticsProxy(Clock* clock,
229 const VideoSendStream::Config& config,
230 VideoEncoderConfig::ContentType content_type)
231 : SendStatisticsProxy(clock, config, content_type) {}
232
233 VideoSendStream::Stats GetStats() override {
234 rtc::CritScope cs(&lock_);
235 if (mock_stats_)
236 return *mock_stats_;
237 return SendStatisticsProxy::GetStats();
238 }
239
Niels Möller213618e2018-07-24 09:29:58 +0200240 int GetInputFrameRate() const override {
241 rtc::CritScope cs(&lock_);
242 if (mock_stats_)
243 return mock_stats_->input_frame_rate;
244 return SendStatisticsProxy::GetInputFrameRate();
245 }
sprangc5d62e22017-04-02 23:53:04 -0700246 void SetMockStats(const VideoSendStream::Stats& stats) {
247 rtc::CritScope cs(&lock_);
248 mock_stats_.emplace(stats);
249 }
250
251 void ResetMockStats() {
252 rtc::CritScope cs(&lock_);
253 mock_stats_.reset();
254 }
255
256 private:
257 rtc::CriticalSection lock_;
Danil Chapovalovb9b146c2018-06-15 12:28:07 +0200258 absl::optional<VideoSendStream::Stats> mock_stats_ RTC_GUARDED_BY(lock_);
sprangc5d62e22017-04-02 23:53:04 -0700259};
260
sprang4847ae62017-06-27 07:06:52 -0700261class MockBitrateObserver : public VideoBitrateAllocationObserver {
262 public:
Erik Språng566124a2018-04-23 12:32:22 +0200263 MOCK_METHOD1(OnBitrateAllocationUpdated, void(const VideoBitrateAllocation&));
sprang4847ae62017-06-27 07:06:52 -0700264};
265
perkj803d97f2016-11-01 11:45:46 -0700266} // namespace
267
mflodmancc3d4422017-08-03 08:27:51 -0700268class VideoStreamEncoderTest : public ::testing::Test {
perkj26091b12016-09-01 01:17:40 -0700269 public:
270 static const int kDefaultTimeoutMs = 30 * 1000;
271
mflodmancc3d4422017-08-03 08:27:51 -0700272 VideoStreamEncoderTest()
perkj26091b12016-09-01 01:17:40 -0700273 : video_send_config_(VideoSendStream::Config(nullptr)),
perkjfa10b552016-10-02 23:45:26 -0700274 codec_width_(320),
275 codec_height_(240),
Åsa Perssonced5cfd2018-08-10 16:16:43 +0200276 max_framerate_(kDefaultFramerate),
perkj26091b12016-09-01 01:17:40 -0700277 fake_encoder_(),
Niels Möller4db138e2018-04-19 09:04:13 +0200278 encoder_factory_(&fake_encoder_),
sprangc5d62e22017-04-02 23:53:04 -0700279 stats_proxy_(new MockableSendStatisticsProxy(
perkj803d97f2016-11-01 11:45:46 -0700280 Clock::GetRealTimeClock(),
281 video_send_config_,
282 webrtc::VideoEncoderConfig::ContentType::kRealtimeVideo)),
perkj26091b12016-09-01 01:17:40 -0700283 sink_(&fake_encoder_) {}
284
285 void SetUp() override {
perkj803d97f2016-11-01 11:45:46 -0700286 metrics::Reset();
perkj26091b12016-09-01 01:17:40 -0700287 video_send_config_ = VideoSendStream::Config(nullptr);
Niels Möller4db138e2018-04-19 09:04:13 +0200288 video_send_config_.encoder_settings.encoder_factory = &encoder_factory_;
Niels Möller259a4972018-04-05 15:36:51 +0200289 video_send_config_.rtp.payload_name = "FAKE";
290 video_send_config_.rtp.payload_type = 125;
perkj26091b12016-09-01 01:17:40 -0700291
Per512ecb32016-09-23 15:52:06 +0200292 VideoEncoderConfig video_encoder_config;
Niels Möller259a4972018-04-05 15:36:51 +0200293 test::FillEncoderConfiguration(kVideoCodecVP8, 1, &video_encoder_config);
sprang4847ae62017-06-27 07:06:52 -0700294 video_encoder_config.video_stream_factory =
295 new rtc::RefCountedObject<VideoStreamFactory>(1, max_framerate_);
Erik Språng08127a92016-11-16 16:41:30 +0100296 video_encoder_config_ = video_encoder_config.Copy();
sprang4847ae62017-06-27 07:06:52 -0700297
298 // Framerate limit is specified by the VideoStreamFactory.
299 std::vector<VideoStream> streams =
300 video_encoder_config.video_stream_factory->CreateEncoderStreams(
301 codec_width_, codec_height_, video_encoder_config);
302 max_framerate_ = streams[0].max_framerate;
303 fake_clock_.SetTimeMicros(1234);
304
Niels Möllerf1338562018-04-26 09:51:47 +0200305 ConfigureEncoder(std::move(video_encoder_config));
asapersson5f7226f2016-11-25 04:37:00 -0800306 }
307
Niels Möllerf1338562018-04-26 09:51:47 +0200308 void ConfigureEncoder(VideoEncoderConfig video_encoder_config) {
mflodmancc3d4422017-08-03 08:27:51 -0700309 if (video_stream_encoder_)
310 video_stream_encoder_->Stop();
311 video_stream_encoder_.reset(new VideoStreamEncoderUnderTest(
perkj803d97f2016-11-01 11:45:46 -0700312 stats_proxy_.get(), video_send_config_.encoder_settings));
mflodmancc3d4422017-08-03 08:27:51 -0700313 video_stream_encoder_->SetSink(&sink_, false /* rotation_applied */);
314 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -0700315 &video_source_, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
mflodmancc3d4422017-08-03 08:27:51 -0700316 video_stream_encoder_->SetStartBitrate(kTargetBitrateBps);
317 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
Niels Möllerf1338562018-04-26 09:51:47 +0200318 kMaxPayloadLength);
mflodmancc3d4422017-08-03 08:27:51 -0700319 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
asapersson5f7226f2016-11-25 04:37:00 -0800320 }
321
322 void ResetEncoder(const std::string& payload_name,
323 size_t num_streams,
324 size_t num_temporal_layers,
emircanbbcc3562017-08-18 00:28:40 -0700325 unsigned char num_spatial_layers,
sprang4847ae62017-06-27 07:06:52 -0700326 bool screenshare) {
Niels Möller259a4972018-04-05 15:36:51 +0200327 video_send_config_.rtp.payload_name = payload_name;
asapersson5f7226f2016-11-25 04:37:00 -0800328
329 VideoEncoderConfig video_encoder_config;
Niels Möller259a4972018-04-05 15:36:51 +0200330 video_encoder_config.codec_type = PayloadStringToCodecType(payload_name);
asapersson5f7226f2016-11-25 04:37:00 -0800331 video_encoder_config.number_of_streams = num_streams;
kthelgason2bc68642017-02-07 07:02:22 -0800332 video_encoder_config.max_bitrate_bps = kTargetBitrateBps;
asapersson5f7226f2016-11-25 04:37:00 -0800333 video_encoder_config.video_stream_factory =
sprangfda496a2017-06-15 04:21:07 -0700334 new rtc::RefCountedObject<VideoStreamFactory>(num_temporal_layers,
335 kDefaultFramerate);
sprang4847ae62017-06-27 07:06:52 -0700336 video_encoder_config.content_type =
337 screenshare ? VideoEncoderConfig::ContentType::kScreen
338 : VideoEncoderConfig::ContentType::kRealtimeVideo;
emircanbbcc3562017-08-18 00:28:40 -0700339 if (payload_name == "VP9") {
340 VideoCodecVP9 vp9_settings = VideoEncoder::GetDefaultVp9Settings();
341 vp9_settings.numberOfSpatialLayers = num_spatial_layers;
342 video_encoder_config.encoder_specific_settings =
343 new rtc::RefCountedObject<
344 VideoEncoderConfig::Vp9EncoderSpecificSettings>(vp9_settings);
345 }
Niels Möllerf1338562018-04-26 09:51:47 +0200346 ConfigureEncoder(std::move(video_encoder_config));
perkj26091b12016-09-01 01:17:40 -0700347 }
348
sprang57c2fff2017-01-16 06:24:02 -0800349 VideoFrame CreateFrame(int64_t ntp_time_ms,
350 rtc::Event* destruction_event) const {
Per512ecb32016-09-23 15:52:06 +0200351 VideoFrame frame(new rtc::RefCountedObject<TestBuffer>(
352 destruction_event, codec_width_, codec_height_),
353 99, 99, kVideoRotation_0);
sprang57c2fff2017-01-16 06:24:02 -0800354 frame.set_ntp_time_ms(ntp_time_ms);
perkj26091b12016-09-01 01:17:40 -0700355 return frame;
356 }
357
sprang57c2fff2017-01-16 06:24:02 -0800358 VideoFrame CreateFrame(int64_t ntp_time_ms, int width, int height) const {
perkj803d97f2016-11-01 11:45:46 -0700359 VideoFrame frame(
360 new rtc::RefCountedObject<TestBuffer>(nullptr, width, height), 99, 99,
361 kVideoRotation_0);
sprang57c2fff2017-01-16 06:24:02 -0800362 frame.set_ntp_time_ms(ntp_time_ms);
sprangc5d62e22017-04-02 23:53:04 -0700363 frame.set_timestamp_us(ntp_time_ms * 1000);
perkj803d97f2016-11-01 11:45:46 -0700364 return frame;
365 }
366
asapersson02465b82017-04-10 01:12:52 -0700367 void VerifyNoLimitation(const rtc::VideoSinkWants& wants) {
asapersson02465b82017-04-10 01:12:52 -0700368 EXPECT_EQ(std::numeric_limits<int>::max(), wants.max_framerate_fps);
asapersson09f05612017-05-15 23:40:18 -0700369 EXPECT_EQ(std::numeric_limits<int>::max(), wants.max_pixel_count);
370 EXPECT_FALSE(wants.target_pixel_count);
asapersson02465b82017-04-10 01:12:52 -0700371 }
372
asapersson09f05612017-05-15 23:40:18 -0700373 void VerifyFpsEqResolutionEq(const rtc::VideoSinkWants& wants1,
374 const rtc::VideoSinkWants& wants2) {
375 EXPECT_EQ(wants1.max_framerate_fps, wants2.max_framerate_fps);
376 EXPECT_EQ(wants1.max_pixel_count, wants2.max_pixel_count);
377 }
378
Åsa Perssonced5cfd2018-08-10 16:16:43 +0200379 void VerifyFpsMaxResolutionMax(const rtc::VideoSinkWants& wants) {
380 EXPECT_EQ(kDefaultFramerate, wants.max_framerate_fps);
381 EXPECT_EQ(std::numeric_limits<int>::max(), wants.max_pixel_count);
382 EXPECT_FALSE(wants.target_pixel_count);
383 }
384
asapersson09f05612017-05-15 23:40:18 -0700385 void VerifyFpsMaxResolutionLt(const rtc::VideoSinkWants& wants1,
386 const rtc::VideoSinkWants& wants2) {
Åsa Perssonced5cfd2018-08-10 16:16:43 +0200387 EXPECT_EQ(kDefaultFramerate, wants1.max_framerate_fps);
asapersson09f05612017-05-15 23:40:18 -0700388 EXPECT_LT(wants1.max_pixel_count, wants2.max_pixel_count);
389 EXPECT_GT(wants1.max_pixel_count, 0);
390 }
391
392 void VerifyFpsMaxResolutionGt(const rtc::VideoSinkWants& wants1,
393 const rtc::VideoSinkWants& wants2) {
Åsa Perssonced5cfd2018-08-10 16:16:43 +0200394 EXPECT_EQ(kDefaultFramerate, wants1.max_framerate_fps);
asapersson09f05612017-05-15 23:40:18 -0700395 EXPECT_GT(wants1.max_pixel_count, wants2.max_pixel_count);
396 }
397
asaperssonf7e294d2017-06-13 23:25:22 -0700398 void VerifyFpsMaxResolutionEq(const rtc::VideoSinkWants& wants1,
399 const rtc::VideoSinkWants& wants2) {
Åsa Perssonced5cfd2018-08-10 16:16:43 +0200400 EXPECT_EQ(kDefaultFramerate, wants1.max_framerate_fps);
asaperssonf7e294d2017-06-13 23:25:22 -0700401 EXPECT_EQ(wants1.max_pixel_count, wants2.max_pixel_count);
402 }
403
404 void VerifyFpsLtResolutionEq(const rtc::VideoSinkWants& wants1,
405 const rtc::VideoSinkWants& wants2) {
406 EXPECT_LT(wants1.max_framerate_fps, wants2.max_framerate_fps);
407 EXPECT_EQ(wants1.max_pixel_count, wants2.max_pixel_count);
408 }
409
410 void VerifyFpsGtResolutionEq(const rtc::VideoSinkWants& wants1,
411 const rtc::VideoSinkWants& wants2) {
412 EXPECT_GT(wants1.max_framerate_fps, wants2.max_framerate_fps);
413 EXPECT_EQ(wants1.max_pixel_count, wants2.max_pixel_count);
414 }
415
416 void VerifyFpsEqResolutionLt(const rtc::VideoSinkWants& wants1,
417 const rtc::VideoSinkWants& wants2) {
418 EXPECT_EQ(wants1.max_framerate_fps, wants2.max_framerate_fps);
419 EXPECT_LT(wants1.max_pixel_count, wants2.max_pixel_count);
420 EXPECT_GT(wants1.max_pixel_count, 0);
421 }
422
423 void VerifyFpsEqResolutionGt(const rtc::VideoSinkWants& wants1,
424 const rtc::VideoSinkWants& wants2) {
425 EXPECT_EQ(wants1.max_framerate_fps, wants2.max_framerate_fps);
426 EXPECT_GT(wants1.max_pixel_count, wants2.max_pixel_count);
427 }
428
asapersson09f05612017-05-15 23:40:18 -0700429 void VerifyFpsMaxResolutionLt(const rtc::VideoSinkWants& wants,
430 int pixel_count) {
Åsa Perssonced5cfd2018-08-10 16:16:43 +0200431 EXPECT_EQ(kDefaultFramerate, wants.max_framerate_fps);
asapersson02465b82017-04-10 01:12:52 -0700432 EXPECT_LT(wants.max_pixel_count, pixel_count);
433 EXPECT_GT(wants.max_pixel_count, 0);
asapersson09f05612017-05-15 23:40:18 -0700434 }
435
436 void VerifyFpsLtResolutionMax(const rtc::VideoSinkWants& wants, int fps) {
437 EXPECT_LT(wants.max_framerate_fps, fps);
438 EXPECT_EQ(std::numeric_limits<int>::max(), wants.max_pixel_count);
439 EXPECT_FALSE(wants.target_pixel_count);
asapersson02465b82017-04-10 01:12:52 -0700440 }
441
asaperssonf7e294d2017-06-13 23:25:22 -0700442 void VerifyFpsEqResolutionMax(const rtc::VideoSinkWants& wants,
443 int expected_fps) {
444 EXPECT_EQ(expected_fps, wants.max_framerate_fps);
445 EXPECT_EQ(std::numeric_limits<int>::max(), wants.max_pixel_count);
446 EXPECT_FALSE(wants.target_pixel_count);
447 }
448
Jonathan Yubc771b72017-12-08 17:04:29 -0800449 void VerifyBalancedModeFpsRange(const rtc::VideoSinkWants& wants,
450 int last_frame_pixels) {
451 // Balanced mode should always scale FPS to the desired range before
452 // attempting to scale resolution.
453 int fps_limit = wants.max_framerate_fps;
454 if (last_frame_pixels <= 320 * 240) {
455 EXPECT_TRUE(7 <= fps_limit && fps_limit <= 10);
456 } else if (last_frame_pixels <= 480 * 270) {
457 EXPECT_TRUE(10 <= fps_limit && fps_limit <= 15);
458 } else if (last_frame_pixels <= 640 * 480) {
459 EXPECT_LE(15, fps_limit);
460 } else {
Åsa Perssonced5cfd2018-08-10 16:16:43 +0200461 EXPECT_EQ(kDefaultFramerate, fps_limit);
Jonathan Yubc771b72017-12-08 17:04:29 -0800462 }
463 }
464
sprang4847ae62017-06-27 07:06:52 -0700465 void WaitForEncodedFrame(int64_t expected_ntp_time) {
466 sink_.WaitForEncodedFrame(expected_ntp_time);
467 fake_clock_.AdvanceTimeMicros(rtc::kNumMicrosecsPerSec / max_framerate_);
468 }
469
470 bool TimedWaitForEncodedFrame(int64_t expected_ntp_time, int64_t timeout_ms) {
471 bool ok = sink_.TimedWaitForEncodedFrame(expected_ntp_time, timeout_ms);
472 fake_clock_.AdvanceTimeMicros(rtc::kNumMicrosecsPerSec / max_framerate_);
473 return ok;
474 }
475
476 void WaitForEncodedFrame(uint32_t expected_width, uint32_t expected_height) {
477 sink_.WaitForEncodedFrame(expected_width, expected_height);
478 fake_clock_.AdvanceTimeMicros(rtc::kNumMicrosecsPerSec / max_framerate_);
479 }
480
481 void ExpectDroppedFrame() {
482 sink_.ExpectDroppedFrame();
483 fake_clock_.AdvanceTimeMicros(rtc::kNumMicrosecsPerSec / max_framerate_);
484 }
485
486 bool WaitForFrame(int64_t timeout_ms) {
487 bool ok = sink_.WaitForFrame(timeout_ms);
488 fake_clock_.AdvanceTimeMicros(rtc::kNumMicrosecsPerSec / max_framerate_);
489 return ok;
490 }
491
perkj26091b12016-09-01 01:17:40 -0700492 class TestEncoder : public test::FakeEncoder {
493 public:
494 TestEncoder()
495 : FakeEncoder(Clock::GetRealTimeClock()),
496 continue_encode_event_(false, false) {}
497
asaperssonfab67072017-04-04 05:51:49 -0700498 VideoCodec codec_config() const {
brandtre78d2662017-01-16 05:57:16 -0800499 rtc::CritScope lock(&crit_sect_);
perkjfa10b552016-10-02 23:45:26 -0700500 return config_;
501 }
502
503 void BlockNextEncode() {
brandtre78d2662017-01-16 05:57:16 -0800504 rtc::CritScope lock(&local_crit_sect_);
perkjfa10b552016-10-02 23:45:26 -0700505 block_next_encode_ = true;
506 }
507
kthelgason876222f2016-11-29 01:44:11 -0800508 VideoEncoder::ScalingSettings GetScalingSettings() const override {
kthelgason2fc52542017-03-03 00:24:41 -0800509 rtc::CritScope lock(&local_crit_sect_);
kthelgasonad9010c2017-02-14 00:46:51 -0800510 if (quality_scaling_)
Niels Möller225c7872018-02-22 15:03:53 +0100511 return VideoEncoder::ScalingSettings(1, 2, kMinPixelsPerFrame);
512 return VideoEncoder::ScalingSettings::kOff;
kthelgason876222f2016-11-29 01:44:11 -0800513 }
514
perkjfa10b552016-10-02 23:45:26 -0700515 void ContinueEncode() { continue_encode_event_.Set(); }
516
517 void CheckLastTimeStampsMatch(int64_t ntp_time_ms,
518 uint32_t timestamp) const {
brandtre78d2662017-01-16 05:57:16 -0800519 rtc::CritScope lock(&local_crit_sect_);
perkjfa10b552016-10-02 23:45:26 -0700520 EXPECT_EQ(timestamp_, timestamp);
521 EXPECT_EQ(ntp_time_ms_, ntp_time_ms);
522 }
523
kthelgason2fc52542017-03-03 00:24:41 -0800524 void SetQualityScaling(bool b) {
525 rtc::CritScope lock(&local_crit_sect_);
526 quality_scaling_ = b;
527 }
kthelgasonad9010c2017-02-14 00:46:51 -0800528
sprangfe627f32017-03-29 08:24:59 -0700529 void ForceInitEncodeFailure(bool force_failure) {
530 rtc::CritScope lock(&local_crit_sect_);
531 force_init_encode_failed_ = force_failure;
532 }
533
perkjfa10b552016-10-02 23:45:26 -0700534 private:
perkj26091b12016-09-01 01:17:40 -0700535 int32_t Encode(const VideoFrame& input_image,
536 const CodecSpecificInfo* codec_specific_info,
537 const std::vector<FrameType>* frame_types) override {
538 bool block_encode;
539 {
brandtre78d2662017-01-16 05:57:16 -0800540 rtc::CritScope lock(&local_crit_sect_);
perkj26091b12016-09-01 01:17:40 -0700541 EXPECT_GT(input_image.timestamp(), timestamp_);
542 EXPECT_GT(input_image.ntp_time_ms(), ntp_time_ms_);
543 EXPECT_EQ(input_image.timestamp(), input_image.ntp_time_ms() * 90);
544
545 timestamp_ = input_image.timestamp();
546 ntp_time_ms_ = input_image.ntp_time_ms();
perkj803d97f2016-11-01 11:45:46 -0700547 last_input_width_ = input_image.width();
548 last_input_height_ = input_image.height();
perkj26091b12016-09-01 01:17:40 -0700549 block_encode = block_next_encode_;
550 block_next_encode_ = false;
551 }
552 int32_t result =
553 FakeEncoder::Encode(input_image, codec_specific_info, frame_types);
554 if (block_encode)
perkja49cbd32016-09-16 07:53:41 -0700555 EXPECT_TRUE(continue_encode_event_.Wait(kDefaultTimeoutMs));
perkj26091b12016-09-01 01:17:40 -0700556 return result;
557 }
558
sprangfe627f32017-03-29 08:24:59 -0700559 int32_t InitEncode(const VideoCodec* config,
560 int32_t number_of_cores,
561 size_t max_payload_size) override {
562 int res =
563 FakeEncoder::InitEncode(config, number_of_cores, max_payload_size);
564 rtc::CritScope lock(&local_crit_sect_);
Erik Språng82fad3d2018-03-21 09:57:23 +0100565 if (config->codecType == kVideoCodecVP8) {
sprangfe627f32017-03-29 08:24:59 -0700566 // Simulate setting up temporal layers, in order to validate the life
567 // cycle of these objects.
568 int num_streams = std::max<int>(1, config->numberOfSimulcastStreams);
sprangfe627f32017-03-29 08:24:59 -0700569 for (int i = 0; i < num_streams; ++i) {
570 allocated_temporal_layers_.emplace_back(
Niels Möller150dcb02018-03-27 14:16:55 +0200571 TemporalLayers::CreateTemporalLayers(*config, i));
sprangfe627f32017-03-29 08:24:59 -0700572 }
573 }
574 if (force_init_encode_failed_)
575 return -1;
576 return res;
577 }
578
brandtre78d2662017-01-16 05:57:16 -0800579 rtc::CriticalSection local_crit_sect_;
danilchapa37de392017-09-09 04:17:22 -0700580 bool block_next_encode_ RTC_GUARDED_BY(local_crit_sect_) = false;
perkj26091b12016-09-01 01:17:40 -0700581 rtc::Event continue_encode_event_;
danilchapa37de392017-09-09 04:17:22 -0700582 uint32_t timestamp_ RTC_GUARDED_BY(local_crit_sect_) = 0;
583 int64_t ntp_time_ms_ RTC_GUARDED_BY(local_crit_sect_) = 0;
584 int last_input_width_ RTC_GUARDED_BY(local_crit_sect_) = 0;
585 int last_input_height_ RTC_GUARDED_BY(local_crit_sect_) = 0;
586 bool quality_scaling_ RTC_GUARDED_BY(local_crit_sect_) = true;
sprangfe627f32017-03-29 08:24:59 -0700587 std::vector<std::unique_ptr<TemporalLayers>> allocated_temporal_layers_
danilchapa37de392017-09-09 04:17:22 -0700588 RTC_GUARDED_BY(local_crit_sect_);
589 bool force_init_encode_failed_ RTC_GUARDED_BY(local_crit_sect_) = false;
perkj26091b12016-09-01 01:17:40 -0700590 };
591
mflodmancc3d4422017-08-03 08:27:51 -0700592 class TestSink : public VideoStreamEncoder::EncoderSink {
perkj26091b12016-09-01 01:17:40 -0700593 public:
594 explicit TestSink(TestEncoder* test_encoder)
595 : test_encoder_(test_encoder), encoded_frame_event_(false, false) {}
596
perkj26091b12016-09-01 01:17:40 -0700597 void WaitForEncodedFrame(int64_t expected_ntp_time) {
sprang4847ae62017-06-27 07:06:52 -0700598 EXPECT_TRUE(
599 TimedWaitForEncodedFrame(expected_ntp_time, kDefaultTimeoutMs));
600 }
601
602 bool TimedWaitForEncodedFrame(int64_t expected_ntp_time,
603 int64_t timeout_ms) {
perkj26091b12016-09-01 01:17:40 -0700604 uint32_t timestamp = 0;
sprang4847ae62017-06-27 07:06:52 -0700605 if (!encoded_frame_event_.Wait(timeout_ms))
606 return false;
perkj26091b12016-09-01 01:17:40 -0700607 {
608 rtc::CritScope lock(&crit_);
sprangb1ca0732017-02-01 08:38:12 -0800609 timestamp = last_timestamp_;
perkj26091b12016-09-01 01:17:40 -0700610 }
611 test_encoder_->CheckLastTimeStampsMatch(expected_ntp_time, timestamp);
sprang4847ae62017-06-27 07:06:52 -0700612 return true;
perkj26091b12016-09-01 01:17:40 -0700613 }
614
sprangb1ca0732017-02-01 08:38:12 -0800615 void WaitForEncodedFrame(uint32_t expected_width,
616 uint32_t expected_height) {
sprangc5d62e22017-04-02 23:53:04 -0700617 EXPECT_TRUE(encoded_frame_event_.Wait(kDefaultTimeoutMs));
Åsa Perssonc74d8da2017-12-04 14:13:56 +0100618 CheckLastFrameSizeMatches(expected_width, expected_height);
sprangc5d62e22017-04-02 23:53:04 -0700619 }
620
Åsa Perssonc74d8da2017-12-04 14:13:56 +0100621 void CheckLastFrameSizeMatches(uint32_t expected_width,
sprangc5d62e22017-04-02 23:53:04 -0700622 uint32_t expected_height) {
sprangb1ca0732017-02-01 08:38:12 -0800623 uint32_t width = 0;
624 uint32_t height = 0;
sprangb1ca0732017-02-01 08:38:12 -0800625 {
626 rtc::CritScope lock(&crit_);
627 width = last_width_;
628 height = last_height_;
629 }
630 EXPECT_EQ(expected_height, height);
631 EXPECT_EQ(expected_width, width);
632 }
633
kthelgason2fc52542017-03-03 00:24:41 -0800634 void ExpectDroppedFrame() { EXPECT_FALSE(encoded_frame_event_.Wait(100)); }
kthelgason2bc68642017-02-07 07:02:22 -0800635
sprangc5d62e22017-04-02 23:53:04 -0700636 bool WaitForFrame(int64_t timeout_ms) {
637 return encoded_frame_event_.Wait(timeout_ms);
638 }
639
perkj26091b12016-09-01 01:17:40 -0700640 void SetExpectNoFrames() {
641 rtc::CritScope lock(&crit_);
642 expect_frames_ = false;
643 }
644
asaperssonfab67072017-04-04 05:51:49 -0700645 int number_of_reconfigurations() const {
Per512ecb32016-09-23 15:52:06 +0200646 rtc::CritScope lock(&crit_);
647 return number_of_reconfigurations_;
648 }
649
asaperssonfab67072017-04-04 05:51:49 -0700650 int last_min_transmit_bitrate() const {
Per512ecb32016-09-23 15:52:06 +0200651 rtc::CritScope lock(&crit_);
652 return min_transmit_bitrate_bps_;
653 }
654
perkj26091b12016-09-01 01:17:40 -0700655 private:
sergeyu2cb155a2016-11-04 11:39:29 -0700656 Result OnEncodedImage(
657 const EncodedImage& encoded_image,
658 const CodecSpecificInfo* codec_specific_info,
659 const RTPFragmentationHeader* fragmentation) override {
Per512ecb32016-09-23 15:52:06 +0200660 rtc::CritScope lock(&crit_);
661 EXPECT_TRUE(expect_frames_);
sprangb1ca0732017-02-01 08:38:12 -0800662 last_timestamp_ = encoded_image._timeStamp;
663 last_width_ = encoded_image._encodedWidth;
664 last_height_ = encoded_image._encodedHeight;
Per512ecb32016-09-23 15:52:06 +0200665 encoded_frame_event_.Set();
sprangb1ca0732017-02-01 08:38:12 -0800666 return Result(Result::OK, last_timestamp_);
Per512ecb32016-09-23 15:52:06 +0200667 }
668
669 void OnEncoderConfigurationChanged(std::vector<VideoStream> streams,
670 int min_transmit_bitrate_bps) override {
671 rtc::CriticalSection crit_;
672 ++number_of_reconfigurations_;
673 min_transmit_bitrate_bps_ = min_transmit_bitrate_bps;
674 }
675
perkj26091b12016-09-01 01:17:40 -0700676 rtc::CriticalSection crit_;
677 TestEncoder* test_encoder_;
678 rtc::Event encoded_frame_event_;
sprangb1ca0732017-02-01 08:38:12 -0800679 uint32_t last_timestamp_ = 0;
680 uint32_t last_height_ = 0;
681 uint32_t last_width_ = 0;
perkj26091b12016-09-01 01:17:40 -0700682 bool expect_frames_ = true;
Per512ecb32016-09-23 15:52:06 +0200683 int number_of_reconfigurations_ = 0;
684 int min_transmit_bitrate_bps_ = 0;
perkj26091b12016-09-01 01:17:40 -0700685 };
686
687 VideoSendStream::Config video_send_config_;
Erik Språng08127a92016-11-16 16:41:30 +0100688 VideoEncoderConfig video_encoder_config_;
Per512ecb32016-09-23 15:52:06 +0200689 int codec_width_;
690 int codec_height_;
sprang4847ae62017-06-27 07:06:52 -0700691 int max_framerate_;
perkj26091b12016-09-01 01:17:40 -0700692 TestEncoder fake_encoder_;
Niels Möller4db138e2018-04-19 09:04:13 +0200693 test::EncoderProxyFactory encoder_factory_;
sprangc5d62e22017-04-02 23:53:04 -0700694 std::unique_ptr<MockableSendStatisticsProxy> stats_proxy_;
perkj26091b12016-09-01 01:17:40 -0700695 TestSink sink_;
sprangb1ca0732017-02-01 08:38:12 -0800696 AdaptingFrameForwarder video_source_;
mflodmancc3d4422017-08-03 08:27:51 -0700697 std::unique_ptr<VideoStreamEncoderUnderTest> video_stream_encoder_;
sprang4847ae62017-06-27 07:06:52 -0700698 rtc::ScopedFakeClock fake_clock_;
perkj26091b12016-09-01 01:17:40 -0700699};
700
mflodmancc3d4422017-08-03 08:27:51 -0700701TEST_F(VideoStreamEncoderTest, EncodeOneFrame) {
702 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkj26091b12016-09-01 01:17:40 -0700703 rtc::Event frame_destroyed_event(false, false);
perkja49cbd32016-09-16 07:53:41 -0700704 video_source_.IncomingCapturedFrame(CreateFrame(1, &frame_destroyed_event));
sprang4847ae62017-06-27 07:06:52 -0700705 WaitForEncodedFrame(1);
perkja49cbd32016-09-16 07:53:41 -0700706 EXPECT_TRUE(frame_destroyed_event.Wait(kDefaultTimeoutMs));
mflodmancc3d4422017-08-03 08:27:51 -0700707 video_stream_encoder_->Stop();
perkj26091b12016-09-01 01:17:40 -0700708}
709
mflodmancc3d4422017-08-03 08:27:51 -0700710TEST_F(VideoStreamEncoderTest, DropsFramesBeforeFirstOnBitrateUpdated) {
perkj26091b12016-09-01 01:17:40 -0700711 // Dropped since no target bitrate has been set.
712 rtc::Event frame_destroyed_event(false, false);
Sebastian Janssona3177052018-04-10 13:05:49 +0200713 // The encoder will cache up to one frame for a short duration. Adding two
714 // frames means that the first frame will be dropped and the second frame will
715 // be sent when the encoder is enabled.
perkja49cbd32016-09-16 07:53:41 -0700716 video_source_.IncomingCapturedFrame(CreateFrame(1, &frame_destroyed_event));
Sebastian Janssona3177052018-04-10 13:05:49 +0200717 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
perkja49cbd32016-09-16 07:53:41 -0700718 EXPECT_TRUE(frame_destroyed_event.Wait(kDefaultTimeoutMs));
perkj26091b12016-09-01 01:17:40 -0700719
mflodmancc3d4422017-08-03 08:27:51 -0700720 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkj26091b12016-09-01 01:17:40 -0700721
Sebastian Janssona3177052018-04-10 13:05:49 +0200722 // The pending frame should be received.
sprang4847ae62017-06-27 07:06:52 -0700723 WaitForEncodedFrame(2);
Sebastian Janssona3177052018-04-10 13:05:49 +0200724 video_source_.IncomingCapturedFrame(CreateFrame(3, nullptr));
725
726 WaitForEncodedFrame(3);
mflodmancc3d4422017-08-03 08:27:51 -0700727 video_stream_encoder_->Stop();
perkj26091b12016-09-01 01:17:40 -0700728}
729
mflodmancc3d4422017-08-03 08:27:51 -0700730TEST_F(VideoStreamEncoderTest, DropsFramesWhenRateSetToZero) {
731 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkja49cbd32016-09-16 07:53:41 -0700732 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700733 WaitForEncodedFrame(1);
perkj26091b12016-09-01 01:17:40 -0700734
mflodmancc3d4422017-08-03 08:27:51 -0700735 video_stream_encoder_->OnBitrateUpdated(0, 0, 0);
Sebastian Janssona3177052018-04-10 13:05:49 +0200736 // The encoder will cache up to one frame for a short duration. Adding two
737 // frames means that the first frame will be dropped and the second frame will
738 // be sent when the encoder is resumed.
perkja49cbd32016-09-16 07:53:41 -0700739 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
Sebastian Janssona3177052018-04-10 13:05:49 +0200740 video_source_.IncomingCapturedFrame(CreateFrame(3, nullptr));
perkj26091b12016-09-01 01:17:40 -0700741
mflodmancc3d4422017-08-03 08:27:51 -0700742 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
sprang4847ae62017-06-27 07:06:52 -0700743 WaitForEncodedFrame(3);
Sebastian Janssona3177052018-04-10 13:05:49 +0200744 video_source_.IncomingCapturedFrame(CreateFrame(4, nullptr));
745 WaitForEncodedFrame(4);
mflodmancc3d4422017-08-03 08:27:51 -0700746 video_stream_encoder_->Stop();
perkj26091b12016-09-01 01:17:40 -0700747}
748
mflodmancc3d4422017-08-03 08:27:51 -0700749TEST_F(VideoStreamEncoderTest, DropsFramesWithSameOrOldNtpTimestamp) {
750 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkja49cbd32016-09-16 07:53:41 -0700751 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700752 WaitForEncodedFrame(1);
perkj26091b12016-09-01 01:17:40 -0700753
754 // This frame will be dropped since it has the same ntp timestamp.
perkja49cbd32016-09-16 07:53:41 -0700755 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
perkj26091b12016-09-01 01:17:40 -0700756
perkja49cbd32016-09-16 07:53:41 -0700757 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700758 WaitForEncodedFrame(2);
mflodmancc3d4422017-08-03 08:27:51 -0700759 video_stream_encoder_->Stop();
perkj26091b12016-09-01 01:17:40 -0700760}
761
mflodmancc3d4422017-08-03 08:27:51 -0700762TEST_F(VideoStreamEncoderTest, DropsFrameAfterStop) {
763 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkj26091b12016-09-01 01:17:40 -0700764
perkja49cbd32016-09-16 07:53:41 -0700765 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700766 WaitForEncodedFrame(1);
perkj26091b12016-09-01 01:17:40 -0700767
mflodmancc3d4422017-08-03 08:27:51 -0700768 video_stream_encoder_->Stop();
perkj26091b12016-09-01 01:17:40 -0700769 sink_.SetExpectNoFrames();
770 rtc::Event frame_destroyed_event(false, false);
perkja49cbd32016-09-16 07:53:41 -0700771 video_source_.IncomingCapturedFrame(CreateFrame(2, &frame_destroyed_event));
772 EXPECT_TRUE(frame_destroyed_event.Wait(kDefaultTimeoutMs));
perkj26091b12016-09-01 01:17:40 -0700773}
774
mflodmancc3d4422017-08-03 08:27:51 -0700775TEST_F(VideoStreamEncoderTest, DropsPendingFramesOnSlowEncode) {
776 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkj26091b12016-09-01 01:17:40 -0700777
778 fake_encoder_.BlockNextEncode();
perkja49cbd32016-09-16 07:53:41 -0700779 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700780 WaitForEncodedFrame(1);
perkj26091b12016-09-01 01:17:40 -0700781 // Here, the encoder thread will be blocked in the TestEncoder waiting for a
782 // call to ContinueEncode.
perkja49cbd32016-09-16 07:53:41 -0700783 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
784 video_source_.IncomingCapturedFrame(CreateFrame(3, nullptr));
perkj26091b12016-09-01 01:17:40 -0700785 fake_encoder_.ContinueEncode();
sprang4847ae62017-06-27 07:06:52 -0700786 WaitForEncodedFrame(3);
perkj26091b12016-09-01 01:17:40 -0700787
mflodmancc3d4422017-08-03 08:27:51 -0700788 video_stream_encoder_->Stop();
perkj26091b12016-09-01 01:17:40 -0700789}
790
mflodmancc3d4422017-08-03 08:27:51 -0700791TEST_F(VideoStreamEncoderTest,
792 ConfigureEncoderTriggersOnEncoderConfigurationChanged) {
793 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
Per21d45d22016-10-30 21:37:57 +0100794 EXPECT_EQ(0, sink_.number_of_reconfigurations());
Per512ecb32016-09-23 15:52:06 +0200795
796 // Capture a frame and wait for it to synchronize with the encoder thread.
Perf8c5f2b2016-09-23 16:24:55 +0200797 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700798 WaitForEncodedFrame(1);
Per21d45d22016-10-30 21:37:57 +0100799 // The encoder will have been configured once when the first frame is
800 // received.
801 EXPECT_EQ(1, sink_.number_of_reconfigurations());
Per512ecb32016-09-23 15:52:06 +0200802
803 VideoEncoderConfig video_encoder_config;
Niels Möller259a4972018-04-05 15:36:51 +0200804 test::FillEncoderConfiguration(kVideoCodecVP8, 1, &video_encoder_config);
Per512ecb32016-09-23 15:52:06 +0200805 video_encoder_config.min_transmit_bitrate_bps = 9999;
mflodmancc3d4422017-08-03 08:27:51 -0700806 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
Niels Möllerf1338562018-04-26 09:51:47 +0200807 kMaxPayloadLength);
Per512ecb32016-09-23 15:52:06 +0200808
809 // Capture a frame and wait for it to synchronize with the encoder thread.
Perf8c5f2b2016-09-23 16:24:55 +0200810 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700811 WaitForEncodedFrame(2);
Per21d45d22016-10-30 21:37:57 +0100812 EXPECT_EQ(2, sink_.number_of_reconfigurations());
perkj3b703ed2016-09-29 23:25:40 -0700813 EXPECT_EQ(9999, sink_.last_min_transmit_bitrate());
perkj26105b42016-09-29 22:39:10 -0700814
mflodmancc3d4422017-08-03 08:27:51 -0700815 video_stream_encoder_->Stop();
perkj26105b42016-09-29 22:39:10 -0700816}
817
mflodmancc3d4422017-08-03 08:27:51 -0700818TEST_F(VideoStreamEncoderTest, FrameResolutionChangeReconfigureEncoder) {
819 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkjfa10b552016-10-02 23:45:26 -0700820
821 // Capture a frame and wait for it to synchronize with the encoder thread.
822 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700823 WaitForEncodedFrame(1);
Per21d45d22016-10-30 21:37:57 +0100824 // The encoder will have been configured once.
825 EXPECT_EQ(1, sink_.number_of_reconfigurations());
perkjfa10b552016-10-02 23:45:26 -0700826 EXPECT_EQ(codec_width_, fake_encoder_.codec_config().width);
827 EXPECT_EQ(codec_height_, fake_encoder_.codec_config().height);
828
829 codec_width_ *= 2;
830 codec_height_ *= 2;
831 // Capture a frame with a higher resolution and wait for it to synchronize
832 // with the encoder thread.
833 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700834 WaitForEncodedFrame(2);
perkjfa10b552016-10-02 23:45:26 -0700835 EXPECT_EQ(codec_width_, fake_encoder_.codec_config().width);
836 EXPECT_EQ(codec_height_, fake_encoder_.codec_config().height);
Per21d45d22016-10-30 21:37:57 +0100837 EXPECT_EQ(2, sink_.number_of_reconfigurations());
perkjfa10b552016-10-02 23:45:26 -0700838
mflodmancc3d4422017-08-03 08:27:51 -0700839 video_stream_encoder_->Stop();
perkjfa10b552016-10-02 23:45:26 -0700840}
841
mflodmancc3d4422017-08-03 08:27:51 -0700842TEST_F(VideoStreamEncoderTest, SwitchSourceDeregisterEncoderAsSink) {
perkj803d97f2016-11-01 11:45:46 -0700843 EXPECT_TRUE(video_source_.has_sinks());
844 test::FrameForwarder new_video_source;
mflodmancc3d4422017-08-03 08:27:51 -0700845 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -0700846 &new_video_source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
perkj803d97f2016-11-01 11:45:46 -0700847 EXPECT_FALSE(video_source_.has_sinks());
848 EXPECT_TRUE(new_video_source.has_sinks());
849
mflodmancc3d4422017-08-03 08:27:51 -0700850 video_stream_encoder_->Stop();
perkj803d97f2016-11-01 11:45:46 -0700851}
852
mflodmancc3d4422017-08-03 08:27:51 -0700853TEST_F(VideoStreamEncoderTest, SinkWantsRotationApplied) {
perkj803d97f2016-11-01 11:45:46 -0700854 EXPECT_FALSE(video_source_.sink_wants().rotation_applied);
mflodmancc3d4422017-08-03 08:27:51 -0700855 video_stream_encoder_->SetSink(&sink_, true /*rotation_applied*/);
perkj803d97f2016-11-01 11:45:46 -0700856 EXPECT_TRUE(video_source_.sink_wants().rotation_applied);
mflodmancc3d4422017-08-03 08:27:51 -0700857 video_stream_encoder_->Stop();
perkj803d97f2016-11-01 11:45:46 -0700858}
859
Jonathan Yubc771b72017-12-08 17:04:29 -0800860TEST_F(VideoStreamEncoderTest, TestCpuDowngrades_BalancedMode) {
861 const int kFramerateFps = 30;
asaperssonf7e294d2017-06-13 23:25:22 -0700862 const int kWidth = 1280;
863 const int kHeight = 720;
Jonathan Yubc771b72017-12-08 17:04:29 -0800864
865 // We rely on the automatic resolution adaptation, but we handle framerate
866 // adaptation manually by mocking the stats proxy.
867 video_source_.set_adaptation_enabled(true);
asaperssonf7e294d2017-06-13 23:25:22 -0700868
Taylor Brandstetter49fcc102018-05-16 14:20:41 -0700869 // Enable BALANCED preference, no initial limitation.
Jonathan Yubc771b72017-12-08 17:04:29 -0800870 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
Taylor Brandstetter49fcc102018-05-16 14:20:41 -0700871 video_stream_encoder_->SetSource(&video_source_,
872 webrtc::DegradationPreference::BALANCED);
Jonathan Yubc771b72017-12-08 17:04:29 -0800873 VerifyNoLimitation(video_source_.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -0700874 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
Jonathan Yubc771b72017-12-08 17:04:29 -0800875 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
asaperssonf7e294d2017-06-13 23:25:22 -0700876 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
877
Jonathan Yubc771b72017-12-08 17:04:29 -0800878 // Adapt down as far as possible.
879 rtc::VideoSinkWants last_wants;
880 int64_t t = 1;
881 int loop_count = 0;
882 do {
883 ++loop_count;
884 last_wants = video_source_.sink_wants();
885
886 // Simulate the framerate we've been asked to adapt to.
887 const int fps = std::min(kFramerateFps, last_wants.max_framerate_fps);
888 const int frame_interval_ms = rtc::kNumMillisecsPerSec / fps;
889 VideoSendStream::Stats mock_stats = stats_proxy_->GetStats();
890 mock_stats.input_frame_rate = fps;
891 stats_proxy_->SetMockStats(mock_stats);
892
893 video_source_.IncomingCapturedFrame(CreateFrame(t, kWidth, kHeight));
894 sink_.WaitForEncodedFrame(t);
895 t += frame_interval_ms;
896
mflodmancc3d4422017-08-03 08:27:51 -0700897 video_stream_encoder_->TriggerCpuOveruse();
Jonathan Yubc771b72017-12-08 17:04:29 -0800898 VerifyBalancedModeFpsRange(
899 video_source_.sink_wants(),
900 *video_source_.last_sent_width() * *video_source_.last_sent_height());
901 } while (video_source_.sink_wants().max_pixel_count <
902 last_wants.max_pixel_count ||
903 video_source_.sink_wants().max_framerate_fps <
904 last_wants.max_framerate_fps);
asaperssonf7e294d2017-06-13 23:25:22 -0700905
Jonathan Yubc771b72017-12-08 17:04:29 -0800906 // Verify that we've adapted all the way down.
907 stats_proxy_->ResetMockStats();
asaperssonf7e294d2017-06-13 23:25:22 -0700908 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
Jonathan Yubc771b72017-12-08 17:04:29 -0800909 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_framerate);
910 EXPECT_EQ(loop_count - 1,
asaperssonf7e294d2017-06-13 23:25:22 -0700911 stats_proxy_->GetStats().number_of_cpu_adapt_changes);
Jonathan Yubc771b72017-12-08 17:04:29 -0800912 EXPECT_EQ(kMinPixelsPerFrame, *video_source_.last_sent_width() *
913 *video_source_.last_sent_height());
914 EXPECT_EQ(kMinBalancedFramerateFps,
915 video_source_.sink_wants().max_framerate_fps);
asaperssonf7e294d2017-06-13 23:25:22 -0700916
Jonathan Yubc771b72017-12-08 17:04:29 -0800917 // Adapt back up the same number of times we adapted down.
918 for (int i = 0; i < loop_count - 1; ++i) {
919 last_wants = video_source_.sink_wants();
920
921 // Simulate the framerate we've been asked to adapt to.
922 const int fps = std::min(kFramerateFps, last_wants.max_framerate_fps);
923 const int frame_interval_ms = rtc::kNumMillisecsPerSec / fps;
924 VideoSendStream::Stats mock_stats = stats_proxy_->GetStats();
925 mock_stats.input_frame_rate = fps;
926 stats_proxy_->SetMockStats(mock_stats);
927
928 video_source_.IncomingCapturedFrame(CreateFrame(t, kWidth, kHeight));
929 sink_.WaitForEncodedFrame(t);
930 t += frame_interval_ms;
931
mflodmancc3d4422017-08-03 08:27:51 -0700932 video_stream_encoder_->TriggerCpuNormalUsage();
Jonathan Yubc771b72017-12-08 17:04:29 -0800933 VerifyBalancedModeFpsRange(
934 video_source_.sink_wants(),
935 *video_source_.last_sent_width() * *video_source_.last_sent_height());
936 EXPECT_TRUE(video_source_.sink_wants().max_pixel_count >
937 last_wants.max_pixel_count ||
938 video_source_.sink_wants().max_framerate_fps >
939 last_wants.max_framerate_fps);
asaperssonf7e294d2017-06-13 23:25:22 -0700940 }
941
Åsa Perssonced5cfd2018-08-10 16:16:43 +0200942 VerifyFpsMaxResolutionMax(video_source_.sink_wants());
Jonathan Yubc771b72017-12-08 17:04:29 -0800943 stats_proxy_->ResetMockStats();
asaperssonf7e294d2017-06-13 23:25:22 -0700944 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
Jonathan Yubc771b72017-12-08 17:04:29 -0800945 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
946 EXPECT_EQ((loop_count - 1) * 2,
947 stats_proxy_->GetStats().number_of_cpu_adapt_changes);
asaperssonf7e294d2017-06-13 23:25:22 -0700948
mflodmancc3d4422017-08-03 08:27:51 -0700949 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -0700950}
mflodmancc3d4422017-08-03 08:27:51 -0700951TEST_F(VideoStreamEncoderTest, SinkWantsStoredByDegradationPreference) {
952 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson02465b82017-04-10 01:12:52 -0700953 VerifyNoLimitation(video_source_.sink_wants());
perkj803d97f2016-11-01 11:45:46 -0700954
sprangc5d62e22017-04-02 23:53:04 -0700955 const int kFrameWidth = 1280;
956 const int kFrameHeight = 720;
sprangc5d62e22017-04-02 23:53:04 -0700957
Åsa Perssonced5cfd2018-08-10 16:16:43 +0200958 int64_t frame_timestamp = 1;
perkj803d97f2016-11-01 11:45:46 -0700959
kthelgason5e13d412016-12-01 03:59:51 -0800960 video_source_.IncomingCapturedFrame(
sprangc5d62e22017-04-02 23:53:04 -0700961 CreateFrame(frame_timestamp, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -0700962 WaitForEncodedFrame(frame_timestamp);
sprangc5d62e22017-04-02 23:53:04 -0700963 frame_timestamp += kFrameIntervalMs;
964
perkj803d97f2016-11-01 11:45:46 -0700965 // Trigger CPU overuse.
mflodmancc3d4422017-08-03 08:27:51 -0700966 video_stream_encoder_->TriggerCpuOveruse();
perkj803d97f2016-11-01 11:45:46 -0700967 video_source_.IncomingCapturedFrame(
sprangc5d62e22017-04-02 23:53:04 -0700968 CreateFrame(frame_timestamp, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -0700969 WaitForEncodedFrame(frame_timestamp);
sprangc5d62e22017-04-02 23:53:04 -0700970 frame_timestamp += kFrameIntervalMs;
sprang3ea3c772017-03-30 07:23:48 -0700971
asapersson0944a802017-04-07 00:57:58 -0700972 // Default degradation preference is maintain-framerate, so will lower max
sprangc5d62e22017-04-02 23:53:04 -0700973 // wanted resolution.
974 EXPECT_FALSE(video_source_.sink_wants().target_pixel_count);
975 EXPECT_LT(video_source_.sink_wants().max_pixel_count,
976 kFrameWidth * kFrameHeight);
Åsa Perssonced5cfd2018-08-10 16:16:43 +0200977 EXPECT_EQ(kDefaultFramerate, video_source_.sink_wants().max_framerate_fps);
sprangc5d62e22017-04-02 23:53:04 -0700978
979 // Set new source, switch to maintain-resolution.
perkj803d97f2016-11-01 11:45:46 -0700980 test::FrameForwarder new_video_source;
mflodmancc3d4422017-08-03 08:27:51 -0700981 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -0700982 &new_video_source, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
perkj803d97f2016-11-01 11:45:46 -0700983
sprangc5d62e22017-04-02 23:53:04 -0700984 // Initially no degradation registered.
Åsa Perssonced5cfd2018-08-10 16:16:43 +0200985 VerifyFpsMaxResolutionMax(new_video_source.sink_wants());
perkj803d97f2016-11-01 11:45:46 -0700986
sprangc5d62e22017-04-02 23:53:04 -0700987 // Force an input frame rate to be available, or the adaptation call won't
988 // know what framerate to adapt form.
asapersson02465b82017-04-10 01:12:52 -0700989 const int kInputFps = 30;
sprangc5d62e22017-04-02 23:53:04 -0700990 VideoSendStream::Stats stats = stats_proxy_->GetStats();
asapersson02465b82017-04-10 01:12:52 -0700991 stats.input_frame_rate = kInputFps;
sprangc5d62e22017-04-02 23:53:04 -0700992 stats_proxy_->SetMockStats(stats);
993
mflodmancc3d4422017-08-03 08:27:51 -0700994 video_stream_encoder_->TriggerCpuOveruse();
perkj803d97f2016-11-01 11:45:46 -0700995 new_video_source.IncomingCapturedFrame(
sprangc5d62e22017-04-02 23:53:04 -0700996 CreateFrame(frame_timestamp, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -0700997 WaitForEncodedFrame(frame_timestamp);
sprangc5d62e22017-04-02 23:53:04 -0700998 frame_timestamp += kFrameIntervalMs;
999
1000 // Some framerate constraint should be set.
sprang84a37592017-02-10 07:04:27 -08001001 EXPECT_FALSE(new_video_source.sink_wants().target_pixel_count);
sprangc5d62e22017-04-02 23:53:04 -07001002 EXPECT_EQ(std::numeric_limits<int>::max(),
1003 new_video_source.sink_wants().max_pixel_count);
asapersson02465b82017-04-10 01:12:52 -07001004 EXPECT_LT(new_video_source.sink_wants().max_framerate_fps, kInputFps);
sprangc5d62e22017-04-02 23:53:04 -07001005
asapersson02465b82017-04-10 01:12:52 -07001006 // Turn off degradation completely.
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001007 video_stream_encoder_->SetSource(&new_video_source,
1008 webrtc::DegradationPreference::DISABLED);
Åsa Perssonced5cfd2018-08-10 16:16:43 +02001009 VerifyFpsMaxResolutionMax(new_video_source.sink_wants());
sprangc5d62e22017-04-02 23:53:04 -07001010
mflodmancc3d4422017-08-03 08:27:51 -07001011 video_stream_encoder_->TriggerCpuOveruse();
sprangc5d62e22017-04-02 23:53:04 -07001012 new_video_source.IncomingCapturedFrame(
1013 CreateFrame(frame_timestamp, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07001014 WaitForEncodedFrame(frame_timestamp);
sprangc5d62e22017-04-02 23:53:04 -07001015 frame_timestamp += kFrameIntervalMs;
1016
1017 // Still no degradation.
Åsa Perssonced5cfd2018-08-10 16:16:43 +02001018 VerifyFpsMaxResolutionMax(new_video_source.sink_wants());
perkj803d97f2016-11-01 11:45:46 -07001019
1020 // Calling SetSource with resolution scaling enabled apply the old SinkWants.
mflodmancc3d4422017-08-03 08:27:51 -07001021 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001022 &new_video_source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
sprangc5d62e22017-04-02 23:53:04 -07001023 EXPECT_LT(new_video_source.sink_wants().max_pixel_count,
1024 kFrameWidth * kFrameHeight);
sprang84a37592017-02-10 07:04:27 -08001025 EXPECT_FALSE(new_video_source.sink_wants().target_pixel_count);
Åsa Perssonced5cfd2018-08-10 16:16:43 +02001026 EXPECT_EQ(kDefaultFramerate, new_video_source.sink_wants().max_framerate_fps);
sprangc5d62e22017-04-02 23:53:04 -07001027
1028 // Calling SetSource with framerate scaling enabled apply the old SinkWants.
mflodmancc3d4422017-08-03 08:27:51 -07001029 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001030 &new_video_source, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
sprangc5d62e22017-04-02 23:53:04 -07001031 EXPECT_FALSE(new_video_source.sink_wants().target_pixel_count);
1032 EXPECT_EQ(std::numeric_limits<int>::max(),
1033 new_video_source.sink_wants().max_pixel_count);
asapersson02465b82017-04-10 01:12:52 -07001034 EXPECT_LT(new_video_source.sink_wants().max_framerate_fps, kInputFps);
perkj803d97f2016-11-01 11:45:46 -07001035
mflodmancc3d4422017-08-03 08:27:51 -07001036 video_stream_encoder_->Stop();
perkj803d97f2016-11-01 11:45:46 -07001037}
1038
mflodmancc3d4422017-08-03 08:27:51 -07001039TEST_F(VideoStreamEncoderTest, StatsTracksQualityAdaptationStats) {
1040 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkj803d97f2016-11-01 11:45:46 -07001041
asaperssonfab67072017-04-04 05:51:49 -07001042 const int kWidth = 1280;
1043 const int kHeight = 720;
asaperssonfab67072017-04-04 05:51:49 -07001044 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001045 WaitForEncodedFrame(1);
asaperssonfab67072017-04-04 05:51:49 -07001046 VideoSendStream::Stats stats = stats_proxy_->GetStats();
1047 EXPECT_FALSE(stats.bw_limited_resolution);
1048 EXPECT_EQ(0, stats.number_of_quality_adapt_changes);
1049
1050 // Trigger adapt down.
mflodmancc3d4422017-08-03 08:27:51 -07001051 video_stream_encoder_->TriggerQualityLow();
asaperssonfab67072017-04-04 05:51:49 -07001052 video_source_.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001053 WaitForEncodedFrame(2);
asaperssonfab67072017-04-04 05:51:49 -07001054
1055 stats = stats_proxy_->GetStats();
1056 EXPECT_TRUE(stats.bw_limited_resolution);
1057 EXPECT_EQ(1, stats.number_of_quality_adapt_changes);
1058
1059 // Trigger adapt up.
mflodmancc3d4422017-08-03 08:27:51 -07001060 video_stream_encoder_->TriggerQualityHigh();
asaperssonfab67072017-04-04 05:51:49 -07001061 video_source_.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001062 WaitForEncodedFrame(3);
asaperssonfab67072017-04-04 05:51:49 -07001063
1064 stats = stats_proxy_->GetStats();
1065 EXPECT_FALSE(stats.bw_limited_resolution);
1066 EXPECT_EQ(2, stats.number_of_quality_adapt_changes);
1067 EXPECT_EQ(0, stats.number_of_cpu_adapt_changes);
1068
mflodmancc3d4422017-08-03 08:27:51 -07001069 video_stream_encoder_->Stop();
asaperssonfab67072017-04-04 05:51:49 -07001070}
1071
mflodmancc3d4422017-08-03 08:27:51 -07001072TEST_F(VideoStreamEncoderTest, StatsTracksCpuAdaptationStats) {
1073 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonfab67072017-04-04 05:51:49 -07001074
1075 const int kWidth = 1280;
1076 const int kHeight = 720;
asaperssonfab67072017-04-04 05:51:49 -07001077 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001078 WaitForEncodedFrame(1);
perkj803d97f2016-11-01 11:45:46 -07001079 VideoSendStream::Stats stats = stats_proxy_->GetStats();
1080 EXPECT_FALSE(stats.cpu_limited_resolution);
1081 EXPECT_EQ(0, stats.number_of_cpu_adapt_changes);
1082
1083 // Trigger CPU overuse.
mflodmancc3d4422017-08-03 08:27:51 -07001084 video_stream_encoder_->TriggerCpuOveruse();
asaperssonfab67072017-04-04 05:51:49 -07001085 video_source_.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001086 WaitForEncodedFrame(2);
perkj803d97f2016-11-01 11:45:46 -07001087
1088 stats = stats_proxy_->GetStats();
1089 EXPECT_TRUE(stats.cpu_limited_resolution);
1090 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1091
1092 // Trigger CPU normal use.
mflodmancc3d4422017-08-03 08:27:51 -07001093 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssonfab67072017-04-04 05:51:49 -07001094 video_source_.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001095 WaitForEncodedFrame(3);
perkj803d97f2016-11-01 11:45:46 -07001096
1097 stats = stats_proxy_->GetStats();
1098 EXPECT_FALSE(stats.cpu_limited_resolution);
1099 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
asaperssonfab67072017-04-04 05:51:49 -07001100 EXPECT_EQ(0, stats.number_of_quality_adapt_changes);
perkj803d97f2016-11-01 11:45:46 -07001101
mflodmancc3d4422017-08-03 08:27:51 -07001102 video_stream_encoder_->Stop();
perkj803d97f2016-11-01 11:45:46 -07001103}
1104
mflodmancc3d4422017-08-03 08:27:51 -07001105TEST_F(VideoStreamEncoderTest, SwitchingSourceKeepsCpuAdaptation) {
1106 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
kthelgason876222f2016-11-29 01:44:11 -08001107
asaperssonfab67072017-04-04 05:51:49 -07001108 const int kWidth = 1280;
1109 const int kHeight = 720;
1110 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001111 WaitForEncodedFrame(1);
kthelgason876222f2016-11-29 01:44:11 -08001112 VideoSendStream::Stats stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001113 EXPECT_FALSE(stats.bw_limited_resolution);
kthelgason876222f2016-11-29 01:44:11 -08001114 EXPECT_FALSE(stats.cpu_limited_resolution);
1115 EXPECT_EQ(0, stats.number_of_cpu_adapt_changes);
1116
asaperssonfab67072017-04-04 05:51:49 -07001117 // Trigger CPU overuse.
mflodmancc3d4422017-08-03 08:27:51 -07001118 video_stream_encoder_->TriggerCpuOveruse();
asaperssonfab67072017-04-04 05:51:49 -07001119 video_source_.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001120 WaitForEncodedFrame(2);
kthelgason876222f2016-11-29 01:44:11 -08001121 stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001122 EXPECT_FALSE(stats.bw_limited_resolution);
kthelgason876222f2016-11-29 01:44:11 -08001123 EXPECT_TRUE(stats.cpu_limited_resolution);
1124 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1125
1126 // Set new source with adaptation still enabled.
1127 test::FrameForwarder new_video_source;
mflodmancc3d4422017-08-03 08:27:51 -07001128 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001129 &new_video_source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
kthelgason876222f2016-11-29 01:44:11 -08001130
asaperssonfab67072017-04-04 05:51:49 -07001131 new_video_source.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001132 WaitForEncodedFrame(3);
kthelgason876222f2016-11-29 01:44:11 -08001133 stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001134 EXPECT_FALSE(stats.bw_limited_resolution);
kthelgason876222f2016-11-29 01:44:11 -08001135 EXPECT_TRUE(stats.cpu_limited_resolution);
1136 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1137
1138 // Set adaptation disabled.
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001139 video_stream_encoder_->SetSource(&new_video_source,
1140 webrtc::DegradationPreference::DISABLED);
kthelgason876222f2016-11-29 01:44:11 -08001141
asaperssonfab67072017-04-04 05:51:49 -07001142 new_video_source.IncomingCapturedFrame(CreateFrame(4, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001143 WaitForEncodedFrame(4);
kthelgason876222f2016-11-29 01:44:11 -08001144 stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001145 EXPECT_FALSE(stats.bw_limited_resolution);
kthelgason876222f2016-11-29 01:44:11 -08001146 EXPECT_FALSE(stats.cpu_limited_resolution);
1147 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1148
1149 // Set adaptation back to enabled.
mflodmancc3d4422017-08-03 08:27:51 -07001150 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001151 &new_video_source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
kthelgason876222f2016-11-29 01:44:11 -08001152
asaperssonfab67072017-04-04 05:51:49 -07001153 new_video_source.IncomingCapturedFrame(CreateFrame(5, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001154 WaitForEncodedFrame(5);
kthelgason876222f2016-11-29 01:44:11 -08001155 stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001156 EXPECT_FALSE(stats.bw_limited_resolution);
kthelgason876222f2016-11-29 01:44:11 -08001157 EXPECT_TRUE(stats.cpu_limited_resolution);
1158 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1159
asaperssonfab67072017-04-04 05:51:49 -07001160 // Trigger CPU normal use.
mflodmancc3d4422017-08-03 08:27:51 -07001161 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssonfab67072017-04-04 05:51:49 -07001162 new_video_source.IncomingCapturedFrame(CreateFrame(6, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001163 WaitForEncodedFrame(6);
kthelgason876222f2016-11-29 01:44:11 -08001164 stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001165 EXPECT_FALSE(stats.bw_limited_resolution);
kthelgason876222f2016-11-29 01:44:11 -08001166 EXPECT_FALSE(stats.cpu_limited_resolution);
1167 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
asapersson02465b82017-04-10 01:12:52 -07001168 EXPECT_EQ(0, stats.number_of_quality_adapt_changes);
kthelgason876222f2016-11-29 01:44:11 -08001169
mflodmancc3d4422017-08-03 08:27:51 -07001170 video_stream_encoder_->Stop();
kthelgason876222f2016-11-29 01:44:11 -08001171}
1172
mflodmancc3d4422017-08-03 08:27:51 -07001173TEST_F(VideoStreamEncoderTest, SwitchingSourceKeepsQualityAdaptation) {
1174 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
kthelgason876222f2016-11-29 01:44:11 -08001175
asaperssonfab67072017-04-04 05:51:49 -07001176 const int kWidth = 1280;
1177 const int kHeight = 720;
1178 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001179 WaitForEncodedFrame(1);
kthelgason876222f2016-11-29 01:44:11 -08001180 VideoSendStream::Stats stats = stats_proxy_->GetStats();
kthelgason876222f2016-11-29 01:44:11 -08001181 EXPECT_FALSE(stats.bw_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001182 EXPECT_FALSE(stats.bw_limited_framerate);
asaperssonfab67072017-04-04 05:51:49 -07001183 EXPECT_EQ(0, stats.number_of_quality_adapt_changes);
kthelgason876222f2016-11-29 01:44:11 -08001184
1185 // Set new source with adaptation still enabled.
1186 test::FrameForwarder new_video_source;
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001187 video_stream_encoder_->SetSource(&new_video_source,
1188 webrtc::DegradationPreference::BALANCED);
kthelgason876222f2016-11-29 01:44:11 -08001189
asaperssonfab67072017-04-04 05:51:49 -07001190 new_video_source.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001191 WaitForEncodedFrame(2);
kthelgason876222f2016-11-29 01:44:11 -08001192 stats = stats_proxy_->GetStats();
kthelgason876222f2016-11-29 01:44:11 -08001193 EXPECT_FALSE(stats.bw_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001194 EXPECT_FALSE(stats.bw_limited_framerate);
asaperssonfab67072017-04-04 05:51:49 -07001195 EXPECT_EQ(0, stats.number_of_quality_adapt_changes);
kthelgason876222f2016-11-29 01:44:11 -08001196
asaperssonfab67072017-04-04 05:51:49 -07001197 // Trigger adapt down.
mflodmancc3d4422017-08-03 08:27:51 -07001198 video_stream_encoder_->TriggerQualityLow();
asaperssonfab67072017-04-04 05:51:49 -07001199 new_video_source.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001200 WaitForEncodedFrame(3);
kthelgason876222f2016-11-29 01:44:11 -08001201 stats = stats_proxy_->GetStats();
kthelgason876222f2016-11-29 01:44:11 -08001202 EXPECT_TRUE(stats.bw_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001203 EXPECT_FALSE(stats.bw_limited_framerate);
asaperssonfab67072017-04-04 05:51:49 -07001204 EXPECT_EQ(1, stats.number_of_quality_adapt_changes);
kthelgason876222f2016-11-29 01:44:11 -08001205
asaperssonfab67072017-04-04 05:51:49 -07001206 // Set new source with adaptation still enabled.
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001207 video_stream_encoder_->SetSource(&new_video_source,
1208 webrtc::DegradationPreference::BALANCED);
kthelgason876222f2016-11-29 01:44:11 -08001209
asaperssonfab67072017-04-04 05:51:49 -07001210 new_video_source.IncomingCapturedFrame(CreateFrame(4, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001211 WaitForEncodedFrame(4);
kthelgason876222f2016-11-29 01:44:11 -08001212 stats = stats_proxy_->GetStats();
kthelgason876222f2016-11-29 01:44:11 -08001213 EXPECT_TRUE(stats.bw_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001214 EXPECT_FALSE(stats.bw_limited_framerate);
asaperssonfab67072017-04-04 05:51:49 -07001215 EXPECT_EQ(1, stats.number_of_quality_adapt_changes);
kthelgason876222f2016-11-29 01:44:11 -08001216
asapersson02465b82017-04-10 01:12:52 -07001217 // Disable resolution scaling.
mflodmancc3d4422017-08-03 08:27:51 -07001218 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001219 &new_video_source, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
kthelgason876222f2016-11-29 01:44:11 -08001220
asaperssonfab67072017-04-04 05:51:49 -07001221 new_video_source.IncomingCapturedFrame(CreateFrame(5, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001222 WaitForEncodedFrame(5);
kthelgason876222f2016-11-29 01:44:11 -08001223 stats = stats_proxy_->GetStats();
kthelgason876222f2016-11-29 01:44:11 -08001224 EXPECT_FALSE(stats.bw_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001225 EXPECT_FALSE(stats.bw_limited_framerate);
asaperssonfab67072017-04-04 05:51:49 -07001226 EXPECT_EQ(1, stats.number_of_quality_adapt_changes);
1227 EXPECT_EQ(0, stats.number_of_cpu_adapt_changes);
kthelgason876222f2016-11-29 01:44:11 -08001228
mflodmancc3d4422017-08-03 08:27:51 -07001229 video_stream_encoder_->Stop();
kthelgason876222f2016-11-29 01:44:11 -08001230}
1231
mflodmancc3d4422017-08-03 08:27:51 -07001232TEST_F(VideoStreamEncoderTest,
1233 QualityAdaptationStatsAreResetWhenScalerIsDisabled) {
1234 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson36e9eb42017-03-31 05:29:12 -07001235
1236 const int kWidth = 1280;
1237 const int kHeight = 720;
Åsa Perssonced5cfd2018-08-10 16:16:43 +02001238 int64_t timestamp_ms = kFrameIntervalMs;
asapersson36e9eb42017-03-31 05:29:12 -07001239 video_source_.set_adaptation_enabled(true);
Åsa Perssonced5cfd2018-08-10 16:16:43 +02001240 video_source_.IncomingCapturedFrame(
1241 CreateFrame(timestamp_ms, kWidth, kHeight));
1242 WaitForEncodedFrame(timestamp_ms);
asapersson36e9eb42017-03-31 05:29:12 -07001243 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1244 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1245 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1246
1247 // Trigger adapt down.
mflodmancc3d4422017-08-03 08:27:51 -07001248 video_stream_encoder_->TriggerQualityLow();
Åsa Perssonced5cfd2018-08-10 16:16:43 +02001249 timestamp_ms += kFrameIntervalMs;
1250 video_source_.IncomingCapturedFrame(
1251 CreateFrame(timestamp_ms, kWidth, kHeight));
1252 WaitForEncodedFrame(timestamp_ms);
asapersson36e9eb42017-03-31 05:29:12 -07001253 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1254 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1255 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1256
1257 // Trigger overuse.
mflodmancc3d4422017-08-03 08:27:51 -07001258 video_stream_encoder_->TriggerCpuOveruse();
Åsa Perssonced5cfd2018-08-10 16:16:43 +02001259 timestamp_ms += kFrameIntervalMs;
1260 video_source_.IncomingCapturedFrame(
1261 CreateFrame(timestamp_ms, kWidth, kHeight));
1262 WaitForEncodedFrame(timestamp_ms);
asapersson36e9eb42017-03-31 05:29:12 -07001263 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1264 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1265 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1266
Niels Möller4db138e2018-04-19 09:04:13 +02001267 // Leave source unchanged, but disable quality scaler.
asapersson36e9eb42017-03-31 05:29:12 -07001268 fake_encoder_.SetQualityScaling(false);
Niels Möller4db138e2018-04-19 09:04:13 +02001269
1270 VideoEncoderConfig video_encoder_config;
1271 test::FillEncoderConfiguration(kVideoCodecVP8, 1, &video_encoder_config);
1272 // Make format different, to force recreation of encoder.
1273 video_encoder_config.video_format.parameters["foo"] = "foo";
1274 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
Niels Möllerf1338562018-04-26 09:51:47 +02001275 kMaxPayloadLength);
Åsa Perssonced5cfd2018-08-10 16:16:43 +02001276 timestamp_ms += kFrameIntervalMs;
1277 video_source_.IncomingCapturedFrame(
1278 CreateFrame(timestamp_ms, kWidth, kHeight));
1279 WaitForEncodedFrame(timestamp_ms);
asapersson36e9eb42017-03-31 05:29:12 -07001280 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1281 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1282 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1283
mflodmancc3d4422017-08-03 08:27:51 -07001284 video_stream_encoder_->Stop();
asapersson36e9eb42017-03-31 05:29:12 -07001285}
1286
mflodmancc3d4422017-08-03 08:27:51 -07001287TEST_F(VideoStreamEncoderTest,
1288 StatsTracksCpuAdaptationStatsWhenSwitchingSource) {
1289 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkj803d97f2016-11-01 11:45:46 -07001290
asapersson0944a802017-04-07 00:57:58 -07001291 const int kWidth = 1280;
1292 const int kHeight = 720;
sprang84a37592017-02-10 07:04:27 -08001293 int sequence = 1;
perkj803d97f2016-11-01 11:45:46 -07001294
asaperssonfab67072017-04-04 05:51:49 -07001295 video_source_.IncomingCapturedFrame(CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001296 WaitForEncodedFrame(sequence++);
perkj803d97f2016-11-01 11:45:46 -07001297 VideoSendStream::Stats stats = stats_proxy_->GetStats();
sprang84a37592017-02-10 07:04:27 -08001298 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001299 EXPECT_FALSE(stats.cpu_limited_framerate);
sprang84a37592017-02-10 07:04:27 -08001300 EXPECT_EQ(0, stats.number_of_cpu_adapt_changes);
1301
asapersson02465b82017-04-10 01:12:52 -07001302 // Trigger CPU overuse, should now adapt down.
mflodmancc3d4422017-08-03 08:27:51 -07001303 video_stream_encoder_->TriggerCpuOveruse();
asaperssonfab67072017-04-04 05:51:49 -07001304 video_source_.IncomingCapturedFrame(CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001305 WaitForEncodedFrame(sequence++);
sprang84a37592017-02-10 07:04:27 -08001306 stats = stats_proxy_->GetStats();
perkj803d97f2016-11-01 11:45:46 -07001307 EXPECT_TRUE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001308 EXPECT_FALSE(stats.cpu_limited_framerate);
perkj803d97f2016-11-01 11:45:46 -07001309 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1310
1311 // Set new source with adaptation still enabled.
1312 test::FrameForwarder new_video_source;
mflodmancc3d4422017-08-03 08:27:51 -07001313 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001314 &new_video_source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
perkj803d97f2016-11-01 11:45:46 -07001315
1316 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001317 CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001318 WaitForEncodedFrame(sequence++);
perkj803d97f2016-11-01 11:45:46 -07001319 stats = stats_proxy_->GetStats();
1320 EXPECT_TRUE(stats.cpu_limited_resolution);
asapersson09f05612017-05-15 23:40:18 -07001321 EXPECT_FALSE(stats.cpu_limited_framerate);
perkj803d97f2016-11-01 11:45:46 -07001322 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1323
sprangc5d62e22017-04-02 23:53:04 -07001324 // Set cpu adaptation by frame dropping.
mflodmancc3d4422017-08-03 08:27:51 -07001325 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001326 &new_video_source, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
perkj803d97f2016-11-01 11:45:46 -07001327 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001328 CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001329 WaitForEncodedFrame(sequence++);
perkj803d97f2016-11-01 11:45:46 -07001330 stats = stats_proxy_->GetStats();
sprangc5d62e22017-04-02 23:53:04 -07001331 // Not adapted at first.
perkj803d97f2016-11-01 11:45:46 -07001332 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson09f05612017-05-15 23:40:18 -07001333 EXPECT_FALSE(stats.cpu_limited_framerate);
perkj803d97f2016-11-01 11:45:46 -07001334 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1335
sprangc5d62e22017-04-02 23:53:04 -07001336 // Force an input frame rate to be available, or the adaptation call won't
asapersson09f05612017-05-15 23:40:18 -07001337 // know what framerate to adapt from.
sprangc5d62e22017-04-02 23:53:04 -07001338 VideoSendStream::Stats mock_stats = stats_proxy_->GetStats();
1339 mock_stats.input_frame_rate = 30;
1340 stats_proxy_->SetMockStats(mock_stats);
mflodmancc3d4422017-08-03 08:27:51 -07001341 video_stream_encoder_->TriggerCpuOveruse();
sprangc5d62e22017-04-02 23:53:04 -07001342 stats_proxy_->ResetMockStats();
1343
1344 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001345 CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001346 WaitForEncodedFrame(sequence++);
sprangc5d62e22017-04-02 23:53:04 -07001347
1348 // Framerate now adapted.
1349 stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001350 EXPECT_FALSE(stats.cpu_limited_resolution);
1351 EXPECT_TRUE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001352 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
1353
1354 // Disable CPU adaptation.
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001355 video_stream_encoder_->SetSource(&new_video_source,
1356 webrtc::DegradationPreference::DISABLED);
sprangc5d62e22017-04-02 23:53:04 -07001357 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001358 CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001359 WaitForEncodedFrame(sequence++);
sprangc5d62e22017-04-02 23:53:04 -07001360
1361 stats = stats_proxy_->GetStats();
1362 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001363 EXPECT_FALSE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001364 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
1365
1366 // Try to trigger overuse. Should not succeed.
1367 stats_proxy_->SetMockStats(mock_stats);
mflodmancc3d4422017-08-03 08:27:51 -07001368 video_stream_encoder_->TriggerCpuOveruse();
sprangc5d62e22017-04-02 23:53:04 -07001369 stats_proxy_->ResetMockStats();
1370
1371 stats = stats_proxy_->GetStats();
1372 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001373 EXPECT_FALSE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001374 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
1375
1376 // Switch back the source with resolution adaptation enabled.
mflodmancc3d4422017-08-03 08:27:51 -07001377 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001378 &video_source_, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
asaperssonfab67072017-04-04 05:51:49 -07001379 video_source_.IncomingCapturedFrame(CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001380 WaitForEncodedFrame(sequence++);
perkj803d97f2016-11-01 11:45:46 -07001381 stats = stats_proxy_->GetStats();
1382 EXPECT_TRUE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001383 EXPECT_FALSE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001384 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
perkj803d97f2016-11-01 11:45:46 -07001385
1386 // Trigger CPU normal usage.
mflodmancc3d4422017-08-03 08:27:51 -07001387 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssonfab67072017-04-04 05:51:49 -07001388 video_source_.IncomingCapturedFrame(CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001389 WaitForEncodedFrame(sequence++);
perkj803d97f2016-11-01 11:45:46 -07001390 stats = stats_proxy_->GetStats();
1391 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001392 EXPECT_FALSE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001393 EXPECT_EQ(3, stats.number_of_cpu_adapt_changes);
1394
1395 // Back to the source with adaptation off, set it back to maintain-resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001396 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001397 &new_video_source, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
sprangc5d62e22017-04-02 23:53:04 -07001398 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001399 CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001400 WaitForEncodedFrame(sequence++);
sprangc5d62e22017-04-02 23:53:04 -07001401 stats = stats_proxy_->GetStats();
asapersson13874762017-06-07 00:01:02 -07001402 // Disabled, since we previously switched the source to disabled.
sprangc5d62e22017-04-02 23:53:04 -07001403 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001404 EXPECT_TRUE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001405 EXPECT_EQ(3, stats.number_of_cpu_adapt_changes);
1406
1407 // Trigger CPU normal usage.
mflodmancc3d4422017-08-03 08:27:51 -07001408 video_stream_encoder_->TriggerCpuNormalUsage();
sprangc5d62e22017-04-02 23:53:04 -07001409 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001410 CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001411 WaitForEncodedFrame(sequence++);
sprangc5d62e22017-04-02 23:53:04 -07001412 stats = stats_proxy_->GetStats();
1413 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001414 EXPECT_FALSE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001415 EXPECT_EQ(4, stats.number_of_cpu_adapt_changes);
asapersson02465b82017-04-10 01:12:52 -07001416 EXPECT_EQ(0, stats.number_of_quality_adapt_changes);
perkj803d97f2016-11-01 11:45:46 -07001417
mflodmancc3d4422017-08-03 08:27:51 -07001418 video_stream_encoder_->Stop();
perkj803d97f2016-11-01 11:45:46 -07001419}
1420
mflodmancc3d4422017-08-03 08:27:51 -07001421TEST_F(VideoStreamEncoderTest,
1422 ScalingUpAndDownDoesNothingWithMaintainResolution) {
asaperssonfab67072017-04-04 05:51:49 -07001423 const int kWidth = 1280;
1424 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001425 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
kthelgason876222f2016-11-29 01:44:11 -08001426
asaperssonfab67072017-04-04 05:51:49 -07001427 // Expect no scaling to begin with.
asapersson02465b82017-04-10 01:12:52 -07001428 VerifyNoLimitation(video_source_.sink_wants());
kthelgason876222f2016-11-29 01:44:11 -08001429
asaperssonfab67072017-04-04 05:51:49 -07001430 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001431 WaitForEncodedFrame(1);
kthelgason876222f2016-11-29 01:44:11 -08001432
asaperssonfab67072017-04-04 05:51:49 -07001433 // Trigger scale down.
mflodmancc3d4422017-08-03 08:27:51 -07001434 video_stream_encoder_->TriggerQualityLow();
kthelgason5e13d412016-12-01 03:59:51 -08001435
asaperssonfab67072017-04-04 05:51:49 -07001436 video_source_.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001437 WaitForEncodedFrame(2);
kthelgason5e13d412016-12-01 03:59:51 -08001438
kthelgason876222f2016-11-29 01:44:11 -08001439 // Expect a scale down.
1440 EXPECT_TRUE(video_source_.sink_wants().max_pixel_count);
asaperssonfab67072017-04-04 05:51:49 -07001441 EXPECT_LT(video_source_.sink_wants().max_pixel_count, kWidth * kHeight);
kthelgason876222f2016-11-29 01:44:11 -08001442
asapersson02465b82017-04-10 01:12:52 -07001443 // Set resolution scaling disabled.
kthelgason876222f2016-11-29 01:44:11 -08001444 test::FrameForwarder new_video_source;
mflodmancc3d4422017-08-03 08:27:51 -07001445 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001446 &new_video_source, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
kthelgason876222f2016-11-29 01:44:11 -08001447
asaperssonfab67072017-04-04 05:51:49 -07001448 // Trigger scale down.
mflodmancc3d4422017-08-03 08:27:51 -07001449 video_stream_encoder_->TriggerQualityLow();
asaperssonfab67072017-04-04 05:51:49 -07001450 new_video_source.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001451 WaitForEncodedFrame(3);
kthelgason876222f2016-11-29 01:44:11 -08001452
asaperssonfab67072017-04-04 05:51:49 -07001453 // Expect no scaling.
sprangc5d62e22017-04-02 23:53:04 -07001454 EXPECT_EQ(std::numeric_limits<int>::max(),
1455 new_video_source.sink_wants().max_pixel_count);
kthelgason876222f2016-11-29 01:44:11 -08001456
asaperssonfab67072017-04-04 05:51:49 -07001457 // Trigger scale up.
mflodmancc3d4422017-08-03 08:27:51 -07001458 video_stream_encoder_->TriggerQualityHigh();
asaperssonfab67072017-04-04 05:51:49 -07001459 new_video_source.IncomingCapturedFrame(CreateFrame(4, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001460 WaitForEncodedFrame(4);
kthelgason876222f2016-11-29 01:44:11 -08001461
asapersson02465b82017-04-10 01:12:52 -07001462 // Expect nothing to change, still no scaling.
sprangc5d62e22017-04-02 23:53:04 -07001463 EXPECT_EQ(std::numeric_limits<int>::max(),
1464 new_video_source.sink_wants().max_pixel_count);
kthelgason876222f2016-11-29 01:44:11 -08001465
mflodmancc3d4422017-08-03 08:27:51 -07001466 video_stream_encoder_->Stop();
kthelgason876222f2016-11-29 01:44:11 -08001467}
1468
mflodmancc3d4422017-08-03 08:27:51 -07001469TEST_F(VideoStreamEncoderTest,
1470 SkipsSameAdaptDownRequest_MaintainFramerateMode) {
asapersson02465b82017-04-10 01:12:52 -07001471 const int kWidth = 1280;
1472 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001473 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson02465b82017-04-10 01:12:52 -07001474
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001475 // Enable MAINTAIN_FRAMERATE preference, no initial limitation.
asapersson02465b82017-04-10 01:12:52 -07001476 test::FrameForwarder source;
mflodmancc3d4422017-08-03 08:27:51 -07001477 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001478 &source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
asapersson02465b82017-04-10 01:12:52 -07001479
1480 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001481 WaitForEncodedFrame(1);
Åsa Perssonced5cfd2018-08-10 16:16:43 +02001482 VerifyFpsMaxResolutionMax(source.sink_wants());
asapersson02465b82017-04-10 01:12:52 -07001483 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1484 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1485
1486 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001487 video_stream_encoder_->TriggerCpuOveruse();
asapersson09f05612017-05-15 23:40:18 -07001488 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
asapersson02465b82017-04-10 01:12:52 -07001489 const int kLastMaxPixelCount = source.sink_wants().max_pixel_count;
1490 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1491 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1492
1493 // Trigger adapt down for same input resolution, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07001494 video_stream_encoder_->TriggerCpuOveruse();
asapersson02465b82017-04-10 01:12:52 -07001495 EXPECT_EQ(kLastMaxPixelCount, source.sink_wants().max_pixel_count);
1496 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1497 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1498
mflodmancc3d4422017-08-03 08:27:51 -07001499 video_stream_encoder_->Stop();
asapersson02465b82017-04-10 01:12:52 -07001500}
1501
mflodmancc3d4422017-08-03 08:27:51 -07001502TEST_F(VideoStreamEncoderTest, SkipsSameOrLargerAdaptDownRequest_BalancedMode) {
asaperssonf7e294d2017-06-13 23:25:22 -07001503 const int kWidth = 1280;
1504 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001505 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -07001506
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001507 // Enable BALANCED preference, no initial limitation.
asaperssonf7e294d2017-06-13 23:25:22 -07001508 test::FrameForwarder source;
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001509 video_stream_encoder_->SetSource(&source,
1510 webrtc::DegradationPreference::BALANCED);
asaperssonf7e294d2017-06-13 23:25:22 -07001511 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
1512 sink_.WaitForEncodedFrame(1);
Åsa Perssonced5cfd2018-08-10 16:16:43 +02001513 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07001514
1515 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001516 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07001517 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
1518 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1519 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1520 const int kLastMaxPixelCount = source.sink_wants().max_pixel_count;
1521
1522 // Trigger adapt down for same input resolution, expect no change.
1523 source.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
1524 sink_.WaitForEncodedFrame(2);
mflodmancc3d4422017-08-03 08:27:51 -07001525 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07001526 EXPECT_EQ(kLastMaxPixelCount, source.sink_wants().max_pixel_count);
1527 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1528 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1529
1530 // Trigger adapt down for larger input resolution, expect no change.
1531 source.IncomingCapturedFrame(CreateFrame(3, kWidth + 1, kHeight + 1));
1532 sink_.WaitForEncodedFrame(3);
mflodmancc3d4422017-08-03 08:27:51 -07001533 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07001534 EXPECT_EQ(kLastMaxPixelCount, source.sink_wants().max_pixel_count);
1535 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1536 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1537
mflodmancc3d4422017-08-03 08:27:51 -07001538 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07001539}
1540
mflodmancc3d4422017-08-03 08:27:51 -07001541TEST_F(VideoStreamEncoderTest,
1542 NoChangeForInitialNormalUsage_MaintainFramerateMode) {
asapersson02465b82017-04-10 01:12:52 -07001543 const int kWidth = 1280;
1544 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001545 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson02465b82017-04-10 01:12:52 -07001546
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001547 // Enable MAINTAIN_FRAMERATE preference, no initial limitation.
asapersson02465b82017-04-10 01:12:52 -07001548 test::FrameForwarder source;
mflodmancc3d4422017-08-03 08:27:51 -07001549 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001550 &source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
asapersson02465b82017-04-10 01:12:52 -07001551
1552 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001553 WaitForEncodedFrame(kWidth, kHeight);
Åsa Perssonced5cfd2018-08-10 16:16:43 +02001554 VerifyFpsMaxResolutionMax(source.sink_wants());
asapersson02465b82017-04-10 01:12:52 -07001555 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1556 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1557
1558 // Trigger adapt up, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07001559 video_stream_encoder_->TriggerCpuNormalUsage();
Åsa Perssonced5cfd2018-08-10 16:16:43 +02001560 VerifyFpsMaxResolutionMax(source.sink_wants());
asapersson02465b82017-04-10 01:12:52 -07001561 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1562 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1563
mflodmancc3d4422017-08-03 08:27:51 -07001564 video_stream_encoder_->Stop();
asapersson02465b82017-04-10 01:12:52 -07001565}
1566
mflodmancc3d4422017-08-03 08:27:51 -07001567TEST_F(VideoStreamEncoderTest,
1568 NoChangeForInitialNormalUsage_MaintainResolutionMode) {
asapersson02465b82017-04-10 01:12:52 -07001569 const int kWidth = 1280;
1570 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001571 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson02465b82017-04-10 01:12:52 -07001572
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001573 // Enable MAINTAIN_RESOLUTION preference, no initial limitation.
asapersson02465b82017-04-10 01:12:52 -07001574 test::FrameForwarder source;
mflodmancc3d4422017-08-03 08:27:51 -07001575 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001576 &source, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
asapersson02465b82017-04-10 01:12:52 -07001577
1578 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001579 WaitForEncodedFrame(kWidth, kHeight);
Åsa Perssonced5cfd2018-08-10 16:16:43 +02001580 VerifyFpsMaxResolutionMax(source.sink_wants());
asapersson09f05612017-05-15 23:40:18 -07001581 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
asapersson02465b82017-04-10 01:12:52 -07001582 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1583
1584 // Trigger adapt up, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07001585 video_stream_encoder_->TriggerCpuNormalUsage();
Åsa Perssonced5cfd2018-08-10 16:16:43 +02001586 VerifyFpsMaxResolutionMax(source.sink_wants());
asapersson09f05612017-05-15 23:40:18 -07001587 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
asapersson02465b82017-04-10 01:12:52 -07001588 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1589
mflodmancc3d4422017-08-03 08:27:51 -07001590 video_stream_encoder_->Stop();
asapersson02465b82017-04-10 01:12:52 -07001591}
1592
mflodmancc3d4422017-08-03 08:27:51 -07001593TEST_F(VideoStreamEncoderTest, NoChangeForInitialNormalUsage_BalancedMode) {
asaperssonf7e294d2017-06-13 23:25:22 -07001594 const int kWidth = 1280;
1595 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001596 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -07001597
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001598 // Enable BALANCED preference, no initial limitation.
asaperssonf7e294d2017-06-13 23:25:22 -07001599 test::FrameForwarder source;
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001600 video_stream_encoder_->SetSource(&source,
1601 webrtc::DegradationPreference::BALANCED);
asaperssonf7e294d2017-06-13 23:25:22 -07001602
1603 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
1604 sink_.WaitForEncodedFrame(kWidth, kHeight);
Åsa Perssonced5cfd2018-08-10 16:16:43 +02001605 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07001606 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1607 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
1608 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1609
1610 // Trigger adapt up, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07001611 video_stream_encoder_->TriggerQualityHigh();
Åsa Perssonced5cfd2018-08-10 16:16:43 +02001612 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07001613 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1614 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
1615 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1616
mflodmancc3d4422017-08-03 08:27:51 -07001617 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07001618}
1619
mflodmancc3d4422017-08-03 08:27:51 -07001620TEST_F(VideoStreamEncoderTest, NoChangeForInitialNormalUsage_DisabledMode) {
asapersson09f05612017-05-15 23:40:18 -07001621 const int kWidth = 1280;
1622 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001623 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson09f05612017-05-15 23:40:18 -07001624
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001625 // Enable DISABLED preference, no initial limitation.
asapersson09f05612017-05-15 23:40:18 -07001626 test::FrameForwarder source;
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001627 video_stream_encoder_->SetSource(&source,
1628 webrtc::DegradationPreference::DISABLED);
asapersson09f05612017-05-15 23:40:18 -07001629
1630 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
1631 sink_.WaitForEncodedFrame(kWidth, kHeight);
Åsa Perssonced5cfd2018-08-10 16:16:43 +02001632 VerifyFpsMaxResolutionMax(source.sink_wants());
asapersson09f05612017-05-15 23:40:18 -07001633 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1634 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
1635 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1636
1637 // Trigger adapt up, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07001638 video_stream_encoder_->TriggerQualityHigh();
Åsa Perssonced5cfd2018-08-10 16:16:43 +02001639 VerifyFpsMaxResolutionMax(source.sink_wants());
asapersson09f05612017-05-15 23:40:18 -07001640 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1641 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
1642 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1643
mflodmancc3d4422017-08-03 08:27:51 -07001644 video_stream_encoder_->Stop();
asapersson09f05612017-05-15 23:40:18 -07001645}
1646
mflodmancc3d4422017-08-03 08:27:51 -07001647TEST_F(VideoStreamEncoderTest,
1648 AdaptsResolutionForLowQuality_MaintainFramerateMode) {
asapersson02465b82017-04-10 01:12:52 -07001649 const int kWidth = 1280;
1650 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001651 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson02465b82017-04-10 01:12:52 -07001652
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001653 // Enable MAINTAIN_FRAMERATE preference, no initial limitation.
asapersson02465b82017-04-10 01:12:52 -07001654 AdaptingFrameForwarder source;
1655 source.set_adaptation_enabled(true);
mflodmancc3d4422017-08-03 08:27:51 -07001656 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001657 &source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
asapersson02465b82017-04-10 01:12:52 -07001658
1659 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001660 WaitForEncodedFrame(1);
Åsa Perssonced5cfd2018-08-10 16:16:43 +02001661 VerifyFpsMaxResolutionMax(source.sink_wants());
asapersson02465b82017-04-10 01:12:52 -07001662 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1663 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1664
1665 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001666 video_stream_encoder_->TriggerQualityLow();
asapersson02465b82017-04-10 01:12:52 -07001667 source.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001668 WaitForEncodedFrame(2);
asapersson09f05612017-05-15 23:40:18 -07001669 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
asapersson02465b82017-04-10 01:12:52 -07001670 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1671 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1672
1673 // Trigger adapt up, expect no restriction.
mflodmancc3d4422017-08-03 08:27:51 -07001674 video_stream_encoder_->TriggerQualityHigh();
Åsa Perssonced5cfd2018-08-10 16:16:43 +02001675 VerifyFpsMaxResolutionMax(source.sink_wants());
asapersson02465b82017-04-10 01:12:52 -07001676 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1677 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1678 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1679
mflodmancc3d4422017-08-03 08:27:51 -07001680 video_stream_encoder_->Stop();
asapersson02465b82017-04-10 01:12:52 -07001681}
1682
mflodmancc3d4422017-08-03 08:27:51 -07001683TEST_F(VideoStreamEncoderTest,
1684 AdaptsFramerateForLowQuality_MaintainResolutionMode) {
asapersson09f05612017-05-15 23:40:18 -07001685 const int kWidth = 1280;
1686 const int kHeight = 720;
1687 const int kInputFps = 30;
mflodmancc3d4422017-08-03 08:27:51 -07001688 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson09f05612017-05-15 23:40:18 -07001689
1690 VideoSendStream::Stats stats = stats_proxy_->GetStats();
1691 stats.input_frame_rate = kInputFps;
1692 stats_proxy_->SetMockStats(stats);
1693
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001694 // Expect no scaling to begin with (preference: MAINTAIN_FRAMERATE).
asapersson09f05612017-05-15 23:40:18 -07001695 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
1696 sink_.WaitForEncodedFrame(1);
Åsa Perssonced5cfd2018-08-10 16:16:43 +02001697 VerifyFpsMaxResolutionMax(video_source_.sink_wants());
asapersson09f05612017-05-15 23:40:18 -07001698
1699 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001700 video_stream_encoder_->TriggerQualityLow();
asapersson09f05612017-05-15 23:40:18 -07001701 video_source_.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
1702 sink_.WaitForEncodedFrame(2);
1703 VerifyFpsMaxResolutionLt(video_source_.sink_wants(), kWidth * kHeight);
1704
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001705 // Enable MAINTAIN_RESOLUTION preference.
asapersson09f05612017-05-15 23:40:18 -07001706 test::FrameForwarder new_video_source;
mflodmancc3d4422017-08-03 08:27:51 -07001707 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001708 &new_video_source, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
Åsa Perssonced5cfd2018-08-10 16:16:43 +02001709 VerifyFpsMaxResolutionMax(new_video_source.sink_wants());
asapersson09f05612017-05-15 23:40:18 -07001710
1711 // Trigger adapt down, expect reduced framerate.
mflodmancc3d4422017-08-03 08:27:51 -07001712 video_stream_encoder_->TriggerQualityLow();
asapersson09f05612017-05-15 23:40:18 -07001713 new_video_source.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
1714 sink_.WaitForEncodedFrame(3);
1715 VerifyFpsLtResolutionMax(new_video_source.sink_wants(), kInputFps);
1716
1717 // Trigger adapt up, expect no restriction.
mflodmancc3d4422017-08-03 08:27:51 -07001718 video_stream_encoder_->TriggerQualityHigh();
Åsa Perssonced5cfd2018-08-10 16:16:43 +02001719 VerifyFpsMaxResolutionMax(new_video_source.sink_wants());
asapersson09f05612017-05-15 23:40:18 -07001720
mflodmancc3d4422017-08-03 08:27:51 -07001721 video_stream_encoder_->Stop();
asapersson09f05612017-05-15 23:40:18 -07001722}
1723
mflodmancc3d4422017-08-03 08:27:51 -07001724TEST_F(VideoStreamEncoderTest, DoesNotScaleBelowSetResolutionLimit) {
asaperssond0de2952017-04-21 01:47:31 -07001725 const int kWidth = 1280;
1726 const int kHeight = 720;
1727 const size_t kNumFrames = 10;
1728
mflodmancc3d4422017-08-03 08:27:51 -07001729 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
kthelgason5e13d412016-12-01 03:59:51 -08001730
asaperssond0de2952017-04-21 01:47:31 -07001731 // Enable adapter, expected input resolutions when downscaling:
asapersson142fcc92017-08-17 08:58:54 -07001732 // 1280x720 -> 960x540 -> 640x360 -> 480x270 -> 320x180 (kMinPixelsPerFrame)
asaperssond0de2952017-04-21 01:47:31 -07001733 video_source_.set_adaptation_enabled(true);
1734
1735 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1736 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1737
1738 int downscales = 0;
1739 for (size_t i = 1; i <= kNumFrames; i++) {
Åsa Perssonced5cfd2018-08-10 16:16:43 +02001740 video_source_.IncomingCapturedFrame(
1741 CreateFrame(i * kFrameIntervalMs, kWidth, kHeight));
1742 WaitForEncodedFrame(i * kFrameIntervalMs);
asaperssond0de2952017-04-21 01:47:31 -07001743
asaperssonfab67072017-04-04 05:51:49 -07001744 // Trigger scale down.
asaperssond0de2952017-04-21 01:47:31 -07001745 rtc::VideoSinkWants last_wants = video_source_.sink_wants();
mflodmancc3d4422017-08-03 08:27:51 -07001746 video_stream_encoder_->TriggerQualityLow();
sprangc5d62e22017-04-02 23:53:04 -07001747 EXPECT_GE(video_source_.sink_wants().max_pixel_count, kMinPixelsPerFrame);
asaperssond0de2952017-04-21 01:47:31 -07001748
1749 if (video_source_.sink_wants().max_pixel_count < last_wants.max_pixel_count)
1750 ++downscales;
1751
1752 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1753 EXPECT_EQ(downscales,
1754 stats_proxy_->GetStats().number_of_quality_adapt_changes);
1755 EXPECT_GT(downscales, 0);
kthelgason5e13d412016-12-01 03:59:51 -08001756 }
mflodmancc3d4422017-08-03 08:27:51 -07001757 video_stream_encoder_->Stop();
asaperssond0de2952017-04-21 01:47:31 -07001758}
1759
mflodmancc3d4422017-08-03 08:27:51 -07001760TEST_F(VideoStreamEncoderTest,
asaperssond0de2952017-04-21 01:47:31 -07001761 AdaptsResolutionUpAndDownTwiceOnOveruse_MaintainFramerateMode) {
1762 const int kWidth = 1280;
1763 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001764 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssond0de2952017-04-21 01:47:31 -07001765
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001766 // Enable MAINTAIN_FRAMERATE preference, no initial limitation.
asaperssond0de2952017-04-21 01:47:31 -07001767 AdaptingFrameForwarder source;
1768 source.set_adaptation_enabled(true);
mflodmancc3d4422017-08-03 08:27:51 -07001769 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001770 &source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
asaperssond0de2952017-04-21 01:47:31 -07001771
Åsa Perssonced5cfd2018-08-10 16:16:43 +02001772 int64_t timestamp_ms = kFrameIntervalMs;
1773 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001774 WaitForEncodedFrame(kWidth, kHeight);
Åsa Perssonced5cfd2018-08-10 16:16:43 +02001775 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssond0de2952017-04-21 01:47:31 -07001776 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1777 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1778
1779 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001780 video_stream_encoder_->TriggerCpuOveruse();
Åsa Perssonced5cfd2018-08-10 16:16:43 +02001781 timestamp_ms += kFrameIntervalMs;
1782 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
1783 WaitForEncodedFrame(timestamp_ms);
asapersson09f05612017-05-15 23:40:18 -07001784 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
asaperssond0de2952017-04-21 01:47:31 -07001785 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1786 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1787
1788 // Trigger adapt up, expect no restriction.
mflodmancc3d4422017-08-03 08:27:51 -07001789 video_stream_encoder_->TriggerCpuNormalUsage();
Åsa Perssonced5cfd2018-08-10 16:16:43 +02001790 timestamp_ms += kFrameIntervalMs;
1791 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001792 WaitForEncodedFrame(kWidth, kHeight);
Åsa Perssonced5cfd2018-08-10 16:16:43 +02001793 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssond0de2952017-04-21 01:47:31 -07001794 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1795 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1796
1797 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001798 video_stream_encoder_->TriggerCpuOveruse();
Åsa Perssonced5cfd2018-08-10 16:16:43 +02001799 timestamp_ms += kFrameIntervalMs;
1800 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
1801 WaitForEncodedFrame(timestamp_ms);
asapersson09f05612017-05-15 23:40:18 -07001802 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
asaperssond0de2952017-04-21 01:47:31 -07001803 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1804 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1805
1806 // Trigger adapt up, expect no restriction.
mflodmancc3d4422017-08-03 08:27:51 -07001807 video_stream_encoder_->TriggerCpuNormalUsage();
Åsa Perssonced5cfd2018-08-10 16:16:43 +02001808 timestamp_ms += kFrameIntervalMs;
1809 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
asapersson09f05612017-05-15 23:40:18 -07001810 sink_.WaitForEncodedFrame(kWidth, kHeight);
Åsa Perssonced5cfd2018-08-10 16:16:43 +02001811 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssond0de2952017-04-21 01:47:31 -07001812 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1813 EXPECT_EQ(4, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1814
mflodmancc3d4422017-08-03 08:27:51 -07001815 video_stream_encoder_->Stop();
asaperssond0de2952017-04-21 01:47:31 -07001816}
1817
mflodmancc3d4422017-08-03 08:27:51 -07001818TEST_F(VideoStreamEncoderTest,
asaperssonf7e294d2017-06-13 23:25:22 -07001819 AdaptsResolutionUpAndDownTwiceForLowQuality_BalancedMode_NoFpsLimit) {
1820 const int kWidth = 1280;
1821 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001822 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -07001823
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001824 // Enable BALANCED preference, no initial limitation.
asaperssonf7e294d2017-06-13 23:25:22 -07001825 AdaptingFrameForwarder source;
1826 source.set_adaptation_enabled(true);
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001827 video_stream_encoder_->SetSource(&source,
1828 webrtc::DegradationPreference::BALANCED);
asaperssonf7e294d2017-06-13 23:25:22 -07001829
Åsa Perssonced5cfd2018-08-10 16:16:43 +02001830 int64_t timestamp_ms = kFrameIntervalMs;
1831 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
asaperssonf7e294d2017-06-13 23:25:22 -07001832 sink_.WaitForEncodedFrame(kWidth, kHeight);
Åsa Perssonced5cfd2018-08-10 16:16:43 +02001833 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07001834 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1835 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1836
1837 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001838 video_stream_encoder_->TriggerQualityLow();
Åsa Perssonced5cfd2018-08-10 16:16:43 +02001839 timestamp_ms += kFrameIntervalMs;
1840 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
1841 sink_.WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07001842 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
1843 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1844 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1845
1846 // Trigger adapt up, expect no restriction.
mflodmancc3d4422017-08-03 08:27:51 -07001847 video_stream_encoder_->TriggerQualityHigh();
Åsa Perssonced5cfd2018-08-10 16:16:43 +02001848 timestamp_ms += kFrameIntervalMs;
1849 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
asaperssonf7e294d2017-06-13 23:25:22 -07001850 sink_.WaitForEncodedFrame(kWidth, kHeight);
Åsa Perssonced5cfd2018-08-10 16:16:43 +02001851 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07001852 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1853 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1854
1855 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001856 video_stream_encoder_->TriggerQualityLow();
Åsa Perssonced5cfd2018-08-10 16:16:43 +02001857 timestamp_ms += kFrameIntervalMs;
1858 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
1859 sink_.WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07001860 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
1861 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1862 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1863
1864 // Trigger adapt up, expect no restriction.
mflodmancc3d4422017-08-03 08:27:51 -07001865 video_stream_encoder_->TriggerQualityHigh();
Åsa Perssonced5cfd2018-08-10 16:16:43 +02001866 timestamp_ms += kFrameIntervalMs;
1867 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
asaperssonf7e294d2017-06-13 23:25:22 -07001868 sink_.WaitForEncodedFrame(kWidth, kHeight);
Åsa Perssonced5cfd2018-08-10 16:16:43 +02001869 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07001870 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1871 EXPECT_EQ(4, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1872
mflodmancc3d4422017-08-03 08:27:51 -07001873 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07001874}
1875
mflodmancc3d4422017-08-03 08:27:51 -07001876TEST_F(VideoStreamEncoderTest,
asaperssond0de2952017-04-21 01:47:31 -07001877 AdaptsResolutionOnOveruseAndLowQuality_MaintainFramerateMode) {
1878 const int kWidth = 1280;
1879 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001880 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssond0de2952017-04-21 01:47:31 -07001881
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001882 // Enable MAINTAIN_FRAMERATE preference, no initial limitation.
asaperssond0de2952017-04-21 01:47:31 -07001883 AdaptingFrameForwarder source;
1884 source.set_adaptation_enabled(true);
mflodmancc3d4422017-08-03 08:27:51 -07001885 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001886 &source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
asaperssond0de2952017-04-21 01:47:31 -07001887
Åsa Perssonced5cfd2018-08-10 16:16:43 +02001888 int64_t timestamp_ms = kFrameIntervalMs;
1889 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001890 WaitForEncodedFrame(kWidth, kHeight);
Åsa Perssonced5cfd2018-08-10 16:16:43 +02001891 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssond0de2952017-04-21 01:47:31 -07001892 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1893 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1894 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1895 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1896
1897 // Trigger cpu adapt down, expect scaled down resolution (960x540).
mflodmancc3d4422017-08-03 08:27:51 -07001898 video_stream_encoder_->TriggerCpuOveruse();
Åsa Perssonced5cfd2018-08-10 16:16:43 +02001899 timestamp_ms += kFrameIntervalMs;
1900 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
1901 WaitForEncodedFrame(timestamp_ms);
asapersson09f05612017-05-15 23:40:18 -07001902 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
asaperssond0de2952017-04-21 01:47:31 -07001903 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1904 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1905 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1906 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1907
1908 // Trigger cpu adapt down, expect scaled down resolution (640x360).
mflodmancc3d4422017-08-03 08:27:51 -07001909 video_stream_encoder_->TriggerCpuOveruse();
Åsa Perssonced5cfd2018-08-10 16:16:43 +02001910 timestamp_ms += kFrameIntervalMs;
1911 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
1912 WaitForEncodedFrame(timestamp_ms);
asapersson09f05612017-05-15 23:40:18 -07001913 VerifyFpsMaxResolutionLt(source.sink_wants(), source.last_wants());
asaperssond0de2952017-04-21 01:47:31 -07001914 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1915 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1916 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1917 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1918
Jonathan Yubc771b72017-12-08 17:04:29 -08001919 // Trigger cpu adapt down, expect scaled down resolution (480x270).
mflodmancc3d4422017-08-03 08:27:51 -07001920 video_stream_encoder_->TriggerCpuOveruse();
Åsa Perssonced5cfd2018-08-10 16:16:43 +02001921 timestamp_ms += kFrameIntervalMs;
1922 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
1923 WaitForEncodedFrame(timestamp_ms);
Jonathan Yubc771b72017-12-08 17:04:29 -08001924 VerifyFpsMaxResolutionLt(source.sink_wants(), source.last_wants());
asaperssond0de2952017-04-21 01:47:31 -07001925 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1926 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
Jonathan Yubc771b72017-12-08 17:04:29 -08001927 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
asaperssond0de2952017-04-21 01:47:31 -07001928 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1929
Jonathan Yubc771b72017-12-08 17:04:29 -08001930 // Trigger quality adapt down, expect scaled down resolution (320x180).
mflodmancc3d4422017-08-03 08:27:51 -07001931 video_stream_encoder_->TriggerQualityLow();
Åsa Perssonced5cfd2018-08-10 16:16:43 +02001932 timestamp_ms += kFrameIntervalMs;
1933 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
1934 WaitForEncodedFrame(timestamp_ms);
asapersson09f05612017-05-15 23:40:18 -07001935 VerifyFpsMaxResolutionLt(source.sink_wants(), source.last_wants());
Jonathan Yubc771b72017-12-08 17:04:29 -08001936 rtc::VideoSinkWants last_wants = source.sink_wants();
asaperssond0de2952017-04-21 01:47:31 -07001937 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1938 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1939 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1940 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1941
Jonathan Yubc771b72017-12-08 17:04:29 -08001942 // Trigger quality adapt down, expect no change (min resolution reached).
1943 video_stream_encoder_->TriggerQualityLow();
Åsa Perssonced5cfd2018-08-10 16:16:43 +02001944 timestamp_ms += kFrameIntervalMs;
1945 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
1946 WaitForEncodedFrame(timestamp_ms);
Jonathan Yubc771b72017-12-08 17:04:29 -08001947 VerifyFpsMaxResolutionEq(source.sink_wants(), last_wants);
1948 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1949 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1950 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1951 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1952
1953 // Trigger cpu adapt up, expect upscaled resolution (480x270).
mflodmancc3d4422017-08-03 08:27:51 -07001954 video_stream_encoder_->TriggerCpuNormalUsage();
Åsa Perssonced5cfd2018-08-10 16:16:43 +02001955 timestamp_ms += kFrameIntervalMs;
1956 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
1957 WaitForEncodedFrame(timestamp_ms);
asapersson09f05612017-05-15 23:40:18 -07001958 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
Jonathan Yubc771b72017-12-08 17:04:29 -08001959 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1960 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1961 EXPECT_EQ(4, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1962 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1963
1964 // Trigger cpu adapt up, expect upscaled resolution (640x360).
1965 video_stream_encoder_->TriggerCpuNormalUsage();
Åsa Perssonced5cfd2018-08-10 16:16:43 +02001966 timestamp_ms += kFrameIntervalMs;
1967 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
1968 WaitForEncodedFrame(timestamp_ms);
Jonathan Yubc771b72017-12-08 17:04:29 -08001969 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
1970 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1971 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1972 EXPECT_EQ(5, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1973 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1974
1975 // Trigger cpu adapt up, expect upscaled resolution (960x540).
1976 video_stream_encoder_->TriggerCpuNormalUsage();
Åsa Perssonced5cfd2018-08-10 16:16:43 +02001977 timestamp_ms += kFrameIntervalMs;
1978 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
1979 WaitForEncodedFrame(timestamp_ms);
Jonathan Yubc771b72017-12-08 17:04:29 -08001980 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
asaperssond0de2952017-04-21 01:47:31 -07001981 last_wants = source.sink_wants();
1982 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1983 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
Jonathan Yubc771b72017-12-08 17:04:29 -08001984 EXPECT_EQ(6, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
asaperssond0de2952017-04-21 01:47:31 -07001985 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1986
1987 // Trigger cpu adapt up, no cpu downgrades, expect no change (960x540).
mflodmancc3d4422017-08-03 08:27:51 -07001988 video_stream_encoder_->TriggerCpuNormalUsage();
Åsa Perssonced5cfd2018-08-10 16:16:43 +02001989 timestamp_ms += kFrameIntervalMs;
1990 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
1991 WaitForEncodedFrame(timestamp_ms);
asapersson09f05612017-05-15 23:40:18 -07001992 VerifyFpsEqResolutionEq(source.sink_wants(), last_wants);
asaperssond0de2952017-04-21 01:47:31 -07001993 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1994 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
Jonathan Yubc771b72017-12-08 17:04:29 -08001995 EXPECT_EQ(6, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
asaperssond0de2952017-04-21 01:47:31 -07001996 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1997
1998 // Trigger quality adapt up, expect no restriction (1280x720).
mflodmancc3d4422017-08-03 08:27:51 -07001999 video_stream_encoder_->TriggerQualityHigh();
Åsa Perssonced5cfd2018-08-10 16:16:43 +02002000 timestamp_ms += kFrameIntervalMs;
2001 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002002 WaitForEncodedFrame(kWidth, kHeight);
asapersson09f05612017-05-15 23:40:18 -07002003 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
Åsa Perssonced5cfd2018-08-10 16:16:43 +02002004 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssond0de2952017-04-21 01:47:31 -07002005 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2006 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
Jonathan Yubc771b72017-12-08 17:04:29 -08002007 EXPECT_EQ(6, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
asaperssond0de2952017-04-21 01:47:31 -07002008 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
kthelgason5e13d412016-12-01 03:59:51 -08002009
mflodmancc3d4422017-08-03 08:27:51 -07002010 video_stream_encoder_->Stop();
kthelgason5e13d412016-12-01 03:59:51 -08002011}
2012
mflodmancc3d4422017-08-03 08:27:51 -07002013TEST_F(VideoStreamEncoderTest, CpuLimitedHistogramIsReported) {
asaperssonfab67072017-04-04 05:51:49 -07002014 const int kWidth = 640;
2015 const int kHeight = 360;
perkj803d97f2016-11-01 11:45:46 -07002016
mflodmancc3d4422017-08-03 08:27:51 -07002017 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
sprang4847ae62017-06-27 07:06:52 -07002018
perkj803d97f2016-11-01 11:45:46 -07002019 for (int i = 1; i <= SendStatisticsProxy::kMinRequiredMetricsSamples; ++i) {
asaperssonfab67072017-04-04 05:51:49 -07002020 video_source_.IncomingCapturedFrame(CreateFrame(i, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002021 WaitForEncodedFrame(i);
perkj803d97f2016-11-01 11:45:46 -07002022 }
2023
mflodmancc3d4422017-08-03 08:27:51 -07002024 video_stream_encoder_->TriggerCpuOveruse();
perkj803d97f2016-11-01 11:45:46 -07002025 for (int i = 1; i <= SendStatisticsProxy::kMinRequiredMetricsSamples; ++i) {
asaperssonfab67072017-04-04 05:51:49 -07002026 video_source_.IncomingCapturedFrame(CreateFrame(
2027 SendStatisticsProxy::kMinRequiredMetricsSamples + i, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002028 WaitForEncodedFrame(SendStatisticsProxy::kMinRequiredMetricsSamples + i);
perkj803d97f2016-11-01 11:45:46 -07002029 }
2030
mflodmancc3d4422017-08-03 08:27:51 -07002031 video_stream_encoder_->Stop();
2032 video_stream_encoder_.reset();
perkj803d97f2016-11-01 11:45:46 -07002033 stats_proxy_.reset();
sprangf8ee65e2017-02-28 08:49:33 -08002034
perkj803d97f2016-11-01 11:45:46 -07002035 EXPECT_EQ(1,
2036 metrics::NumSamples("WebRTC.Video.CpuLimitedResolutionInPercent"));
2037 EXPECT_EQ(
2038 1, metrics::NumEvents("WebRTC.Video.CpuLimitedResolutionInPercent", 50));
2039}
2040
mflodmancc3d4422017-08-03 08:27:51 -07002041TEST_F(VideoStreamEncoderTest,
2042 CpuLimitedHistogramIsNotReportedForDisabledDegradation) {
2043 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonf4e44af2017-04-19 02:01:06 -07002044 const int kWidth = 640;
2045 const int kHeight = 360;
2046
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002047 video_stream_encoder_->SetSource(&video_source_,
2048 webrtc::DegradationPreference::DISABLED);
asaperssonf4e44af2017-04-19 02:01:06 -07002049
2050 for (int i = 1; i <= SendStatisticsProxy::kMinRequiredMetricsSamples; ++i) {
2051 video_source_.IncomingCapturedFrame(CreateFrame(i, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002052 WaitForEncodedFrame(i);
asaperssonf4e44af2017-04-19 02:01:06 -07002053 }
2054
mflodmancc3d4422017-08-03 08:27:51 -07002055 video_stream_encoder_->Stop();
2056 video_stream_encoder_.reset();
asaperssonf4e44af2017-04-19 02:01:06 -07002057 stats_proxy_.reset();
2058
2059 EXPECT_EQ(0,
2060 metrics::NumSamples("WebRTC.Video.CpuLimitedResolutionInPercent"));
2061}
2062
mflodmancc3d4422017-08-03 08:27:51 -07002063TEST_F(VideoStreamEncoderTest, CallsBitrateObserver) {
sprang4847ae62017-06-27 07:06:52 -07002064 MockBitrateObserver bitrate_observer;
Niels Möller0327c2d2018-05-21 14:09:31 +02002065 video_stream_encoder_->SetBitrateAllocationObserver(&bitrate_observer);
sprang57c2fff2017-01-16 06:24:02 -08002066
2067 const int kDefaultFps = 30;
Erik Språng566124a2018-04-23 12:32:22 +02002068 const VideoBitrateAllocation expected_bitrate =
sprang57c2fff2017-01-16 06:24:02 -08002069 DefaultVideoBitrateAllocator(fake_encoder_.codec_config())
kthelgason2bc68642017-02-07 07:02:22 -08002070 .GetAllocation(kLowTargetBitrateBps, kDefaultFps);
sprang57c2fff2017-01-16 06:24:02 -08002071
2072 // First called on bitrate updated, then again on first frame.
2073 EXPECT_CALL(bitrate_observer, OnBitrateAllocationUpdated(expected_bitrate))
2074 .Times(2);
mflodmancc3d4422017-08-03 08:27:51 -07002075 video_stream_encoder_->OnBitrateUpdated(kLowTargetBitrateBps, 0, 0);
sprang57c2fff2017-01-16 06:24:02 -08002076
2077 const int64_t kStartTimeMs = 1;
2078 video_source_.IncomingCapturedFrame(
2079 CreateFrame(kStartTimeMs, codec_width_, codec_height_));
sprang4847ae62017-06-27 07:06:52 -07002080 WaitForEncodedFrame(kStartTimeMs);
sprang57c2fff2017-01-16 06:24:02 -08002081
2082 // Not called on second frame.
2083 EXPECT_CALL(bitrate_observer, OnBitrateAllocationUpdated(expected_bitrate))
2084 .Times(0);
2085 video_source_.IncomingCapturedFrame(
2086 CreateFrame(kStartTimeMs + 1, codec_width_, codec_height_));
sprang4847ae62017-06-27 07:06:52 -07002087 WaitForEncodedFrame(kStartTimeMs + 1);
sprang57c2fff2017-01-16 06:24:02 -08002088
2089 // Called after a process interval.
2090 const int64_t kProcessIntervalMs =
2091 vcm::VCMProcessTimer::kDefaultProcessIntervalMs;
sprang4847ae62017-06-27 07:06:52 -07002092 fake_clock_.AdvanceTimeMicros(rtc::kNumMicrosecsPerMillisec *
2093 (kProcessIntervalMs + (1000 / kDefaultFps)));
sprang57c2fff2017-01-16 06:24:02 -08002094 EXPECT_CALL(bitrate_observer, OnBitrateAllocationUpdated(expected_bitrate))
2095 .Times(1);
2096 video_source_.IncomingCapturedFrame(CreateFrame(
2097 kStartTimeMs + kProcessIntervalMs, codec_width_, codec_height_));
sprang4847ae62017-06-27 07:06:52 -07002098 WaitForEncodedFrame(kStartTimeMs + kProcessIntervalMs);
sprang57c2fff2017-01-16 06:24:02 -08002099
mflodmancc3d4422017-08-03 08:27:51 -07002100 video_stream_encoder_->Stop();
sprang57c2fff2017-01-16 06:24:02 -08002101}
2102
Niels Möller7dc26b72017-12-06 10:27:48 +01002103TEST_F(VideoStreamEncoderTest, OveruseDetectorUpdatedOnReconfigureAndAdaption) {
2104 const int kFrameWidth = 1280;
2105 const int kFrameHeight = 720;
2106 const int kFramerate = 24;
2107
2108 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
2109 test::FrameForwarder source;
2110 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002111 &source, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
Niels Möller7dc26b72017-12-06 10:27:48 +01002112
2113 // Insert a single frame, triggering initial configuration.
2114 source.IncomingCapturedFrame(CreateFrame(1, kFrameWidth, kFrameHeight));
2115 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2116
2117 EXPECT_EQ(
2118 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2119 kDefaultFramerate);
2120
2121 // Trigger reconfigure encoder (without resetting the entire instance).
2122 VideoEncoderConfig video_encoder_config;
Niels Möller259a4972018-04-05 15:36:51 +02002123 video_encoder_config.codec_type = kVideoCodecVP8;
Niels Möller7dc26b72017-12-06 10:27:48 +01002124 video_encoder_config.max_bitrate_bps = kTargetBitrateBps;
2125 video_encoder_config.number_of_streams = 1;
2126 video_encoder_config.video_stream_factory =
2127 new rtc::RefCountedObject<VideoStreamFactory>(1, kFramerate);
2128 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
Niels Möllerf1338562018-04-26 09:51:47 +02002129 kMaxPayloadLength);
Niels Möller7dc26b72017-12-06 10:27:48 +01002130 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2131
2132 // Detector should be updated with fps limit from codec config.
2133 EXPECT_EQ(
2134 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2135 kFramerate);
2136
2137 // Trigger overuse, max framerate should be reduced.
2138 VideoSendStream::Stats stats = stats_proxy_->GetStats();
2139 stats.input_frame_rate = kFramerate;
2140 stats_proxy_->SetMockStats(stats);
2141 video_stream_encoder_->TriggerCpuOveruse();
2142 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2143 int adapted_framerate =
2144 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate();
2145 EXPECT_LT(adapted_framerate, kFramerate);
2146
2147 // Trigger underuse, max framerate should go back to codec configured fps.
2148 // Set extra low fps, to make sure it's actually reset, not just incremented.
2149 stats = stats_proxy_->GetStats();
2150 stats.input_frame_rate = adapted_framerate / 2;
2151 stats_proxy_->SetMockStats(stats);
2152 video_stream_encoder_->TriggerCpuNormalUsage();
2153 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2154 EXPECT_EQ(
2155 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2156 kFramerate);
2157
2158 video_stream_encoder_->Stop();
2159}
2160
2161TEST_F(VideoStreamEncoderTest,
2162 OveruseDetectorUpdatedRespectsFramerateAfterUnderuse) {
2163 const int kFrameWidth = 1280;
2164 const int kFrameHeight = 720;
2165 const int kLowFramerate = 15;
2166 const int kHighFramerate = 25;
2167
2168 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
2169 test::FrameForwarder source;
2170 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002171 &source, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
Niels Möller7dc26b72017-12-06 10:27:48 +01002172
2173 // Trigger initial configuration.
2174 VideoEncoderConfig video_encoder_config;
Niels Möller259a4972018-04-05 15:36:51 +02002175 video_encoder_config.codec_type = kVideoCodecVP8;
Niels Möller7dc26b72017-12-06 10:27:48 +01002176 video_encoder_config.max_bitrate_bps = kTargetBitrateBps;
2177 video_encoder_config.number_of_streams = 1;
2178 video_encoder_config.video_stream_factory =
2179 new rtc::RefCountedObject<VideoStreamFactory>(1, kLowFramerate);
2180 source.IncomingCapturedFrame(CreateFrame(1, kFrameWidth, kFrameHeight));
2181 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
Niels Möllerf1338562018-04-26 09:51:47 +02002182 kMaxPayloadLength);
Niels Möller7dc26b72017-12-06 10:27:48 +01002183 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2184
2185 EXPECT_EQ(
2186 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2187 kLowFramerate);
2188
2189 // Trigger overuse, max framerate should be reduced.
2190 VideoSendStream::Stats stats = stats_proxy_->GetStats();
2191 stats.input_frame_rate = kLowFramerate;
2192 stats_proxy_->SetMockStats(stats);
2193 video_stream_encoder_->TriggerCpuOveruse();
2194 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2195 int adapted_framerate =
2196 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate();
2197 EXPECT_LT(adapted_framerate, kLowFramerate);
2198
2199 // Reconfigure the encoder with a new (higher max framerate), max fps should
2200 // still respect the adaptation.
2201 video_encoder_config.video_stream_factory =
2202 new rtc::RefCountedObject<VideoStreamFactory>(1, kHighFramerate);
2203 source.IncomingCapturedFrame(CreateFrame(1, kFrameWidth, kFrameHeight));
2204 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
Niels Möllerf1338562018-04-26 09:51:47 +02002205 kMaxPayloadLength);
Niels Möller7dc26b72017-12-06 10:27:48 +01002206 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2207
2208 EXPECT_EQ(
2209 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2210 adapted_framerate);
2211
2212 // Trigger underuse, max framerate should go back to codec configured fps.
2213 stats = stats_proxy_->GetStats();
2214 stats.input_frame_rate = adapted_framerate;
2215 stats_proxy_->SetMockStats(stats);
2216 video_stream_encoder_->TriggerCpuNormalUsage();
2217 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2218 EXPECT_EQ(
2219 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2220 kHighFramerate);
2221
2222 video_stream_encoder_->Stop();
2223}
2224
mflodmancc3d4422017-08-03 08:27:51 -07002225TEST_F(VideoStreamEncoderTest,
2226 OveruseDetectorUpdatedOnDegradationPreferenceChange) {
sprangfda496a2017-06-15 04:21:07 -07002227 const int kFrameWidth = 1280;
2228 const int kFrameHeight = 720;
2229 const int kFramerate = 24;
2230
mflodmancc3d4422017-08-03 08:27:51 -07002231 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
sprangfda496a2017-06-15 04:21:07 -07002232 test::FrameForwarder source;
mflodmancc3d4422017-08-03 08:27:51 -07002233 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002234 &source, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
sprangfda496a2017-06-15 04:21:07 -07002235
2236 // Trigger initial configuration.
2237 VideoEncoderConfig video_encoder_config;
Niels Möller259a4972018-04-05 15:36:51 +02002238 video_encoder_config.codec_type = kVideoCodecVP8;
sprangfda496a2017-06-15 04:21:07 -07002239 video_encoder_config.max_bitrate_bps = kTargetBitrateBps;
2240 video_encoder_config.number_of_streams = 1;
2241 video_encoder_config.video_stream_factory =
2242 new rtc::RefCountedObject<VideoStreamFactory>(1, kFramerate);
2243 source.IncomingCapturedFrame(CreateFrame(1, kFrameWidth, kFrameHeight));
mflodmancc3d4422017-08-03 08:27:51 -07002244 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
Niels Möllerf1338562018-04-26 09:51:47 +02002245 kMaxPayloadLength);
mflodmancc3d4422017-08-03 08:27:51 -07002246 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
sprangfda496a2017-06-15 04:21:07 -07002247
Niels Möller7dc26b72017-12-06 10:27:48 +01002248 EXPECT_EQ(
2249 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2250 kFramerate);
sprangfda496a2017-06-15 04:21:07 -07002251
2252 // Trigger overuse, max framerate should be reduced.
2253 VideoSendStream::Stats stats = stats_proxy_->GetStats();
2254 stats.input_frame_rate = kFramerate;
2255 stats_proxy_->SetMockStats(stats);
mflodmancc3d4422017-08-03 08:27:51 -07002256 video_stream_encoder_->TriggerCpuOveruse();
2257 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
Niels Möller7dc26b72017-12-06 10:27:48 +01002258 int adapted_framerate =
2259 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate();
sprangfda496a2017-06-15 04:21:07 -07002260 EXPECT_LT(adapted_framerate, kFramerate);
2261
2262 // Change degradation preference to not enable framerate scaling. Target
2263 // framerate should be changed to codec defined limit.
mflodmancc3d4422017-08-03 08:27:51 -07002264 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002265 &source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
mflodmancc3d4422017-08-03 08:27:51 -07002266 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
Niels Möller7dc26b72017-12-06 10:27:48 +01002267 EXPECT_EQ(
2268 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2269 kFramerate);
sprangfda496a2017-06-15 04:21:07 -07002270
mflodmancc3d4422017-08-03 08:27:51 -07002271 video_stream_encoder_->Stop();
sprangfda496a2017-06-15 04:21:07 -07002272}
2273
mflodmancc3d4422017-08-03 08:27:51 -07002274TEST_F(VideoStreamEncoderTest, DropsFramesAndScalesWhenBitrateIsTooLow) {
asaperssonfab67072017-04-04 05:51:49 -07002275 const int kTooLowBitrateForFrameSizeBps = 10000;
mflodmancc3d4422017-08-03 08:27:51 -07002276 video_stream_encoder_->OnBitrateUpdated(kTooLowBitrateForFrameSizeBps, 0, 0);
asaperssonfab67072017-04-04 05:51:49 -07002277 const int kWidth = 640;
2278 const int kHeight = 360;
kthelgason2bc68642017-02-07 07:02:22 -08002279
asaperssonfab67072017-04-04 05:51:49 -07002280 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
kthelgason2bc68642017-02-07 07:02:22 -08002281
2282 // Expect to drop this frame, the wait should time out.
sprang4847ae62017-06-27 07:06:52 -07002283 ExpectDroppedFrame();
kthelgason2bc68642017-02-07 07:02:22 -08002284
2285 // Expect the sink_wants to specify a scaled frame.
asapersson0944a802017-04-07 00:57:58 -07002286 EXPECT_LT(video_source_.sink_wants().max_pixel_count, kWidth * kHeight);
kthelgason2bc68642017-02-07 07:02:22 -08002287
sprangc5d62e22017-04-02 23:53:04 -07002288 int last_pixel_count = video_source_.sink_wants().max_pixel_count;
kthelgason2bc68642017-02-07 07:02:22 -08002289
asaperssonfab67072017-04-04 05:51:49 -07002290 // Next frame is scaled.
kthelgason2bc68642017-02-07 07:02:22 -08002291 video_source_.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07002292 CreateFrame(2, kWidth * 3 / 4, kHeight * 3 / 4));
kthelgason2bc68642017-02-07 07:02:22 -08002293
2294 // Expect to drop this frame, the wait should time out.
sprang4847ae62017-06-27 07:06:52 -07002295 ExpectDroppedFrame();
kthelgason2bc68642017-02-07 07:02:22 -08002296
sprangc5d62e22017-04-02 23:53:04 -07002297 EXPECT_LT(video_source_.sink_wants().max_pixel_count, last_pixel_count);
kthelgason2bc68642017-02-07 07:02:22 -08002298
mflodmancc3d4422017-08-03 08:27:51 -07002299 video_stream_encoder_->Stop();
kthelgason2bc68642017-02-07 07:02:22 -08002300}
2301
mflodmancc3d4422017-08-03 08:27:51 -07002302TEST_F(VideoStreamEncoderTest,
2303 NumberOfDroppedFramesLimitedWhenBitrateIsTooLow) {
asaperssonfab67072017-04-04 05:51:49 -07002304 const int kTooLowBitrateForFrameSizeBps = 10000;
mflodmancc3d4422017-08-03 08:27:51 -07002305 video_stream_encoder_->OnBitrateUpdated(kTooLowBitrateForFrameSizeBps, 0, 0);
asaperssonfab67072017-04-04 05:51:49 -07002306 const int kWidth = 640;
2307 const int kHeight = 360;
kthelgason2bc68642017-02-07 07:02:22 -08002308
2309 // We expect the n initial frames to get dropped.
2310 int i;
2311 for (i = 1; i <= kMaxInitialFramedrop; ++i) {
asaperssonfab67072017-04-04 05:51:49 -07002312 video_source_.IncomingCapturedFrame(CreateFrame(i, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002313 ExpectDroppedFrame();
kthelgason2bc68642017-02-07 07:02:22 -08002314 }
2315 // The n+1th frame should not be dropped, even though it's size is too large.
asaperssonfab67072017-04-04 05:51:49 -07002316 video_source_.IncomingCapturedFrame(CreateFrame(i, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002317 WaitForEncodedFrame(i);
kthelgason2bc68642017-02-07 07:02:22 -08002318
2319 // Expect the sink_wants to specify a scaled frame.
asaperssonfab67072017-04-04 05:51:49 -07002320 EXPECT_LT(video_source_.sink_wants().max_pixel_count, kWidth * kHeight);
kthelgason2bc68642017-02-07 07:02:22 -08002321
mflodmancc3d4422017-08-03 08:27:51 -07002322 video_stream_encoder_->Stop();
kthelgason2bc68642017-02-07 07:02:22 -08002323}
2324
mflodmancc3d4422017-08-03 08:27:51 -07002325TEST_F(VideoStreamEncoderTest,
2326 InitialFrameDropOffWithMaintainResolutionPreference) {
asaperssonfab67072017-04-04 05:51:49 -07002327 const int kWidth = 640;
2328 const int kHeight = 360;
mflodmancc3d4422017-08-03 08:27:51 -07002329 video_stream_encoder_->OnBitrateUpdated(kLowTargetBitrateBps, 0, 0);
kthelgason2bc68642017-02-07 07:02:22 -08002330
2331 // Set degradation preference.
mflodmancc3d4422017-08-03 08:27:51 -07002332 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002333 &video_source_, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
kthelgason2bc68642017-02-07 07:02:22 -08002334
asaperssonfab67072017-04-04 05:51:49 -07002335 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
kthelgason2bc68642017-02-07 07:02:22 -08002336 // Frame should not be dropped, even if it's too large.
sprang4847ae62017-06-27 07:06:52 -07002337 WaitForEncodedFrame(1);
kthelgason2bc68642017-02-07 07:02:22 -08002338
mflodmancc3d4422017-08-03 08:27:51 -07002339 video_stream_encoder_->Stop();
kthelgason2bc68642017-02-07 07:02:22 -08002340}
2341
mflodmancc3d4422017-08-03 08:27:51 -07002342TEST_F(VideoStreamEncoderTest, InitialFrameDropOffWhenEncoderDisabledScaling) {
asaperssonfab67072017-04-04 05:51:49 -07002343 const int kWidth = 640;
2344 const int kHeight = 360;
kthelgasonad9010c2017-02-14 00:46:51 -08002345 fake_encoder_.SetQualityScaling(false);
Niels Möller4db138e2018-04-19 09:04:13 +02002346
2347 VideoEncoderConfig video_encoder_config;
2348 test::FillEncoderConfiguration(kVideoCodecVP8, 1, &video_encoder_config);
2349 // Make format different, to force recreation of encoder.
2350 video_encoder_config.video_format.parameters["foo"] = "foo";
2351 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
Niels Möllerf1338562018-04-26 09:51:47 +02002352 kMaxPayloadLength);
mflodmancc3d4422017-08-03 08:27:51 -07002353 video_stream_encoder_->OnBitrateUpdated(kLowTargetBitrateBps, 0, 0);
asapersson09f05612017-05-15 23:40:18 -07002354
kthelgasonb83797b2017-02-14 11:57:25 -08002355 // Force quality scaler reconfiguration by resetting the source.
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002356 video_stream_encoder_->SetSource(&video_source_,
2357 webrtc::DegradationPreference::BALANCED);
kthelgasonad9010c2017-02-14 00:46:51 -08002358
asaperssonfab67072017-04-04 05:51:49 -07002359 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
kthelgasonad9010c2017-02-14 00:46:51 -08002360 // Frame should not be dropped, even if it's too large.
sprang4847ae62017-06-27 07:06:52 -07002361 WaitForEncodedFrame(1);
kthelgasonad9010c2017-02-14 00:46:51 -08002362
mflodmancc3d4422017-08-03 08:27:51 -07002363 video_stream_encoder_->Stop();
kthelgasonad9010c2017-02-14 00:46:51 -08002364 fake_encoder_.SetQualityScaling(true);
2365}
2366
mflodmancc3d4422017-08-03 08:27:51 -07002367TEST_F(VideoStreamEncoderTest,
asaperssond0de2952017-04-21 01:47:31 -07002368 ResolutionNotAdaptedForTooSmallFrame_MaintainFramerateMode) {
2369 const int kTooSmallWidth = 10;
2370 const int kTooSmallHeight = 10;
mflodmancc3d4422017-08-03 08:27:51 -07002371 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssond0de2952017-04-21 01:47:31 -07002372
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002373 // Enable MAINTAIN_FRAMERATE preference, no initial limitation.
asaperssond0de2952017-04-21 01:47:31 -07002374 test::FrameForwarder source;
mflodmancc3d4422017-08-03 08:27:51 -07002375 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002376 &source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
asaperssond0de2952017-04-21 01:47:31 -07002377 VerifyNoLimitation(source.sink_wants());
2378 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2379
2380 // Trigger adapt down, too small frame, expect no change.
2381 source.IncomingCapturedFrame(CreateFrame(1, kTooSmallWidth, kTooSmallHeight));
sprang4847ae62017-06-27 07:06:52 -07002382 WaitForEncodedFrame(1);
mflodmancc3d4422017-08-03 08:27:51 -07002383 video_stream_encoder_->TriggerCpuOveruse();
Åsa Perssonced5cfd2018-08-10 16:16:43 +02002384 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssond0de2952017-04-21 01:47:31 -07002385 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2386 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2387
mflodmancc3d4422017-08-03 08:27:51 -07002388 video_stream_encoder_->Stop();
asaperssond0de2952017-04-21 01:47:31 -07002389}
2390
mflodmancc3d4422017-08-03 08:27:51 -07002391TEST_F(VideoStreamEncoderTest,
2392 ResolutionNotAdaptedForTooSmallFrame_BalancedMode) {
asaperssonf7e294d2017-06-13 23:25:22 -07002393 const int kTooSmallWidth = 10;
2394 const int kTooSmallHeight = 10;
2395 const int kFpsLimit = 7;
mflodmancc3d4422017-08-03 08:27:51 -07002396 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -07002397
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002398 // Enable BALANCED preference, no initial limitation.
asaperssonf7e294d2017-06-13 23:25:22 -07002399 test::FrameForwarder source;
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002400 video_stream_encoder_->SetSource(&source,
2401 webrtc::DegradationPreference::BALANCED);
asaperssonf7e294d2017-06-13 23:25:22 -07002402 VerifyNoLimitation(source.sink_wants());
2403 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2404 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2405
2406 // Trigger adapt down, expect limited framerate.
2407 source.IncomingCapturedFrame(CreateFrame(1, kTooSmallWidth, kTooSmallHeight));
sprang4847ae62017-06-27 07:06:52 -07002408 WaitForEncodedFrame(1);
mflodmancc3d4422017-08-03 08:27:51 -07002409 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002410 VerifyFpsEqResolutionMax(source.sink_wants(), kFpsLimit);
2411 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2412 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2413 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2414
2415 // Trigger adapt down, too small frame, expect no change.
2416 source.IncomingCapturedFrame(CreateFrame(2, kTooSmallWidth, kTooSmallHeight));
sprang4847ae62017-06-27 07:06:52 -07002417 WaitForEncodedFrame(2);
mflodmancc3d4422017-08-03 08:27:51 -07002418 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002419 VerifyFpsEqResolutionMax(source.sink_wants(), kFpsLimit);
2420 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2421 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2422 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2423
mflodmancc3d4422017-08-03 08:27:51 -07002424 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07002425}
2426
mflodmancc3d4422017-08-03 08:27:51 -07002427TEST_F(VideoStreamEncoderTest, FailingInitEncodeDoesntCauseCrash) {
asapersson02465b82017-04-10 01:12:52 -07002428 fake_encoder_.ForceInitEncodeFailure(true);
mflodmancc3d4422017-08-03 08:27:51 -07002429 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
Niels Möllerf1338562018-04-26 09:51:47 +02002430 ResetEncoder("VP8", 2, 1, 1, false);
asapersson02465b82017-04-10 01:12:52 -07002431 const int kFrameWidth = 1280;
2432 const int kFrameHeight = 720;
2433 video_source_.IncomingCapturedFrame(
2434 CreateFrame(1, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002435 ExpectDroppedFrame();
mflodmancc3d4422017-08-03 08:27:51 -07002436 video_stream_encoder_->Stop();
asapersson02465b82017-04-10 01:12:52 -07002437}
2438
sprangb1ca0732017-02-01 08:38:12 -08002439// TODO(sprang): Extend this with fps throttling and any "balanced" extensions.
mflodmancc3d4422017-08-03 08:27:51 -07002440TEST_F(VideoStreamEncoderTest,
2441 AdaptsResolutionOnOveruse_MaintainFramerateMode) {
2442 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
sprangb1ca0732017-02-01 08:38:12 -08002443
2444 const int kFrameWidth = 1280;
2445 const int kFrameHeight = 720;
2446 // Enabled default VideoAdapter downscaling. First step is 3/4, not 3/5 as
mflodmancc3d4422017-08-03 08:27:51 -07002447 // requested by
2448 // VideoStreamEncoder::VideoSourceProxy::RequestResolutionLowerThan().
sprangb1ca0732017-02-01 08:38:12 -08002449 video_source_.set_adaptation_enabled(true);
2450
2451 video_source_.IncomingCapturedFrame(
Åsa Perssonced5cfd2018-08-10 16:16:43 +02002452 CreateFrame(1 * kFrameIntervalMs, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002453 WaitForEncodedFrame(kFrameWidth, kFrameHeight);
sprangb1ca0732017-02-01 08:38:12 -08002454
2455 // Trigger CPU overuse, downscale by 3/4.
mflodmancc3d4422017-08-03 08:27:51 -07002456 video_stream_encoder_->TriggerCpuOveruse();
sprangb1ca0732017-02-01 08:38:12 -08002457 video_source_.IncomingCapturedFrame(
Åsa Perssonced5cfd2018-08-10 16:16:43 +02002458 CreateFrame(2 * kFrameIntervalMs, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002459 WaitForEncodedFrame((kFrameWidth * 3) / 4, (kFrameHeight * 3) / 4);
sprangb1ca0732017-02-01 08:38:12 -08002460
asaperssonfab67072017-04-04 05:51:49 -07002461 // Trigger CPU normal use, return to original resolution.
mflodmancc3d4422017-08-03 08:27:51 -07002462 video_stream_encoder_->TriggerCpuNormalUsage();
sprangb1ca0732017-02-01 08:38:12 -08002463 video_source_.IncomingCapturedFrame(
Åsa Perssonced5cfd2018-08-10 16:16:43 +02002464 CreateFrame(3 * kFrameIntervalMs, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002465 WaitForEncodedFrame(kFrameWidth, kFrameHeight);
sprangb1ca0732017-02-01 08:38:12 -08002466
mflodmancc3d4422017-08-03 08:27:51 -07002467 video_stream_encoder_->Stop();
sprangb1ca0732017-02-01 08:38:12 -08002468}
sprangfe627f32017-03-29 08:24:59 -07002469
mflodmancc3d4422017-08-03 08:27:51 -07002470TEST_F(VideoStreamEncoderTest,
2471 AdaptsFramerateOnOveruse_MaintainResolutionMode) {
sprangc5d62e22017-04-02 23:53:04 -07002472 const int kFrameWidth = 1280;
2473 const int kFrameHeight = 720;
sprangc5d62e22017-04-02 23:53:04 -07002474
mflodmancc3d4422017-08-03 08:27:51 -07002475 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
2476 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002477 &video_source_, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
sprangc5d62e22017-04-02 23:53:04 -07002478 video_source_.set_adaptation_enabled(true);
2479
sprang4847ae62017-06-27 07:06:52 -07002480 int64_t timestamp_ms = fake_clock_.TimeNanos() / rtc::kNumNanosecsPerMillisec;
sprangc5d62e22017-04-02 23:53:04 -07002481
2482 video_source_.IncomingCapturedFrame(
2483 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002484 WaitForEncodedFrame(timestamp_ms);
sprangc5d62e22017-04-02 23:53:04 -07002485
2486 // Try to trigger overuse. No fps estimate available => no effect.
mflodmancc3d4422017-08-03 08:27:51 -07002487 video_stream_encoder_->TriggerCpuOveruse();
sprangc5d62e22017-04-02 23:53:04 -07002488
2489 // Insert frames for one second to get a stable estimate.
sprang4847ae62017-06-27 07:06:52 -07002490 for (int i = 0; i < max_framerate_; ++i) {
sprangc5d62e22017-04-02 23:53:04 -07002491 timestamp_ms += kFrameIntervalMs;
sprangc5d62e22017-04-02 23:53:04 -07002492 video_source_.IncomingCapturedFrame(
2493 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002494 WaitForEncodedFrame(timestamp_ms);
sprangc5d62e22017-04-02 23:53:04 -07002495 }
2496
2497 // Trigger CPU overuse, reduce framerate by 2/3.
mflodmancc3d4422017-08-03 08:27:51 -07002498 video_stream_encoder_->TriggerCpuOveruse();
sprangc5d62e22017-04-02 23:53:04 -07002499 int num_frames_dropped = 0;
sprang4847ae62017-06-27 07:06:52 -07002500 for (int i = 0; i < max_framerate_; ++i) {
sprangc5d62e22017-04-02 23:53:04 -07002501 timestamp_ms += kFrameIntervalMs;
sprangc5d62e22017-04-02 23:53:04 -07002502 video_source_.IncomingCapturedFrame(
2503 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002504 if (!WaitForFrame(kFrameTimeoutMs)) {
sprangc5d62e22017-04-02 23:53:04 -07002505 ++num_frames_dropped;
2506 } else {
Åsa Perssonc74d8da2017-12-04 14:13:56 +01002507 sink_.CheckLastFrameSizeMatches(kFrameWidth, kFrameHeight);
sprangc5d62e22017-04-02 23:53:04 -07002508 }
2509 }
2510
sprang4847ae62017-06-27 07:06:52 -07002511 // Add some slack to account for frames dropped by the frame dropper.
2512 const int kErrorMargin = 1;
2513 EXPECT_NEAR(num_frames_dropped, max_framerate_ - (max_framerate_ * 2 / 3),
sprangc5d62e22017-04-02 23:53:04 -07002514 kErrorMargin);
2515
2516 // Trigger CPU overuse, reduce framerate by 2/3 again.
mflodmancc3d4422017-08-03 08:27:51 -07002517 video_stream_encoder_->TriggerCpuOveruse();
sprangc5d62e22017-04-02 23:53:04 -07002518 num_frames_dropped = 0;
Åsa Perssonced5cfd2018-08-10 16:16:43 +02002519 for (int i = 0; i <= max_framerate_; ++i) {
sprangc5d62e22017-04-02 23:53:04 -07002520 timestamp_ms += kFrameIntervalMs;
sprangc5d62e22017-04-02 23:53:04 -07002521 video_source_.IncomingCapturedFrame(
2522 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002523 if (!WaitForFrame(kFrameTimeoutMs)) {
sprangc5d62e22017-04-02 23:53:04 -07002524 ++num_frames_dropped;
2525 } else {
Åsa Perssonc74d8da2017-12-04 14:13:56 +01002526 sink_.CheckLastFrameSizeMatches(kFrameWidth, kFrameHeight);
sprangc5d62e22017-04-02 23:53:04 -07002527 }
2528 }
sprang4847ae62017-06-27 07:06:52 -07002529 EXPECT_NEAR(num_frames_dropped, max_framerate_ - (max_framerate_ * 4 / 9),
sprangc5d62e22017-04-02 23:53:04 -07002530 kErrorMargin);
2531
2532 // Go back up one step.
mflodmancc3d4422017-08-03 08:27:51 -07002533 video_stream_encoder_->TriggerCpuNormalUsage();
sprangc5d62e22017-04-02 23:53:04 -07002534 num_frames_dropped = 0;
sprang4847ae62017-06-27 07:06:52 -07002535 for (int i = 0; i < max_framerate_; ++i) {
sprangc5d62e22017-04-02 23:53:04 -07002536 timestamp_ms += kFrameIntervalMs;
sprangc5d62e22017-04-02 23:53:04 -07002537 video_source_.IncomingCapturedFrame(
2538 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002539 if (!WaitForFrame(kFrameTimeoutMs)) {
sprangc5d62e22017-04-02 23:53:04 -07002540 ++num_frames_dropped;
2541 } else {
Åsa Perssonc74d8da2017-12-04 14:13:56 +01002542 sink_.CheckLastFrameSizeMatches(kFrameWidth, kFrameHeight);
sprangc5d62e22017-04-02 23:53:04 -07002543 }
2544 }
sprang4847ae62017-06-27 07:06:52 -07002545 EXPECT_NEAR(num_frames_dropped, max_framerate_ - (max_framerate_ * 2 / 3),
sprangc5d62e22017-04-02 23:53:04 -07002546 kErrorMargin);
2547
2548 // Go back up to original mode.
mflodmancc3d4422017-08-03 08:27:51 -07002549 video_stream_encoder_->TriggerCpuNormalUsage();
sprangc5d62e22017-04-02 23:53:04 -07002550 num_frames_dropped = 0;
sprang4847ae62017-06-27 07:06:52 -07002551 for (int i = 0; i < max_framerate_; ++i) {
sprangc5d62e22017-04-02 23:53:04 -07002552 timestamp_ms += kFrameIntervalMs;
sprangc5d62e22017-04-02 23:53:04 -07002553 video_source_.IncomingCapturedFrame(
2554 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002555 if (!WaitForFrame(kFrameTimeoutMs)) {
sprangc5d62e22017-04-02 23:53:04 -07002556 ++num_frames_dropped;
2557 } else {
Åsa Perssonc74d8da2017-12-04 14:13:56 +01002558 sink_.CheckLastFrameSizeMatches(kFrameWidth, kFrameHeight);
sprangc5d62e22017-04-02 23:53:04 -07002559 }
2560 }
2561 EXPECT_NEAR(num_frames_dropped, 0, kErrorMargin);
2562
mflodmancc3d4422017-08-03 08:27:51 -07002563 video_stream_encoder_->Stop();
sprangc5d62e22017-04-02 23:53:04 -07002564}
2565
mflodmancc3d4422017-08-03 08:27:51 -07002566TEST_F(VideoStreamEncoderTest, DoesntAdaptDownPastMinFramerate) {
sprangc5d62e22017-04-02 23:53:04 -07002567 const int kFramerateFps = 5;
2568 const int kFrameIntervalMs = rtc::kNumMillisecsPerSec / kFramerateFps;
sprangc5d62e22017-04-02 23:53:04 -07002569 const int kFrameWidth = 1280;
2570 const int kFrameHeight = 720;
2571
sprang4847ae62017-06-27 07:06:52 -07002572 // Reconfigure encoder with two temporal layers and screensharing, which will
2573 // disable frame dropping and make testing easier.
Niels Möllerf1338562018-04-26 09:51:47 +02002574 ResetEncoder("VP8", 1, 2, 1, true);
sprang4847ae62017-06-27 07:06:52 -07002575
mflodmancc3d4422017-08-03 08:27:51 -07002576 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
2577 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002578 &video_source_, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
sprangc5d62e22017-04-02 23:53:04 -07002579 video_source_.set_adaptation_enabled(true);
2580
sprang4847ae62017-06-27 07:06:52 -07002581 int64_t timestamp_ms = fake_clock_.TimeNanos() / rtc::kNumNanosecsPerMillisec;
sprangc5d62e22017-04-02 23:53:04 -07002582
2583 // Trigger overuse as much as we can.
Jonathan Yubc771b72017-12-08 17:04:29 -08002584 rtc::VideoSinkWants last_wants;
2585 do {
2586 last_wants = video_source_.sink_wants();
2587
sprangc5d62e22017-04-02 23:53:04 -07002588 // Insert frames to get a new fps estimate...
2589 for (int j = 0; j < kFramerateFps; ++j) {
2590 video_source_.IncomingCapturedFrame(
2591 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
Jonathan Yubc771b72017-12-08 17:04:29 -08002592 if (video_source_.last_sent_width()) {
2593 sink_.WaitForEncodedFrame(timestamp_ms);
2594 }
sprangc5d62e22017-04-02 23:53:04 -07002595 timestamp_ms += kFrameIntervalMs;
Yves Gerey665174f2018-06-19 15:03:05 +02002596 fake_clock_.AdvanceTimeMicros(kFrameIntervalMs *
2597 rtc::kNumMicrosecsPerMillisec);
sprangc5d62e22017-04-02 23:53:04 -07002598 }
2599 // ...and then try to adapt again.
mflodmancc3d4422017-08-03 08:27:51 -07002600 video_stream_encoder_->TriggerCpuOveruse();
Jonathan Yubc771b72017-12-08 17:04:29 -08002601 } while (video_source_.sink_wants().max_framerate_fps <
2602 last_wants.max_framerate_fps);
sprangc5d62e22017-04-02 23:53:04 -07002603
Jonathan Yubc771b72017-12-08 17:04:29 -08002604 VerifyFpsEqResolutionMax(video_source_.sink_wants(), kMinFramerateFps);
asaperssonf7e294d2017-06-13 23:25:22 -07002605
mflodmancc3d4422017-08-03 08:27:51 -07002606 video_stream_encoder_->Stop();
sprangc5d62e22017-04-02 23:53:04 -07002607}
asaperssonf7e294d2017-06-13 23:25:22 -07002608
mflodmancc3d4422017-08-03 08:27:51 -07002609TEST_F(VideoStreamEncoderTest,
2610 AdaptsResolutionAndFramerateForLowQuality_BalancedMode) {
asaperssonf7e294d2017-06-13 23:25:22 -07002611 const int kWidth = 1280;
2612 const int kHeight = 720;
2613 const int64_t kFrameIntervalMs = 150;
2614 int64_t timestamp_ms = kFrameIntervalMs;
mflodmancc3d4422017-08-03 08:27:51 -07002615 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -07002616
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002617 // Enable BALANCED preference, no initial limitation.
asaperssonf7e294d2017-06-13 23:25:22 -07002618 AdaptingFrameForwarder source;
2619 source.set_adaptation_enabled(true);
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002620 video_stream_encoder_->SetSource(&source,
2621 webrtc::DegradationPreference::BALANCED);
asaperssonf7e294d2017-06-13 23:25:22 -07002622 timestamp_ms += kFrameIntervalMs;
2623 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002624 WaitForEncodedFrame(kWidth, kHeight);
Åsa Perssonced5cfd2018-08-10 16:16:43 +02002625 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07002626 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2627 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2628 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2629
2630 // Trigger adapt down, expect scaled down resolution (960x540@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002631 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002632 timestamp_ms += kFrameIntervalMs;
2633 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002634 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002635 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
2636 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2637 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2638 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2639
2640 // Trigger adapt down, expect scaled down resolution (640x360@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002641 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002642 timestamp_ms += kFrameIntervalMs;
2643 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002644 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002645 VerifyFpsMaxResolutionLt(source.sink_wants(), source.last_wants());
2646 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2647 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2648 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2649
2650 // Trigger adapt down, expect reduced fps (640x360@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07002651 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002652 timestamp_ms += kFrameIntervalMs;
2653 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002654 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002655 VerifyFpsLtResolutionEq(source.sink_wants(), source.last_wants());
2656 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2657 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2658 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2659
2660 // Trigger adapt down, expect scaled down resolution (480x270@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07002661 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002662 timestamp_ms += kFrameIntervalMs;
2663 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002664 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002665 VerifyFpsEqResolutionLt(source.sink_wants(), source.last_wants());
2666 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2667 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2668 EXPECT_EQ(4, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2669
2670 // Restrict bitrate, trigger adapt down, expect reduced fps (480x270@10fps).
mflodmancc3d4422017-08-03 08:27:51 -07002671 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002672 timestamp_ms += kFrameIntervalMs;
2673 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002674 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002675 VerifyFpsLtResolutionEq(source.sink_wants(), source.last_wants());
2676 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2677 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2678 EXPECT_EQ(5, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2679
2680 // Trigger adapt down, expect scaled down resolution (320x180@10fps).
mflodmancc3d4422017-08-03 08:27:51 -07002681 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002682 timestamp_ms += kFrameIntervalMs;
2683 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002684 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002685 VerifyFpsEqResolutionLt(source.sink_wants(), source.last_wants());
2686 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2687 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2688 EXPECT_EQ(6, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2689
2690 // Trigger adapt down, expect reduced fps (320x180@7fps).
mflodmancc3d4422017-08-03 08:27:51 -07002691 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002692 timestamp_ms += kFrameIntervalMs;
2693 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002694 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002695 VerifyFpsLtResolutionEq(source.sink_wants(), source.last_wants());
2696 rtc::VideoSinkWants last_wants = source.sink_wants();
2697 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2698 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2699 EXPECT_EQ(7, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2700
2701 // Trigger adapt down, min resolution reached, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07002702 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002703 timestamp_ms += kFrameIntervalMs;
2704 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002705 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002706 VerifyFpsEqResolutionEq(source.sink_wants(), last_wants);
2707 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2708 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2709 EXPECT_EQ(7, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2710
2711 // Trigger adapt down, expect expect increased fps (320x180@10fps).
mflodmancc3d4422017-08-03 08:27:51 -07002712 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002713 timestamp_ms += kFrameIntervalMs;
2714 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002715 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002716 VerifyFpsGtResolutionEq(source.sink_wants(), source.last_wants());
2717 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2718 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2719 EXPECT_EQ(8, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2720
2721 // Trigger adapt up, expect upscaled resolution (480x270@10fps).
mflodmancc3d4422017-08-03 08:27:51 -07002722 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002723 timestamp_ms += kFrameIntervalMs;
2724 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002725 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002726 VerifyFpsEqResolutionGt(source.sink_wants(), source.last_wants());
2727 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2728 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2729 EXPECT_EQ(9, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2730
2731 // Increase bitrate, trigger adapt up, expect increased fps (480x270@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07002732 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002733 timestamp_ms += kFrameIntervalMs;
2734 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002735 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002736 VerifyFpsGtResolutionEq(source.sink_wants(), source.last_wants());
2737 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2738 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2739 EXPECT_EQ(10, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2740
2741 // Trigger adapt up, expect upscaled resolution (640x360@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07002742 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002743 timestamp_ms += kFrameIntervalMs;
2744 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002745 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002746 VerifyFpsEqResolutionGt(source.sink_wants(), source.last_wants());
2747 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2748 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2749 EXPECT_EQ(11, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2750
2751 // Trigger adapt up, expect increased fps (640x360@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002752 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002753 timestamp_ms += kFrameIntervalMs;
2754 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002755 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002756 VerifyFpsMaxResolutionEq(source.sink_wants(), source.last_wants());
2757 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2758 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2759 EXPECT_EQ(12, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2760
2761 // Trigger adapt up, expect upscaled resolution (960x540@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002762 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002763 timestamp_ms += kFrameIntervalMs;
2764 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002765 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002766 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
2767 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2768 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2769 EXPECT_EQ(13, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2770
2771 // Trigger adapt up, expect no restriction (1280x720fps@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002772 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002773 timestamp_ms += kFrameIntervalMs;
2774 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002775 WaitForEncodedFrame(kWidth, kHeight);
asaperssonf7e294d2017-06-13 23:25:22 -07002776 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
Åsa Perssonced5cfd2018-08-10 16:16:43 +02002777 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07002778 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2779 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2780 EXPECT_EQ(14, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2781
2782 // Trigger adapt up, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07002783 video_stream_encoder_->TriggerQualityHigh();
Åsa Perssonced5cfd2018-08-10 16:16:43 +02002784 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07002785 EXPECT_EQ(14, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2786
mflodmancc3d4422017-08-03 08:27:51 -07002787 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07002788}
2789
mflodmancc3d4422017-08-03 08:27:51 -07002790TEST_F(VideoStreamEncoderTest, AdaptWithTwoReasonsAndDifferentOrder_Framerate) {
asaperssonf7e294d2017-06-13 23:25:22 -07002791 const int kWidth = 1280;
2792 const int kHeight = 720;
2793 const int64_t kFrameIntervalMs = 150;
2794 int64_t timestamp_ms = kFrameIntervalMs;
mflodmancc3d4422017-08-03 08:27:51 -07002795 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -07002796
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002797 // Enable BALANCED preference, no initial limitation.
asaperssonf7e294d2017-06-13 23:25:22 -07002798 AdaptingFrameForwarder source;
2799 source.set_adaptation_enabled(true);
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002800 video_stream_encoder_->SetSource(&source,
2801 webrtc::DegradationPreference::BALANCED);
asaperssonf7e294d2017-06-13 23:25:22 -07002802 timestamp_ms += kFrameIntervalMs;
2803 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002804 WaitForEncodedFrame(kWidth, kHeight);
Åsa Perssonced5cfd2018-08-10 16:16:43 +02002805 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07002806 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2807 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2808 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2809 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
2810 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2811 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2812
2813 // Trigger cpu adapt down, expect scaled down resolution (960x540@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002814 video_stream_encoder_->TriggerCpuOveruse();
asaperssonf7e294d2017-06-13 23:25:22 -07002815 timestamp_ms += kFrameIntervalMs;
2816 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002817 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002818 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
2819 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2820 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2821 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2822 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
2823 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2824 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2825
2826 // Trigger cpu adapt down, expect scaled down resolution (640x360@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002827 video_stream_encoder_->TriggerCpuOveruse();
asaperssonf7e294d2017-06-13 23:25:22 -07002828 timestamp_ms += kFrameIntervalMs;
2829 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002830 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002831 VerifyFpsMaxResolutionLt(source.sink_wants(), source.last_wants());
2832 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2833 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2834 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2835 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
2836 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2837 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2838
2839 // Trigger quality adapt down, expect reduced fps (640x360@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07002840 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002841 timestamp_ms += kFrameIntervalMs;
2842 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002843 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002844 VerifyFpsLtResolutionEq(source.sink_wants(), source.last_wants());
2845 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2846 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2847 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2848 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
2849 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2850 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2851
2852 // Trigger cpu adapt up, expect increased fps (640x360@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002853 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssonf7e294d2017-06-13 23:25:22 -07002854 timestamp_ms += kFrameIntervalMs;
2855 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002856 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002857 VerifyFpsMaxResolutionEq(source.sink_wants(), source.last_wants());
2858 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2859 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2860 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2861 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
2862 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2863 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2864
2865 // Trigger quality adapt up, expect upscaled resolution (960x540@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002866 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002867 timestamp_ms += kFrameIntervalMs;
2868 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002869 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002870 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
2871 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2872 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2873 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2874 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
2875 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2876 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2877
2878 // Trigger cpu adapt up, expect no restriction (1280x720fps@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002879 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssonf7e294d2017-06-13 23:25:22 -07002880 timestamp_ms += kFrameIntervalMs;
2881 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002882 WaitForEncodedFrame(kWidth, kHeight);
asaperssonf7e294d2017-06-13 23:25:22 -07002883 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
Åsa Perssonced5cfd2018-08-10 16:16:43 +02002884 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07002885 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2886 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2887 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2888 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
2889 EXPECT_EQ(4, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2890 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2891
2892 // Trigger adapt up, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07002893 video_stream_encoder_->TriggerQualityHigh();
Åsa Perssonced5cfd2018-08-10 16:16:43 +02002894 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07002895 EXPECT_EQ(4, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2896 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2897
mflodmancc3d4422017-08-03 08:27:51 -07002898 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07002899}
2900
mflodmancc3d4422017-08-03 08:27:51 -07002901TEST_F(VideoStreamEncoderTest,
2902 AdaptWithTwoReasonsAndDifferentOrder_Resolution) {
asaperssonf7e294d2017-06-13 23:25:22 -07002903 const int kWidth = 640;
2904 const int kHeight = 360;
2905 const int kFpsLimit = 15;
2906 const int64_t kFrameIntervalMs = 150;
2907 int64_t timestamp_ms = kFrameIntervalMs;
mflodmancc3d4422017-08-03 08:27:51 -07002908 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -07002909
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002910 // Enable BALANCED preference, no initial limitation.
asaperssonf7e294d2017-06-13 23:25:22 -07002911 AdaptingFrameForwarder source;
2912 source.set_adaptation_enabled(true);
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002913 video_stream_encoder_->SetSource(&source,
2914 webrtc::DegradationPreference::BALANCED);
asaperssonf7e294d2017-06-13 23:25:22 -07002915 timestamp_ms += kFrameIntervalMs;
2916 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002917 WaitForEncodedFrame(kWidth, kHeight);
Åsa Perssonced5cfd2018-08-10 16:16:43 +02002918 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07002919 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2920 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2921 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2922 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
2923 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2924 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2925
2926 // Trigger cpu adapt down, expect scaled down framerate (640x360@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07002927 video_stream_encoder_->TriggerCpuOveruse();
asaperssonf7e294d2017-06-13 23:25:22 -07002928 timestamp_ms += kFrameIntervalMs;
2929 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002930 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002931 VerifyFpsEqResolutionMax(source.sink_wants(), kFpsLimit);
2932 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2933 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2934 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2935 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_framerate);
2936 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2937 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2938
2939 // Trigger quality adapt down, expect scaled down resolution (480x270@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07002940 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002941 timestamp_ms += kFrameIntervalMs;
2942 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002943 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002944 VerifyFpsEqResolutionLt(source.sink_wants(), source.last_wants());
2945 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2946 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2947 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2948 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_framerate);
2949 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2950 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2951
2952 // Trigger cpu adapt up, expect upscaled resolution (640x360@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07002953 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssonf7e294d2017-06-13 23:25:22 -07002954 timestamp_ms += kFrameIntervalMs;
2955 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002956 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002957 VerifyFpsEqResolutionGt(source.sink_wants(), source.last_wants());
2958 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2959 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2960 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2961 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
2962 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2963 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2964
2965 // Trigger quality adapt up, expect increased fps (640x360@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002966 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002967 timestamp_ms += kFrameIntervalMs;
2968 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002969 WaitForEncodedFrame(timestamp_ms);
Åsa Perssonced5cfd2018-08-10 16:16:43 +02002970 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07002971 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2972 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2973 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2974 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
2975 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2976 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2977
2978 // Trigger adapt up, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07002979 video_stream_encoder_->TriggerQualityHigh();
Åsa Perssonced5cfd2018-08-10 16:16:43 +02002980 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07002981 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2982 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2983
mflodmancc3d4422017-08-03 08:27:51 -07002984 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07002985}
2986
mflodmancc3d4422017-08-03 08:27:51 -07002987TEST_F(VideoStreamEncoderTest, AcceptsFullHdAdaptedDownSimulcastFrames) {
ilnik6b826ef2017-06-16 06:53:48 -07002988 // Simulates simulcast behavior and makes highest stream resolutions divisible
2989 // by 4.
2990 class CroppingVideoStreamFactory
2991 : public VideoEncoderConfig::VideoStreamFactoryInterface {
2992 public:
2993 explicit CroppingVideoStreamFactory(size_t num_temporal_layers,
2994 int framerate)
2995 : num_temporal_layers_(num_temporal_layers), framerate_(framerate) {
2996 EXPECT_GT(num_temporal_layers, 0u);
2997 EXPECT_GT(framerate, 0);
2998 }
2999
3000 private:
3001 std::vector<VideoStream> CreateEncoderStreams(
3002 int width,
3003 int height,
3004 const VideoEncoderConfig& encoder_config) override {
Yves Gerey665174f2018-06-19 15:03:05 +02003005 std::vector<VideoStream> streams = test::CreateVideoStreams(
3006 width - width % 4, height - height % 4, encoder_config);
ilnik6b826ef2017-06-16 06:53:48 -07003007 for (VideoStream& stream : streams) {
Sergey Silkina796a7e2018-03-01 15:11:29 +01003008 stream.num_temporal_layers = num_temporal_layers_;
ilnik6b826ef2017-06-16 06:53:48 -07003009 stream.max_framerate = framerate_;
3010 }
3011 return streams;
3012 }
3013
3014 const size_t num_temporal_layers_;
3015 const int framerate_;
3016 };
3017
3018 const int kFrameWidth = 1920;
3019 const int kFrameHeight = 1080;
3020 // 3/4 of 1920.
3021 const int kAdaptedFrameWidth = 1440;
3022 // 3/4 of 1080 rounded down to multiple of 4.
3023 const int kAdaptedFrameHeight = 808;
3024 const int kFramerate = 24;
3025
mflodmancc3d4422017-08-03 08:27:51 -07003026 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
ilnik6b826ef2017-06-16 06:53:48 -07003027 // Trigger reconfigure encoder (without resetting the entire instance).
3028 VideoEncoderConfig video_encoder_config;
Niels Möller259a4972018-04-05 15:36:51 +02003029 video_encoder_config.codec_type = kVideoCodecVP8;
ilnik6b826ef2017-06-16 06:53:48 -07003030 video_encoder_config.max_bitrate_bps = kTargetBitrateBps;
3031 video_encoder_config.number_of_streams = 1;
3032 video_encoder_config.video_stream_factory =
3033 new rtc::RefCountedObject<CroppingVideoStreamFactory>(1, kFramerate);
mflodmancc3d4422017-08-03 08:27:51 -07003034 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
Niels Möllerf1338562018-04-26 09:51:47 +02003035 kMaxPayloadLength);
mflodmancc3d4422017-08-03 08:27:51 -07003036 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
ilnik6b826ef2017-06-16 06:53:48 -07003037
3038 video_source_.set_adaptation_enabled(true);
3039
3040 video_source_.IncomingCapturedFrame(
3041 CreateFrame(1, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07003042 WaitForEncodedFrame(kFrameWidth, kFrameHeight);
ilnik6b826ef2017-06-16 06:53:48 -07003043
3044 // Trigger CPU overuse, downscale by 3/4.
mflodmancc3d4422017-08-03 08:27:51 -07003045 video_stream_encoder_->TriggerCpuOveruse();
ilnik6b826ef2017-06-16 06:53:48 -07003046 video_source_.IncomingCapturedFrame(
3047 CreateFrame(2, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07003048 WaitForEncodedFrame(kAdaptedFrameWidth, kAdaptedFrameHeight);
ilnik6b826ef2017-06-16 06:53:48 -07003049
mflodmancc3d4422017-08-03 08:27:51 -07003050 video_stream_encoder_->Stop();
ilnik6b826ef2017-06-16 06:53:48 -07003051}
3052
mflodmancc3d4422017-08-03 08:27:51 -07003053TEST_F(VideoStreamEncoderTest, PeriodicallyUpdatesChannelParameters) {
sprang4847ae62017-06-27 07:06:52 -07003054 const int kFrameWidth = 1280;
3055 const int kFrameHeight = 720;
3056 const int kLowFps = 2;
3057 const int kHighFps = 30;
3058
mflodmancc3d4422017-08-03 08:27:51 -07003059 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
sprang4847ae62017-06-27 07:06:52 -07003060
3061 int64_t timestamp_ms = fake_clock_.TimeNanos() / rtc::kNumNanosecsPerMillisec;
3062 max_framerate_ = kLowFps;
3063
3064 // Insert 2 seconds of 2fps video.
3065 for (int i = 0; i < kLowFps * 2; ++i) {
3066 video_source_.IncomingCapturedFrame(
3067 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
3068 WaitForEncodedFrame(timestamp_ms);
3069 timestamp_ms += 1000 / kLowFps;
3070 }
3071
3072 // Make sure encoder is updated with new target.
mflodmancc3d4422017-08-03 08:27:51 -07003073 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
sprang4847ae62017-06-27 07:06:52 -07003074 video_source_.IncomingCapturedFrame(
3075 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
3076 WaitForEncodedFrame(timestamp_ms);
3077 timestamp_ms += 1000 / kLowFps;
3078
3079 EXPECT_EQ(kLowFps, fake_encoder_.GetConfiguredInputFramerate());
3080
3081 // Insert 30fps frames for just a little more than the forced update period.
3082 const int kVcmTimerIntervalFrames =
3083 (vcm::VCMProcessTimer::kDefaultProcessIntervalMs * kHighFps) / 1000;
3084 const int kFrameIntervalMs = 1000 / kHighFps;
3085 max_framerate_ = kHighFps;
3086 for (int i = 0; i < kVcmTimerIntervalFrames + 2; ++i) {
3087 video_source_.IncomingCapturedFrame(
3088 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
3089 // Wait for encoded frame, but skip ahead if it doesn't arrive as it might
3090 // be dropped if the encoder hans't been updated with the new higher target
3091 // framerate yet, causing it to overshoot the target bitrate and then
3092 // suffering the wrath of the media optimizer.
3093 TimedWaitForEncodedFrame(timestamp_ms, 2 * kFrameIntervalMs);
3094 timestamp_ms += kFrameIntervalMs;
3095 }
3096
3097 // Don expect correct measurement just yet, but it should be higher than
3098 // before.
3099 EXPECT_GT(fake_encoder_.GetConfiguredInputFramerate(), kLowFps);
3100
mflodmancc3d4422017-08-03 08:27:51 -07003101 video_stream_encoder_->Stop();
sprang4847ae62017-06-27 07:06:52 -07003102}
3103
mflodmancc3d4422017-08-03 08:27:51 -07003104TEST_F(VideoStreamEncoderTest, DoesNotUpdateBitrateAllocationWhenSuspended) {
sprang4847ae62017-06-27 07:06:52 -07003105 const int kFrameWidth = 1280;
3106 const int kFrameHeight = 720;
3107 const int kTargetBitrateBps = 1000000;
3108
3109 MockBitrateObserver bitrate_observer;
Niels Möller0327c2d2018-05-21 14:09:31 +02003110 video_stream_encoder_->SetBitrateAllocationObserver(&bitrate_observer);
sprang4847ae62017-06-27 07:06:52 -07003111
3112 EXPECT_CALL(bitrate_observer, OnBitrateAllocationUpdated(_)).Times(1);
3113 // Initial bitrate update.
mflodmancc3d4422017-08-03 08:27:51 -07003114 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
3115 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
sprang4847ae62017-06-27 07:06:52 -07003116
3117 // Insert a first video frame, causes another bitrate update.
3118 int64_t timestamp_ms = fake_clock_.TimeNanos() / rtc::kNumNanosecsPerMillisec;
3119 EXPECT_CALL(bitrate_observer, OnBitrateAllocationUpdated(_)).Times(1);
3120 video_source_.IncomingCapturedFrame(
3121 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
3122 WaitForEncodedFrame(timestamp_ms);
3123
3124 // Next, simulate video suspension due to pacer queue overrun.
mflodmancc3d4422017-08-03 08:27:51 -07003125 video_stream_encoder_->OnBitrateUpdated(0, 0, 1);
sprang4847ae62017-06-27 07:06:52 -07003126
3127 // Skip ahead until a new periodic parameter update should have occured.
3128 timestamp_ms += vcm::VCMProcessTimer::kDefaultProcessIntervalMs;
3129 fake_clock_.AdvanceTimeMicros(
3130 vcm::VCMProcessTimer::kDefaultProcessIntervalMs *
3131 rtc::kNumMicrosecsPerMillisec);
3132
3133 // Bitrate observer should not be called.
3134 EXPECT_CALL(bitrate_observer, OnBitrateAllocationUpdated(_)).Times(0);
3135 video_source_.IncomingCapturedFrame(
3136 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
3137 ExpectDroppedFrame();
3138
mflodmancc3d4422017-08-03 08:27:51 -07003139 video_stream_encoder_->Stop();
sprang4847ae62017-06-27 07:06:52 -07003140}
ilnik6b826ef2017-06-16 06:53:48 -07003141
Niels Möller4db138e2018-04-19 09:04:13 +02003142TEST_F(VideoStreamEncoderTest,
3143 DefaultCpuAdaptationThresholdsForSoftwareEncoder) {
3144 const int kFrameWidth = 1280;
3145 const int kFrameHeight = 720;
3146 const CpuOveruseOptions default_options;
3147 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
3148 video_source_.IncomingCapturedFrame(
3149 CreateFrame(1, kFrameWidth, kFrameHeight));
3150 WaitForEncodedFrame(1);
3151 EXPECT_EQ(video_stream_encoder_->overuse_detector_proxy_->GetOptions()
3152 .low_encode_usage_threshold_percent,
3153 default_options.low_encode_usage_threshold_percent);
3154 EXPECT_EQ(video_stream_encoder_->overuse_detector_proxy_->GetOptions()
3155 .high_encode_usage_threshold_percent,
3156 default_options.high_encode_usage_threshold_percent);
3157 video_stream_encoder_->Stop();
3158}
3159
3160TEST_F(VideoStreamEncoderTest,
3161 HigherCpuAdaptationThresholdsForHardwareEncoder) {
3162 const int kFrameWidth = 1280;
3163 const int kFrameHeight = 720;
3164 CpuOveruseOptions hardware_options;
3165 hardware_options.low_encode_usage_threshold_percent = 150;
3166 hardware_options.high_encode_usage_threshold_percent = 200;
3167 encoder_factory_.SetIsHardwareAccelerated(true);
3168
3169 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
3170 video_source_.IncomingCapturedFrame(
3171 CreateFrame(1, kFrameWidth, kFrameHeight));
3172 WaitForEncodedFrame(1);
3173 EXPECT_EQ(video_stream_encoder_->overuse_detector_proxy_->GetOptions()
3174 .low_encode_usage_threshold_percent,
3175 hardware_options.low_encode_usage_threshold_percent);
3176 EXPECT_EQ(video_stream_encoder_->overuse_detector_proxy_->GetOptions()
3177 .high_encode_usage_threshold_percent,
3178 hardware_options.high_encode_usage_threshold_percent);
3179 video_stream_encoder_->Stop();
3180}
3181
perkj26091b12016-09-01 01:17:40 -07003182} // namespace webrtc