blob: 8ce5071422e3ceffaba2ccb784a6150262309737 [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
kthelgason33ce8892016-12-09 03:53:59 -080034namespace {
kthelgason33ce8892016-12-09 03:53:59 -080035const int kMinPixelsPerFrame = 320 * 180;
sprangc5d62e22017-04-02 23:53:04 -070036const int kMinFramerateFps = 2;
Jonathan Yubc771b72017-12-08 17:04:29 -080037const int kMinBalancedFramerateFps = 7;
sprangc5d62e22017-04-02 23:53:04 -070038const int64_t kFrameTimeoutMs = 100;
39} // namespace
kthelgason33ce8892016-12-09 03:53:59 -080040
perkj26091b12016-09-01 01:17:40 -070041namespace webrtc {
42
sprangb1ca0732017-02-01 08:38:12 -080043using ScaleReason = AdaptationObserverInterface::AdaptReason;
sprang57c2fff2017-01-16 06:24:02 -080044using ::testing::_;
45using ::testing::Return;
kthelgason876222f2016-11-29 01:44:11 -080046
perkj803d97f2016-11-01 11:45:46 -070047namespace {
asapersson5f7226f2016-11-25 04:37:00 -080048const size_t kMaxPayloadLength = 1440;
kthelgason2bc68642017-02-07 07:02:22 -080049const int kTargetBitrateBps = 1000000;
50const int kLowTargetBitrateBps = kTargetBitrateBps / 10;
51const int kMaxInitialFramedrop = 4;
sprangfda496a2017-06-15 04:21:07 -070052const int kDefaultFramerate = 30;
asapersson5f7226f2016-11-25 04:37:00 -080053
perkj803d97f2016-11-01 11:45:46 -070054class TestBuffer : public webrtc::I420Buffer {
55 public:
56 TestBuffer(rtc::Event* event, int width, int height)
57 : I420Buffer(width, height), event_(event) {}
58
59 private:
60 friend class rtc::RefCountedObject<TestBuffer>;
61 ~TestBuffer() override {
62 if (event_)
63 event_->Set();
64 }
65 rtc::Event* const event_;
66};
67
Niels Möller7dc26b72017-12-06 10:27:48 +010068class CpuOveruseDetectorProxy : public OveruseFrameDetector {
69 public:
Niels Möllerd1f7eb62018-03-28 16:40:58 +020070 explicit CpuOveruseDetectorProxy(CpuOveruseMetricsObserver* metrics_observer)
71 : OveruseFrameDetector(metrics_observer),
Niels Möller7dc26b72017-12-06 10:27:48 +010072 last_target_framerate_fps_(-1) {}
73 virtual ~CpuOveruseDetectorProxy() {}
74
75 void OnTargetFramerateUpdated(int framerate_fps) override {
76 rtc::CritScope cs(&lock_);
77 last_target_framerate_fps_ = framerate_fps;
78 OveruseFrameDetector::OnTargetFramerateUpdated(framerate_fps);
79 }
80
81 int GetLastTargetFramerate() {
82 rtc::CritScope cs(&lock_);
83 return last_target_framerate_fps_;
84 }
85
Niels Möller4db138e2018-04-19 09:04:13 +020086 CpuOveruseOptions GetOptions() { return options_; }
87
Niels Möller7dc26b72017-12-06 10:27:48 +010088 private:
89 rtc::CriticalSection lock_;
90 int last_target_framerate_fps_ RTC_GUARDED_BY(lock_);
91};
92
mflodmancc3d4422017-08-03 08:27:51 -070093class VideoStreamEncoderUnderTest : public VideoStreamEncoder {
perkj803d97f2016-11-01 11:45:46 -070094 public:
Yves Gerey665174f2018-06-19 15:03:05 +020095 VideoStreamEncoderUnderTest(
96 SendStatisticsProxy* stats_proxy,
97 const VideoSendStream::Config::EncoderSettings& settings)
98 : VideoStreamEncoder(1 /* number_of_cores */,
99 stats_proxy,
100 settings,
101 nullptr /* pre_encode_callback */,
102 std::unique_ptr<OveruseFrameDetector>(
103 overuse_detector_proxy_ =
104 new CpuOveruseDetectorProxy(stats_proxy))) {}
perkj803d97f2016-11-01 11:45:46 -0700105
sprangb1ca0732017-02-01 08:38:12 -0800106 void PostTaskAndWait(bool down, AdaptReason reason) {
perkj803d97f2016-11-01 11:45:46 -0700107 rtc::Event event(false, false);
kthelgason876222f2016-11-29 01:44:11 -0800108 encoder_queue()->PostTask([this, &event, reason, down] {
sprangb1ca0732017-02-01 08:38:12 -0800109 down ? AdaptDown(reason) : AdaptUp(reason);
perkj803d97f2016-11-01 11:45:46 -0700110 event.Set();
111 });
perkj070ba852017-02-16 15:46:27 -0800112 ASSERT_TRUE(event.Wait(5000));
perkj803d97f2016-11-01 11:45:46 -0700113 }
114
kthelgason2fc52542017-03-03 00:24:41 -0800115 // This is used as a synchronisation mechanism, to make sure that the
116 // encoder queue is not blocked before we start sending it frames.
117 void WaitUntilTaskQueueIsIdle() {
118 rtc::Event event(false, false);
Yves Gerey665174f2018-06-19 15:03:05 +0200119 encoder_queue()->PostTask([&event] { event.Set(); });
kthelgason2fc52542017-03-03 00:24:41 -0800120 ASSERT_TRUE(event.Wait(5000));
121 }
122
sprangb1ca0732017-02-01 08:38:12 -0800123 void TriggerCpuOveruse() { PostTaskAndWait(true, AdaptReason::kCpu); }
kthelgason876222f2016-11-29 01:44:11 -0800124
sprangb1ca0732017-02-01 08:38:12 -0800125 void TriggerCpuNormalUsage() { PostTaskAndWait(false, AdaptReason::kCpu); }
kthelgason876222f2016-11-29 01:44:11 -0800126
sprangb1ca0732017-02-01 08:38:12 -0800127 void TriggerQualityLow() { PostTaskAndWait(true, AdaptReason::kQuality); }
kthelgason876222f2016-11-29 01:44:11 -0800128
sprangb1ca0732017-02-01 08:38:12 -0800129 void TriggerQualityHigh() { PostTaskAndWait(false, AdaptReason::kQuality); }
sprangfda496a2017-06-15 04:21:07 -0700130
Niels Möller7dc26b72017-12-06 10:27:48 +0100131 CpuOveruseDetectorProxy* overuse_detector_proxy_;
perkj803d97f2016-11-01 11:45:46 -0700132};
133
asapersson5f7226f2016-11-25 04:37:00 -0800134class VideoStreamFactory
135 : public VideoEncoderConfig::VideoStreamFactoryInterface {
136 public:
sprangfda496a2017-06-15 04:21:07 -0700137 explicit VideoStreamFactory(size_t num_temporal_layers, int framerate)
138 : num_temporal_layers_(num_temporal_layers), framerate_(framerate) {
asapersson5f7226f2016-11-25 04:37:00 -0800139 EXPECT_GT(num_temporal_layers, 0u);
sprangfda496a2017-06-15 04:21:07 -0700140 EXPECT_GT(framerate, 0);
asapersson5f7226f2016-11-25 04:37:00 -0800141 }
142
143 private:
144 std::vector<VideoStream> CreateEncoderStreams(
145 int width,
146 int height,
147 const VideoEncoderConfig& encoder_config) override {
148 std::vector<VideoStream> streams =
149 test::CreateVideoStreams(width, height, encoder_config);
150 for (VideoStream& stream : streams) {
Sergey Silkina796a7e2018-03-01 15:11:29 +0100151 stream.num_temporal_layers = num_temporal_layers_;
sprangfda496a2017-06-15 04:21:07 -0700152 stream.max_framerate = framerate_;
asapersson5f7226f2016-11-25 04:37:00 -0800153 }
154 return streams;
155 }
sprangfda496a2017-06-15 04:21:07 -0700156
asapersson5f7226f2016-11-25 04:37:00 -0800157 const size_t num_temporal_layers_;
sprangfda496a2017-06-15 04:21:07 -0700158 const int framerate_;
asapersson5f7226f2016-11-25 04:37:00 -0800159};
160
sprangb1ca0732017-02-01 08:38:12 -0800161class AdaptingFrameForwarder : public test::FrameForwarder {
162 public:
163 AdaptingFrameForwarder() : adaptation_enabled_(false) {}
asaperssonfab67072017-04-04 05:51:49 -0700164 ~AdaptingFrameForwarder() override {}
sprangb1ca0732017-02-01 08:38:12 -0800165
166 void set_adaptation_enabled(bool enabled) {
167 rtc::CritScope cs(&crit_);
168 adaptation_enabled_ = enabled;
169 }
170
asaperssonfab67072017-04-04 05:51:49 -0700171 bool adaption_enabled() const {
sprangb1ca0732017-02-01 08:38:12 -0800172 rtc::CritScope cs(&crit_);
173 return adaptation_enabled_;
174 }
175
asapersson09f05612017-05-15 23:40:18 -0700176 rtc::VideoSinkWants last_wants() const {
177 rtc::CritScope cs(&crit_);
178 return last_wants_;
179 }
180
Danil Chapovalovb9b146c2018-06-15 12:28:07 +0200181 absl::optional<int> last_sent_width() const { return last_width_; }
182 absl::optional<int> last_sent_height() const { return last_height_; }
Jonathan Yubc771b72017-12-08 17:04:29 -0800183
sprangb1ca0732017-02-01 08:38:12 -0800184 void IncomingCapturedFrame(const VideoFrame& video_frame) override {
185 int cropped_width = 0;
186 int cropped_height = 0;
187 int out_width = 0;
188 int out_height = 0;
sprangc5d62e22017-04-02 23:53:04 -0700189 if (adaption_enabled()) {
190 if (adapter_.AdaptFrameResolution(
191 video_frame.width(), video_frame.height(),
192 video_frame.timestamp_us() * 1000, &cropped_width,
193 &cropped_height, &out_width, &out_height)) {
194 VideoFrame adapted_frame(new rtc::RefCountedObject<TestBuffer>(
195 nullptr, out_width, out_height),
196 99, 99, kVideoRotation_0);
197 adapted_frame.set_ntp_time_ms(video_frame.ntp_time_ms());
198 test::FrameForwarder::IncomingCapturedFrame(adapted_frame);
Jonathan Yubc771b72017-12-08 17:04:29 -0800199 last_width_.emplace(adapted_frame.width());
200 last_height_.emplace(adapted_frame.height());
201 } else {
Danil Chapovalovb9b146c2018-06-15 12:28:07 +0200202 last_width_ = absl::nullopt;
203 last_height_ = absl::nullopt;
sprangc5d62e22017-04-02 23:53:04 -0700204 }
sprangb1ca0732017-02-01 08:38:12 -0800205 } else {
206 test::FrameForwarder::IncomingCapturedFrame(video_frame);
Jonathan Yubc771b72017-12-08 17:04:29 -0800207 last_width_.emplace(video_frame.width());
208 last_height_.emplace(video_frame.height());
sprangb1ca0732017-02-01 08:38:12 -0800209 }
210 }
211
212 void AddOrUpdateSink(rtc::VideoSinkInterface<VideoFrame>* sink,
213 const rtc::VideoSinkWants& wants) override {
214 rtc::CritScope cs(&crit_);
asapersson09f05612017-05-15 23:40:18 -0700215 last_wants_ = sink_wants();
sprangc5d62e22017-04-02 23:53:04 -0700216 adapter_.OnResolutionFramerateRequest(wants.target_pixel_count,
217 wants.max_pixel_count,
218 wants.max_framerate_fps);
sprangb1ca0732017-02-01 08:38:12 -0800219 test::FrameForwarder::AddOrUpdateSink(sink, wants);
220 }
sprangb1ca0732017-02-01 08:38:12 -0800221 cricket::VideoAdapter adapter_;
danilchapa37de392017-09-09 04:17:22 -0700222 bool adaptation_enabled_ RTC_GUARDED_BY(crit_);
223 rtc::VideoSinkWants last_wants_ RTC_GUARDED_BY(crit_);
Danil Chapovalovb9b146c2018-06-15 12:28:07 +0200224 absl::optional<int> last_width_;
225 absl::optional<int> last_height_;
sprangb1ca0732017-02-01 08:38:12 -0800226};
sprangc5d62e22017-04-02 23:53:04 -0700227
228class MockableSendStatisticsProxy : public SendStatisticsProxy {
229 public:
230 MockableSendStatisticsProxy(Clock* clock,
231 const VideoSendStream::Config& config,
232 VideoEncoderConfig::ContentType content_type)
233 : SendStatisticsProxy(clock, config, content_type) {}
234
235 VideoSendStream::Stats GetStats() override {
236 rtc::CritScope cs(&lock_);
237 if (mock_stats_)
238 return *mock_stats_;
239 return SendStatisticsProxy::GetStats();
240 }
241
242 void SetMockStats(const VideoSendStream::Stats& stats) {
243 rtc::CritScope cs(&lock_);
244 mock_stats_.emplace(stats);
245 }
246
247 void ResetMockStats() {
248 rtc::CritScope cs(&lock_);
249 mock_stats_.reset();
250 }
251
252 private:
253 rtc::CriticalSection lock_;
Danil Chapovalovb9b146c2018-06-15 12:28:07 +0200254 absl::optional<VideoSendStream::Stats> mock_stats_ RTC_GUARDED_BY(lock_);
sprangc5d62e22017-04-02 23:53:04 -0700255};
256
sprang4847ae62017-06-27 07:06:52 -0700257class MockBitrateObserver : public VideoBitrateAllocationObserver {
258 public:
Erik Språng566124a2018-04-23 12:32:22 +0200259 MOCK_METHOD1(OnBitrateAllocationUpdated, void(const VideoBitrateAllocation&));
sprang4847ae62017-06-27 07:06:52 -0700260};
261
perkj803d97f2016-11-01 11:45:46 -0700262} // namespace
263
mflodmancc3d4422017-08-03 08:27:51 -0700264class VideoStreamEncoderTest : public ::testing::Test {
perkj26091b12016-09-01 01:17:40 -0700265 public:
266 static const int kDefaultTimeoutMs = 30 * 1000;
267
mflodmancc3d4422017-08-03 08:27:51 -0700268 VideoStreamEncoderTest()
perkj26091b12016-09-01 01:17:40 -0700269 : video_send_config_(VideoSendStream::Config(nullptr)),
perkjfa10b552016-10-02 23:45:26 -0700270 codec_width_(320),
271 codec_height_(240),
sprang4847ae62017-06-27 07:06:52 -0700272 max_framerate_(30),
perkj26091b12016-09-01 01:17:40 -0700273 fake_encoder_(),
Niels Möller4db138e2018-04-19 09:04:13 +0200274 encoder_factory_(&fake_encoder_),
sprangc5d62e22017-04-02 23:53:04 -0700275 stats_proxy_(new MockableSendStatisticsProxy(
perkj803d97f2016-11-01 11:45:46 -0700276 Clock::GetRealTimeClock(),
277 video_send_config_,
278 webrtc::VideoEncoderConfig::ContentType::kRealtimeVideo)),
perkj26091b12016-09-01 01:17:40 -0700279 sink_(&fake_encoder_) {}
280
281 void SetUp() override {
perkj803d97f2016-11-01 11:45:46 -0700282 metrics::Reset();
perkj26091b12016-09-01 01:17:40 -0700283 video_send_config_ = VideoSendStream::Config(nullptr);
Niels Möller4db138e2018-04-19 09:04:13 +0200284 video_send_config_.encoder_settings.encoder_factory = &encoder_factory_;
Niels Möller259a4972018-04-05 15:36:51 +0200285 video_send_config_.rtp.payload_name = "FAKE";
286 video_send_config_.rtp.payload_type = 125;
perkj26091b12016-09-01 01:17:40 -0700287
Per512ecb32016-09-23 15:52:06 +0200288 VideoEncoderConfig video_encoder_config;
Niels Möller259a4972018-04-05 15:36:51 +0200289 test::FillEncoderConfiguration(kVideoCodecVP8, 1, &video_encoder_config);
sprang4847ae62017-06-27 07:06:52 -0700290 video_encoder_config.video_stream_factory =
291 new rtc::RefCountedObject<VideoStreamFactory>(1, max_framerate_);
Erik Språng08127a92016-11-16 16:41:30 +0100292 video_encoder_config_ = video_encoder_config.Copy();
sprang4847ae62017-06-27 07:06:52 -0700293
294 // Framerate limit is specified by the VideoStreamFactory.
295 std::vector<VideoStream> streams =
296 video_encoder_config.video_stream_factory->CreateEncoderStreams(
297 codec_width_, codec_height_, video_encoder_config);
298 max_framerate_ = streams[0].max_framerate;
299 fake_clock_.SetTimeMicros(1234);
300
Niels Möllerf1338562018-04-26 09:51:47 +0200301 ConfigureEncoder(std::move(video_encoder_config));
asapersson5f7226f2016-11-25 04:37:00 -0800302 }
303
Niels Möllerf1338562018-04-26 09:51:47 +0200304 void ConfigureEncoder(VideoEncoderConfig video_encoder_config) {
mflodmancc3d4422017-08-03 08:27:51 -0700305 if (video_stream_encoder_)
306 video_stream_encoder_->Stop();
307 video_stream_encoder_.reset(new VideoStreamEncoderUnderTest(
perkj803d97f2016-11-01 11:45:46 -0700308 stats_proxy_.get(), video_send_config_.encoder_settings));
mflodmancc3d4422017-08-03 08:27:51 -0700309 video_stream_encoder_->SetSink(&sink_, false /* rotation_applied */);
310 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -0700311 &video_source_, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
mflodmancc3d4422017-08-03 08:27:51 -0700312 video_stream_encoder_->SetStartBitrate(kTargetBitrateBps);
313 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
Niels Möllerf1338562018-04-26 09:51:47 +0200314 kMaxPayloadLength);
mflodmancc3d4422017-08-03 08:27:51 -0700315 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
asapersson5f7226f2016-11-25 04:37:00 -0800316 }
317
318 void ResetEncoder(const std::string& payload_name,
319 size_t num_streams,
320 size_t num_temporal_layers,
emircanbbcc3562017-08-18 00:28:40 -0700321 unsigned char num_spatial_layers,
sprang4847ae62017-06-27 07:06:52 -0700322 bool screenshare) {
Niels Möller259a4972018-04-05 15:36:51 +0200323 video_send_config_.rtp.payload_name = payload_name;
asapersson5f7226f2016-11-25 04:37:00 -0800324
325 VideoEncoderConfig video_encoder_config;
Niels Möller259a4972018-04-05 15:36:51 +0200326 video_encoder_config.codec_type = PayloadStringToCodecType(payload_name);
asapersson5f7226f2016-11-25 04:37:00 -0800327 video_encoder_config.number_of_streams = num_streams;
kthelgason2bc68642017-02-07 07:02:22 -0800328 video_encoder_config.max_bitrate_bps = kTargetBitrateBps;
asapersson5f7226f2016-11-25 04:37:00 -0800329 video_encoder_config.video_stream_factory =
sprangfda496a2017-06-15 04:21:07 -0700330 new rtc::RefCountedObject<VideoStreamFactory>(num_temporal_layers,
331 kDefaultFramerate);
sprang4847ae62017-06-27 07:06:52 -0700332 video_encoder_config.content_type =
333 screenshare ? VideoEncoderConfig::ContentType::kScreen
334 : VideoEncoderConfig::ContentType::kRealtimeVideo;
emircanbbcc3562017-08-18 00:28:40 -0700335 if (payload_name == "VP9") {
336 VideoCodecVP9 vp9_settings = VideoEncoder::GetDefaultVp9Settings();
337 vp9_settings.numberOfSpatialLayers = num_spatial_layers;
338 video_encoder_config.encoder_specific_settings =
339 new rtc::RefCountedObject<
340 VideoEncoderConfig::Vp9EncoderSpecificSettings>(vp9_settings);
341 }
Niels Möllerf1338562018-04-26 09:51:47 +0200342 ConfigureEncoder(std::move(video_encoder_config));
perkj26091b12016-09-01 01:17:40 -0700343 }
344
sprang57c2fff2017-01-16 06:24:02 -0800345 VideoFrame CreateFrame(int64_t ntp_time_ms,
346 rtc::Event* destruction_event) const {
Per512ecb32016-09-23 15:52:06 +0200347 VideoFrame frame(new rtc::RefCountedObject<TestBuffer>(
348 destruction_event, codec_width_, codec_height_),
349 99, 99, kVideoRotation_0);
sprang57c2fff2017-01-16 06:24:02 -0800350 frame.set_ntp_time_ms(ntp_time_ms);
perkj26091b12016-09-01 01:17:40 -0700351 return frame;
352 }
353
sprang57c2fff2017-01-16 06:24:02 -0800354 VideoFrame CreateFrame(int64_t ntp_time_ms, int width, int height) const {
perkj803d97f2016-11-01 11:45:46 -0700355 VideoFrame frame(
356 new rtc::RefCountedObject<TestBuffer>(nullptr, width, height), 99, 99,
357 kVideoRotation_0);
sprang57c2fff2017-01-16 06:24:02 -0800358 frame.set_ntp_time_ms(ntp_time_ms);
sprangc5d62e22017-04-02 23:53:04 -0700359 frame.set_timestamp_us(ntp_time_ms * 1000);
perkj803d97f2016-11-01 11:45:46 -0700360 return frame;
361 }
362
asapersson02465b82017-04-10 01:12:52 -0700363 void VerifyNoLimitation(const rtc::VideoSinkWants& wants) {
asapersson02465b82017-04-10 01:12:52 -0700364 EXPECT_EQ(std::numeric_limits<int>::max(), wants.max_framerate_fps);
asapersson09f05612017-05-15 23:40:18 -0700365 EXPECT_EQ(std::numeric_limits<int>::max(), wants.max_pixel_count);
366 EXPECT_FALSE(wants.target_pixel_count);
asapersson02465b82017-04-10 01:12:52 -0700367 }
368
asapersson09f05612017-05-15 23:40:18 -0700369 void VerifyFpsEqResolutionEq(const rtc::VideoSinkWants& wants1,
370 const rtc::VideoSinkWants& wants2) {
371 EXPECT_EQ(wants1.max_framerate_fps, wants2.max_framerate_fps);
372 EXPECT_EQ(wants1.max_pixel_count, wants2.max_pixel_count);
373 }
374
375 void VerifyFpsMaxResolutionLt(const rtc::VideoSinkWants& wants1,
376 const rtc::VideoSinkWants& wants2) {
377 EXPECT_EQ(std::numeric_limits<int>::max(), wants1.max_framerate_fps);
378 EXPECT_LT(wants1.max_pixel_count, wants2.max_pixel_count);
379 EXPECT_GT(wants1.max_pixel_count, 0);
380 }
381
382 void VerifyFpsMaxResolutionGt(const rtc::VideoSinkWants& wants1,
383 const rtc::VideoSinkWants& wants2) {
384 EXPECT_EQ(std::numeric_limits<int>::max(), wants1.max_framerate_fps);
385 EXPECT_GT(wants1.max_pixel_count, wants2.max_pixel_count);
386 }
387
asaperssonf7e294d2017-06-13 23:25:22 -0700388 void VerifyFpsMaxResolutionEq(const rtc::VideoSinkWants& wants1,
389 const rtc::VideoSinkWants& wants2) {
390 EXPECT_EQ(std::numeric_limits<int>::max(), wants1.max_framerate_fps);
391 EXPECT_EQ(wants1.max_pixel_count, wants2.max_pixel_count);
392 }
393
394 void VerifyFpsLtResolutionEq(const rtc::VideoSinkWants& wants1,
395 const rtc::VideoSinkWants& wants2) {
396 EXPECT_LT(wants1.max_framerate_fps, wants2.max_framerate_fps);
397 EXPECT_EQ(wants1.max_pixel_count, wants2.max_pixel_count);
398 }
399
400 void VerifyFpsGtResolutionEq(const rtc::VideoSinkWants& wants1,
401 const rtc::VideoSinkWants& wants2) {
402 EXPECT_GT(wants1.max_framerate_fps, wants2.max_framerate_fps);
403 EXPECT_EQ(wants1.max_pixel_count, wants2.max_pixel_count);
404 }
405
406 void VerifyFpsEqResolutionLt(const rtc::VideoSinkWants& wants1,
407 const rtc::VideoSinkWants& wants2) {
408 EXPECT_EQ(wants1.max_framerate_fps, wants2.max_framerate_fps);
409 EXPECT_LT(wants1.max_pixel_count, wants2.max_pixel_count);
410 EXPECT_GT(wants1.max_pixel_count, 0);
411 }
412
413 void VerifyFpsEqResolutionGt(const rtc::VideoSinkWants& wants1,
414 const rtc::VideoSinkWants& wants2) {
415 EXPECT_EQ(wants1.max_framerate_fps, wants2.max_framerate_fps);
416 EXPECT_GT(wants1.max_pixel_count, wants2.max_pixel_count);
417 }
418
asapersson09f05612017-05-15 23:40:18 -0700419 void VerifyFpsMaxResolutionLt(const rtc::VideoSinkWants& wants,
420 int pixel_count) {
421 EXPECT_EQ(std::numeric_limits<int>::max(), wants.max_framerate_fps);
asapersson02465b82017-04-10 01:12:52 -0700422 EXPECT_LT(wants.max_pixel_count, pixel_count);
423 EXPECT_GT(wants.max_pixel_count, 0);
asapersson09f05612017-05-15 23:40:18 -0700424 }
425
426 void VerifyFpsLtResolutionMax(const rtc::VideoSinkWants& wants, int fps) {
427 EXPECT_LT(wants.max_framerate_fps, fps);
428 EXPECT_EQ(std::numeric_limits<int>::max(), wants.max_pixel_count);
429 EXPECT_FALSE(wants.target_pixel_count);
asapersson02465b82017-04-10 01:12:52 -0700430 }
431
asaperssonf7e294d2017-06-13 23:25:22 -0700432 void VerifyFpsEqResolutionMax(const rtc::VideoSinkWants& wants,
433 int expected_fps) {
434 EXPECT_EQ(expected_fps, wants.max_framerate_fps);
435 EXPECT_EQ(std::numeric_limits<int>::max(), wants.max_pixel_count);
436 EXPECT_FALSE(wants.target_pixel_count);
437 }
438
Jonathan Yubc771b72017-12-08 17:04:29 -0800439 void VerifyBalancedModeFpsRange(const rtc::VideoSinkWants& wants,
440 int last_frame_pixels) {
441 // Balanced mode should always scale FPS to the desired range before
442 // attempting to scale resolution.
443 int fps_limit = wants.max_framerate_fps;
444 if (last_frame_pixels <= 320 * 240) {
445 EXPECT_TRUE(7 <= fps_limit && fps_limit <= 10);
446 } else if (last_frame_pixels <= 480 * 270) {
447 EXPECT_TRUE(10 <= fps_limit && fps_limit <= 15);
448 } else if (last_frame_pixels <= 640 * 480) {
449 EXPECT_LE(15, fps_limit);
450 } else {
451 EXPECT_EQ(std::numeric_limits<int>::max(), fps_limit);
452 }
453 }
454
sprang4847ae62017-06-27 07:06:52 -0700455 void WaitForEncodedFrame(int64_t expected_ntp_time) {
456 sink_.WaitForEncodedFrame(expected_ntp_time);
457 fake_clock_.AdvanceTimeMicros(rtc::kNumMicrosecsPerSec / max_framerate_);
458 }
459
460 bool TimedWaitForEncodedFrame(int64_t expected_ntp_time, int64_t timeout_ms) {
461 bool ok = sink_.TimedWaitForEncodedFrame(expected_ntp_time, timeout_ms);
462 fake_clock_.AdvanceTimeMicros(rtc::kNumMicrosecsPerSec / max_framerate_);
463 return ok;
464 }
465
466 void WaitForEncodedFrame(uint32_t expected_width, uint32_t expected_height) {
467 sink_.WaitForEncodedFrame(expected_width, expected_height);
468 fake_clock_.AdvanceTimeMicros(rtc::kNumMicrosecsPerSec / max_framerate_);
469 }
470
471 void ExpectDroppedFrame() {
472 sink_.ExpectDroppedFrame();
473 fake_clock_.AdvanceTimeMicros(rtc::kNumMicrosecsPerSec / max_framerate_);
474 }
475
476 bool WaitForFrame(int64_t timeout_ms) {
477 bool ok = sink_.WaitForFrame(timeout_ms);
478 fake_clock_.AdvanceTimeMicros(rtc::kNumMicrosecsPerSec / max_framerate_);
479 return ok;
480 }
481
perkj26091b12016-09-01 01:17:40 -0700482 class TestEncoder : public test::FakeEncoder {
483 public:
484 TestEncoder()
485 : FakeEncoder(Clock::GetRealTimeClock()),
486 continue_encode_event_(false, false) {}
487
asaperssonfab67072017-04-04 05:51:49 -0700488 VideoCodec codec_config() const {
brandtre78d2662017-01-16 05:57:16 -0800489 rtc::CritScope lock(&crit_sect_);
perkjfa10b552016-10-02 23:45:26 -0700490 return config_;
491 }
492
493 void BlockNextEncode() {
brandtre78d2662017-01-16 05:57:16 -0800494 rtc::CritScope lock(&local_crit_sect_);
perkjfa10b552016-10-02 23:45:26 -0700495 block_next_encode_ = true;
496 }
497
kthelgason876222f2016-11-29 01:44:11 -0800498 VideoEncoder::ScalingSettings GetScalingSettings() const override {
kthelgason2fc52542017-03-03 00:24:41 -0800499 rtc::CritScope lock(&local_crit_sect_);
kthelgasonad9010c2017-02-14 00:46:51 -0800500 if (quality_scaling_)
Niels Möller225c7872018-02-22 15:03:53 +0100501 return VideoEncoder::ScalingSettings(1, 2, kMinPixelsPerFrame);
502 return VideoEncoder::ScalingSettings::kOff;
kthelgason876222f2016-11-29 01:44:11 -0800503 }
504
perkjfa10b552016-10-02 23:45:26 -0700505 void ContinueEncode() { continue_encode_event_.Set(); }
506
507 void CheckLastTimeStampsMatch(int64_t ntp_time_ms,
508 uint32_t timestamp) const {
brandtre78d2662017-01-16 05:57:16 -0800509 rtc::CritScope lock(&local_crit_sect_);
perkjfa10b552016-10-02 23:45:26 -0700510 EXPECT_EQ(timestamp_, timestamp);
511 EXPECT_EQ(ntp_time_ms_, ntp_time_ms);
512 }
513
kthelgason2fc52542017-03-03 00:24:41 -0800514 void SetQualityScaling(bool b) {
515 rtc::CritScope lock(&local_crit_sect_);
516 quality_scaling_ = b;
517 }
kthelgasonad9010c2017-02-14 00:46:51 -0800518
sprangfe627f32017-03-29 08:24:59 -0700519 void ForceInitEncodeFailure(bool force_failure) {
520 rtc::CritScope lock(&local_crit_sect_);
521 force_init_encode_failed_ = force_failure;
522 }
523
perkjfa10b552016-10-02 23:45:26 -0700524 private:
perkj26091b12016-09-01 01:17:40 -0700525 int32_t Encode(const VideoFrame& input_image,
526 const CodecSpecificInfo* codec_specific_info,
527 const std::vector<FrameType>* frame_types) override {
528 bool block_encode;
529 {
brandtre78d2662017-01-16 05:57:16 -0800530 rtc::CritScope lock(&local_crit_sect_);
perkj26091b12016-09-01 01:17:40 -0700531 EXPECT_GT(input_image.timestamp(), timestamp_);
532 EXPECT_GT(input_image.ntp_time_ms(), ntp_time_ms_);
533 EXPECT_EQ(input_image.timestamp(), input_image.ntp_time_ms() * 90);
534
535 timestamp_ = input_image.timestamp();
536 ntp_time_ms_ = input_image.ntp_time_ms();
perkj803d97f2016-11-01 11:45:46 -0700537 last_input_width_ = input_image.width();
538 last_input_height_ = input_image.height();
perkj26091b12016-09-01 01:17:40 -0700539 block_encode = block_next_encode_;
540 block_next_encode_ = false;
541 }
542 int32_t result =
543 FakeEncoder::Encode(input_image, codec_specific_info, frame_types);
544 if (block_encode)
perkja49cbd32016-09-16 07:53:41 -0700545 EXPECT_TRUE(continue_encode_event_.Wait(kDefaultTimeoutMs));
perkj26091b12016-09-01 01:17:40 -0700546 return result;
547 }
548
sprangfe627f32017-03-29 08:24:59 -0700549 int32_t InitEncode(const VideoCodec* config,
550 int32_t number_of_cores,
551 size_t max_payload_size) override {
552 int res =
553 FakeEncoder::InitEncode(config, number_of_cores, max_payload_size);
554 rtc::CritScope lock(&local_crit_sect_);
Erik Språng82fad3d2018-03-21 09:57:23 +0100555 if (config->codecType == kVideoCodecVP8) {
sprangfe627f32017-03-29 08:24:59 -0700556 // Simulate setting up temporal layers, in order to validate the life
557 // cycle of these objects.
558 int num_streams = std::max<int>(1, config->numberOfSimulcastStreams);
sprangfe627f32017-03-29 08:24:59 -0700559 for (int i = 0; i < num_streams; ++i) {
560 allocated_temporal_layers_.emplace_back(
Niels Möller150dcb02018-03-27 14:16:55 +0200561 TemporalLayers::CreateTemporalLayers(*config, i));
sprangfe627f32017-03-29 08:24:59 -0700562 }
563 }
564 if (force_init_encode_failed_)
565 return -1;
566 return res;
567 }
568
brandtre78d2662017-01-16 05:57:16 -0800569 rtc::CriticalSection local_crit_sect_;
danilchapa37de392017-09-09 04:17:22 -0700570 bool block_next_encode_ RTC_GUARDED_BY(local_crit_sect_) = false;
perkj26091b12016-09-01 01:17:40 -0700571 rtc::Event continue_encode_event_;
danilchapa37de392017-09-09 04:17:22 -0700572 uint32_t timestamp_ RTC_GUARDED_BY(local_crit_sect_) = 0;
573 int64_t ntp_time_ms_ RTC_GUARDED_BY(local_crit_sect_) = 0;
574 int last_input_width_ RTC_GUARDED_BY(local_crit_sect_) = 0;
575 int last_input_height_ RTC_GUARDED_BY(local_crit_sect_) = 0;
576 bool quality_scaling_ RTC_GUARDED_BY(local_crit_sect_) = true;
sprangfe627f32017-03-29 08:24:59 -0700577 std::vector<std::unique_ptr<TemporalLayers>> allocated_temporal_layers_
danilchapa37de392017-09-09 04:17:22 -0700578 RTC_GUARDED_BY(local_crit_sect_);
579 bool force_init_encode_failed_ RTC_GUARDED_BY(local_crit_sect_) = false;
perkj26091b12016-09-01 01:17:40 -0700580 };
581
mflodmancc3d4422017-08-03 08:27:51 -0700582 class TestSink : public VideoStreamEncoder::EncoderSink {
perkj26091b12016-09-01 01:17:40 -0700583 public:
584 explicit TestSink(TestEncoder* test_encoder)
585 : test_encoder_(test_encoder), encoded_frame_event_(false, false) {}
586
perkj26091b12016-09-01 01:17:40 -0700587 void WaitForEncodedFrame(int64_t expected_ntp_time) {
sprang4847ae62017-06-27 07:06:52 -0700588 EXPECT_TRUE(
589 TimedWaitForEncodedFrame(expected_ntp_time, kDefaultTimeoutMs));
590 }
591
592 bool TimedWaitForEncodedFrame(int64_t expected_ntp_time,
593 int64_t timeout_ms) {
perkj26091b12016-09-01 01:17:40 -0700594 uint32_t timestamp = 0;
sprang4847ae62017-06-27 07:06:52 -0700595 if (!encoded_frame_event_.Wait(timeout_ms))
596 return false;
perkj26091b12016-09-01 01:17:40 -0700597 {
598 rtc::CritScope lock(&crit_);
sprangb1ca0732017-02-01 08:38:12 -0800599 timestamp = last_timestamp_;
perkj26091b12016-09-01 01:17:40 -0700600 }
601 test_encoder_->CheckLastTimeStampsMatch(expected_ntp_time, timestamp);
sprang4847ae62017-06-27 07:06:52 -0700602 return true;
perkj26091b12016-09-01 01:17:40 -0700603 }
604
sprangb1ca0732017-02-01 08:38:12 -0800605 void WaitForEncodedFrame(uint32_t expected_width,
606 uint32_t expected_height) {
sprangc5d62e22017-04-02 23:53:04 -0700607 EXPECT_TRUE(encoded_frame_event_.Wait(kDefaultTimeoutMs));
Åsa Perssonc74d8da2017-12-04 14:13:56 +0100608 CheckLastFrameSizeMatches(expected_width, expected_height);
sprangc5d62e22017-04-02 23:53:04 -0700609 }
610
Åsa Perssonc74d8da2017-12-04 14:13:56 +0100611 void CheckLastFrameSizeMatches(uint32_t expected_width,
sprangc5d62e22017-04-02 23:53:04 -0700612 uint32_t expected_height) {
sprangb1ca0732017-02-01 08:38:12 -0800613 uint32_t width = 0;
614 uint32_t height = 0;
sprangb1ca0732017-02-01 08:38:12 -0800615 {
616 rtc::CritScope lock(&crit_);
617 width = last_width_;
618 height = last_height_;
619 }
620 EXPECT_EQ(expected_height, height);
621 EXPECT_EQ(expected_width, width);
622 }
623
kthelgason2fc52542017-03-03 00:24:41 -0800624 void ExpectDroppedFrame() { EXPECT_FALSE(encoded_frame_event_.Wait(100)); }
kthelgason2bc68642017-02-07 07:02:22 -0800625
sprangc5d62e22017-04-02 23:53:04 -0700626 bool WaitForFrame(int64_t timeout_ms) {
627 return encoded_frame_event_.Wait(timeout_ms);
628 }
629
perkj26091b12016-09-01 01:17:40 -0700630 void SetExpectNoFrames() {
631 rtc::CritScope lock(&crit_);
632 expect_frames_ = false;
633 }
634
asaperssonfab67072017-04-04 05:51:49 -0700635 int number_of_reconfigurations() const {
Per512ecb32016-09-23 15:52:06 +0200636 rtc::CritScope lock(&crit_);
637 return number_of_reconfigurations_;
638 }
639
asaperssonfab67072017-04-04 05:51:49 -0700640 int last_min_transmit_bitrate() const {
Per512ecb32016-09-23 15:52:06 +0200641 rtc::CritScope lock(&crit_);
642 return min_transmit_bitrate_bps_;
643 }
644
perkj26091b12016-09-01 01:17:40 -0700645 private:
sergeyu2cb155a2016-11-04 11:39:29 -0700646 Result OnEncodedImage(
647 const EncodedImage& encoded_image,
648 const CodecSpecificInfo* codec_specific_info,
649 const RTPFragmentationHeader* fragmentation) override {
Per512ecb32016-09-23 15:52:06 +0200650 rtc::CritScope lock(&crit_);
651 EXPECT_TRUE(expect_frames_);
sprangb1ca0732017-02-01 08:38:12 -0800652 last_timestamp_ = encoded_image._timeStamp;
653 last_width_ = encoded_image._encodedWidth;
654 last_height_ = encoded_image._encodedHeight;
Per512ecb32016-09-23 15:52:06 +0200655 encoded_frame_event_.Set();
sprangb1ca0732017-02-01 08:38:12 -0800656 return Result(Result::OK, last_timestamp_);
Per512ecb32016-09-23 15:52:06 +0200657 }
658
659 void OnEncoderConfigurationChanged(std::vector<VideoStream> streams,
660 int min_transmit_bitrate_bps) override {
661 rtc::CriticalSection crit_;
662 ++number_of_reconfigurations_;
663 min_transmit_bitrate_bps_ = min_transmit_bitrate_bps;
664 }
665
perkj26091b12016-09-01 01:17:40 -0700666 rtc::CriticalSection crit_;
667 TestEncoder* test_encoder_;
668 rtc::Event encoded_frame_event_;
sprangb1ca0732017-02-01 08:38:12 -0800669 uint32_t last_timestamp_ = 0;
670 uint32_t last_height_ = 0;
671 uint32_t last_width_ = 0;
perkj26091b12016-09-01 01:17:40 -0700672 bool expect_frames_ = true;
Per512ecb32016-09-23 15:52:06 +0200673 int number_of_reconfigurations_ = 0;
674 int min_transmit_bitrate_bps_ = 0;
perkj26091b12016-09-01 01:17:40 -0700675 };
676
677 VideoSendStream::Config video_send_config_;
Erik Språng08127a92016-11-16 16:41:30 +0100678 VideoEncoderConfig video_encoder_config_;
Per512ecb32016-09-23 15:52:06 +0200679 int codec_width_;
680 int codec_height_;
sprang4847ae62017-06-27 07:06:52 -0700681 int max_framerate_;
perkj26091b12016-09-01 01:17:40 -0700682 TestEncoder fake_encoder_;
Niels Möller4db138e2018-04-19 09:04:13 +0200683 test::EncoderProxyFactory encoder_factory_;
sprangc5d62e22017-04-02 23:53:04 -0700684 std::unique_ptr<MockableSendStatisticsProxy> stats_proxy_;
perkj26091b12016-09-01 01:17:40 -0700685 TestSink sink_;
sprangb1ca0732017-02-01 08:38:12 -0800686 AdaptingFrameForwarder video_source_;
mflodmancc3d4422017-08-03 08:27:51 -0700687 std::unique_ptr<VideoStreamEncoderUnderTest> video_stream_encoder_;
sprang4847ae62017-06-27 07:06:52 -0700688 rtc::ScopedFakeClock fake_clock_;
perkj26091b12016-09-01 01:17:40 -0700689};
690
mflodmancc3d4422017-08-03 08:27:51 -0700691TEST_F(VideoStreamEncoderTest, EncodeOneFrame) {
692 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkj26091b12016-09-01 01:17:40 -0700693 rtc::Event frame_destroyed_event(false, false);
perkja49cbd32016-09-16 07:53:41 -0700694 video_source_.IncomingCapturedFrame(CreateFrame(1, &frame_destroyed_event));
sprang4847ae62017-06-27 07:06:52 -0700695 WaitForEncodedFrame(1);
perkja49cbd32016-09-16 07:53:41 -0700696 EXPECT_TRUE(frame_destroyed_event.Wait(kDefaultTimeoutMs));
mflodmancc3d4422017-08-03 08:27:51 -0700697 video_stream_encoder_->Stop();
perkj26091b12016-09-01 01:17:40 -0700698}
699
mflodmancc3d4422017-08-03 08:27:51 -0700700TEST_F(VideoStreamEncoderTest, DropsFramesBeforeFirstOnBitrateUpdated) {
perkj26091b12016-09-01 01:17:40 -0700701 // Dropped since no target bitrate has been set.
702 rtc::Event frame_destroyed_event(false, false);
Sebastian Janssona3177052018-04-10 13:05:49 +0200703 // The encoder will cache up to one frame for a short duration. Adding two
704 // frames means that the first frame will be dropped and the second frame will
705 // be sent when the encoder is enabled.
perkja49cbd32016-09-16 07:53:41 -0700706 video_source_.IncomingCapturedFrame(CreateFrame(1, &frame_destroyed_event));
Sebastian Janssona3177052018-04-10 13:05:49 +0200707 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
perkja49cbd32016-09-16 07:53:41 -0700708 EXPECT_TRUE(frame_destroyed_event.Wait(kDefaultTimeoutMs));
perkj26091b12016-09-01 01:17:40 -0700709
mflodmancc3d4422017-08-03 08:27:51 -0700710 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkj26091b12016-09-01 01:17:40 -0700711
Sebastian Janssona3177052018-04-10 13:05:49 +0200712 // The pending frame should be received.
sprang4847ae62017-06-27 07:06:52 -0700713 WaitForEncodedFrame(2);
Sebastian Janssona3177052018-04-10 13:05:49 +0200714 video_source_.IncomingCapturedFrame(CreateFrame(3, nullptr));
715
716 WaitForEncodedFrame(3);
mflodmancc3d4422017-08-03 08:27:51 -0700717 video_stream_encoder_->Stop();
perkj26091b12016-09-01 01:17:40 -0700718}
719
mflodmancc3d4422017-08-03 08:27:51 -0700720TEST_F(VideoStreamEncoderTest, DropsFramesWhenRateSetToZero) {
721 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkja49cbd32016-09-16 07:53:41 -0700722 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700723 WaitForEncodedFrame(1);
perkj26091b12016-09-01 01:17:40 -0700724
mflodmancc3d4422017-08-03 08:27:51 -0700725 video_stream_encoder_->OnBitrateUpdated(0, 0, 0);
Sebastian Janssona3177052018-04-10 13:05:49 +0200726 // The encoder will cache up to one frame for a short duration. Adding two
727 // frames means that the first frame will be dropped and the second frame will
728 // be sent when the encoder is resumed.
perkja49cbd32016-09-16 07:53:41 -0700729 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
Sebastian Janssona3177052018-04-10 13:05:49 +0200730 video_source_.IncomingCapturedFrame(CreateFrame(3, nullptr));
perkj26091b12016-09-01 01:17:40 -0700731
mflodmancc3d4422017-08-03 08:27:51 -0700732 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
sprang4847ae62017-06-27 07:06:52 -0700733 WaitForEncodedFrame(3);
Sebastian Janssona3177052018-04-10 13:05:49 +0200734 video_source_.IncomingCapturedFrame(CreateFrame(4, nullptr));
735 WaitForEncodedFrame(4);
mflodmancc3d4422017-08-03 08:27:51 -0700736 video_stream_encoder_->Stop();
perkj26091b12016-09-01 01:17:40 -0700737}
738
mflodmancc3d4422017-08-03 08:27:51 -0700739TEST_F(VideoStreamEncoderTest, DropsFramesWithSameOrOldNtpTimestamp) {
740 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkja49cbd32016-09-16 07:53:41 -0700741 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700742 WaitForEncodedFrame(1);
perkj26091b12016-09-01 01:17:40 -0700743
744 // This frame will be dropped since it has the same ntp timestamp.
perkja49cbd32016-09-16 07:53:41 -0700745 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
perkj26091b12016-09-01 01:17:40 -0700746
perkja49cbd32016-09-16 07:53:41 -0700747 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700748 WaitForEncodedFrame(2);
mflodmancc3d4422017-08-03 08:27:51 -0700749 video_stream_encoder_->Stop();
perkj26091b12016-09-01 01:17:40 -0700750}
751
mflodmancc3d4422017-08-03 08:27:51 -0700752TEST_F(VideoStreamEncoderTest, DropsFrameAfterStop) {
753 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkj26091b12016-09-01 01:17:40 -0700754
perkja49cbd32016-09-16 07:53:41 -0700755 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700756 WaitForEncodedFrame(1);
perkj26091b12016-09-01 01:17:40 -0700757
mflodmancc3d4422017-08-03 08:27:51 -0700758 video_stream_encoder_->Stop();
perkj26091b12016-09-01 01:17:40 -0700759 sink_.SetExpectNoFrames();
760 rtc::Event frame_destroyed_event(false, false);
perkja49cbd32016-09-16 07:53:41 -0700761 video_source_.IncomingCapturedFrame(CreateFrame(2, &frame_destroyed_event));
762 EXPECT_TRUE(frame_destroyed_event.Wait(kDefaultTimeoutMs));
perkj26091b12016-09-01 01:17:40 -0700763}
764
mflodmancc3d4422017-08-03 08:27:51 -0700765TEST_F(VideoStreamEncoderTest, DropsPendingFramesOnSlowEncode) {
766 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkj26091b12016-09-01 01:17:40 -0700767
768 fake_encoder_.BlockNextEncode();
perkja49cbd32016-09-16 07:53:41 -0700769 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700770 WaitForEncodedFrame(1);
perkj26091b12016-09-01 01:17:40 -0700771 // Here, the encoder thread will be blocked in the TestEncoder waiting for a
772 // call to ContinueEncode.
perkja49cbd32016-09-16 07:53:41 -0700773 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
774 video_source_.IncomingCapturedFrame(CreateFrame(3, nullptr));
perkj26091b12016-09-01 01:17:40 -0700775 fake_encoder_.ContinueEncode();
sprang4847ae62017-06-27 07:06:52 -0700776 WaitForEncodedFrame(3);
perkj26091b12016-09-01 01:17:40 -0700777
mflodmancc3d4422017-08-03 08:27:51 -0700778 video_stream_encoder_->Stop();
perkj26091b12016-09-01 01:17:40 -0700779}
780
mflodmancc3d4422017-08-03 08:27:51 -0700781TEST_F(VideoStreamEncoderTest,
782 ConfigureEncoderTriggersOnEncoderConfigurationChanged) {
783 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
Per21d45d22016-10-30 21:37:57 +0100784 EXPECT_EQ(0, sink_.number_of_reconfigurations());
Per512ecb32016-09-23 15:52:06 +0200785
786 // Capture a frame and wait for it to synchronize with the encoder thread.
Perf8c5f2b2016-09-23 16:24:55 +0200787 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700788 WaitForEncodedFrame(1);
Per21d45d22016-10-30 21:37:57 +0100789 // The encoder will have been configured once when the first frame is
790 // received.
791 EXPECT_EQ(1, sink_.number_of_reconfigurations());
Per512ecb32016-09-23 15:52:06 +0200792
793 VideoEncoderConfig video_encoder_config;
Niels Möller259a4972018-04-05 15:36:51 +0200794 test::FillEncoderConfiguration(kVideoCodecVP8, 1, &video_encoder_config);
Per512ecb32016-09-23 15:52:06 +0200795 video_encoder_config.min_transmit_bitrate_bps = 9999;
mflodmancc3d4422017-08-03 08:27:51 -0700796 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
Niels Möllerf1338562018-04-26 09:51:47 +0200797 kMaxPayloadLength);
Per512ecb32016-09-23 15:52:06 +0200798
799 // Capture a frame and wait for it to synchronize with the encoder thread.
Perf8c5f2b2016-09-23 16:24:55 +0200800 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700801 WaitForEncodedFrame(2);
Per21d45d22016-10-30 21:37:57 +0100802 EXPECT_EQ(2, sink_.number_of_reconfigurations());
perkj3b703ed2016-09-29 23:25:40 -0700803 EXPECT_EQ(9999, sink_.last_min_transmit_bitrate());
perkj26105b42016-09-29 22:39:10 -0700804
mflodmancc3d4422017-08-03 08:27:51 -0700805 video_stream_encoder_->Stop();
perkj26105b42016-09-29 22:39:10 -0700806}
807
mflodmancc3d4422017-08-03 08:27:51 -0700808TEST_F(VideoStreamEncoderTest, FrameResolutionChangeReconfigureEncoder) {
809 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkjfa10b552016-10-02 23:45:26 -0700810
811 // Capture a frame and wait for it to synchronize with the encoder thread.
812 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700813 WaitForEncodedFrame(1);
Per21d45d22016-10-30 21:37:57 +0100814 // The encoder will have been configured once.
815 EXPECT_EQ(1, sink_.number_of_reconfigurations());
perkjfa10b552016-10-02 23:45:26 -0700816 EXPECT_EQ(codec_width_, fake_encoder_.codec_config().width);
817 EXPECT_EQ(codec_height_, fake_encoder_.codec_config().height);
818
819 codec_width_ *= 2;
820 codec_height_ *= 2;
821 // Capture a frame with a higher resolution and wait for it to synchronize
822 // with the encoder thread.
823 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700824 WaitForEncodedFrame(2);
perkjfa10b552016-10-02 23:45:26 -0700825 EXPECT_EQ(codec_width_, fake_encoder_.codec_config().width);
826 EXPECT_EQ(codec_height_, fake_encoder_.codec_config().height);
Per21d45d22016-10-30 21:37:57 +0100827 EXPECT_EQ(2, sink_.number_of_reconfigurations());
perkjfa10b552016-10-02 23:45:26 -0700828
mflodmancc3d4422017-08-03 08:27:51 -0700829 video_stream_encoder_->Stop();
perkjfa10b552016-10-02 23:45:26 -0700830}
831
mflodmancc3d4422017-08-03 08:27:51 -0700832TEST_F(VideoStreamEncoderTest, SwitchSourceDeregisterEncoderAsSink) {
perkj803d97f2016-11-01 11:45:46 -0700833 EXPECT_TRUE(video_source_.has_sinks());
834 test::FrameForwarder new_video_source;
mflodmancc3d4422017-08-03 08:27:51 -0700835 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -0700836 &new_video_source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
perkj803d97f2016-11-01 11:45:46 -0700837 EXPECT_FALSE(video_source_.has_sinks());
838 EXPECT_TRUE(new_video_source.has_sinks());
839
mflodmancc3d4422017-08-03 08:27:51 -0700840 video_stream_encoder_->Stop();
perkj803d97f2016-11-01 11:45:46 -0700841}
842
mflodmancc3d4422017-08-03 08:27:51 -0700843TEST_F(VideoStreamEncoderTest, SinkWantsRotationApplied) {
perkj803d97f2016-11-01 11:45:46 -0700844 EXPECT_FALSE(video_source_.sink_wants().rotation_applied);
mflodmancc3d4422017-08-03 08:27:51 -0700845 video_stream_encoder_->SetSink(&sink_, true /*rotation_applied*/);
perkj803d97f2016-11-01 11:45:46 -0700846 EXPECT_TRUE(video_source_.sink_wants().rotation_applied);
mflodmancc3d4422017-08-03 08:27:51 -0700847 video_stream_encoder_->Stop();
perkj803d97f2016-11-01 11:45:46 -0700848}
849
Jonathan Yubc771b72017-12-08 17:04:29 -0800850TEST_F(VideoStreamEncoderTest, TestCpuDowngrades_BalancedMode) {
851 const int kFramerateFps = 30;
asaperssonf7e294d2017-06-13 23:25:22 -0700852 const int kWidth = 1280;
853 const int kHeight = 720;
Jonathan Yubc771b72017-12-08 17:04:29 -0800854
855 // We rely on the automatic resolution adaptation, but we handle framerate
856 // adaptation manually by mocking the stats proxy.
857 video_source_.set_adaptation_enabled(true);
asaperssonf7e294d2017-06-13 23:25:22 -0700858
Taylor Brandstetter49fcc102018-05-16 14:20:41 -0700859 // Enable BALANCED preference, no initial limitation.
Jonathan Yubc771b72017-12-08 17:04:29 -0800860 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
Taylor Brandstetter49fcc102018-05-16 14:20:41 -0700861 video_stream_encoder_->SetSource(&video_source_,
862 webrtc::DegradationPreference::BALANCED);
Jonathan Yubc771b72017-12-08 17:04:29 -0800863 VerifyNoLimitation(video_source_.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -0700864 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
Jonathan Yubc771b72017-12-08 17:04:29 -0800865 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
asaperssonf7e294d2017-06-13 23:25:22 -0700866 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
867
Jonathan Yubc771b72017-12-08 17:04:29 -0800868 // Adapt down as far as possible.
869 rtc::VideoSinkWants last_wants;
870 int64_t t = 1;
871 int loop_count = 0;
872 do {
873 ++loop_count;
874 last_wants = video_source_.sink_wants();
875
876 // Simulate the framerate we've been asked to adapt to.
877 const int fps = std::min(kFramerateFps, last_wants.max_framerate_fps);
878 const int frame_interval_ms = rtc::kNumMillisecsPerSec / fps;
879 VideoSendStream::Stats mock_stats = stats_proxy_->GetStats();
880 mock_stats.input_frame_rate = fps;
881 stats_proxy_->SetMockStats(mock_stats);
882
883 video_source_.IncomingCapturedFrame(CreateFrame(t, kWidth, kHeight));
884 sink_.WaitForEncodedFrame(t);
885 t += frame_interval_ms;
886
mflodmancc3d4422017-08-03 08:27:51 -0700887 video_stream_encoder_->TriggerCpuOveruse();
Jonathan Yubc771b72017-12-08 17:04:29 -0800888 VerifyBalancedModeFpsRange(
889 video_source_.sink_wants(),
890 *video_source_.last_sent_width() * *video_source_.last_sent_height());
891 } while (video_source_.sink_wants().max_pixel_count <
892 last_wants.max_pixel_count ||
893 video_source_.sink_wants().max_framerate_fps <
894 last_wants.max_framerate_fps);
asaperssonf7e294d2017-06-13 23:25:22 -0700895
Jonathan Yubc771b72017-12-08 17:04:29 -0800896 // Verify that we've adapted all the way down.
897 stats_proxy_->ResetMockStats();
asaperssonf7e294d2017-06-13 23:25:22 -0700898 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
Jonathan Yubc771b72017-12-08 17:04:29 -0800899 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_framerate);
900 EXPECT_EQ(loop_count - 1,
asaperssonf7e294d2017-06-13 23:25:22 -0700901 stats_proxy_->GetStats().number_of_cpu_adapt_changes);
Jonathan Yubc771b72017-12-08 17:04:29 -0800902 EXPECT_EQ(kMinPixelsPerFrame, *video_source_.last_sent_width() *
903 *video_source_.last_sent_height());
904 EXPECT_EQ(kMinBalancedFramerateFps,
905 video_source_.sink_wants().max_framerate_fps);
asaperssonf7e294d2017-06-13 23:25:22 -0700906
Jonathan Yubc771b72017-12-08 17:04:29 -0800907 // Adapt back up the same number of times we adapted down.
908 for (int i = 0; i < loop_count - 1; ++i) {
909 last_wants = video_source_.sink_wants();
910
911 // Simulate the framerate we've been asked to adapt to.
912 const int fps = std::min(kFramerateFps, last_wants.max_framerate_fps);
913 const int frame_interval_ms = rtc::kNumMillisecsPerSec / fps;
914 VideoSendStream::Stats mock_stats = stats_proxy_->GetStats();
915 mock_stats.input_frame_rate = fps;
916 stats_proxy_->SetMockStats(mock_stats);
917
918 video_source_.IncomingCapturedFrame(CreateFrame(t, kWidth, kHeight));
919 sink_.WaitForEncodedFrame(t);
920 t += frame_interval_ms;
921
mflodmancc3d4422017-08-03 08:27:51 -0700922 video_stream_encoder_->TriggerCpuNormalUsage();
Jonathan Yubc771b72017-12-08 17:04:29 -0800923 VerifyBalancedModeFpsRange(
924 video_source_.sink_wants(),
925 *video_source_.last_sent_width() * *video_source_.last_sent_height());
926 EXPECT_TRUE(video_source_.sink_wants().max_pixel_count >
927 last_wants.max_pixel_count ||
928 video_source_.sink_wants().max_framerate_fps >
929 last_wants.max_framerate_fps);
asaperssonf7e294d2017-06-13 23:25:22 -0700930 }
931
Jonathan Yubc771b72017-12-08 17:04:29 -0800932 VerifyNoLimitation(video_source_.sink_wants());
933 stats_proxy_->ResetMockStats();
asaperssonf7e294d2017-06-13 23:25:22 -0700934 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
Jonathan Yubc771b72017-12-08 17:04:29 -0800935 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
936 EXPECT_EQ((loop_count - 1) * 2,
937 stats_proxy_->GetStats().number_of_cpu_adapt_changes);
asaperssonf7e294d2017-06-13 23:25:22 -0700938
mflodmancc3d4422017-08-03 08:27:51 -0700939 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -0700940}
mflodmancc3d4422017-08-03 08:27:51 -0700941TEST_F(VideoStreamEncoderTest, SinkWantsStoredByDegradationPreference) {
942 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson02465b82017-04-10 01:12:52 -0700943 VerifyNoLimitation(video_source_.sink_wants());
perkj803d97f2016-11-01 11:45:46 -0700944
sprangc5d62e22017-04-02 23:53:04 -0700945 const int kFrameWidth = 1280;
946 const int kFrameHeight = 720;
947 const int kFrameIntervalMs = 1000 / 30;
948
949 int frame_timestamp = 1;
perkj803d97f2016-11-01 11:45:46 -0700950
kthelgason5e13d412016-12-01 03:59:51 -0800951 video_source_.IncomingCapturedFrame(
sprangc5d62e22017-04-02 23:53:04 -0700952 CreateFrame(frame_timestamp, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -0700953 WaitForEncodedFrame(frame_timestamp);
sprangc5d62e22017-04-02 23:53:04 -0700954 frame_timestamp += kFrameIntervalMs;
955
perkj803d97f2016-11-01 11:45:46 -0700956 // Trigger CPU overuse.
mflodmancc3d4422017-08-03 08:27:51 -0700957 video_stream_encoder_->TriggerCpuOveruse();
perkj803d97f2016-11-01 11:45:46 -0700958 video_source_.IncomingCapturedFrame(
sprangc5d62e22017-04-02 23:53:04 -0700959 CreateFrame(frame_timestamp, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -0700960 WaitForEncodedFrame(frame_timestamp);
sprangc5d62e22017-04-02 23:53:04 -0700961 frame_timestamp += kFrameIntervalMs;
sprang3ea3c772017-03-30 07:23:48 -0700962
asapersson0944a802017-04-07 00:57:58 -0700963 // Default degradation preference is maintain-framerate, so will lower max
sprangc5d62e22017-04-02 23:53:04 -0700964 // wanted resolution.
965 EXPECT_FALSE(video_source_.sink_wants().target_pixel_count);
966 EXPECT_LT(video_source_.sink_wants().max_pixel_count,
967 kFrameWidth * kFrameHeight);
968 EXPECT_EQ(std::numeric_limits<int>::max(),
969 video_source_.sink_wants().max_framerate_fps);
970
971 // Set new source, switch to maintain-resolution.
perkj803d97f2016-11-01 11:45:46 -0700972 test::FrameForwarder new_video_source;
mflodmancc3d4422017-08-03 08:27:51 -0700973 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -0700974 &new_video_source, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
perkj803d97f2016-11-01 11:45:46 -0700975
sprangc5d62e22017-04-02 23:53:04 -0700976 // Initially no degradation registered.
asapersson02465b82017-04-10 01:12:52 -0700977 VerifyNoLimitation(new_video_source.sink_wants());
perkj803d97f2016-11-01 11:45:46 -0700978
sprangc5d62e22017-04-02 23:53:04 -0700979 // Force an input frame rate to be available, or the adaptation call won't
980 // know what framerate to adapt form.
asapersson02465b82017-04-10 01:12:52 -0700981 const int kInputFps = 30;
sprangc5d62e22017-04-02 23:53:04 -0700982 VideoSendStream::Stats stats = stats_proxy_->GetStats();
asapersson02465b82017-04-10 01:12:52 -0700983 stats.input_frame_rate = kInputFps;
sprangc5d62e22017-04-02 23:53:04 -0700984 stats_proxy_->SetMockStats(stats);
985
mflodmancc3d4422017-08-03 08:27:51 -0700986 video_stream_encoder_->TriggerCpuOveruse();
perkj803d97f2016-11-01 11:45:46 -0700987 new_video_source.IncomingCapturedFrame(
sprangc5d62e22017-04-02 23:53:04 -0700988 CreateFrame(frame_timestamp, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -0700989 WaitForEncodedFrame(frame_timestamp);
sprangc5d62e22017-04-02 23:53:04 -0700990 frame_timestamp += kFrameIntervalMs;
991
992 // Some framerate constraint should be set.
sprang84a37592017-02-10 07:04:27 -0800993 EXPECT_FALSE(new_video_source.sink_wants().target_pixel_count);
sprangc5d62e22017-04-02 23:53:04 -0700994 EXPECT_EQ(std::numeric_limits<int>::max(),
995 new_video_source.sink_wants().max_pixel_count);
asapersson02465b82017-04-10 01:12:52 -0700996 EXPECT_LT(new_video_source.sink_wants().max_framerate_fps, kInputFps);
sprangc5d62e22017-04-02 23:53:04 -0700997
asapersson02465b82017-04-10 01:12:52 -0700998 // Turn off degradation completely.
Taylor Brandstetter49fcc102018-05-16 14:20:41 -0700999 video_stream_encoder_->SetSource(&new_video_source,
1000 webrtc::DegradationPreference::DISABLED);
asapersson02465b82017-04-10 01:12:52 -07001001 VerifyNoLimitation(new_video_source.sink_wants());
sprangc5d62e22017-04-02 23:53:04 -07001002
mflodmancc3d4422017-08-03 08:27:51 -07001003 video_stream_encoder_->TriggerCpuOveruse();
sprangc5d62e22017-04-02 23:53:04 -07001004 new_video_source.IncomingCapturedFrame(
1005 CreateFrame(frame_timestamp, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07001006 WaitForEncodedFrame(frame_timestamp);
sprangc5d62e22017-04-02 23:53:04 -07001007 frame_timestamp += kFrameIntervalMs;
1008
1009 // Still no degradation.
asapersson02465b82017-04-10 01:12:52 -07001010 VerifyNoLimitation(new_video_source.sink_wants());
perkj803d97f2016-11-01 11:45:46 -07001011
1012 // Calling SetSource with resolution scaling enabled apply the old SinkWants.
mflodmancc3d4422017-08-03 08:27:51 -07001013 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001014 &new_video_source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
sprangc5d62e22017-04-02 23:53:04 -07001015 EXPECT_LT(new_video_source.sink_wants().max_pixel_count,
1016 kFrameWidth * kFrameHeight);
sprang84a37592017-02-10 07:04:27 -08001017 EXPECT_FALSE(new_video_source.sink_wants().target_pixel_count);
sprangc5d62e22017-04-02 23:53:04 -07001018 EXPECT_EQ(std::numeric_limits<int>::max(),
1019 new_video_source.sink_wants().max_framerate_fps);
1020
1021 // Calling SetSource with framerate scaling enabled apply the old SinkWants.
mflodmancc3d4422017-08-03 08:27:51 -07001022 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001023 &new_video_source, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
sprangc5d62e22017-04-02 23:53:04 -07001024 EXPECT_FALSE(new_video_source.sink_wants().target_pixel_count);
1025 EXPECT_EQ(std::numeric_limits<int>::max(),
1026 new_video_source.sink_wants().max_pixel_count);
asapersson02465b82017-04-10 01:12:52 -07001027 EXPECT_LT(new_video_source.sink_wants().max_framerate_fps, kInputFps);
perkj803d97f2016-11-01 11:45:46 -07001028
mflodmancc3d4422017-08-03 08:27:51 -07001029 video_stream_encoder_->Stop();
perkj803d97f2016-11-01 11:45:46 -07001030}
1031
mflodmancc3d4422017-08-03 08:27:51 -07001032TEST_F(VideoStreamEncoderTest, StatsTracksQualityAdaptationStats) {
1033 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkj803d97f2016-11-01 11:45:46 -07001034
asaperssonfab67072017-04-04 05:51:49 -07001035 const int kWidth = 1280;
1036 const int kHeight = 720;
asaperssonfab67072017-04-04 05:51:49 -07001037 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001038 WaitForEncodedFrame(1);
asaperssonfab67072017-04-04 05:51:49 -07001039 VideoSendStream::Stats stats = stats_proxy_->GetStats();
1040 EXPECT_FALSE(stats.bw_limited_resolution);
1041 EXPECT_EQ(0, stats.number_of_quality_adapt_changes);
1042
1043 // Trigger adapt down.
mflodmancc3d4422017-08-03 08:27:51 -07001044 video_stream_encoder_->TriggerQualityLow();
asaperssonfab67072017-04-04 05:51:49 -07001045 video_source_.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001046 WaitForEncodedFrame(2);
asaperssonfab67072017-04-04 05:51:49 -07001047
1048 stats = stats_proxy_->GetStats();
1049 EXPECT_TRUE(stats.bw_limited_resolution);
1050 EXPECT_EQ(1, stats.number_of_quality_adapt_changes);
1051
1052 // Trigger adapt up.
mflodmancc3d4422017-08-03 08:27:51 -07001053 video_stream_encoder_->TriggerQualityHigh();
asaperssonfab67072017-04-04 05:51:49 -07001054 video_source_.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001055 WaitForEncodedFrame(3);
asaperssonfab67072017-04-04 05:51:49 -07001056
1057 stats = stats_proxy_->GetStats();
1058 EXPECT_FALSE(stats.bw_limited_resolution);
1059 EXPECT_EQ(2, stats.number_of_quality_adapt_changes);
1060 EXPECT_EQ(0, stats.number_of_cpu_adapt_changes);
1061
mflodmancc3d4422017-08-03 08:27:51 -07001062 video_stream_encoder_->Stop();
asaperssonfab67072017-04-04 05:51:49 -07001063}
1064
mflodmancc3d4422017-08-03 08:27:51 -07001065TEST_F(VideoStreamEncoderTest, StatsTracksCpuAdaptationStats) {
1066 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonfab67072017-04-04 05:51:49 -07001067
1068 const int kWidth = 1280;
1069 const int kHeight = 720;
asaperssonfab67072017-04-04 05:51:49 -07001070 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001071 WaitForEncodedFrame(1);
perkj803d97f2016-11-01 11:45:46 -07001072 VideoSendStream::Stats stats = stats_proxy_->GetStats();
1073 EXPECT_FALSE(stats.cpu_limited_resolution);
1074 EXPECT_EQ(0, stats.number_of_cpu_adapt_changes);
1075
1076 // Trigger CPU overuse.
mflodmancc3d4422017-08-03 08:27:51 -07001077 video_stream_encoder_->TriggerCpuOveruse();
asaperssonfab67072017-04-04 05:51:49 -07001078 video_source_.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001079 WaitForEncodedFrame(2);
perkj803d97f2016-11-01 11:45:46 -07001080
1081 stats = stats_proxy_->GetStats();
1082 EXPECT_TRUE(stats.cpu_limited_resolution);
1083 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1084
1085 // Trigger CPU normal use.
mflodmancc3d4422017-08-03 08:27:51 -07001086 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssonfab67072017-04-04 05:51:49 -07001087 video_source_.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001088 WaitForEncodedFrame(3);
perkj803d97f2016-11-01 11:45:46 -07001089
1090 stats = stats_proxy_->GetStats();
1091 EXPECT_FALSE(stats.cpu_limited_resolution);
1092 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
asaperssonfab67072017-04-04 05:51:49 -07001093 EXPECT_EQ(0, stats.number_of_quality_adapt_changes);
perkj803d97f2016-11-01 11:45:46 -07001094
mflodmancc3d4422017-08-03 08:27:51 -07001095 video_stream_encoder_->Stop();
perkj803d97f2016-11-01 11:45:46 -07001096}
1097
mflodmancc3d4422017-08-03 08:27:51 -07001098TEST_F(VideoStreamEncoderTest, SwitchingSourceKeepsCpuAdaptation) {
1099 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
kthelgason876222f2016-11-29 01:44:11 -08001100
asaperssonfab67072017-04-04 05:51:49 -07001101 const int kWidth = 1280;
1102 const int kHeight = 720;
1103 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001104 WaitForEncodedFrame(1);
kthelgason876222f2016-11-29 01:44:11 -08001105 VideoSendStream::Stats stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001106 EXPECT_FALSE(stats.bw_limited_resolution);
kthelgason876222f2016-11-29 01:44:11 -08001107 EXPECT_FALSE(stats.cpu_limited_resolution);
1108 EXPECT_EQ(0, stats.number_of_cpu_adapt_changes);
1109
asaperssonfab67072017-04-04 05:51:49 -07001110 // Trigger CPU overuse.
mflodmancc3d4422017-08-03 08:27:51 -07001111 video_stream_encoder_->TriggerCpuOveruse();
asaperssonfab67072017-04-04 05:51:49 -07001112 video_source_.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001113 WaitForEncodedFrame(2);
kthelgason876222f2016-11-29 01:44:11 -08001114 stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001115 EXPECT_FALSE(stats.bw_limited_resolution);
kthelgason876222f2016-11-29 01:44:11 -08001116 EXPECT_TRUE(stats.cpu_limited_resolution);
1117 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1118
1119 // Set new source with adaptation still enabled.
1120 test::FrameForwarder new_video_source;
mflodmancc3d4422017-08-03 08:27:51 -07001121 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001122 &new_video_source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
kthelgason876222f2016-11-29 01:44:11 -08001123
asaperssonfab67072017-04-04 05:51:49 -07001124 new_video_source.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001125 WaitForEncodedFrame(3);
kthelgason876222f2016-11-29 01:44:11 -08001126 stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001127 EXPECT_FALSE(stats.bw_limited_resolution);
kthelgason876222f2016-11-29 01:44:11 -08001128 EXPECT_TRUE(stats.cpu_limited_resolution);
1129 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1130
1131 // Set adaptation disabled.
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001132 video_stream_encoder_->SetSource(&new_video_source,
1133 webrtc::DegradationPreference::DISABLED);
kthelgason876222f2016-11-29 01:44:11 -08001134
asaperssonfab67072017-04-04 05:51:49 -07001135 new_video_source.IncomingCapturedFrame(CreateFrame(4, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001136 WaitForEncodedFrame(4);
kthelgason876222f2016-11-29 01:44:11 -08001137 stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001138 EXPECT_FALSE(stats.bw_limited_resolution);
kthelgason876222f2016-11-29 01:44:11 -08001139 EXPECT_FALSE(stats.cpu_limited_resolution);
1140 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1141
1142 // Set adaptation back to enabled.
mflodmancc3d4422017-08-03 08:27:51 -07001143 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001144 &new_video_source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
kthelgason876222f2016-11-29 01:44:11 -08001145
asaperssonfab67072017-04-04 05:51:49 -07001146 new_video_source.IncomingCapturedFrame(CreateFrame(5, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001147 WaitForEncodedFrame(5);
kthelgason876222f2016-11-29 01:44:11 -08001148 stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001149 EXPECT_FALSE(stats.bw_limited_resolution);
kthelgason876222f2016-11-29 01:44:11 -08001150 EXPECT_TRUE(stats.cpu_limited_resolution);
1151 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1152
asaperssonfab67072017-04-04 05:51:49 -07001153 // Trigger CPU normal use.
mflodmancc3d4422017-08-03 08:27:51 -07001154 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssonfab67072017-04-04 05:51:49 -07001155 new_video_source.IncomingCapturedFrame(CreateFrame(6, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001156 WaitForEncodedFrame(6);
kthelgason876222f2016-11-29 01:44:11 -08001157 stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001158 EXPECT_FALSE(stats.bw_limited_resolution);
kthelgason876222f2016-11-29 01:44:11 -08001159 EXPECT_FALSE(stats.cpu_limited_resolution);
1160 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
asapersson02465b82017-04-10 01:12:52 -07001161 EXPECT_EQ(0, stats.number_of_quality_adapt_changes);
kthelgason876222f2016-11-29 01:44:11 -08001162
mflodmancc3d4422017-08-03 08:27:51 -07001163 video_stream_encoder_->Stop();
kthelgason876222f2016-11-29 01:44:11 -08001164}
1165
mflodmancc3d4422017-08-03 08:27:51 -07001166TEST_F(VideoStreamEncoderTest, SwitchingSourceKeepsQualityAdaptation) {
1167 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
kthelgason876222f2016-11-29 01:44:11 -08001168
asaperssonfab67072017-04-04 05:51:49 -07001169 const int kWidth = 1280;
1170 const int kHeight = 720;
1171 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001172 WaitForEncodedFrame(1);
kthelgason876222f2016-11-29 01:44:11 -08001173 VideoSendStream::Stats stats = stats_proxy_->GetStats();
kthelgason876222f2016-11-29 01:44:11 -08001174 EXPECT_FALSE(stats.bw_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001175 EXPECT_FALSE(stats.bw_limited_framerate);
asaperssonfab67072017-04-04 05:51:49 -07001176 EXPECT_EQ(0, stats.number_of_quality_adapt_changes);
kthelgason876222f2016-11-29 01:44:11 -08001177
1178 // Set new source with adaptation still enabled.
1179 test::FrameForwarder new_video_source;
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001180 video_stream_encoder_->SetSource(&new_video_source,
1181 webrtc::DegradationPreference::BALANCED);
kthelgason876222f2016-11-29 01:44:11 -08001182
asaperssonfab67072017-04-04 05:51:49 -07001183 new_video_source.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001184 WaitForEncodedFrame(2);
kthelgason876222f2016-11-29 01:44:11 -08001185 stats = stats_proxy_->GetStats();
kthelgason876222f2016-11-29 01:44:11 -08001186 EXPECT_FALSE(stats.bw_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001187 EXPECT_FALSE(stats.bw_limited_framerate);
asaperssonfab67072017-04-04 05:51:49 -07001188 EXPECT_EQ(0, stats.number_of_quality_adapt_changes);
kthelgason876222f2016-11-29 01:44:11 -08001189
asaperssonfab67072017-04-04 05:51:49 -07001190 // Trigger adapt down.
mflodmancc3d4422017-08-03 08:27:51 -07001191 video_stream_encoder_->TriggerQualityLow();
asaperssonfab67072017-04-04 05:51:49 -07001192 new_video_source.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001193 WaitForEncodedFrame(3);
kthelgason876222f2016-11-29 01:44:11 -08001194 stats = stats_proxy_->GetStats();
kthelgason876222f2016-11-29 01:44:11 -08001195 EXPECT_TRUE(stats.bw_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001196 EXPECT_FALSE(stats.bw_limited_framerate);
asaperssonfab67072017-04-04 05:51:49 -07001197 EXPECT_EQ(1, stats.number_of_quality_adapt_changes);
kthelgason876222f2016-11-29 01:44:11 -08001198
asaperssonfab67072017-04-04 05:51:49 -07001199 // Set new source with adaptation still enabled.
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001200 video_stream_encoder_->SetSource(&new_video_source,
1201 webrtc::DegradationPreference::BALANCED);
kthelgason876222f2016-11-29 01:44:11 -08001202
asaperssonfab67072017-04-04 05:51:49 -07001203 new_video_source.IncomingCapturedFrame(CreateFrame(4, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001204 WaitForEncodedFrame(4);
kthelgason876222f2016-11-29 01:44:11 -08001205 stats = stats_proxy_->GetStats();
kthelgason876222f2016-11-29 01:44:11 -08001206 EXPECT_TRUE(stats.bw_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001207 EXPECT_FALSE(stats.bw_limited_framerate);
asaperssonfab67072017-04-04 05:51:49 -07001208 EXPECT_EQ(1, stats.number_of_quality_adapt_changes);
kthelgason876222f2016-11-29 01:44:11 -08001209
asapersson02465b82017-04-10 01:12:52 -07001210 // Disable resolution scaling.
mflodmancc3d4422017-08-03 08:27:51 -07001211 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001212 &new_video_source, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
kthelgason876222f2016-11-29 01:44:11 -08001213
asaperssonfab67072017-04-04 05:51:49 -07001214 new_video_source.IncomingCapturedFrame(CreateFrame(5, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001215 WaitForEncodedFrame(5);
kthelgason876222f2016-11-29 01:44:11 -08001216 stats = stats_proxy_->GetStats();
kthelgason876222f2016-11-29 01:44:11 -08001217 EXPECT_FALSE(stats.bw_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001218 EXPECT_FALSE(stats.bw_limited_framerate);
asaperssonfab67072017-04-04 05:51:49 -07001219 EXPECT_EQ(1, stats.number_of_quality_adapt_changes);
1220 EXPECT_EQ(0, stats.number_of_cpu_adapt_changes);
kthelgason876222f2016-11-29 01:44:11 -08001221
mflodmancc3d4422017-08-03 08:27:51 -07001222 video_stream_encoder_->Stop();
kthelgason876222f2016-11-29 01:44:11 -08001223}
1224
mflodmancc3d4422017-08-03 08:27:51 -07001225TEST_F(VideoStreamEncoderTest,
1226 QualityAdaptationStatsAreResetWhenScalerIsDisabled) {
1227 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson36e9eb42017-03-31 05:29:12 -07001228
1229 const int kWidth = 1280;
1230 const int kHeight = 720;
1231 video_source_.set_adaptation_enabled(true);
1232 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001233 WaitForEncodedFrame(1);
asapersson36e9eb42017-03-31 05:29:12 -07001234 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1235 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1236 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1237
1238 // Trigger adapt down.
mflodmancc3d4422017-08-03 08:27:51 -07001239 video_stream_encoder_->TriggerQualityLow();
asapersson36e9eb42017-03-31 05:29:12 -07001240 video_source_.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001241 WaitForEncodedFrame(2);
asapersson36e9eb42017-03-31 05:29:12 -07001242 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1243 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1244 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1245
1246 // Trigger overuse.
mflodmancc3d4422017-08-03 08:27:51 -07001247 video_stream_encoder_->TriggerCpuOveruse();
asapersson36e9eb42017-03-31 05:29:12 -07001248 video_source_.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001249 WaitForEncodedFrame(3);
asapersson36e9eb42017-03-31 05:29:12 -07001250 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1251 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1252 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1253
Niels Möller4db138e2018-04-19 09:04:13 +02001254 // Leave source unchanged, but disable quality scaler.
asapersson36e9eb42017-03-31 05:29:12 -07001255 fake_encoder_.SetQualityScaling(false);
Niels Möller4db138e2018-04-19 09:04:13 +02001256
1257 VideoEncoderConfig video_encoder_config;
1258 test::FillEncoderConfiguration(kVideoCodecVP8, 1, &video_encoder_config);
1259 // Make format different, to force recreation of encoder.
1260 video_encoder_config.video_format.parameters["foo"] = "foo";
1261 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
Niels Möllerf1338562018-04-26 09:51:47 +02001262 kMaxPayloadLength);
asapersson36e9eb42017-03-31 05:29:12 -07001263
1264 video_source_.IncomingCapturedFrame(CreateFrame(4, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001265 WaitForEncodedFrame(4);
asapersson36e9eb42017-03-31 05:29:12 -07001266 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1267 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1268 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1269
mflodmancc3d4422017-08-03 08:27:51 -07001270 video_stream_encoder_->Stop();
asapersson36e9eb42017-03-31 05:29:12 -07001271}
1272
mflodmancc3d4422017-08-03 08:27:51 -07001273TEST_F(VideoStreamEncoderTest,
1274 StatsTracksCpuAdaptationStatsWhenSwitchingSource) {
1275 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkj803d97f2016-11-01 11:45:46 -07001276
asapersson0944a802017-04-07 00:57:58 -07001277 const int kWidth = 1280;
1278 const int kHeight = 720;
sprang84a37592017-02-10 07:04:27 -08001279 int sequence = 1;
perkj803d97f2016-11-01 11:45:46 -07001280
asaperssonfab67072017-04-04 05:51:49 -07001281 video_source_.IncomingCapturedFrame(CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001282 WaitForEncodedFrame(sequence++);
perkj803d97f2016-11-01 11:45:46 -07001283 VideoSendStream::Stats stats = stats_proxy_->GetStats();
sprang84a37592017-02-10 07:04:27 -08001284 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001285 EXPECT_FALSE(stats.cpu_limited_framerate);
sprang84a37592017-02-10 07:04:27 -08001286 EXPECT_EQ(0, stats.number_of_cpu_adapt_changes);
1287
asapersson02465b82017-04-10 01:12:52 -07001288 // Trigger CPU overuse, should now adapt down.
mflodmancc3d4422017-08-03 08:27:51 -07001289 video_stream_encoder_->TriggerCpuOveruse();
asaperssonfab67072017-04-04 05:51:49 -07001290 video_source_.IncomingCapturedFrame(CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001291 WaitForEncodedFrame(sequence++);
sprang84a37592017-02-10 07:04:27 -08001292 stats = stats_proxy_->GetStats();
perkj803d97f2016-11-01 11:45:46 -07001293 EXPECT_TRUE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001294 EXPECT_FALSE(stats.cpu_limited_framerate);
perkj803d97f2016-11-01 11:45:46 -07001295 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1296
1297 // Set new source with adaptation still enabled.
1298 test::FrameForwarder new_video_source;
mflodmancc3d4422017-08-03 08:27:51 -07001299 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001300 &new_video_source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
perkj803d97f2016-11-01 11:45:46 -07001301
1302 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001303 CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001304 WaitForEncodedFrame(sequence++);
perkj803d97f2016-11-01 11:45:46 -07001305 stats = stats_proxy_->GetStats();
1306 EXPECT_TRUE(stats.cpu_limited_resolution);
asapersson09f05612017-05-15 23:40:18 -07001307 EXPECT_FALSE(stats.cpu_limited_framerate);
perkj803d97f2016-11-01 11:45:46 -07001308 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1309
sprangc5d62e22017-04-02 23:53:04 -07001310 // Set cpu adaptation by frame dropping.
mflodmancc3d4422017-08-03 08:27:51 -07001311 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001312 &new_video_source, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
perkj803d97f2016-11-01 11:45:46 -07001313 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001314 CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001315 WaitForEncodedFrame(sequence++);
perkj803d97f2016-11-01 11:45:46 -07001316 stats = stats_proxy_->GetStats();
sprangc5d62e22017-04-02 23:53:04 -07001317 // Not adapted at first.
perkj803d97f2016-11-01 11:45:46 -07001318 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson09f05612017-05-15 23:40:18 -07001319 EXPECT_FALSE(stats.cpu_limited_framerate);
perkj803d97f2016-11-01 11:45:46 -07001320 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1321
sprangc5d62e22017-04-02 23:53:04 -07001322 // Force an input frame rate to be available, or the adaptation call won't
asapersson09f05612017-05-15 23:40:18 -07001323 // know what framerate to adapt from.
sprangc5d62e22017-04-02 23:53:04 -07001324 VideoSendStream::Stats mock_stats = stats_proxy_->GetStats();
1325 mock_stats.input_frame_rate = 30;
1326 stats_proxy_->SetMockStats(mock_stats);
mflodmancc3d4422017-08-03 08:27:51 -07001327 video_stream_encoder_->TriggerCpuOveruse();
sprangc5d62e22017-04-02 23:53:04 -07001328 stats_proxy_->ResetMockStats();
1329
1330 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001331 CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001332 WaitForEncodedFrame(sequence++);
sprangc5d62e22017-04-02 23:53:04 -07001333
1334 // Framerate now adapted.
1335 stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001336 EXPECT_FALSE(stats.cpu_limited_resolution);
1337 EXPECT_TRUE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001338 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
1339
1340 // Disable CPU adaptation.
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001341 video_stream_encoder_->SetSource(&new_video_source,
1342 webrtc::DegradationPreference::DISABLED);
sprangc5d62e22017-04-02 23:53:04 -07001343 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001344 CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001345 WaitForEncodedFrame(sequence++);
sprangc5d62e22017-04-02 23:53:04 -07001346
1347 stats = stats_proxy_->GetStats();
1348 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001349 EXPECT_FALSE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001350 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
1351
1352 // Try to trigger overuse. Should not succeed.
1353 stats_proxy_->SetMockStats(mock_stats);
mflodmancc3d4422017-08-03 08:27:51 -07001354 video_stream_encoder_->TriggerCpuOveruse();
sprangc5d62e22017-04-02 23:53:04 -07001355 stats_proxy_->ResetMockStats();
1356
1357 stats = stats_proxy_->GetStats();
1358 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001359 EXPECT_FALSE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001360 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
1361
1362 // Switch back the source with resolution adaptation enabled.
mflodmancc3d4422017-08-03 08:27:51 -07001363 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001364 &video_source_, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
asaperssonfab67072017-04-04 05:51:49 -07001365 video_source_.IncomingCapturedFrame(CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001366 WaitForEncodedFrame(sequence++);
perkj803d97f2016-11-01 11:45:46 -07001367 stats = stats_proxy_->GetStats();
1368 EXPECT_TRUE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001369 EXPECT_FALSE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001370 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
perkj803d97f2016-11-01 11:45:46 -07001371
1372 // Trigger CPU normal usage.
mflodmancc3d4422017-08-03 08:27:51 -07001373 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssonfab67072017-04-04 05:51:49 -07001374 video_source_.IncomingCapturedFrame(CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001375 WaitForEncodedFrame(sequence++);
perkj803d97f2016-11-01 11:45:46 -07001376 stats = stats_proxy_->GetStats();
1377 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001378 EXPECT_FALSE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001379 EXPECT_EQ(3, stats.number_of_cpu_adapt_changes);
1380
1381 // Back to the source with adaptation off, set it back to maintain-resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001382 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001383 &new_video_source, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
sprangc5d62e22017-04-02 23:53:04 -07001384 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001385 CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001386 WaitForEncodedFrame(sequence++);
sprangc5d62e22017-04-02 23:53:04 -07001387 stats = stats_proxy_->GetStats();
asapersson13874762017-06-07 00:01:02 -07001388 // Disabled, since we previously switched the source to disabled.
sprangc5d62e22017-04-02 23:53:04 -07001389 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001390 EXPECT_TRUE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001391 EXPECT_EQ(3, stats.number_of_cpu_adapt_changes);
1392
1393 // Trigger CPU normal usage.
mflodmancc3d4422017-08-03 08:27:51 -07001394 video_stream_encoder_->TriggerCpuNormalUsage();
sprangc5d62e22017-04-02 23:53:04 -07001395 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001396 CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001397 WaitForEncodedFrame(sequence++);
sprangc5d62e22017-04-02 23:53:04 -07001398 stats = stats_proxy_->GetStats();
1399 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001400 EXPECT_FALSE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001401 EXPECT_EQ(4, stats.number_of_cpu_adapt_changes);
asapersson02465b82017-04-10 01:12:52 -07001402 EXPECT_EQ(0, stats.number_of_quality_adapt_changes);
perkj803d97f2016-11-01 11:45:46 -07001403
mflodmancc3d4422017-08-03 08:27:51 -07001404 video_stream_encoder_->Stop();
perkj803d97f2016-11-01 11:45:46 -07001405}
1406
mflodmancc3d4422017-08-03 08:27:51 -07001407TEST_F(VideoStreamEncoderTest,
1408 ScalingUpAndDownDoesNothingWithMaintainResolution) {
asaperssonfab67072017-04-04 05:51:49 -07001409 const int kWidth = 1280;
1410 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001411 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
kthelgason876222f2016-11-29 01:44:11 -08001412
asaperssonfab67072017-04-04 05:51:49 -07001413 // Expect no scaling to begin with.
asapersson02465b82017-04-10 01:12:52 -07001414 VerifyNoLimitation(video_source_.sink_wants());
kthelgason876222f2016-11-29 01:44:11 -08001415
asaperssonfab67072017-04-04 05:51:49 -07001416 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001417 WaitForEncodedFrame(1);
kthelgason876222f2016-11-29 01:44:11 -08001418
asaperssonfab67072017-04-04 05:51:49 -07001419 // Trigger scale down.
mflodmancc3d4422017-08-03 08:27:51 -07001420 video_stream_encoder_->TriggerQualityLow();
kthelgason5e13d412016-12-01 03:59:51 -08001421
asaperssonfab67072017-04-04 05:51:49 -07001422 video_source_.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001423 WaitForEncodedFrame(2);
kthelgason5e13d412016-12-01 03:59:51 -08001424
kthelgason876222f2016-11-29 01:44:11 -08001425 // Expect a scale down.
1426 EXPECT_TRUE(video_source_.sink_wants().max_pixel_count);
asaperssonfab67072017-04-04 05:51:49 -07001427 EXPECT_LT(video_source_.sink_wants().max_pixel_count, kWidth * kHeight);
kthelgason876222f2016-11-29 01:44:11 -08001428
asapersson02465b82017-04-10 01:12:52 -07001429 // Set resolution scaling disabled.
kthelgason876222f2016-11-29 01:44:11 -08001430 test::FrameForwarder new_video_source;
mflodmancc3d4422017-08-03 08:27:51 -07001431 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001432 &new_video_source, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
kthelgason876222f2016-11-29 01:44:11 -08001433
asaperssonfab67072017-04-04 05:51:49 -07001434 // Trigger scale down.
mflodmancc3d4422017-08-03 08:27:51 -07001435 video_stream_encoder_->TriggerQualityLow();
asaperssonfab67072017-04-04 05:51:49 -07001436 new_video_source.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001437 WaitForEncodedFrame(3);
kthelgason876222f2016-11-29 01:44:11 -08001438
asaperssonfab67072017-04-04 05:51:49 -07001439 // Expect no scaling.
sprangc5d62e22017-04-02 23:53:04 -07001440 EXPECT_EQ(std::numeric_limits<int>::max(),
1441 new_video_source.sink_wants().max_pixel_count);
kthelgason876222f2016-11-29 01:44:11 -08001442
asaperssonfab67072017-04-04 05:51:49 -07001443 // Trigger scale up.
mflodmancc3d4422017-08-03 08:27:51 -07001444 video_stream_encoder_->TriggerQualityHigh();
asaperssonfab67072017-04-04 05:51:49 -07001445 new_video_source.IncomingCapturedFrame(CreateFrame(4, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001446 WaitForEncodedFrame(4);
kthelgason876222f2016-11-29 01:44:11 -08001447
asapersson02465b82017-04-10 01:12:52 -07001448 // Expect nothing to change, still no scaling.
sprangc5d62e22017-04-02 23:53:04 -07001449 EXPECT_EQ(std::numeric_limits<int>::max(),
1450 new_video_source.sink_wants().max_pixel_count);
kthelgason876222f2016-11-29 01:44:11 -08001451
mflodmancc3d4422017-08-03 08:27:51 -07001452 video_stream_encoder_->Stop();
kthelgason876222f2016-11-29 01:44:11 -08001453}
1454
mflodmancc3d4422017-08-03 08:27:51 -07001455TEST_F(VideoStreamEncoderTest,
1456 SkipsSameAdaptDownRequest_MaintainFramerateMode) {
asapersson02465b82017-04-10 01:12:52 -07001457 const int kWidth = 1280;
1458 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001459 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson02465b82017-04-10 01:12:52 -07001460
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001461 // Enable MAINTAIN_FRAMERATE preference, no initial limitation.
asapersson02465b82017-04-10 01:12:52 -07001462 test::FrameForwarder source;
mflodmancc3d4422017-08-03 08:27:51 -07001463 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001464 &source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
asapersson02465b82017-04-10 01:12:52 -07001465
1466 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001467 WaitForEncodedFrame(1);
asapersson02465b82017-04-10 01:12:52 -07001468 VerifyNoLimitation(source.sink_wants());
1469 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1470 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1471
1472 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001473 video_stream_encoder_->TriggerCpuOveruse();
asapersson09f05612017-05-15 23:40:18 -07001474 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
asapersson02465b82017-04-10 01:12:52 -07001475 const int kLastMaxPixelCount = source.sink_wants().max_pixel_count;
1476 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1477 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1478
1479 // Trigger adapt down for same input resolution, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07001480 video_stream_encoder_->TriggerCpuOveruse();
asapersson02465b82017-04-10 01:12:52 -07001481 EXPECT_EQ(kLastMaxPixelCount, source.sink_wants().max_pixel_count);
1482 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1483 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1484
mflodmancc3d4422017-08-03 08:27:51 -07001485 video_stream_encoder_->Stop();
asapersson02465b82017-04-10 01:12:52 -07001486}
1487
mflodmancc3d4422017-08-03 08:27:51 -07001488TEST_F(VideoStreamEncoderTest, SkipsSameOrLargerAdaptDownRequest_BalancedMode) {
asaperssonf7e294d2017-06-13 23:25:22 -07001489 const int kWidth = 1280;
1490 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001491 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -07001492
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001493 // Enable BALANCED preference, no initial limitation.
asaperssonf7e294d2017-06-13 23:25:22 -07001494 test::FrameForwarder source;
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001495 video_stream_encoder_->SetSource(&source,
1496 webrtc::DegradationPreference::BALANCED);
asaperssonf7e294d2017-06-13 23:25:22 -07001497 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
1498 sink_.WaitForEncodedFrame(1);
1499 VerifyNoLimitation(source.sink_wants());
1500
1501 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001502 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07001503 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
1504 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1505 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1506 const int kLastMaxPixelCount = source.sink_wants().max_pixel_count;
1507
1508 // Trigger adapt down for same input resolution, expect no change.
1509 source.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
1510 sink_.WaitForEncodedFrame(2);
mflodmancc3d4422017-08-03 08:27:51 -07001511 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07001512 EXPECT_EQ(kLastMaxPixelCount, source.sink_wants().max_pixel_count);
1513 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1514 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1515
1516 // Trigger adapt down for larger input resolution, expect no change.
1517 source.IncomingCapturedFrame(CreateFrame(3, kWidth + 1, kHeight + 1));
1518 sink_.WaitForEncodedFrame(3);
mflodmancc3d4422017-08-03 08:27:51 -07001519 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07001520 EXPECT_EQ(kLastMaxPixelCount, source.sink_wants().max_pixel_count);
1521 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1522 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1523
mflodmancc3d4422017-08-03 08:27:51 -07001524 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07001525}
1526
mflodmancc3d4422017-08-03 08:27:51 -07001527TEST_F(VideoStreamEncoderTest,
1528 NoChangeForInitialNormalUsage_MaintainFramerateMode) {
asapersson02465b82017-04-10 01:12:52 -07001529 const int kWidth = 1280;
1530 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001531 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson02465b82017-04-10 01:12:52 -07001532
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001533 // Enable MAINTAIN_FRAMERATE preference, no initial limitation.
asapersson02465b82017-04-10 01:12:52 -07001534 test::FrameForwarder source;
mflodmancc3d4422017-08-03 08:27:51 -07001535 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001536 &source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
asapersson02465b82017-04-10 01:12:52 -07001537
1538 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001539 WaitForEncodedFrame(kWidth, kHeight);
asapersson02465b82017-04-10 01:12:52 -07001540 VerifyNoLimitation(source.sink_wants());
1541 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1542 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1543
1544 // Trigger adapt up, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07001545 video_stream_encoder_->TriggerCpuNormalUsage();
asapersson02465b82017-04-10 01:12:52 -07001546 VerifyNoLimitation(source.sink_wants());
1547 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1548 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1549
mflodmancc3d4422017-08-03 08:27:51 -07001550 video_stream_encoder_->Stop();
asapersson02465b82017-04-10 01:12:52 -07001551}
1552
mflodmancc3d4422017-08-03 08:27:51 -07001553TEST_F(VideoStreamEncoderTest,
1554 NoChangeForInitialNormalUsage_MaintainResolutionMode) {
asapersson02465b82017-04-10 01:12:52 -07001555 const int kWidth = 1280;
1556 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001557 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson02465b82017-04-10 01:12:52 -07001558
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001559 // Enable MAINTAIN_RESOLUTION preference, no initial limitation.
asapersson02465b82017-04-10 01:12:52 -07001560 test::FrameForwarder source;
mflodmancc3d4422017-08-03 08:27:51 -07001561 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001562 &source, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
asapersson02465b82017-04-10 01:12:52 -07001563
1564 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001565 WaitForEncodedFrame(kWidth, kHeight);
asapersson02465b82017-04-10 01:12:52 -07001566 VerifyNoLimitation(source.sink_wants());
asapersson09f05612017-05-15 23:40:18 -07001567 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
asapersson02465b82017-04-10 01:12:52 -07001568 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1569
1570 // Trigger adapt up, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07001571 video_stream_encoder_->TriggerCpuNormalUsage();
asapersson02465b82017-04-10 01:12:52 -07001572 VerifyNoLimitation(source.sink_wants());
asapersson09f05612017-05-15 23:40:18 -07001573 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
asapersson02465b82017-04-10 01:12:52 -07001574 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1575
mflodmancc3d4422017-08-03 08:27:51 -07001576 video_stream_encoder_->Stop();
asapersson02465b82017-04-10 01:12:52 -07001577}
1578
mflodmancc3d4422017-08-03 08:27:51 -07001579TEST_F(VideoStreamEncoderTest, NoChangeForInitialNormalUsage_BalancedMode) {
asaperssonf7e294d2017-06-13 23:25:22 -07001580 const int kWidth = 1280;
1581 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001582 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -07001583
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001584 // Enable BALANCED preference, no initial limitation.
asaperssonf7e294d2017-06-13 23:25:22 -07001585 test::FrameForwarder source;
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001586 video_stream_encoder_->SetSource(&source,
1587 webrtc::DegradationPreference::BALANCED);
asaperssonf7e294d2017-06-13 23:25:22 -07001588
1589 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
1590 sink_.WaitForEncodedFrame(kWidth, kHeight);
1591 VerifyNoLimitation(source.sink_wants());
1592 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1593 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
1594 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1595
1596 // Trigger adapt up, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07001597 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07001598 VerifyNoLimitation(source.sink_wants());
1599 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1600 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
1601 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1602
mflodmancc3d4422017-08-03 08:27:51 -07001603 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07001604}
1605
mflodmancc3d4422017-08-03 08:27:51 -07001606TEST_F(VideoStreamEncoderTest, NoChangeForInitialNormalUsage_DisabledMode) {
asapersson09f05612017-05-15 23:40:18 -07001607 const int kWidth = 1280;
1608 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001609 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson09f05612017-05-15 23:40:18 -07001610
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001611 // Enable DISABLED preference, no initial limitation.
asapersson09f05612017-05-15 23:40:18 -07001612 test::FrameForwarder source;
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001613 video_stream_encoder_->SetSource(&source,
1614 webrtc::DegradationPreference::DISABLED);
asapersson09f05612017-05-15 23:40:18 -07001615
1616 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
1617 sink_.WaitForEncodedFrame(kWidth, kHeight);
1618 VerifyNoLimitation(source.sink_wants());
1619 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1620 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
1621 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1622
1623 // Trigger adapt up, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07001624 video_stream_encoder_->TriggerQualityHigh();
asapersson09f05612017-05-15 23:40:18 -07001625 VerifyNoLimitation(source.sink_wants());
1626 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1627 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
1628 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1629
mflodmancc3d4422017-08-03 08:27:51 -07001630 video_stream_encoder_->Stop();
asapersson09f05612017-05-15 23:40:18 -07001631}
1632
mflodmancc3d4422017-08-03 08:27:51 -07001633TEST_F(VideoStreamEncoderTest,
1634 AdaptsResolutionForLowQuality_MaintainFramerateMode) {
asapersson02465b82017-04-10 01:12:52 -07001635 const int kWidth = 1280;
1636 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001637 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson02465b82017-04-10 01:12:52 -07001638
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001639 // Enable MAINTAIN_FRAMERATE preference, no initial limitation.
asapersson02465b82017-04-10 01:12:52 -07001640 AdaptingFrameForwarder source;
1641 source.set_adaptation_enabled(true);
mflodmancc3d4422017-08-03 08:27:51 -07001642 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001643 &source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
asapersson02465b82017-04-10 01:12:52 -07001644
1645 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001646 WaitForEncodedFrame(1);
asapersson02465b82017-04-10 01:12:52 -07001647 VerifyNoLimitation(source.sink_wants());
1648 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1649 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1650
1651 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001652 video_stream_encoder_->TriggerQualityLow();
asapersson02465b82017-04-10 01:12:52 -07001653 source.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001654 WaitForEncodedFrame(2);
asapersson09f05612017-05-15 23:40:18 -07001655 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
asapersson02465b82017-04-10 01:12:52 -07001656 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1657 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1658
1659 // Trigger adapt up, expect no restriction.
mflodmancc3d4422017-08-03 08:27:51 -07001660 video_stream_encoder_->TriggerQualityHigh();
asapersson02465b82017-04-10 01:12:52 -07001661 VerifyNoLimitation(source.sink_wants());
1662 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1663 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1664 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1665
mflodmancc3d4422017-08-03 08:27:51 -07001666 video_stream_encoder_->Stop();
asapersson02465b82017-04-10 01:12:52 -07001667}
1668
mflodmancc3d4422017-08-03 08:27:51 -07001669TEST_F(VideoStreamEncoderTest,
1670 AdaptsFramerateForLowQuality_MaintainResolutionMode) {
asapersson09f05612017-05-15 23:40:18 -07001671 const int kWidth = 1280;
1672 const int kHeight = 720;
1673 const int kInputFps = 30;
mflodmancc3d4422017-08-03 08:27:51 -07001674 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson09f05612017-05-15 23:40:18 -07001675
1676 VideoSendStream::Stats stats = stats_proxy_->GetStats();
1677 stats.input_frame_rate = kInputFps;
1678 stats_proxy_->SetMockStats(stats);
1679
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001680 // Expect no scaling to begin with (preference: MAINTAIN_FRAMERATE).
asapersson09f05612017-05-15 23:40:18 -07001681 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
1682 sink_.WaitForEncodedFrame(1);
1683 VerifyNoLimitation(video_source_.sink_wants());
1684
1685 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001686 video_stream_encoder_->TriggerQualityLow();
asapersson09f05612017-05-15 23:40:18 -07001687 video_source_.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
1688 sink_.WaitForEncodedFrame(2);
1689 VerifyFpsMaxResolutionLt(video_source_.sink_wants(), kWidth * kHeight);
1690
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001691 // Enable MAINTAIN_RESOLUTION preference.
asapersson09f05612017-05-15 23:40:18 -07001692 test::FrameForwarder new_video_source;
mflodmancc3d4422017-08-03 08:27:51 -07001693 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001694 &new_video_source, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
asapersson09f05612017-05-15 23:40:18 -07001695 VerifyNoLimitation(new_video_source.sink_wants());
1696
1697 // Trigger adapt down, expect reduced framerate.
mflodmancc3d4422017-08-03 08:27:51 -07001698 video_stream_encoder_->TriggerQualityLow();
asapersson09f05612017-05-15 23:40:18 -07001699 new_video_source.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
1700 sink_.WaitForEncodedFrame(3);
1701 VerifyFpsLtResolutionMax(new_video_source.sink_wants(), kInputFps);
1702
1703 // Trigger adapt up, expect no restriction.
mflodmancc3d4422017-08-03 08:27:51 -07001704 video_stream_encoder_->TriggerQualityHigh();
asapersson09f05612017-05-15 23:40:18 -07001705 VerifyNoLimitation(new_video_source.sink_wants());
1706
mflodmancc3d4422017-08-03 08:27:51 -07001707 video_stream_encoder_->Stop();
asapersson09f05612017-05-15 23:40:18 -07001708}
1709
mflodmancc3d4422017-08-03 08:27:51 -07001710TEST_F(VideoStreamEncoderTest, DoesNotScaleBelowSetResolutionLimit) {
asaperssond0de2952017-04-21 01:47:31 -07001711 const int kWidth = 1280;
1712 const int kHeight = 720;
1713 const size_t kNumFrames = 10;
1714
mflodmancc3d4422017-08-03 08:27:51 -07001715 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
kthelgason5e13d412016-12-01 03:59:51 -08001716
asaperssond0de2952017-04-21 01:47:31 -07001717 // Enable adapter, expected input resolutions when downscaling:
asapersson142fcc92017-08-17 08:58:54 -07001718 // 1280x720 -> 960x540 -> 640x360 -> 480x270 -> 320x180 (kMinPixelsPerFrame)
asaperssond0de2952017-04-21 01:47:31 -07001719 video_source_.set_adaptation_enabled(true);
1720
1721 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1722 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1723
1724 int downscales = 0;
1725 for (size_t i = 1; i <= kNumFrames; i++) {
1726 video_source_.IncomingCapturedFrame(CreateFrame(i, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001727 WaitForEncodedFrame(i);
asaperssond0de2952017-04-21 01:47:31 -07001728
asaperssonfab67072017-04-04 05:51:49 -07001729 // Trigger scale down.
asaperssond0de2952017-04-21 01:47:31 -07001730 rtc::VideoSinkWants last_wants = video_source_.sink_wants();
mflodmancc3d4422017-08-03 08:27:51 -07001731 video_stream_encoder_->TriggerQualityLow();
sprangc5d62e22017-04-02 23:53:04 -07001732 EXPECT_GE(video_source_.sink_wants().max_pixel_count, kMinPixelsPerFrame);
asaperssond0de2952017-04-21 01:47:31 -07001733
1734 if (video_source_.sink_wants().max_pixel_count < last_wants.max_pixel_count)
1735 ++downscales;
1736
1737 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1738 EXPECT_EQ(downscales,
1739 stats_proxy_->GetStats().number_of_quality_adapt_changes);
1740 EXPECT_GT(downscales, 0);
kthelgason5e13d412016-12-01 03:59:51 -08001741 }
mflodmancc3d4422017-08-03 08:27:51 -07001742 video_stream_encoder_->Stop();
asaperssond0de2952017-04-21 01:47:31 -07001743}
1744
mflodmancc3d4422017-08-03 08:27:51 -07001745TEST_F(VideoStreamEncoderTest,
asaperssond0de2952017-04-21 01:47:31 -07001746 AdaptsResolutionUpAndDownTwiceOnOveruse_MaintainFramerateMode) {
1747 const int kWidth = 1280;
1748 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001749 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssond0de2952017-04-21 01:47:31 -07001750
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001751 // Enable MAINTAIN_FRAMERATE preference, no initial limitation.
asaperssond0de2952017-04-21 01:47:31 -07001752 AdaptingFrameForwarder source;
1753 source.set_adaptation_enabled(true);
mflodmancc3d4422017-08-03 08:27:51 -07001754 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001755 &source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
asaperssond0de2952017-04-21 01:47:31 -07001756
1757 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001758 WaitForEncodedFrame(kWidth, kHeight);
asaperssond0de2952017-04-21 01:47:31 -07001759 VerifyNoLimitation(source.sink_wants());
1760 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1761 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1762
1763 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001764 video_stream_encoder_->TriggerCpuOveruse();
asaperssond0de2952017-04-21 01:47:31 -07001765 source.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001766 WaitForEncodedFrame(2);
asapersson09f05612017-05-15 23:40:18 -07001767 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
asaperssond0de2952017-04-21 01:47:31 -07001768 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1769 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1770
1771 // Trigger adapt up, expect no restriction.
mflodmancc3d4422017-08-03 08:27:51 -07001772 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssond0de2952017-04-21 01:47:31 -07001773 source.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001774 WaitForEncodedFrame(kWidth, kHeight);
asaperssond0de2952017-04-21 01:47:31 -07001775 VerifyNoLimitation(source.sink_wants());
1776 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1777 EXPECT_EQ(2, 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();
asaperssond0de2952017-04-21 01:47:31 -07001781 source.IncomingCapturedFrame(CreateFrame(4, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001782 WaitForEncodedFrame(4);
asapersson09f05612017-05-15 23:40:18 -07001783 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
asaperssond0de2952017-04-21 01:47:31 -07001784 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1785 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1786
1787 // Trigger adapt up, expect no restriction.
mflodmancc3d4422017-08-03 08:27:51 -07001788 video_stream_encoder_->TriggerCpuNormalUsage();
asapersson09f05612017-05-15 23:40:18 -07001789 source.IncomingCapturedFrame(CreateFrame(5, kWidth, kHeight));
1790 sink_.WaitForEncodedFrame(kWidth, kHeight);
asaperssond0de2952017-04-21 01:47:31 -07001791 VerifyNoLimitation(source.sink_wants());
1792 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1793 EXPECT_EQ(4, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1794
mflodmancc3d4422017-08-03 08:27:51 -07001795 video_stream_encoder_->Stop();
asaperssond0de2952017-04-21 01:47:31 -07001796}
1797
mflodmancc3d4422017-08-03 08:27:51 -07001798TEST_F(VideoStreamEncoderTest,
asaperssonf7e294d2017-06-13 23:25:22 -07001799 AdaptsResolutionUpAndDownTwiceForLowQuality_BalancedMode_NoFpsLimit) {
1800 const int kWidth = 1280;
1801 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001802 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -07001803
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001804 // Enable BALANCED preference, no initial limitation.
asaperssonf7e294d2017-06-13 23:25:22 -07001805 AdaptingFrameForwarder source;
1806 source.set_adaptation_enabled(true);
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001807 video_stream_encoder_->SetSource(&source,
1808 webrtc::DegradationPreference::BALANCED);
asaperssonf7e294d2017-06-13 23:25:22 -07001809
1810 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
1811 sink_.WaitForEncodedFrame(kWidth, kHeight);
1812 VerifyNoLimitation(source.sink_wants());
1813 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1814 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1815
1816 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001817 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07001818 source.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
1819 sink_.WaitForEncodedFrame(2);
1820 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
1821 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1822 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1823
1824 // Trigger adapt up, expect no restriction.
mflodmancc3d4422017-08-03 08:27:51 -07001825 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07001826 source.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
1827 sink_.WaitForEncodedFrame(kWidth, kHeight);
1828 VerifyNoLimitation(source.sink_wants());
1829 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1830 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1831
1832 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001833 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07001834 source.IncomingCapturedFrame(CreateFrame(4, kWidth, kHeight));
1835 sink_.WaitForEncodedFrame(4);
1836 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
1837 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1838 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1839
1840 // Trigger adapt up, expect no restriction.
mflodmancc3d4422017-08-03 08:27:51 -07001841 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07001842 source.IncomingCapturedFrame(CreateFrame(5, kWidth, kHeight));
1843 sink_.WaitForEncodedFrame(kWidth, kHeight);
1844 VerifyNoLimitation(source.sink_wants());
1845 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1846 EXPECT_EQ(4, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1847
mflodmancc3d4422017-08-03 08:27:51 -07001848 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07001849}
1850
mflodmancc3d4422017-08-03 08:27:51 -07001851TEST_F(VideoStreamEncoderTest,
asaperssond0de2952017-04-21 01:47:31 -07001852 AdaptsResolutionOnOveruseAndLowQuality_MaintainFramerateMode) {
1853 const int kWidth = 1280;
1854 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001855 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssond0de2952017-04-21 01:47:31 -07001856
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001857 // Enable MAINTAIN_FRAMERATE preference, no initial limitation.
asaperssond0de2952017-04-21 01:47:31 -07001858 AdaptingFrameForwarder source;
1859 source.set_adaptation_enabled(true);
mflodmancc3d4422017-08-03 08:27:51 -07001860 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001861 &source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
asaperssond0de2952017-04-21 01:47:31 -07001862
1863 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001864 WaitForEncodedFrame(kWidth, kHeight);
asaperssond0de2952017-04-21 01:47:31 -07001865 VerifyNoLimitation(source.sink_wants());
1866 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1867 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1868 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1869 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1870
1871 // Trigger cpu adapt down, expect scaled down resolution (960x540).
mflodmancc3d4422017-08-03 08:27:51 -07001872 video_stream_encoder_->TriggerCpuOveruse();
asaperssond0de2952017-04-21 01:47:31 -07001873 source.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001874 WaitForEncodedFrame(2);
asapersson09f05612017-05-15 23:40:18 -07001875 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
asaperssond0de2952017-04-21 01:47:31 -07001876 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1877 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1878 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1879 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1880
1881 // Trigger cpu adapt down, expect scaled down resolution (640x360).
mflodmancc3d4422017-08-03 08:27:51 -07001882 video_stream_encoder_->TriggerCpuOveruse();
asaperssond0de2952017-04-21 01:47:31 -07001883 source.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001884 WaitForEncodedFrame(3);
asapersson09f05612017-05-15 23:40:18 -07001885 VerifyFpsMaxResolutionLt(source.sink_wants(), source.last_wants());
asaperssond0de2952017-04-21 01:47:31 -07001886 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1887 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1888 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1889 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1890
Jonathan Yubc771b72017-12-08 17:04:29 -08001891 // Trigger cpu adapt down, expect scaled down resolution (480x270).
mflodmancc3d4422017-08-03 08:27:51 -07001892 video_stream_encoder_->TriggerCpuOveruse();
asaperssond0de2952017-04-21 01:47:31 -07001893 source.IncomingCapturedFrame(CreateFrame(4, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001894 WaitForEncodedFrame(4);
Jonathan Yubc771b72017-12-08 17:04:29 -08001895 VerifyFpsMaxResolutionLt(source.sink_wants(), source.last_wants());
asaperssond0de2952017-04-21 01:47:31 -07001896 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1897 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
Jonathan Yubc771b72017-12-08 17:04:29 -08001898 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
asaperssond0de2952017-04-21 01:47:31 -07001899 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1900
Jonathan Yubc771b72017-12-08 17:04:29 -08001901 // Trigger quality adapt down, expect scaled down resolution (320x180).
mflodmancc3d4422017-08-03 08:27:51 -07001902 video_stream_encoder_->TriggerQualityLow();
asaperssond0de2952017-04-21 01:47:31 -07001903 source.IncomingCapturedFrame(CreateFrame(5, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001904 WaitForEncodedFrame(5);
asapersson09f05612017-05-15 23:40:18 -07001905 VerifyFpsMaxResolutionLt(source.sink_wants(), source.last_wants());
Jonathan Yubc771b72017-12-08 17:04:29 -08001906 rtc::VideoSinkWants last_wants = source.sink_wants();
asaperssond0de2952017-04-21 01:47:31 -07001907 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1908 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1909 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1910 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1911
Jonathan Yubc771b72017-12-08 17:04:29 -08001912 // Trigger quality adapt down, expect no change (min resolution reached).
1913 video_stream_encoder_->TriggerQualityLow();
1914 source.IncomingCapturedFrame(CreateFrame(6, kWidth, kHeight));
1915 WaitForEncodedFrame(6);
1916 VerifyFpsMaxResolutionEq(source.sink_wants(), last_wants);
1917 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1918 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1919 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1920 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1921
1922 // Trigger cpu adapt up, expect upscaled resolution (480x270).
mflodmancc3d4422017-08-03 08:27:51 -07001923 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssond0de2952017-04-21 01:47:31 -07001924 source.IncomingCapturedFrame(CreateFrame(7, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001925 WaitForEncodedFrame(7);
asapersson09f05612017-05-15 23:40:18 -07001926 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
Jonathan Yubc771b72017-12-08 17:04:29 -08001927 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1928 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1929 EXPECT_EQ(4, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1930 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1931
1932 // Trigger cpu adapt up, expect upscaled resolution (640x360).
1933 video_stream_encoder_->TriggerCpuNormalUsage();
1934 source.IncomingCapturedFrame(CreateFrame(8, kWidth, kHeight));
1935 WaitForEncodedFrame(8);
1936 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
1937 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1938 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1939 EXPECT_EQ(5, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1940 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1941
1942 // Trigger cpu adapt up, expect upscaled resolution (960x540).
1943 video_stream_encoder_->TriggerCpuNormalUsage();
1944 source.IncomingCapturedFrame(CreateFrame(9, kWidth, kHeight));
1945 WaitForEncodedFrame(9);
1946 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
asaperssond0de2952017-04-21 01:47:31 -07001947 last_wants = source.sink_wants();
1948 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1949 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
Jonathan Yubc771b72017-12-08 17:04:29 -08001950 EXPECT_EQ(6, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
asaperssond0de2952017-04-21 01:47:31 -07001951 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1952
1953 // Trigger cpu adapt up, no cpu downgrades, expect no change (960x540).
mflodmancc3d4422017-08-03 08:27:51 -07001954 video_stream_encoder_->TriggerCpuNormalUsage();
Jonathan Yubc771b72017-12-08 17:04:29 -08001955 source.IncomingCapturedFrame(CreateFrame(10, kWidth, kHeight));
1956 WaitForEncodedFrame(10);
asapersson09f05612017-05-15 23:40:18 -07001957 VerifyFpsEqResolutionEq(source.sink_wants(), last_wants);
asaperssond0de2952017-04-21 01:47:31 -07001958 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1959 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
Jonathan Yubc771b72017-12-08 17:04:29 -08001960 EXPECT_EQ(6, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
asaperssond0de2952017-04-21 01:47:31 -07001961 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1962
1963 // Trigger quality adapt up, expect no restriction (1280x720).
mflodmancc3d4422017-08-03 08:27:51 -07001964 video_stream_encoder_->TriggerQualityHigh();
Jonathan Yubc771b72017-12-08 17:04:29 -08001965 source.IncomingCapturedFrame(CreateFrame(11, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001966 WaitForEncodedFrame(kWidth, kHeight);
asapersson09f05612017-05-15 23:40:18 -07001967 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
asaperssond0de2952017-04-21 01:47:31 -07001968 VerifyNoLimitation(source.sink_wants());
1969 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1970 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
Jonathan Yubc771b72017-12-08 17:04:29 -08001971 EXPECT_EQ(6, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
asaperssond0de2952017-04-21 01:47:31 -07001972 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
kthelgason5e13d412016-12-01 03:59:51 -08001973
mflodmancc3d4422017-08-03 08:27:51 -07001974 video_stream_encoder_->Stop();
kthelgason5e13d412016-12-01 03:59:51 -08001975}
1976
mflodmancc3d4422017-08-03 08:27:51 -07001977TEST_F(VideoStreamEncoderTest, CpuLimitedHistogramIsReported) {
asaperssonfab67072017-04-04 05:51:49 -07001978 const int kWidth = 640;
1979 const int kHeight = 360;
perkj803d97f2016-11-01 11:45:46 -07001980
mflodmancc3d4422017-08-03 08:27:51 -07001981 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
sprang4847ae62017-06-27 07:06:52 -07001982
perkj803d97f2016-11-01 11:45:46 -07001983 for (int i = 1; i <= SendStatisticsProxy::kMinRequiredMetricsSamples; ++i) {
asaperssonfab67072017-04-04 05:51:49 -07001984 video_source_.IncomingCapturedFrame(CreateFrame(i, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001985 WaitForEncodedFrame(i);
perkj803d97f2016-11-01 11:45:46 -07001986 }
1987
mflodmancc3d4422017-08-03 08:27:51 -07001988 video_stream_encoder_->TriggerCpuOveruse();
perkj803d97f2016-11-01 11:45:46 -07001989 for (int i = 1; i <= SendStatisticsProxy::kMinRequiredMetricsSamples; ++i) {
asaperssonfab67072017-04-04 05:51:49 -07001990 video_source_.IncomingCapturedFrame(CreateFrame(
1991 SendStatisticsProxy::kMinRequiredMetricsSamples + i, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001992 WaitForEncodedFrame(SendStatisticsProxy::kMinRequiredMetricsSamples + i);
perkj803d97f2016-11-01 11:45:46 -07001993 }
1994
mflodmancc3d4422017-08-03 08:27:51 -07001995 video_stream_encoder_->Stop();
1996 video_stream_encoder_.reset();
perkj803d97f2016-11-01 11:45:46 -07001997 stats_proxy_.reset();
sprangf8ee65e2017-02-28 08:49:33 -08001998
perkj803d97f2016-11-01 11:45:46 -07001999 EXPECT_EQ(1,
2000 metrics::NumSamples("WebRTC.Video.CpuLimitedResolutionInPercent"));
2001 EXPECT_EQ(
2002 1, metrics::NumEvents("WebRTC.Video.CpuLimitedResolutionInPercent", 50));
2003}
2004
mflodmancc3d4422017-08-03 08:27:51 -07002005TEST_F(VideoStreamEncoderTest,
2006 CpuLimitedHistogramIsNotReportedForDisabledDegradation) {
2007 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonf4e44af2017-04-19 02:01:06 -07002008 const int kWidth = 640;
2009 const int kHeight = 360;
2010
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002011 video_stream_encoder_->SetSource(&video_source_,
2012 webrtc::DegradationPreference::DISABLED);
asaperssonf4e44af2017-04-19 02:01:06 -07002013
2014 for (int i = 1; i <= SendStatisticsProxy::kMinRequiredMetricsSamples; ++i) {
2015 video_source_.IncomingCapturedFrame(CreateFrame(i, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002016 WaitForEncodedFrame(i);
asaperssonf4e44af2017-04-19 02:01:06 -07002017 }
2018
mflodmancc3d4422017-08-03 08:27:51 -07002019 video_stream_encoder_->Stop();
2020 video_stream_encoder_.reset();
asaperssonf4e44af2017-04-19 02:01:06 -07002021 stats_proxy_.reset();
2022
2023 EXPECT_EQ(0,
2024 metrics::NumSamples("WebRTC.Video.CpuLimitedResolutionInPercent"));
2025}
2026
mflodmancc3d4422017-08-03 08:27:51 -07002027TEST_F(VideoStreamEncoderTest, CallsBitrateObserver) {
sprang4847ae62017-06-27 07:06:52 -07002028 MockBitrateObserver bitrate_observer;
Niels Möller0327c2d2018-05-21 14:09:31 +02002029 video_stream_encoder_->SetBitrateAllocationObserver(&bitrate_observer);
sprang57c2fff2017-01-16 06:24:02 -08002030
2031 const int kDefaultFps = 30;
Erik Språng566124a2018-04-23 12:32:22 +02002032 const VideoBitrateAllocation expected_bitrate =
sprang57c2fff2017-01-16 06:24:02 -08002033 DefaultVideoBitrateAllocator(fake_encoder_.codec_config())
kthelgason2bc68642017-02-07 07:02:22 -08002034 .GetAllocation(kLowTargetBitrateBps, kDefaultFps);
sprang57c2fff2017-01-16 06:24:02 -08002035
2036 // First called on bitrate updated, then again on first frame.
2037 EXPECT_CALL(bitrate_observer, OnBitrateAllocationUpdated(expected_bitrate))
2038 .Times(2);
mflodmancc3d4422017-08-03 08:27:51 -07002039 video_stream_encoder_->OnBitrateUpdated(kLowTargetBitrateBps, 0, 0);
sprang57c2fff2017-01-16 06:24:02 -08002040
2041 const int64_t kStartTimeMs = 1;
2042 video_source_.IncomingCapturedFrame(
2043 CreateFrame(kStartTimeMs, codec_width_, codec_height_));
sprang4847ae62017-06-27 07:06:52 -07002044 WaitForEncodedFrame(kStartTimeMs);
sprang57c2fff2017-01-16 06:24:02 -08002045
2046 // Not called on second frame.
2047 EXPECT_CALL(bitrate_observer, OnBitrateAllocationUpdated(expected_bitrate))
2048 .Times(0);
2049 video_source_.IncomingCapturedFrame(
2050 CreateFrame(kStartTimeMs + 1, codec_width_, codec_height_));
sprang4847ae62017-06-27 07:06:52 -07002051 WaitForEncodedFrame(kStartTimeMs + 1);
sprang57c2fff2017-01-16 06:24:02 -08002052
2053 // Called after a process interval.
2054 const int64_t kProcessIntervalMs =
2055 vcm::VCMProcessTimer::kDefaultProcessIntervalMs;
sprang4847ae62017-06-27 07:06:52 -07002056 fake_clock_.AdvanceTimeMicros(rtc::kNumMicrosecsPerMillisec *
2057 (kProcessIntervalMs + (1000 / kDefaultFps)));
sprang57c2fff2017-01-16 06:24:02 -08002058 EXPECT_CALL(bitrate_observer, OnBitrateAllocationUpdated(expected_bitrate))
2059 .Times(1);
2060 video_source_.IncomingCapturedFrame(CreateFrame(
2061 kStartTimeMs + kProcessIntervalMs, codec_width_, codec_height_));
sprang4847ae62017-06-27 07:06:52 -07002062 WaitForEncodedFrame(kStartTimeMs + kProcessIntervalMs);
sprang57c2fff2017-01-16 06:24:02 -08002063
mflodmancc3d4422017-08-03 08:27:51 -07002064 video_stream_encoder_->Stop();
sprang57c2fff2017-01-16 06:24:02 -08002065}
2066
Niels Möller7dc26b72017-12-06 10:27:48 +01002067TEST_F(VideoStreamEncoderTest, OveruseDetectorUpdatedOnReconfigureAndAdaption) {
2068 const int kFrameWidth = 1280;
2069 const int kFrameHeight = 720;
2070 const int kFramerate = 24;
2071
2072 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
2073 test::FrameForwarder source;
2074 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002075 &source, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
Niels Möller7dc26b72017-12-06 10:27:48 +01002076
2077 // Insert a single frame, triggering initial configuration.
2078 source.IncomingCapturedFrame(CreateFrame(1, kFrameWidth, kFrameHeight));
2079 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2080
2081 EXPECT_EQ(
2082 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2083 kDefaultFramerate);
2084
2085 // Trigger reconfigure encoder (without resetting the entire instance).
2086 VideoEncoderConfig video_encoder_config;
Niels Möller259a4972018-04-05 15:36:51 +02002087 video_encoder_config.codec_type = kVideoCodecVP8;
Niels Möller7dc26b72017-12-06 10:27:48 +01002088 video_encoder_config.max_bitrate_bps = kTargetBitrateBps;
2089 video_encoder_config.number_of_streams = 1;
2090 video_encoder_config.video_stream_factory =
2091 new rtc::RefCountedObject<VideoStreamFactory>(1, kFramerate);
2092 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
Niels Möllerf1338562018-04-26 09:51:47 +02002093 kMaxPayloadLength);
Niels Möller7dc26b72017-12-06 10:27:48 +01002094 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2095
2096 // Detector should be updated with fps limit from codec config.
2097 EXPECT_EQ(
2098 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2099 kFramerate);
2100
2101 // Trigger overuse, max framerate should be reduced.
2102 VideoSendStream::Stats stats = stats_proxy_->GetStats();
2103 stats.input_frame_rate = kFramerate;
2104 stats_proxy_->SetMockStats(stats);
2105 video_stream_encoder_->TriggerCpuOveruse();
2106 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2107 int adapted_framerate =
2108 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate();
2109 EXPECT_LT(adapted_framerate, kFramerate);
2110
2111 // Trigger underuse, max framerate should go back to codec configured fps.
2112 // Set extra low fps, to make sure it's actually reset, not just incremented.
2113 stats = stats_proxy_->GetStats();
2114 stats.input_frame_rate = adapted_framerate / 2;
2115 stats_proxy_->SetMockStats(stats);
2116 video_stream_encoder_->TriggerCpuNormalUsage();
2117 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2118 EXPECT_EQ(
2119 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2120 kFramerate);
2121
2122 video_stream_encoder_->Stop();
2123}
2124
2125TEST_F(VideoStreamEncoderTest,
2126 OveruseDetectorUpdatedRespectsFramerateAfterUnderuse) {
2127 const int kFrameWidth = 1280;
2128 const int kFrameHeight = 720;
2129 const int kLowFramerate = 15;
2130 const int kHighFramerate = 25;
2131
2132 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
2133 test::FrameForwarder source;
2134 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002135 &source, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
Niels Möller7dc26b72017-12-06 10:27:48 +01002136
2137 // Trigger initial configuration.
2138 VideoEncoderConfig video_encoder_config;
Niels Möller259a4972018-04-05 15:36:51 +02002139 video_encoder_config.codec_type = kVideoCodecVP8;
Niels Möller7dc26b72017-12-06 10:27:48 +01002140 video_encoder_config.max_bitrate_bps = kTargetBitrateBps;
2141 video_encoder_config.number_of_streams = 1;
2142 video_encoder_config.video_stream_factory =
2143 new rtc::RefCountedObject<VideoStreamFactory>(1, kLowFramerate);
2144 source.IncomingCapturedFrame(CreateFrame(1, kFrameWidth, kFrameHeight));
2145 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
Niels Möllerf1338562018-04-26 09:51:47 +02002146 kMaxPayloadLength);
Niels Möller7dc26b72017-12-06 10:27:48 +01002147 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2148
2149 EXPECT_EQ(
2150 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2151 kLowFramerate);
2152
2153 // Trigger overuse, max framerate should be reduced.
2154 VideoSendStream::Stats stats = stats_proxy_->GetStats();
2155 stats.input_frame_rate = kLowFramerate;
2156 stats_proxy_->SetMockStats(stats);
2157 video_stream_encoder_->TriggerCpuOveruse();
2158 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2159 int adapted_framerate =
2160 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate();
2161 EXPECT_LT(adapted_framerate, kLowFramerate);
2162
2163 // Reconfigure the encoder with a new (higher max framerate), max fps should
2164 // still respect the adaptation.
2165 video_encoder_config.video_stream_factory =
2166 new rtc::RefCountedObject<VideoStreamFactory>(1, kHighFramerate);
2167 source.IncomingCapturedFrame(CreateFrame(1, kFrameWidth, kFrameHeight));
2168 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
Niels Möllerf1338562018-04-26 09:51:47 +02002169 kMaxPayloadLength);
Niels Möller7dc26b72017-12-06 10:27:48 +01002170 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2171
2172 EXPECT_EQ(
2173 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2174 adapted_framerate);
2175
2176 // Trigger underuse, max framerate should go back to codec configured fps.
2177 stats = stats_proxy_->GetStats();
2178 stats.input_frame_rate = adapted_framerate;
2179 stats_proxy_->SetMockStats(stats);
2180 video_stream_encoder_->TriggerCpuNormalUsage();
2181 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2182 EXPECT_EQ(
2183 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2184 kHighFramerate);
2185
2186 video_stream_encoder_->Stop();
2187}
2188
mflodmancc3d4422017-08-03 08:27:51 -07002189TEST_F(VideoStreamEncoderTest,
2190 OveruseDetectorUpdatedOnDegradationPreferenceChange) {
sprangfda496a2017-06-15 04:21:07 -07002191 const int kFrameWidth = 1280;
2192 const int kFrameHeight = 720;
2193 const int kFramerate = 24;
2194
mflodmancc3d4422017-08-03 08:27:51 -07002195 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
sprangfda496a2017-06-15 04:21:07 -07002196 test::FrameForwarder source;
mflodmancc3d4422017-08-03 08:27:51 -07002197 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002198 &source, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
sprangfda496a2017-06-15 04:21:07 -07002199
2200 // Trigger initial configuration.
2201 VideoEncoderConfig video_encoder_config;
Niels Möller259a4972018-04-05 15:36:51 +02002202 video_encoder_config.codec_type = kVideoCodecVP8;
sprangfda496a2017-06-15 04:21:07 -07002203 video_encoder_config.max_bitrate_bps = kTargetBitrateBps;
2204 video_encoder_config.number_of_streams = 1;
2205 video_encoder_config.video_stream_factory =
2206 new rtc::RefCountedObject<VideoStreamFactory>(1, kFramerate);
2207 source.IncomingCapturedFrame(CreateFrame(1, kFrameWidth, kFrameHeight));
mflodmancc3d4422017-08-03 08:27:51 -07002208 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
Niels Möllerf1338562018-04-26 09:51:47 +02002209 kMaxPayloadLength);
mflodmancc3d4422017-08-03 08:27:51 -07002210 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
sprangfda496a2017-06-15 04:21:07 -07002211
Niels Möller7dc26b72017-12-06 10:27:48 +01002212 EXPECT_EQ(
2213 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2214 kFramerate);
sprangfda496a2017-06-15 04:21:07 -07002215
2216 // Trigger overuse, max framerate should be reduced.
2217 VideoSendStream::Stats stats = stats_proxy_->GetStats();
2218 stats.input_frame_rate = kFramerate;
2219 stats_proxy_->SetMockStats(stats);
mflodmancc3d4422017-08-03 08:27:51 -07002220 video_stream_encoder_->TriggerCpuOveruse();
2221 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
Niels Möller7dc26b72017-12-06 10:27:48 +01002222 int adapted_framerate =
2223 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate();
sprangfda496a2017-06-15 04:21:07 -07002224 EXPECT_LT(adapted_framerate, kFramerate);
2225
2226 // Change degradation preference to not enable framerate scaling. Target
2227 // framerate should be changed to codec defined limit.
mflodmancc3d4422017-08-03 08:27:51 -07002228 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002229 &source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
mflodmancc3d4422017-08-03 08:27:51 -07002230 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
Niels Möller7dc26b72017-12-06 10:27:48 +01002231 EXPECT_EQ(
2232 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2233 kFramerate);
sprangfda496a2017-06-15 04:21:07 -07002234
mflodmancc3d4422017-08-03 08:27:51 -07002235 video_stream_encoder_->Stop();
sprangfda496a2017-06-15 04:21:07 -07002236}
2237
mflodmancc3d4422017-08-03 08:27:51 -07002238TEST_F(VideoStreamEncoderTest, DropsFramesAndScalesWhenBitrateIsTooLow) {
asaperssonfab67072017-04-04 05:51:49 -07002239 const int kTooLowBitrateForFrameSizeBps = 10000;
mflodmancc3d4422017-08-03 08:27:51 -07002240 video_stream_encoder_->OnBitrateUpdated(kTooLowBitrateForFrameSizeBps, 0, 0);
asaperssonfab67072017-04-04 05:51:49 -07002241 const int kWidth = 640;
2242 const int kHeight = 360;
kthelgason2bc68642017-02-07 07:02:22 -08002243
asaperssonfab67072017-04-04 05:51:49 -07002244 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
kthelgason2bc68642017-02-07 07:02:22 -08002245
2246 // Expect to drop this frame, the wait should time out.
sprang4847ae62017-06-27 07:06:52 -07002247 ExpectDroppedFrame();
kthelgason2bc68642017-02-07 07:02:22 -08002248
2249 // Expect the sink_wants to specify a scaled frame.
asapersson0944a802017-04-07 00:57:58 -07002250 EXPECT_LT(video_source_.sink_wants().max_pixel_count, kWidth * kHeight);
kthelgason2bc68642017-02-07 07:02:22 -08002251
sprangc5d62e22017-04-02 23:53:04 -07002252 int last_pixel_count = video_source_.sink_wants().max_pixel_count;
kthelgason2bc68642017-02-07 07:02:22 -08002253
asaperssonfab67072017-04-04 05:51:49 -07002254 // Next frame is scaled.
kthelgason2bc68642017-02-07 07:02:22 -08002255 video_source_.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07002256 CreateFrame(2, kWidth * 3 / 4, kHeight * 3 / 4));
kthelgason2bc68642017-02-07 07:02:22 -08002257
2258 // Expect to drop this frame, the wait should time out.
sprang4847ae62017-06-27 07:06:52 -07002259 ExpectDroppedFrame();
kthelgason2bc68642017-02-07 07:02:22 -08002260
sprangc5d62e22017-04-02 23:53:04 -07002261 EXPECT_LT(video_source_.sink_wants().max_pixel_count, last_pixel_count);
kthelgason2bc68642017-02-07 07:02:22 -08002262
mflodmancc3d4422017-08-03 08:27:51 -07002263 video_stream_encoder_->Stop();
kthelgason2bc68642017-02-07 07:02:22 -08002264}
2265
mflodmancc3d4422017-08-03 08:27:51 -07002266TEST_F(VideoStreamEncoderTest,
2267 NumberOfDroppedFramesLimitedWhenBitrateIsTooLow) {
asaperssonfab67072017-04-04 05:51:49 -07002268 const int kTooLowBitrateForFrameSizeBps = 10000;
mflodmancc3d4422017-08-03 08:27:51 -07002269 video_stream_encoder_->OnBitrateUpdated(kTooLowBitrateForFrameSizeBps, 0, 0);
asaperssonfab67072017-04-04 05:51:49 -07002270 const int kWidth = 640;
2271 const int kHeight = 360;
kthelgason2bc68642017-02-07 07:02:22 -08002272
2273 // We expect the n initial frames to get dropped.
2274 int i;
2275 for (i = 1; i <= kMaxInitialFramedrop; ++i) {
asaperssonfab67072017-04-04 05:51:49 -07002276 video_source_.IncomingCapturedFrame(CreateFrame(i, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002277 ExpectDroppedFrame();
kthelgason2bc68642017-02-07 07:02:22 -08002278 }
2279 // The n+1th frame should not be dropped, even though it's size is too large.
asaperssonfab67072017-04-04 05:51:49 -07002280 video_source_.IncomingCapturedFrame(CreateFrame(i, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002281 WaitForEncodedFrame(i);
kthelgason2bc68642017-02-07 07:02:22 -08002282
2283 // Expect the sink_wants to specify a scaled frame.
asaperssonfab67072017-04-04 05:51:49 -07002284 EXPECT_LT(video_source_.sink_wants().max_pixel_count, kWidth * kHeight);
kthelgason2bc68642017-02-07 07:02:22 -08002285
mflodmancc3d4422017-08-03 08:27:51 -07002286 video_stream_encoder_->Stop();
kthelgason2bc68642017-02-07 07:02:22 -08002287}
2288
mflodmancc3d4422017-08-03 08:27:51 -07002289TEST_F(VideoStreamEncoderTest,
2290 InitialFrameDropOffWithMaintainResolutionPreference) {
asaperssonfab67072017-04-04 05:51:49 -07002291 const int kWidth = 640;
2292 const int kHeight = 360;
mflodmancc3d4422017-08-03 08:27:51 -07002293 video_stream_encoder_->OnBitrateUpdated(kLowTargetBitrateBps, 0, 0);
kthelgason2bc68642017-02-07 07:02:22 -08002294
2295 // Set degradation preference.
mflodmancc3d4422017-08-03 08:27:51 -07002296 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002297 &video_source_, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
kthelgason2bc68642017-02-07 07:02:22 -08002298
asaperssonfab67072017-04-04 05:51:49 -07002299 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
kthelgason2bc68642017-02-07 07:02:22 -08002300 // Frame should not be dropped, even if it's too large.
sprang4847ae62017-06-27 07:06:52 -07002301 WaitForEncodedFrame(1);
kthelgason2bc68642017-02-07 07:02:22 -08002302
mflodmancc3d4422017-08-03 08:27:51 -07002303 video_stream_encoder_->Stop();
kthelgason2bc68642017-02-07 07:02:22 -08002304}
2305
mflodmancc3d4422017-08-03 08:27:51 -07002306TEST_F(VideoStreamEncoderTest, InitialFrameDropOffWhenEncoderDisabledScaling) {
asaperssonfab67072017-04-04 05:51:49 -07002307 const int kWidth = 640;
2308 const int kHeight = 360;
kthelgasonad9010c2017-02-14 00:46:51 -08002309 fake_encoder_.SetQualityScaling(false);
Niels Möller4db138e2018-04-19 09:04:13 +02002310
2311 VideoEncoderConfig video_encoder_config;
2312 test::FillEncoderConfiguration(kVideoCodecVP8, 1, &video_encoder_config);
2313 // Make format different, to force recreation of encoder.
2314 video_encoder_config.video_format.parameters["foo"] = "foo";
2315 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
Niels Möllerf1338562018-04-26 09:51:47 +02002316 kMaxPayloadLength);
mflodmancc3d4422017-08-03 08:27:51 -07002317 video_stream_encoder_->OnBitrateUpdated(kLowTargetBitrateBps, 0, 0);
asapersson09f05612017-05-15 23:40:18 -07002318
kthelgasonb83797b2017-02-14 11:57:25 -08002319 // Force quality scaler reconfiguration by resetting the source.
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002320 video_stream_encoder_->SetSource(&video_source_,
2321 webrtc::DegradationPreference::BALANCED);
kthelgasonad9010c2017-02-14 00:46:51 -08002322
asaperssonfab67072017-04-04 05:51:49 -07002323 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
kthelgasonad9010c2017-02-14 00:46:51 -08002324 // Frame should not be dropped, even if it's too large.
sprang4847ae62017-06-27 07:06:52 -07002325 WaitForEncodedFrame(1);
kthelgasonad9010c2017-02-14 00:46:51 -08002326
mflodmancc3d4422017-08-03 08:27:51 -07002327 video_stream_encoder_->Stop();
kthelgasonad9010c2017-02-14 00:46:51 -08002328 fake_encoder_.SetQualityScaling(true);
2329}
2330
mflodmancc3d4422017-08-03 08:27:51 -07002331TEST_F(VideoStreamEncoderTest,
asaperssond0de2952017-04-21 01:47:31 -07002332 ResolutionNotAdaptedForTooSmallFrame_MaintainFramerateMode) {
2333 const int kTooSmallWidth = 10;
2334 const int kTooSmallHeight = 10;
mflodmancc3d4422017-08-03 08:27:51 -07002335 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssond0de2952017-04-21 01:47:31 -07002336
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002337 // Enable MAINTAIN_FRAMERATE preference, no initial limitation.
asaperssond0de2952017-04-21 01:47:31 -07002338 test::FrameForwarder source;
mflodmancc3d4422017-08-03 08:27:51 -07002339 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002340 &source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
asaperssond0de2952017-04-21 01:47:31 -07002341 VerifyNoLimitation(source.sink_wants());
2342 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2343
2344 // Trigger adapt down, too small frame, expect no change.
2345 source.IncomingCapturedFrame(CreateFrame(1, kTooSmallWidth, kTooSmallHeight));
sprang4847ae62017-06-27 07:06:52 -07002346 WaitForEncodedFrame(1);
mflodmancc3d4422017-08-03 08:27:51 -07002347 video_stream_encoder_->TriggerCpuOveruse();
asaperssond0de2952017-04-21 01:47:31 -07002348 VerifyNoLimitation(source.sink_wants());
2349 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2350 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2351
mflodmancc3d4422017-08-03 08:27:51 -07002352 video_stream_encoder_->Stop();
asaperssond0de2952017-04-21 01:47:31 -07002353}
2354
mflodmancc3d4422017-08-03 08:27:51 -07002355TEST_F(VideoStreamEncoderTest,
2356 ResolutionNotAdaptedForTooSmallFrame_BalancedMode) {
asaperssonf7e294d2017-06-13 23:25:22 -07002357 const int kTooSmallWidth = 10;
2358 const int kTooSmallHeight = 10;
2359 const int kFpsLimit = 7;
mflodmancc3d4422017-08-03 08:27:51 -07002360 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -07002361
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002362 // Enable BALANCED preference, no initial limitation.
asaperssonf7e294d2017-06-13 23:25:22 -07002363 test::FrameForwarder source;
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002364 video_stream_encoder_->SetSource(&source,
2365 webrtc::DegradationPreference::BALANCED);
asaperssonf7e294d2017-06-13 23:25:22 -07002366 VerifyNoLimitation(source.sink_wants());
2367 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2368 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2369
2370 // Trigger adapt down, expect limited framerate.
2371 source.IncomingCapturedFrame(CreateFrame(1, kTooSmallWidth, kTooSmallHeight));
sprang4847ae62017-06-27 07:06:52 -07002372 WaitForEncodedFrame(1);
mflodmancc3d4422017-08-03 08:27:51 -07002373 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002374 VerifyFpsEqResolutionMax(source.sink_wants(), kFpsLimit);
2375 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2376 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2377 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2378
2379 // Trigger adapt down, too small frame, expect no change.
2380 source.IncomingCapturedFrame(CreateFrame(2, kTooSmallWidth, kTooSmallHeight));
sprang4847ae62017-06-27 07:06:52 -07002381 WaitForEncodedFrame(2);
mflodmancc3d4422017-08-03 08:27:51 -07002382 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002383 VerifyFpsEqResolutionMax(source.sink_wants(), kFpsLimit);
2384 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2385 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2386 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2387
mflodmancc3d4422017-08-03 08:27:51 -07002388 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07002389}
2390
mflodmancc3d4422017-08-03 08:27:51 -07002391TEST_F(VideoStreamEncoderTest, FailingInitEncodeDoesntCauseCrash) {
asapersson02465b82017-04-10 01:12:52 -07002392 fake_encoder_.ForceInitEncodeFailure(true);
mflodmancc3d4422017-08-03 08:27:51 -07002393 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
Niels Möllerf1338562018-04-26 09:51:47 +02002394 ResetEncoder("VP8", 2, 1, 1, false);
asapersson02465b82017-04-10 01:12:52 -07002395 const int kFrameWidth = 1280;
2396 const int kFrameHeight = 720;
2397 video_source_.IncomingCapturedFrame(
2398 CreateFrame(1, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002399 ExpectDroppedFrame();
mflodmancc3d4422017-08-03 08:27:51 -07002400 video_stream_encoder_->Stop();
asapersson02465b82017-04-10 01:12:52 -07002401}
2402
sprangb1ca0732017-02-01 08:38:12 -08002403// TODO(sprang): Extend this with fps throttling and any "balanced" extensions.
mflodmancc3d4422017-08-03 08:27:51 -07002404TEST_F(VideoStreamEncoderTest,
2405 AdaptsResolutionOnOveruse_MaintainFramerateMode) {
2406 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
sprangb1ca0732017-02-01 08:38:12 -08002407
2408 const int kFrameWidth = 1280;
2409 const int kFrameHeight = 720;
2410 // Enabled default VideoAdapter downscaling. First step is 3/4, not 3/5 as
mflodmancc3d4422017-08-03 08:27:51 -07002411 // requested by
2412 // VideoStreamEncoder::VideoSourceProxy::RequestResolutionLowerThan().
sprangb1ca0732017-02-01 08:38:12 -08002413 video_source_.set_adaptation_enabled(true);
2414
2415 video_source_.IncomingCapturedFrame(
2416 CreateFrame(1, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002417 WaitForEncodedFrame(kFrameWidth, kFrameHeight);
sprangb1ca0732017-02-01 08:38:12 -08002418
2419 // Trigger CPU overuse, downscale by 3/4.
mflodmancc3d4422017-08-03 08:27:51 -07002420 video_stream_encoder_->TriggerCpuOveruse();
sprangb1ca0732017-02-01 08:38:12 -08002421 video_source_.IncomingCapturedFrame(
2422 CreateFrame(2, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002423 WaitForEncodedFrame((kFrameWidth * 3) / 4, (kFrameHeight * 3) / 4);
sprangb1ca0732017-02-01 08:38:12 -08002424
asaperssonfab67072017-04-04 05:51:49 -07002425 // Trigger CPU normal use, return to original resolution.
mflodmancc3d4422017-08-03 08:27:51 -07002426 video_stream_encoder_->TriggerCpuNormalUsage();
sprangb1ca0732017-02-01 08:38:12 -08002427 video_source_.IncomingCapturedFrame(
2428 CreateFrame(3, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002429 WaitForEncodedFrame(kFrameWidth, kFrameHeight);
sprangb1ca0732017-02-01 08:38:12 -08002430
mflodmancc3d4422017-08-03 08:27:51 -07002431 video_stream_encoder_->Stop();
sprangb1ca0732017-02-01 08:38:12 -08002432}
sprangfe627f32017-03-29 08:24:59 -07002433
mflodmancc3d4422017-08-03 08:27:51 -07002434TEST_F(VideoStreamEncoderTest,
2435 AdaptsFramerateOnOveruse_MaintainResolutionMode) {
sprangc5d62e22017-04-02 23:53:04 -07002436 const int kFrameWidth = 1280;
2437 const int kFrameHeight = 720;
sprang4847ae62017-06-27 07:06:52 -07002438 int kFrameIntervalMs = rtc::kNumMillisecsPerSec / max_framerate_;
sprangc5d62e22017-04-02 23:53:04 -07002439
mflodmancc3d4422017-08-03 08:27:51 -07002440 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
2441 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002442 &video_source_, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
sprangc5d62e22017-04-02 23:53:04 -07002443 video_source_.set_adaptation_enabled(true);
2444
sprang4847ae62017-06-27 07:06:52 -07002445 int64_t timestamp_ms = fake_clock_.TimeNanos() / rtc::kNumNanosecsPerMillisec;
sprangc5d62e22017-04-02 23:53:04 -07002446
2447 video_source_.IncomingCapturedFrame(
2448 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002449 WaitForEncodedFrame(timestamp_ms);
sprangc5d62e22017-04-02 23:53:04 -07002450
2451 // Try to trigger overuse. No fps estimate available => no effect.
mflodmancc3d4422017-08-03 08:27:51 -07002452 video_stream_encoder_->TriggerCpuOveruse();
sprangc5d62e22017-04-02 23:53:04 -07002453
2454 // Insert frames for one second to get a stable estimate.
sprang4847ae62017-06-27 07:06:52 -07002455 for (int i = 0; i < max_framerate_; ++i) {
sprangc5d62e22017-04-02 23:53:04 -07002456 timestamp_ms += kFrameIntervalMs;
sprangc5d62e22017-04-02 23:53:04 -07002457 video_source_.IncomingCapturedFrame(
2458 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002459 WaitForEncodedFrame(timestamp_ms);
sprangc5d62e22017-04-02 23:53:04 -07002460 }
2461
2462 // Trigger CPU overuse, reduce framerate by 2/3.
mflodmancc3d4422017-08-03 08:27:51 -07002463 video_stream_encoder_->TriggerCpuOveruse();
sprangc5d62e22017-04-02 23:53:04 -07002464 int num_frames_dropped = 0;
sprang4847ae62017-06-27 07:06:52 -07002465 for (int i = 0; i < max_framerate_; ++i) {
sprangc5d62e22017-04-02 23:53:04 -07002466 timestamp_ms += kFrameIntervalMs;
sprangc5d62e22017-04-02 23:53:04 -07002467 video_source_.IncomingCapturedFrame(
2468 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002469 if (!WaitForFrame(kFrameTimeoutMs)) {
sprangc5d62e22017-04-02 23:53:04 -07002470 ++num_frames_dropped;
2471 } else {
Åsa Perssonc74d8da2017-12-04 14:13:56 +01002472 sink_.CheckLastFrameSizeMatches(kFrameWidth, kFrameHeight);
sprangc5d62e22017-04-02 23:53:04 -07002473 }
2474 }
2475
sprang4847ae62017-06-27 07:06:52 -07002476 // Add some slack to account for frames dropped by the frame dropper.
2477 const int kErrorMargin = 1;
2478 EXPECT_NEAR(num_frames_dropped, max_framerate_ - (max_framerate_ * 2 / 3),
sprangc5d62e22017-04-02 23:53:04 -07002479 kErrorMargin);
2480
2481 // Trigger CPU overuse, reduce framerate by 2/3 again.
mflodmancc3d4422017-08-03 08:27:51 -07002482 video_stream_encoder_->TriggerCpuOveruse();
sprangc5d62e22017-04-02 23:53:04 -07002483 num_frames_dropped = 0;
sprang4847ae62017-06-27 07:06:52 -07002484 for (int i = 0; i < max_framerate_; ++i) {
sprangc5d62e22017-04-02 23:53:04 -07002485 timestamp_ms += kFrameIntervalMs;
sprangc5d62e22017-04-02 23:53:04 -07002486 video_source_.IncomingCapturedFrame(
2487 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002488 if (!WaitForFrame(kFrameTimeoutMs)) {
sprangc5d62e22017-04-02 23:53:04 -07002489 ++num_frames_dropped;
2490 } else {
Åsa Perssonc74d8da2017-12-04 14:13:56 +01002491 sink_.CheckLastFrameSizeMatches(kFrameWidth, kFrameHeight);
sprangc5d62e22017-04-02 23:53:04 -07002492 }
2493 }
sprang4847ae62017-06-27 07:06:52 -07002494 EXPECT_NEAR(num_frames_dropped, max_framerate_ - (max_framerate_ * 4 / 9),
sprangc5d62e22017-04-02 23:53:04 -07002495 kErrorMargin);
2496
2497 // Go back up one step.
mflodmancc3d4422017-08-03 08:27:51 -07002498 video_stream_encoder_->TriggerCpuNormalUsage();
sprangc5d62e22017-04-02 23:53:04 -07002499 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 }
sprang4847ae62017-06-27 07:06:52 -07002510 EXPECT_NEAR(num_frames_dropped, max_framerate_ - (max_framerate_ * 2 / 3),
sprangc5d62e22017-04-02 23:53:04 -07002511 kErrorMargin);
2512
2513 // Go back up to original mode.
mflodmancc3d4422017-08-03 08:27:51 -07002514 video_stream_encoder_->TriggerCpuNormalUsage();
sprangc5d62e22017-04-02 23:53:04 -07002515 num_frames_dropped = 0;
sprang4847ae62017-06-27 07:06:52 -07002516 for (int i = 0; i < max_framerate_; ++i) {
sprangc5d62e22017-04-02 23:53:04 -07002517 timestamp_ms += kFrameIntervalMs;
sprangc5d62e22017-04-02 23:53:04 -07002518 video_source_.IncomingCapturedFrame(
2519 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002520 if (!WaitForFrame(kFrameTimeoutMs)) {
sprangc5d62e22017-04-02 23:53:04 -07002521 ++num_frames_dropped;
2522 } else {
Åsa Perssonc74d8da2017-12-04 14:13:56 +01002523 sink_.CheckLastFrameSizeMatches(kFrameWidth, kFrameHeight);
sprangc5d62e22017-04-02 23:53:04 -07002524 }
2525 }
2526 EXPECT_NEAR(num_frames_dropped, 0, kErrorMargin);
2527
mflodmancc3d4422017-08-03 08:27:51 -07002528 video_stream_encoder_->Stop();
sprangc5d62e22017-04-02 23:53:04 -07002529}
2530
mflodmancc3d4422017-08-03 08:27:51 -07002531TEST_F(VideoStreamEncoderTest, DoesntAdaptDownPastMinFramerate) {
sprangc5d62e22017-04-02 23:53:04 -07002532 const int kFramerateFps = 5;
2533 const int kFrameIntervalMs = rtc::kNumMillisecsPerSec / kFramerateFps;
sprangc5d62e22017-04-02 23:53:04 -07002534 const int kFrameWidth = 1280;
2535 const int kFrameHeight = 720;
2536
sprang4847ae62017-06-27 07:06:52 -07002537 // Reconfigure encoder with two temporal layers and screensharing, which will
2538 // disable frame dropping and make testing easier.
Niels Möllerf1338562018-04-26 09:51:47 +02002539 ResetEncoder("VP8", 1, 2, 1, true);
sprang4847ae62017-06-27 07:06:52 -07002540
mflodmancc3d4422017-08-03 08:27:51 -07002541 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
2542 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002543 &video_source_, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
sprangc5d62e22017-04-02 23:53:04 -07002544 video_source_.set_adaptation_enabled(true);
2545
sprang4847ae62017-06-27 07:06:52 -07002546 int64_t timestamp_ms = fake_clock_.TimeNanos() / rtc::kNumNanosecsPerMillisec;
sprangc5d62e22017-04-02 23:53:04 -07002547
2548 // Trigger overuse as much as we can.
Jonathan Yubc771b72017-12-08 17:04:29 -08002549 rtc::VideoSinkWants last_wants;
2550 do {
2551 last_wants = video_source_.sink_wants();
2552
sprangc5d62e22017-04-02 23:53:04 -07002553 // Insert frames to get a new fps estimate...
2554 for (int j = 0; j < kFramerateFps; ++j) {
2555 video_source_.IncomingCapturedFrame(
2556 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
Jonathan Yubc771b72017-12-08 17:04:29 -08002557 if (video_source_.last_sent_width()) {
2558 sink_.WaitForEncodedFrame(timestamp_ms);
2559 }
sprangc5d62e22017-04-02 23:53:04 -07002560 timestamp_ms += kFrameIntervalMs;
Yves Gerey665174f2018-06-19 15:03:05 +02002561 fake_clock_.AdvanceTimeMicros(kFrameIntervalMs *
2562 rtc::kNumMicrosecsPerMillisec);
sprangc5d62e22017-04-02 23:53:04 -07002563 }
2564 // ...and then try to adapt again.
mflodmancc3d4422017-08-03 08:27:51 -07002565 video_stream_encoder_->TriggerCpuOveruse();
Jonathan Yubc771b72017-12-08 17:04:29 -08002566 } while (video_source_.sink_wants().max_framerate_fps <
2567 last_wants.max_framerate_fps);
sprangc5d62e22017-04-02 23:53:04 -07002568
Jonathan Yubc771b72017-12-08 17:04:29 -08002569 VerifyFpsEqResolutionMax(video_source_.sink_wants(), kMinFramerateFps);
asaperssonf7e294d2017-06-13 23:25:22 -07002570
mflodmancc3d4422017-08-03 08:27:51 -07002571 video_stream_encoder_->Stop();
sprangc5d62e22017-04-02 23:53:04 -07002572}
asaperssonf7e294d2017-06-13 23:25:22 -07002573
mflodmancc3d4422017-08-03 08:27:51 -07002574TEST_F(VideoStreamEncoderTest,
2575 AdaptsResolutionAndFramerateForLowQuality_BalancedMode) {
asaperssonf7e294d2017-06-13 23:25:22 -07002576 const int kWidth = 1280;
2577 const int kHeight = 720;
2578 const int64_t kFrameIntervalMs = 150;
2579 int64_t timestamp_ms = kFrameIntervalMs;
mflodmancc3d4422017-08-03 08:27:51 -07002580 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -07002581
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002582 // Enable BALANCED preference, no initial limitation.
asaperssonf7e294d2017-06-13 23:25:22 -07002583 AdaptingFrameForwarder source;
2584 source.set_adaptation_enabled(true);
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002585 video_stream_encoder_->SetSource(&source,
2586 webrtc::DegradationPreference::BALANCED);
asaperssonf7e294d2017-06-13 23:25:22 -07002587 timestamp_ms += kFrameIntervalMs;
2588 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002589 WaitForEncodedFrame(kWidth, kHeight);
asaperssonf7e294d2017-06-13 23:25:22 -07002590 VerifyNoLimitation(source.sink_wants());
2591 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2592 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2593 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2594
2595 // Trigger adapt down, expect scaled down resolution (960x540@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002596 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002597 timestamp_ms += kFrameIntervalMs;
2598 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002599 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002600 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
2601 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2602 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2603 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2604
2605 // Trigger adapt down, expect scaled down resolution (640x360@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002606 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002607 timestamp_ms += kFrameIntervalMs;
2608 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002609 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002610 VerifyFpsMaxResolutionLt(source.sink_wants(), source.last_wants());
2611 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2612 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2613 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2614
2615 // Trigger adapt down, expect reduced fps (640x360@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07002616 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002617 timestamp_ms += kFrameIntervalMs;
2618 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002619 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002620 VerifyFpsLtResolutionEq(source.sink_wants(), source.last_wants());
2621 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2622 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2623 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2624
2625 // Trigger adapt down, expect scaled down resolution (480x270@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07002626 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002627 timestamp_ms += kFrameIntervalMs;
2628 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002629 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002630 VerifyFpsEqResolutionLt(source.sink_wants(), source.last_wants());
2631 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2632 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2633 EXPECT_EQ(4, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2634
2635 // Restrict bitrate, trigger adapt down, expect reduced fps (480x270@10fps).
mflodmancc3d4422017-08-03 08:27:51 -07002636 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002637 timestamp_ms += kFrameIntervalMs;
2638 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002639 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002640 VerifyFpsLtResolutionEq(source.sink_wants(), source.last_wants());
2641 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2642 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2643 EXPECT_EQ(5, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2644
2645 // Trigger adapt down, expect scaled down resolution (320x180@10fps).
mflodmancc3d4422017-08-03 08:27:51 -07002646 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002647 timestamp_ms += kFrameIntervalMs;
2648 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002649 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002650 VerifyFpsEqResolutionLt(source.sink_wants(), source.last_wants());
2651 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2652 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2653 EXPECT_EQ(6, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2654
2655 // Trigger adapt down, expect reduced fps (320x180@7fps).
mflodmancc3d4422017-08-03 08:27:51 -07002656 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002657 timestamp_ms += kFrameIntervalMs;
2658 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002659 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002660 VerifyFpsLtResolutionEq(source.sink_wants(), source.last_wants());
2661 rtc::VideoSinkWants last_wants = source.sink_wants();
2662 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2663 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2664 EXPECT_EQ(7, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2665
2666 // Trigger adapt down, min resolution reached, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07002667 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002668 timestamp_ms += kFrameIntervalMs;
2669 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002670 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002671 VerifyFpsEqResolutionEq(source.sink_wants(), last_wants);
2672 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2673 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2674 EXPECT_EQ(7, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2675
2676 // Trigger adapt down, expect expect increased fps (320x180@10fps).
mflodmancc3d4422017-08-03 08:27:51 -07002677 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002678 timestamp_ms += kFrameIntervalMs;
2679 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002680 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002681 VerifyFpsGtResolutionEq(source.sink_wants(), source.last_wants());
2682 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2683 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2684 EXPECT_EQ(8, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2685
2686 // Trigger adapt up, expect upscaled resolution (480x270@10fps).
mflodmancc3d4422017-08-03 08:27:51 -07002687 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002688 timestamp_ms += kFrameIntervalMs;
2689 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002690 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002691 VerifyFpsEqResolutionGt(source.sink_wants(), source.last_wants());
2692 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2693 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2694 EXPECT_EQ(9, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2695
2696 // Increase bitrate, trigger adapt up, expect increased fps (480x270@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07002697 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002698 timestamp_ms += kFrameIntervalMs;
2699 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002700 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002701 VerifyFpsGtResolutionEq(source.sink_wants(), source.last_wants());
2702 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2703 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2704 EXPECT_EQ(10, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2705
2706 // Trigger adapt up, expect upscaled resolution (640x360@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07002707 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002708 timestamp_ms += kFrameIntervalMs;
2709 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002710 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002711 VerifyFpsEqResolutionGt(source.sink_wants(), source.last_wants());
2712 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2713 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2714 EXPECT_EQ(11, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2715
2716 // Trigger adapt up, expect increased fps (640x360@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002717 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002718 timestamp_ms += kFrameIntervalMs;
2719 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002720 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002721 VerifyFpsMaxResolutionEq(source.sink_wants(), source.last_wants());
2722 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2723 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2724 EXPECT_EQ(12, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2725
2726 // Trigger adapt up, expect upscaled resolution (960x540@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002727 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002728 timestamp_ms += kFrameIntervalMs;
2729 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002730 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002731 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
2732 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2733 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2734 EXPECT_EQ(13, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2735
2736 // Trigger adapt up, expect no restriction (1280x720fps@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002737 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002738 timestamp_ms += kFrameIntervalMs;
2739 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002740 WaitForEncodedFrame(kWidth, kHeight);
asaperssonf7e294d2017-06-13 23:25:22 -07002741 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
2742 VerifyNoLimitation(source.sink_wants());
2743 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2744 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2745 EXPECT_EQ(14, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2746
2747 // Trigger adapt up, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07002748 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002749 VerifyNoLimitation(source.sink_wants());
2750 EXPECT_EQ(14, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2751
mflodmancc3d4422017-08-03 08:27:51 -07002752 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07002753}
2754
mflodmancc3d4422017-08-03 08:27:51 -07002755TEST_F(VideoStreamEncoderTest, AdaptWithTwoReasonsAndDifferentOrder_Framerate) {
asaperssonf7e294d2017-06-13 23:25:22 -07002756 const int kWidth = 1280;
2757 const int kHeight = 720;
2758 const int64_t kFrameIntervalMs = 150;
2759 int64_t timestamp_ms = kFrameIntervalMs;
mflodmancc3d4422017-08-03 08:27:51 -07002760 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -07002761
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002762 // Enable BALANCED preference, no initial limitation.
asaperssonf7e294d2017-06-13 23:25:22 -07002763 AdaptingFrameForwarder source;
2764 source.set_adaptation_enabled(true);
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002765 video_stream_encoder_->SetSource(&source,
2766 webrtc::DegradationPreference::BALANCED);
asaperssonf7e294d2017-06-13 23:25:22 -07002767 timestamp_ms += kFrameIntervalMs;
2768 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002769 WaitForEncodedFrame(kWidth, kHeight);
asaperssonf7e294d2017-06-13 23:25:22 -07002770 VerifyNoLimitation(source.sink_wants());
2771 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2772 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2773 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2774 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
2775 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2776 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2777
2778 // Trigger cpu adapt down, expect scaled down resolution (960x540@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002779 video_stream_encoder_->TriggerCpuOveruse();
asaperssonf7e294d2017-06-13 23:25:22 -07002780 timestamp_ms += kFrameIntervalMs;
2781 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002782 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002783 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
2784 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2785 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2786 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2787 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
2788 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2789 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2790
2791 // Trigger cpu adapt down, expect scaled down resolution (640x360@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002792 video_stream_encoder_->TriggerCpuOveruse();
asaperssonf7e294d2017-06-13 23:25:22 -07002793 timestamp_ms += kFrameIntervalMs;
2794 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002795 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002796 VerifyFpsMaxResolutionLt(source.sink_wants(), source.last_wants());
2797 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2798 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2799 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2800 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
2801 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2802 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2803
2804 // Trigger quality adapt down, expect reduced fps (640x360@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07002805 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002806 timestamp_ms += kFrameIntervalMs;
2807 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002808 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002809 VerifyFpsLtResolutionEq(source.sink_wants(), source.last_wants());
2810 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2811 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2812 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2813 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
2814 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2815 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2816
2817 // Trigger cpu adapt up, expect increased fps (640x360@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002818 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssonf7e294d2017-06-13 23:25:22 -07002819 timestamp_ms += kFrameIntervalMs;
2820 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002821 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002822 VerifyFpsMaxResolutionEq(source.sink_wants(), source.last_wants());
2823 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2824 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2825 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2826 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
2827 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2828 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2829
2830 // Trigger quality adapt up, expect upscaled resolution (960x540@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002831 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002832 timestamp_ms += kFrameIntervalMs;
2833 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002834 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002835 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
2836 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2837 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2838 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2839 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
2840 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2841 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2842
2843 // Trigger cpu adapt up, expect no restriction (1280x720fps@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002844 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssonf7e294d2017-06-13 23:25:22 -07002845 timestamp_ms += kFrameIntervalMs;
2846 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002847 WaitForEncodedFrame(kWidth, kHeight);
asaperssonf7e294d2017-06-13 23:25:22 -07002848 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
2849 VerifyNoLimitation(source.sink_wants());
2850 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2851 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2852 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2853 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
2854 EXPECT_EQ(4, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2855 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2856
2857 // Trigger adapt up, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07002858 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002859 VerifyNoLimitation(source.sink_wants());
2860 EXPECT_EQ(4, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2861 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2862
mflodmancc3d4422017-08-03 08:27:51 -07002863 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07002864}
2865
mflodmancc3d4422017-08-03 08:27:51 -07002866TEST_F(VideoStreamEncoderTest,
2867 AdaptWithTwoReasonsAndDifferentOrder_Resolution) {
asaperssonf7e294d2017-06-13 23:25:22 -07002868 const int kWidth = 640;
2869 const int kHeight = 360;
2870 const int kFpsLimit = 15;
2871 const int64_t kFrameIntervalMs = 150;
2872 int64_t timestamp_ms = kFrameIntervalMs;
mflodmancc3d4422017-08-03 08:27:51 -07002873 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -07002874
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002875 // Enable BALANCED preference, no initial limitation.
asaperssonf7e294d2017-06-13 23:25:22 -07002876 AdaptingFrameForwarder source;
2877 source.set_adaptation_enabled(true);
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002878 video_stream_encoder_->SetSource(&source,
2879 webrtc::DegradationPreference::BALANCED);
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 VerifyNoLimitation(source.sink_wants());
2884 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2885 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2886 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2887 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
2888 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2889 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2890
2891 // Trigger cpu adapt down, expect scaled down framerate (640x360@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07002892 video_stream_encoder_->TriggerCpuOveruse();
asaperssonf7e294d2017-06-13 23:25:22 -07002893 timestamp_ms += kFrameIntervalMs;
2894 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002895 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002896 VerifyFpsEqResolutionMax(source.sink_wants(), kFpsLimit);
2897 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2898 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2899 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2900 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_framerate);
2901 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2902 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2903
2904 // Trigger quality adapt down, expect scaled down resolution (480x270@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07002905 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002906 timestamp_ms += kFrameIntervalMs;
2907 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002908 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002909 VerifyFpsEqResolutionLt(source.sink_wants(), source.last_wants());
2910 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2911 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2912 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2913 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_framerate);
2914 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2915 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2916
2917 // Trigger cpu adapt up, expect upscaled resolution (640x360@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07002918 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssonf7e294d2017-06-13 23:25:22 -07002919 timestamp_ms += kFrameIntervalMs;
2920 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002921 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002922 VerifyFpsEqResolutionGt(source.sink_wants(), source.last_wants());
2923 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2924 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2925 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2926 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
2927 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2928 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2929
2930 // Trigger quality adapt up, expect increased fps (640x360@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002931 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002932 timestamp_ms += kFrameIntervalMs;
2933 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002934 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002935 VerifyNoLimitation(source.sink_wants());
2936 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2937 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2938 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2939 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
2940 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2941 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2942
2943 // Trigger adapt up, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07002944 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002945 VerifyNoLimitation(source.sink_wants());
2946 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2947 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2948
mflodmancc3d4422017-08-03 08:27:51 -07002949 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07002950}
2951
mflodmancc3d4422017-08-03 08:27:51 -07002952TEST_F(VideoStreamEncoderTest, AcceptsFullHdAdaptedDownSimulcastFrames) {
ilnik6b826ef2017-06-16 06:53:48 -07002953 // Simulates simulcast behavior and makes highest stream resolutions divisible
2954 // by 4.
2955 class CroppingVideoStreamFactory
2956 : public VideoEncoderConfig::VideoStreamFactoryInterface {
2957 public:
2958 explicit CroppingVideoStreamFactory(size_t num_temporal_layers,
2959 int framerate)
2960 : num_temporal_layers_(num_temporal_layers), framerate_(framerate) {
2961 EXPECT_GT(num_temporal_layers, 0u);
2962 EXPECT_GT(framerate, 0);
2963 }
2964
2965 private:
2966 std::vector<VideoStream> CreateEncoderStreams(
2967 int width,
2968 int height,
2969 const VideoEncoderConfig& encoder_config) override {
Yves Gerey665174f2018-06-19 15:03:05 +02002970 std::vector<VideoStream> streams = test::CreateVideoStreams(
2971 width - width % 4, height - height % 4, encoder_config);
ilnik6b826ef2017-06-16 06:53:48 -07002972 for (VideoStream& stream : streams) {
Sergey Silkina796a7e2018-03-01 15:11:29 +01002973 stream.num_temporal_layers = num_temporal_layers_;
ilnik6b826ef2017-06-16 06:53:48 -07002974 stream.max_framerate = framerate_;
2975 }
2976 return streams;
2977 }
2978
2979 const size_t num_temporal_layers_;
2980 const int framerate_;
2981 };
2982
2983 const int kFrameWidth = 1920;
2984 const int kFrameHeight = 1080;
2985 // 3/4 of 1920.
2986 const int kAdaptedFrameWidth = 1440;
2987 // 3/4 of 1080 rounded down to multiple of 4.
2988 const int kAdaptedFrameHeight = 808;
2989 const int kFramerate = 24;
2990
mflodmancc3d4422017-08-03 08:27:51 -07002991 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
ilnik6b826ef2017-06-16 06:53:48 -07002992 // Trigger reconfigure encoder (without resetting the entire instance).
2993 VideoEncoderConfig video_encoder_config;
Niels Möller259a4972018-04-05 15:36:51 +02002994 video_encoder_config.codec_type = kVideoCodecVP8;
ilnik6b826ef2017-06-16 06:53:48 -07002995 video_encoder_config.max_bitrate_bps = kTargetBitrateBps;
2996 video_encoder_config.number_of_streams = 1;
2997 video_encoder_config.video_stream_factory =
2998 new rtc::RefCountedObject<CroppingVideoStreamFactory>(1, kFramerate);
mflodmancc3d4422017-08-03 08:27:51 -07002999 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
Niels Möllerf1338562018-04-26 09:51:47 +02003000 kMaxPayloadLength);
mflodmancc3d4422017-08-03 08:27:51 -07003001 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
ilnik6b826ef2017-06-16 06:53:48 -07003002
3003 video_source_.set_adaptation_enabled(true);
3004
3005 video_source_.IncomingCapturedFrame(
3006 CreateFrame(1, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07003007 WaitForEncodedFrame(kFrameWidth, kFrameHeight);
ilnik6b826ef2017-06-16 06:53:48 -07003008
3009 // Trigger CPU overuse, downscale by 3/4.
mflodmancc3d4422017-08-03 08:27:51 -07003010 video_stream_encoder_->TriggerCpuOveruse();
ilnik6b826ef2017-06-16 06:53:48 -07003011 video_source_.IncomingCapturedFrame(
3012 CreateFrame(2, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07003013 WaitForEncodedFrame(kAdaptedFrameWidth, kAdaptedFrameHeight);
ilnik6b826ef2017-06-16 06:53:48 -07003014
mflodmancc3d4422017-08-03 08:27:51 -07003015 video_stream_encoder_->Stop();
ilnik6b826ef2017-06-16 06:53:48 -07003016}
3017
mflodmancc3d4422017-08-03 08:27:51 -07003018TEST_F(VideoStreamEncoderTest, PeriodicallyUpdatesChannelParameters) {
sprang4847ae62017-06-27 07:06:52 -07003019 const int kFrameWidth = 1280;
3020 const int kFrameHeight = 720;
3021 const int kLowFps = 2;
3022 const int kHighFps = 30;
3023
mflodmancc3d4422017-08-03 08:27:51 -07003024 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
sprang4847ae62017-06-27 07:06:52 -07003025
3026 int64_t timestamp_ms = fake_clock_.TimeNanos() / rtc::kNumNanosecsPerMillisec;
3027 max_framerate_ = kLowFps;
3028
3029 // Insert 2 seconds of 2fps video.
3030 for (int i = 0; i < kLowFps * 2; ++i) {
3031 video_source_.IncomingCapturedFrame(
3032 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
3033 WaitForEncodedFrame(timestamp_ms);
3034 timestamp_ms += 1000 / kLowFps;
3035 }
3036
3037 // Make sure encoder is updated with new target.
mflodmancc3d4422017-08-03 08:27:51 -07003038 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
sprang4847ae62017-06-27 07:06:52 -07003039 video_source_.IncomingCapturedFrame(
3040 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
3041 WaitForEncodedFrame(timestamp_ms);
3042 timestamp_ms += 1000 / kLowFps;
3043
3044 EXPECT_EQ(kLowFps, fake_encoder_.GetConfiguredInputFramerate());
3045
3046 // Insert 30fps frames for just a little more than the forced update period.
3047 const int kVcmTimerIntervalFrames =
3048 (vcm::VCMProcessTimer::kDefaultProcessIntervalMs * kHighFps) / 1000;
3049 const int kFrameIntervalMs = 1000 / kHighFps;
3050 max_framerate_ = kHighFps;
3051 for (int i = 0; i < kVcmTimerIntervalFrames + 2; ++i) {
3052 video_source_.IncomingCapturedFrame(
3053 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
3054 // Wait for encoded frame, but skip ahead if it doesn't arrive as it might
3055 // be dropped if the encoder hans't been updated with the new higher target
3056 // framerate yet, causing it to overshoot the target bitrate and then
3057 // suffering the wrath of the media optimizer.
3058 TimedWaitForEncodedFrame(timestamp_ms, 2 * kFrameIntervalMs);
3059 timestamp_ms += kFrameIntervalMs;
3060 }
3061
3062 // Don expect correct measurement just yet, but it should be higher than
3063 // before.
3064 EXPECT_GT(fake_encoder_.GetConfiguredInputFramerate(), kLowFps);
3065
mflodmancc3d4422017-08-03 08:27:51 -07003066 video_stream_encoder_->Stop();
sprang4847ae62017-06-27 07:06:52 -07003067}
3068
mflodmancc3d4422017-08-03 08:27:51 -07003069TEST_F(VideoStreamEncoderTest, DoesNotUpdateBitrateAllocationWhenSuspended) {
sprang4847ae62017-06-27 07:06:52 -07003070 const int kFrameWidth = 1280;
3071 const int kFrameHeight = 720;
3072 const int kTargetBitrateBps = 1000000;
3073
3074 MockBitrateObserver bitrate_observer;
Niels Möller0327c2d2018-05-21 14:09:31 +02003075 video_stream_encoder_->SetBitrateAllocationObserver(&bitrate_observer);
sprang4847ae62017-06-27 07:06:52 -07003076
3077 EXPECT_CALL(bitrate_observer, OnBitrateAllocationUpdated(_)).Times(1);
3078 // Initial bitrate update.
mflodmancc3d4422017-08-03 08:27:51 -07003079 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
3080 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
sprang4847ae62017-06-27 07:06:52 -07003081
3082 // Insert a first video frame, causes another bitrate update.
3083 int64_t timestamp_ms = fake_clock_.TimeNanos() / rtc::kNumNanosecsPerMillisec;
3084 EXPECT_CALL(bitrate_observer, OnBitrateAllocationUpdated(_)).Times(1);
3085 video_source_.IncomingCapturedFrame(
3086 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
3087 WaitForEncodedFrame(timestamp_ms);
3088
3089 // Next, simulate video suspension due to pacer queue overrun.
mflodmancc3d4422017-08-03 08:27:51 -07003090 video_stream_encoder_->OnBitrateUpdated(0, 0, 1);
sprang4847ae62017-06-27 07:06:52 -07003091
3092 // Skip ahead until a new periodic parameter update should have occured.
3093 timestamp_ms += vcm::VCMProcessTimer::kDefaultProcessIntervalMs;
3094 fake_clock_.AdvanceTimeMicros(
3095 vcm::VCMProcessTimer::kDefaultProcessIntervalMs *
3096 rtc::kNumMicrosecsPerMillisec);
3097
3098 // Bitrate observer should not be called.
3099 EXPECT_CALL(bitrate_observer, OnBitrateAllocationUpdated(_)).Times(0);
3100 video_source_.IncomingCapturedFrame(
3101 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
3102 ExpectDroppedFrame();
3103
mflodmancc3d4422017-08-03 08:27:51 -07003104 video_stream_encoder_->Stop();
sprang4847ae62017-06-27 07:06:52 -07003105}
ilnik6b826ef2017-06-16 06:53:48 -07003106
Niels Möller4db138e2018-04-19 09:04:13 +02003107TEST_F(VideoStreamEncoderTest,
3108 DefaultCpuAdaptationThresholdsForSoftwareEncoder) {
3109 const int kFrameWidth = 1280;
3110 const int kFrameHeight = 720;
3111 const CpuOveruseOptions default_options;
3112 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
3113 video_source_.IncomingCapturedFrame(
3114 CreateFrame(1, kFrameWidth, kFrameHeight));
3115 WaitForEncodedFrame(1);
3116 EXPECT_EQ(video_stream_encoder_->overuse_detector_proxy_->GetOptions()
3117 .low_encode_usage_threshold_percent,
3118 default_options.low_encode_usage_threshold_percent);
3119 EXPECT_EQ(video_stream_encoder_->overuse_detector_proxy_->GetOptions()
3120 .high_encode_usage_threshold_percent,
3121 default_options.high_encode_usage_threshold_percent);
3122 video_stream_encoder_->Stop();
3123}
3124
3125TEST_F(VideoStreamEncoderTest,
3126 HigherCpuAdaptationThresholdsForHardwareEncoder) {
3127 const int kFrameWidth = 1280;
3128 const int kFrameHeight = 720;
3129 CpuOveruseOptions hardware_options;
3130 hardware_options.low_encode_usage_threshold_percent = 150;
3131 hardware_options.high_encode_usage_threshold_percent = 200;
3132 encoder_factory_.SetIsHardwareAccelerated(true);
3133
3134 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
3135 video_source_.IncomingCapturedFrame(
3136 CreateFrame(1, kFrameWidth, kFrameHeight));
3137 WaitForEncodedFrame(1);
3138 EXPECT_EQ(video_stream_encoder_->overuse_detector_proxy_->GetOptions()
3139 .low_encode_usage_threshold_percent,
3140 hardware_options.low_encode_usage_threshold_percent);
3141 EXPECT_EQ(video_stream_encoder_->overuse_detector_proxy_->GetOptions()
3142 .high_encode_usage_threshold_percent,
3143 hardware_options.high_encode_usage_threshold_percent);
3144 video_stream_encoder_->Stop();
3145}
3146
perkj26091b12016-09-01 01:17:40 -07003147} // namespace webrtc