blob: 2510d48d1b9bc9007fa104a34fd535a9b4ea35a8 [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
Erik Språng4529fbc2018-10-12 10:30:31 +020011#include "video/video_stream_encoder.h"
12
sprangfe627f32017-03-29 08:24:59 -070013#include <algorithm>
perkj803d97f2016-11-01 11:45:46 -070014#include <limits>
Per512ecb32016-09-23 15:52:06 +020015#include <utility>
16
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020017#include "api/video/i420_buffer.h"
Erik Språng4529fbc2018-10-12 10:30:31 +020018#include "api/video_codecs/create_vp8_temporal_layers.h"
19#include "api/video_codecs/vp8_temporal_layers.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020020#include "media/base/videoadapter.h"
Sergey Silkin86684962018-03-28 19:32:37 +020021#include "modules/video_coding/codecs/vp9/include/vp9_globals.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020022#include "modules/video_coding/utility/default_video_bitrate_allocator.h"
23#include "rtc_base/fakeclock.h"
24#include "rtc_base/logging.h"
Stefan Holmerdbdb3a02018-07-17 16:03:46 +020025#include "rtc_base/refcountedobject.h"
Mirko Bonadei17f48782018-09-28 08:51:10 +020026#include "system_wrappers/include/metrics.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020027#include "system_wrappers/include/sleep.h"
28#include "test/encoder_settings.h"
29#include "test/fake_encoder.h"
Kári Tristan Helgason639602a2018-08-02 10:51:40 +020030#include "test/field_trial.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020031#include "test/frame_generator.h"
32#include "test/gmock.h"
33#include "test/gtest.h"
Niels Möllercbcbc222018-09-28 09:07:24 +020034#include "test/video_encoder_proxy_factory.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020035#include "video/send_statistics_proxy.h"
perkj26091b12016-09-01 01:17:40 -070036
37namespace webrtc {
38
sprangb1ca0732017-02-01 08:38:12 -080039using ScaleReason = AdaptationObserverInterface::AdaptReason;
sprang57c2fff2017-01-16 06:24:02 -080040using ::testing::_;
41using ::testing::Return;
kthelgason876222f2016-11-29 01:44:11 -080042
perkj803d97f2016-11-01 11:45:46 -070043namespace {
Åsa Persson8c1bf952018-09-13 10:42:19 +020044const int kMinPixelsPerFrame = 320 * 180;
45const int kMinFramerateFps = 2;
46const int kMinBalancedFramerateFps = 7;
47const int64_t kFrameTimeoutMs = 100;
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;
Åsa Persson8c1bf952018-09-13 10:42:19 +020053const int64_t kFrameIntervalMs = rtc::kNumMillisecsPerSec / kDefaultFramerate;
asapersson5f7226f2016-11-25 04:37:00 -080054
perkj803d97f2016-11-01 11:45:46 -070055class TestBuffer : public webrtc::I420Buffer {
56 public:
57 TestBuffer(rtc::Event* event, int width, int height)
58 : I420Buffer(width, height), event_(event) {}
59
60 private:
61 friend class rtc::RefCountedObject<TestBuffer>;
62 ~TestBuffer() override {
63 if (event_)
64 event_->Set();
65 }
66 rtc::Event* const event_;
67};
68
Niels Möller7dc26b72017-12-06 10:27:48 +010069class CpuOveruseDetectorProxy : public OveruseFrameDetector {
70 public:
Niels Möllerd1f7eb62018-03-28 16:40:58 +020071 explicit CpuOveruseDetectorProxy(CpuOveruseMetricsObserver* metrics_observer)
72 : OveruseFrameDetector(metrics_observer),
Niels Möller7dc26b72017-12-06 10:27:48 +010073 last_target_framerate_fps_(-1) {}
74 virtual ~CpuOveruseDetectorProxy() {}
75
76 void OnTargetFramerateUpdated(int framerate_fps) override {
77 rtc::CritScope cs(&lock_);
78 last_target_framerate_fps_ = framerate_fps;
79 OveruseFrameDetector::OnTargetFramerateUpdated(framerate_fps);
80 }
81
82 int GetLastTargetFramerate() {
83 rtc::CritScope cs(&lock_);
84 return last_target_framerate_fps_;
85 }
86
Niels Möller4db138e2018-04-19 09:04:13 +020087 CpuOveruseOptions GetOptions() { return options_; }
88
Niels Möller7dc26b72017-12-06 10:27:48 +010089 private:
90 rtc::CriticalSection lock_;
91 int last_target_framerate_fps_ RTC_GUARDED_BY(lock_);
92};
93
mflodmancc3d4422017-08-03 08:27:51 -070094class VideoStreamEncoderUnderTest : public VideoStreamEncoder {
perkj803d97f2016-11-01 11:45:46 -070095 public:
Niels Möller213618e2018-07-24 09:29:58 +020096 VideoStreamEncoderUnderTest(SendStatisticsProxy* stats_proxy,
97 const VideoStreamEncoderSettings& settings)
Yves Gerey665174f2018-06-19 15:03:05 +020098 : 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) {
Niels Möllerc572ff32018-11-07 08:43:50 +0100107 rtc::Event event;
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() {
Niels Möllerc572ff32018-11-07 08:43:50 +0100118 rtc::Event event;
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
Niels Möller213618e2018-07-24 09:29:58 +0200228// TODO(nisse): Mock only VideoStreamEncoderObserver.
sprangc5d62e22017-04-02 23:53:04 -0700229class MockableSendStatisticsProxy : public SendStatisticsProxy {
230 public:
231 MockableSendStatisticsProxy(Clock* clock,
232 const VideoSendStream::Config& config,
233 VideoEncoderConfig::ContentType content_type)
234 : SendStatisticsProxy(clock, config, content_type) {}
235
236 VideoSendStream::Stats GetStats() override {
237 rtc::CritScope cs(&lock_);
238 if (mock_stats_)
239 return *mock_stats_;
240 return SendStatisticsProxy::GetStats();
241 }
242
Niels Möller213618e2018-07-24 09:29:58 +0200243 int GetInputFrameRate() const override {
244 rtc::CritScope cs(&lock_);
245 if (mock_stats_)
246 return mock_stats_->input_frame_rate;
247 return SendStatisticsProxy::GetInputFrameRate();
248 }
sprangc5d62e22017-04-02 23:53:04 -0700249 void SetMockStats(const VideoSendStream::Stats& stats) {
250 rtc::CritScope cs(&lock_);
251 mock_stats_.emplace(stats);
252 }
253
254 void ResetMockStats() {
255 rtc::CritScope cs(&lock_);
256 mock_stats_.reset();
257 }
258
259 private:
260 rtc::CriticalSection lock_;
Danil Chapovalovb9b146c2018-06-15 12:28:07 +0200261 absl::optional<VideoSendStream::Stats> mock_stats_ RTC_GUARDED_BY(lock_);
sprangc5d62e22017-04-02 23:53:04 -0700262};
263
sprang4847ae62017-06-27 07:06:52 -0700264class MockBitrateObserver : public VideoBitrateAllocationObserver {
265 public:
Erik Språng566124a2018-04-23 12:32:22 +0200266 MOCK_METHOD1(OnBitrateAllocationUpdated, void(const VideoBitrateAllocation&));
sprang4847ae62017-06-27 07:06:52 -0700267};
268
perkj803d97f2016-11-01 11:45:46 -0700269} // namespace
270
mflodmancc3d4422017-08-03 08:27:51 -0700271class VideoStreamEncoderTest : public ::testing::Test {
perkj26091b12016-09-01 01:17:40 -0700272 public:
273 static const int kDefaultTimeoutMs = 30 * 1000;
274
mflodmancc3d4422017-08-03 08:27:51 -0700275 VideoStreamEncoderTest()
perkj26091b12016-09-01 01:17:40 -0700276 : video_send_config_(VideoSendStream::Config(nullptr)),
perkjfa10b552016-10-02 23:45:26 -0700277 codec_width_(320),
278 codec_height_(240),
Åsa Persson8c1bf952018-09-13 10:42:19 +0200279 max_framerate_(kDefaultFramerate),
perkj26091b12016-09-01 01:17:40 -0700280 fake_encoder_(),
Niels Möller4db138e2018-04-19 09:04:13 +0200281 encoder_factory_(&fake_encoder_),
sprangc5d62e22017-04-02 23:53:04 -0700282 stats_proxy_(new MockableSendStatisticsProxy(
perkj803d97f2016-11-01 11:45:46 -0700283 Clock::GetRealTimeClock(),
284 video_send_config_,
285 webrtc::VideoEncoderConfig::ContentType::kRealtimeVideo)),
perkj26091b12016-09-01 01:17:40 -0700286 sink_(&fake_encoder_) {}
287
288 void SetUp() override {
perkj803d97f2016-11-01 11:45:46 -0700289 metrics::Reset();
perkj26091b12016-09-01 01:17:40 -0700290 video_send_config_ = VideoSendStream::Config(nullptr);
Niels Möller4db138e2018-04-19 09:04:13 +0200291 video_send_config_.encoder_settings.encoder_factory = &encoder_factory_;
Niels Möller259a4972018-04-05 15:36:51 +0200292 video_send_config_.rtp.payload_name = "FAKE";
293 video_send_config_.rtp.payload_type = 125;
perkj26091b12016-09-01 01:17:40 -0700294
Per512ecb32016-09-23 15:52:06 +0200295 VideoEncoderConfig video_encoder_config;
Niels Möller259a4972018-04-05 15:36:51 +0200296 test::FillEncoderConfiguration(kVideoCodecVP8, 1, &video_encoder_config);
sprang4847ae62017-06-27 07:06:52 -0700297 video_encoder_config.video_stream_factory =
298 new rtc::RefCountedObject<VideoStreamFactory>(1, max_framerate_);
Erik Språng08127a92016-11-16 16:41:30 +0100299 video_encoder_config_ = video_encoder_config.Copy();
sprang4847ae62017-06-27 07:06:52 -0700300
301 // Framerate limit is specified by the VideoStreamFactory.
302 std::vector<VideoStream> streams =
303 video_encoder_config.video_stream_factory->CreateEncoderStreams(
304 codec_width_, codec_height_, video_encoder_config);
305 max_framerate_ = streams[0].max_framerate;
306 fake_clock_.SetTimeMicros(1234);
307
Niels Möllerf1338562018-04-26 09:51:47 +0200308 ConfigureEncoder(std::move(video_encoder_config));
asapersson5f7226f2016-11-25 04:37:00 -0800309 }
310
Niels Möllerf1338562018-04-26 09:51:47 +0200311 void ConfigureEncoder(VideoEncoderConfig video_encoder_config) {
mflodmancc3d4422017-08-03 08:27:51 -0700312 if (video_stream_encoder_)
313 video_stream_encoder_->Stop();
314 video_stream_encoder_.reset(new VideoStreamEncoderUnderTest(
perkj803d97f2016-11-01 11:45:46 -0700315 stats_proxy_.get(), video_send_config_.encoder_settings));
mflodmancc3d4422017-08-03 08:27:51 -0700316 video_stream_encoder_->SetSink(&sink_, false /* rotation_applied */);
317 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -0700318 &video_source_, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
mflodmancc3d4422017-08-03 08:27:51 -0700319 video_stream_encoder_->SetStartBitrate(kTargetBitrateBps);
320 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
Niels Möllerf1338562018-04-26 09:51:47 +0200321 kMaxPayloadLength);
mflodmancc3d4422017-08-03 08:27:51 -0700322 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
asapersson5f7226f2016-11-25 04:37:00 -0800323 }
324
325 void ResetEncoder(const std::string& payload_name,
326 size_t num_streams,
327 size_t num_temporal_layers,
emircanbbcc3562017-08-18 00:28:40 -0700328 unsigned char num_spatial_layers,
sprang4847ae62017-06-27 07:06:52 -0700329 bool screenshare) {
Niels Möller259a4972018-04-05 15:36:51 +0200330 video_send_config_.rtp.payload_name = payload_name;
asapersson5f7226f2016-11-25 04:37:00 -0800331
332 VideoEncoderConfig video_encoder_config;
Niels Möller259a4972018-04-05 15:36:51 +0200333 video_encoder_config.codec_type = PayloadStringToCodecType(payload_name);
asapersson5f7226f2016-11-25 04:37:00 -0800334 video_encoder_config.number_of_streams = num_streams;
kthelgason2bc68642017-02-07 07:02:22 -0800335 video_encoder_config.max_bitrate_bps = kTargetBitrateBps;
asapersson5f7226f2016-11-25 04:37:00 -0800336 video_encoder_config.video_stream_factory =
sprangfda496a2017-06-15 04:21:07 -0700337 new rtc::RefCountedObject<VideoStreamFactory>(num_temporal_layers,
338 kDefaultFramerate);
sprang4847ae62017-06-27 07:06:52 -0700339 video_encoder_config.content_type =
340 screenshare ? VideoEncoderConfig::ContentType::kScreen
341 : VideoEncoderConfig::ContentType::kRealtimeVideo;
emircanbbcc3562017-08-18 00:28:40 -0700342 if (payload_name == "VP9") {
343 VideoCodecVP9 vp9_settings = VideoEncoder::GetDefaultVp9Settings();
344 vp9_settings.numberOfSpatialLayers = num_spatial_layers;
345 video_encoder_config.encoder_specific_settings =
346 new rtc::RefCountedObject<
347 VideoEncoderConfig::Vp9EncoderSpecificSettings>(vp9_settings);
348 }
Niels Möllerf1338562018-04-26 09:51:47 +0200349 ConfigureEncoder(std::move(video_encoder_config));
perkj26091b12016-09-01 01:17:40 -0700350 }
351
sprang57c2fff2017-01-16 06:24:02 -0800352 VideoFrame CreateFrame(int64_t ntp_time_ms,
353 rtc::Event* destruction_event) const {
Per512ecb32016-09-23 15:52:06 +0200354 VideoFrame frame(new rtc::RefCountedObject<TestBuffer>(
355 destruction_event, codec_width_, codec_height_),
356 99, 99, kVideoRotation_0);
sprang57c2fff2017-01-16 06:24:02 -0800357 frame.set_ntp_time_ms(ntp_time_ms);
perkj26091b12016-09-01 01:17:40 -0700358 return frame;
359 }
360
sprang57c2fff2017-01-16 06:24:02 -0800361 VideoFrame CreateFrame(int64_t ntp_time_ms, int width, int height) const {
perkj803d97f2016-11-01 11:45:46 -0700362 VideoFrame frame(
363 new rtc::RefCountedObject<TestBuffer>(nullptr, width, height), 99, 99,
364 kVideoRotation_0);
sprang57c2fff2017-01-16 06:24:02 -0800365 frame.set_ntp_time_ms(ntp_time_ms);
sprangc5d62e22017-04-02 23:53:04 -0700366 frame.set_timestamp_us(ntp_time_ms * 1000);
perkj803d97f2016-11-01 11:45:46 -0700367 return frame;
368 }
369
asapersson02465b82017-04-10 01:12:52 -0700370 void VerifyNoLimitation(const rtc::VideoSinkWants& wants) {
asapersson02465b82017-04-10 01:12:52 -0700371 EXPECT_EQ(std::numeric_limits<int>::max(), wants.max_framerate_fps);
asapersson09f05612017-05-15 23:40:18 -0700372 EXPECT_EQ(std::numeric_limits<int>::max(), wants.max_pixel_count);
373 EXPECT_FALSE(wants.target_pixel_count);
asapersson02465b82017-04-10 01:12:52 -0700374 }
375
asapersson09f05612017-05-15 23:40:18 -0700376 void VerifyFpsEqResolutionEq(const rtc::VideoSinkWants& wants1,
377 const rtc::VideoSinkWants& wants2) {
378 EXPECT_EQ(wants1.max_framerate_fps, wants2.max_framerate_fps);
379 EXPECT_EQ(wants1.max_pixel_count, wants2.max_pixel_count);
380 }
381
Åsa Persson8c1bf952018-09-13 10:42:19 +0200382 void VerifyFpsMaxResolutionMax(const rtc::VideoSinkWants& wants) {
383 EXPECT_EQ(kDefaultFramerate, wants.max_framerate_fps);
384 EXPECT_EQ(std::numeric_limits<int>::max(), wants.max_pixel_count);
385 EXPECT_FALSE(wants.target_pixel_count);
386 }
387
asapersson09f05612017-05-15 23:40:18 -0700388 void VerifyFpsMaxResolutionLt(const rtc::VideoSinkWants& wants1,
389 const rtc::VideoSinkWants& wants2) {
Åsa Persson8c1bf952018-09-13 10:42:19 +0200390 EXPECT_EQ(kDefaultFramerate, wants1.max_framerate_fps);
asapersson09f05612017-05-15 23:40:18 -0700391 EXPECT_LT(wants1.max_pixel_count, wants2.max_pixel_count);
392 EXPECT_GT(wants1.max_pixel_count, 0);
393 }
394
395 void VerifyFpsMaxResolutionGt(const rtc::VideoSinkWants& wants1,
396 const rtc::VideoSinkWants& wants2) {
Åsa Persson8c1bf952018-09-13 10:42:19 +0200397 EXPECT_EQ(kDefaultFramerate, wants1.max_framerate_fps);
asapersson09f05612017-05-15 23:40:18 -0700398 EXPECT_GT(wants1.max_pixel_count, wants2.max_pixel_count);
399 }
400
asaperssonf7e294d2017-06-13 23:25:22 -0700401 void VerifyFpsMaxResolutionEq(const rtc::VideoSinkWants& wants1,
402 const rtc::VideoSinkWants& wants2) {
Åsa Persson8c1bf952018-09-13 10:42:19 +0200403 EXPECT_EQ(kDefaultFramerate, wants1.max_framerate_fps);
asaperssonf7e294d2017-06-13 23:25:22 -0700404 EXPECT_EQ(wants1.max_pixel_count, wants2.max_pixel_count);
405 }
406
407 void VerifyFpsLtResolutionEq(const rtc::VideoSinkWants& wants1,
408 const rtc::VideoSinkWants& wants2) {
409 EXPECT_LT(wants1.max_framerate_fps, wants2.max_framerate_fps);
410 EXPECT_EQ(wants1.max_pixel_count, wants2.max_pixel_count);
411 }
412
413 void VerifyFpsGtResolutionEq(const rtc::VideoSinkWants& wants1,
414 const rtc::VideoSinkWants& wants2) {
415 EXPECT_GT(wants1.max_framerate_fps, wants2.max_framerate_fps);
416 EXPECT_EQ(wants1.max_pixel_count, wants2.max_pixel_count);
417 }
418
419 void VerifyFpsEqResolutionLt(const rtc::VideoSinkWants& wants1,
420 const rtc::VideoSinkWants& wants2) {
421 EXPECT_EQ(wants1.max_framerate_fps, wants2.max_framerate_fps);
422 EXPECT_LT(wants1.max_pixel_count, wants2.max_pixel_count);
423 EXPECT_GT(wants1.max_pixel_count, 0);
424 }
425
426 void VerifyFpsEqResolutionGt(const rtc::VideoSinkWants& wants1,
427 const rtc::VideoSinkWants& wants2) {
428 EXPECT_EQ(wants1.max_framerate_fps, wants2.max_framerate_fps);
429 EXPECT_GT(wants1.max_pixel_count, wants2.max_pixel_count);
430 }
431
asapersson09f05612017-05-15 23:40:18 -0700432 void VerifyFpsMaxResolutionLt(const rtc::VideoSinkWants& wants,
433 int pixel_count) {
Åsa Persson8c1bf952018-09-13 10:42:19 +0200434 EXPECT_EQ(kDefaultFramerate, wants.max_framerate_fps);
asapersson02465b82017-04-10 01:12:52 -0700435 EXPECT_LT(wants.max_pixel_count, pixel_count);
436 EXPECT_GT(wants.max_pixel_count, 0);
asapersson09f05612017-05-15 23:40:18 -0700437 }
438
439 void VerifyFpsLtResolutionMax(const rtc::VideoSinkWants& wants, int fps) {
440 EXPECT_LT(wants.max_framerate_fps, fps);
441 EXPECT_EQ(std::numeric_limits<int>::max(), wants.max_pixel_count);
442 EXPECT_FALSE(wants.target_pixel_count);
asapersson02465b82017-04-10 01:12:52 -0700443 }
444
asaperssonf7e294d2017-06-13 23:25:22 -0700445 void VerifyFpsEqResolutionMax(const rtc::VideoSinkWants& wants,
446 int expected_fps) {
447 EXPECT_EQ(expected_fps, wants.max_framerate_fps);
448 EXPECT_EQ(std::numeric_limits<int>::max(), wants.max_pixel_count);
449 EXPECT_FALSE(wants.target_pixel_count);
450 }
451
Jonathan Yubc771b72017-12-08 17:04:29 -0800452 void VerifyBalancedModeFpsRange(const rtc::VideoSinkWants& wants,
453 int last_frame_pixels) {
454 // Balanced mode should always scale FPS to the desired range before
455 // attempting to scale resolution.
456 int fps_limit = wants.max_framerate_fps;
457 if (last_frame_pixels <= 320 * 240) {
458 EXPECT_TRUE(7 <= fps_limit && fps_limit <= 10);
459 } else if (last_frame_pixels <= 480 * 270) {
460 EXPECT_TRUE(10 <= fps_limit && fps_limit <= 15);
461 } else if (last_frame_pixels <= 640 * 480) {
462 EXPECT_LE(15, fps_limit);
463 } else {
Åsa Persson8c1bf952018-09-13 10:42:19 +0200464 EXPECT_EQ(kDefaultFramerate, fps_limit);
Jonathan Yubc771b72017-12-08 17:04:29 -0800465 }
466 }
467
sprang4847ae62017-06-27 07:06:52 -0700468 void WaitForEncodedFrame(int64_t expected_ntp_time) {
469 sink_.WaitForEncodedFrame(expected_ntp_time);
470 fake_clock_.AdvanceTimeMicros(rtc::kNumMicrosecsPerSec / max_framerate_);
471 }
472
473 bool TimedWaitForEncodedFrame(int64_t expected_ntp_time, int64_t timeout_ms) {
474 bool ok = sink_.TimedWaitForEncodedFrame(expected_ntp_time, timeout_ms);
475 fake_clock_.AdvanceTimeMicros(rtc::kNumMicrosecsPerSec / max_framerate_);
476 return ok;
477 }
478
479 void WaitForEncodedFrame(uint32_t expected_width, uint32_t expected_height) {
480 sink_.WaitForEncodedFrame(expected_width, expected_height);
481 fake_clock_.AdvanceTimeMicros(rtc::kNumMicrosecsPerSec / max_framerate_);
482 }
483
484 void ExpectDroppedFrame() {
485 sink_.ExpectDroppedFrame();
486 fake_clock_.AdvanceTimeMicros(rtc::kNumMicrosecsPerSec / max_framerate_);
487 }
488
489 bool WaitForFrame(int64_t timeout_ms) {
490 bool ok = sink_.WaitForFrame(timeout_ms);
491 fake_clock_.AdvanceTimeMicros(rtc::kNumMicrosecsPerSec / max_framerate_);
492 return ok;
493 }
494
perkj26091b12016-09-01 01:17:40 -0700495 class TestEncoder : public test::FakeEncoder {
496 public:
Niels Möllerc572ff32018-11-07 08:43:50 +0100497 TestEncoder() : FakeEncoder(Clock::GetRealTimeClock()) {}
perkj26091b12016-09-01 01:17:40 -0700498
asaperssonfab67072017-04-04 05:51:49 -0700499 VideoCodec codec_config() const {
brandtre78d2662017-01-16 05:57:16 -0800500 rtc::CritScope lock(&crit_sect_);
perkjfa10b552016-10-02 23:45:26 -0700501 return config_;
502 }
503
504 void BlockNextEncode() {
brandtre78d2662017-01-16 05:57:16 -0800505 rtc::CritScope lock(&local_crit_sect_);
perkjfa10b552016-10-02 23:45:26 -0700506 block_next_encode_ = true;
507 }
508
Erik Språngaed30702018-11-05 12:57:17 +0100509 VideoEncoder::EncoderInfo GetEncoderInfo() const override {
510 EncoderInfo info;
kthelgason2fc52542017-03-03 00:24:41 -0800511 rtc::CritScope lock(&local_crit_sect_);
Erik Språngaed30702018-11-05 12:57:17 +0100512 if (quality_scaling_) {
513 info.scaling_settings =
514 VideoEncoder::ScalingSettings(1, 2, kMinPixelsPerFrame);
515 }
516 return info;
kthelgason876222f2016-11-29 01:44:11 -0800517 }
518
perkjfa10b552016-10-02 23:45:26 -0700519 void ContinueEncode() { continue_encode_event_.Set(); }
520
521 void CheckLastTimeStampsMatch(int64_t ntp_time_ms,
522 uint32_t timestamp) const {
brandtre78d2662017-01-16 05:57:16 -0800523 rtc::CritScope lock(&local_crit_sect_);
perkjfa10b552016-10-02 23:45:26 -0700524 EXPECT_EQ(timestamp_, timestamp);
525 EXPECT_EQ(ntp_time_ms_, ntp_time_ms);
526 }
527
kthelgason2fc52542017-03-03 00:24:41 -0800528 void SetQualityScaling(bool b) {
529 rtc::CritScope lock(&local_crit_sect_);
530 quality_scaling_ = b;
531 }
kthelgasonad9010c2017-02-14 00:46:51 -0800532
sprangfe627f32017-03-29 08:24:59 -0700533 void ForceInitEncodeFailure(bool force_failure) {
534 rtc::CritScope lock(&local_crit_sect_);
535 force_init_encode_failed_ = force_failure;
536 }
537
perkjfa10b552016-10-02 23:45:26 -0700538 private:
perkj26091b12016-09-01 01:17:40 -0700539 int32_t Encode(const VideoFrame& input_image,
540 const CodecSpecificInfo* codec_specific_info,
541 const std::vector<FrameType>* frame_types) override {
542 bool block_encode;
543 {
brandtre78d2662017-01-16 05:57:16 -0800544 rtc::CritScope lock(&local_crit_sect_);
perkj26091b12016-09-01 01:17:40 -0700545 EXPECT_GT(input_image.timestamp(), timestamp_);
546 EXPECT_GT(input_image.ntp_time_ms(), ntp_time_ms_);
547 EXPECT_EQ(input_image.timestamp(), input_image.ntp_time_ms() * 90);
548
549 timestamp_ = input_image.timestamp();
550 ntp_time_ms_ = input_image.ntp_time_ms();
perkj803d97f2016-11-01 11:45:46 -0700551 last_input_width_ = input_image.width();
552 last_input_height_ = input_image.height();
perkj26091b12016-09-01 01:17:40 -0700553 block_encode = block_next_encode_;
554 block_next_encode_ = false;
555 }
556 int32_t result =
557 FakeEncoder::Encode(input_image, codec_specific_info, frame_types);
558 if (block_encode)
perkja49cbd32016-09-16 07:53:41 -0700559 EXPECT_TRUE(continue_encode_event_.Wait(kDefaultTimeoutMs));
perkj26091b12016-09-01 01:17:40 -0700560 return result;
561 }
562
sprangfe627f32017-03-29 08:24:59 -0700563 int32_t InitEncode(const VideoCodec* config,
564 int32_t number_of_cores,
565 size_t max_payload_size) override {
566 int res =
567 FakeEncoder::InitEncode(config, number_of_cores, max_payload_size);
568 rtc::CritScope lock(&local_crit_sect_);
Erik Språng82fad3d2018-03-21 09:57:23 +0100569 if (config->codecType == kVideoCodecVP8) {
sprangfe627f32017-03-29 08:24:59 -0700570 // Simulate setting up temporal layers, in order to validate the life
571 // cycle of these objects.
572 int num_streams = std::max<int>(1, config->numberOfSimulcastStreams);
sprangfe627f32017-03-29 08:24:59 -0700573 for (int i = 0; i < num_streams; ++i) {
574 allocated_temporal_layers_.emplace_back(
Erik Språng4529fbc2018-10-12 10:30:31 +0200575 CreateVp8TemporalLayers(Vp8TemporalLayersType::kFixedPattern,
576 config->VP8().numberOfTemporalLayers));
sprangfe627f32017-03-29 08:24:59 -0700577 }
578 }
579 if (force_init_encode_failed_)
580 return -1;
581 return res;
582 }
583
brandtre78d2662017-01-16 05:57:16 -0800584 rtc::CriticalSection local_crit_sect_;
danilchapa37de392017-09-09 04:17:22 -0700585 bool block_next_encode_ RTC_GUARDED_BY(local_crit_sect_) = false;
perkj26091b12016-09-01 01:17:40 -0700586 rtc::Event continue_encode_event_;
danilchapa37de392017-09-09 04:17:22 -0700587 uint32_t timestamp_ RTC_GUARDED_BY(local_crit_sect_) = 0;
588 int64_t ntp_time_ms_ RTC_GUARDED_BY(local_crit_sect_) = 0;
589 int last_input_width_ RTC_GUARDED_BY(local_crit_sect_) = 0;
590 int last_input_height_ RTC_GUARDED_BY(local_crit_sect_) = 0;
591 bool quality_scaling_ RTC_GUARDED_BY(local_crit_sect_) = true;
Erik Språng4529fbc2018-10-12 10:30:31 +0200592 std::vector<std::unique_ptr<Vp8TemporalLayers>> allocated_temporal_layers_
danilchapa37de392017-09-09 04:17:22 -0700593 RTC_GUARDED_BY(local_crit_sect_);
594 bool force_init_encode_failed_ RTC_GUARDED_BY(local_crit_sect_) = false;
perkj26091b12016-09-01 01:17:40 -0700595 };
596
mflodmancc3d4422017-08-03 08:27:51 -0700597 class TestSink : public VideoStreamEncoder::EncoderSink {
perkj26091b12016-09-01 01:17:40 -0700598 public:
599 explicit TestSink(TestEncoder* test_encoder)
Niels Möllerc572ff32018-11-07 08:43:50 +0100600 : test_encoder_(test_encoder) {}
perkj26091b12016-09-01 01:17:40 -0700601
perkj26091b12016-09-01 01:17:40 -0700602 void WaitForEncodedFrame(int64_t expected_ntp_time) {
sprang4847ae62017-06-27 07:06:52 -0700603 EXPECT_TRUE(
604 TimedWaitForEncodedFrame(expected_ntp_time, kDefaultTimeoutMs));
605 }
606
607 bool TimedWaitForEncodedFrame(int64_t expected_ntp_time,
608 int64_t timeout_ms) {
perkj26091b12016-09-01 01:17:40 -0700609 uint32_t timestamp = 0;
sprang4847ae62017-06-27 07:06:52 -0700610 if (!encoded_frame_event_.Wait(timeout_ms))
611 return false;
perkj26091b12016-09-01 01:17:40 -0700612 {
613 rtc::CritScope lock(&crit_);
sprangb1ca0732017-02-01 08:38:12 -0800614 timestamp = last_timestamp_;
perkj26091b12016-09-01 01:17:40 -0700615 }
616 test_encoder_->CheckLastTimeStampsMatch(expected_ntp_time, timestamp);
sprang4847ae62017-06-27 07:06:52 -0700617 return true;
perkj26091b12016-09-01 01:17:40 -0700618 }
619
sprangb1ca0732017-02-01 08:38:12 -0800620 void WaitForEncodedFrame(uint32_t expected_width,
621 uint32_t expected_height) {
sprangc5d62e22017-04-02 23:53:04 -0700622 EXPECT_TRUE(encoded_frame_event_.Wait(kDefaultTimeoutMs));
Åsa Perssonc74d8da2017-12-04 14:13:56 +0100623 CheckLastFrameSizeMatches(expected_width, expected_height);
sprangc5d62e22017-04-02 23:53:04 -0700624 }
625
Åsa Perssonc74d8da2017-12-04 14:13:56 +0100626 void CheckLastFrameSizeMatches(uint32_t expected_width,
sprangc5d62e22017-04-02 23:53:04 -0700627 uint32_t expected_height) {
sprangb1ca0732017-02-01 08:38:12 -0800628 uint32_t width = 0;
629 uint32_t height = 0;
sprangb1ca0732017-02-01 08:38:12 -0800630 {
631 rtc::CritScope lock(&crit_);
632 width = last_width_;
633 height = last_height_;
634 }
635 EXPECT_EQ(expected_height, height);
636 EXPECT_EQ(expected_width, width);
637 }
638
kthelgason2fc52542017-03-03 00:24:41 -0800639 void ExpectDroppedFrame() { EXPECT_FALSE(encoded_frame_event_.Wait(100)); }
kthelgason2bc68642017-02-07 07:02:22 -0800640
sprangc5d62e22017-04-02 23:53:04 -0700641 bool WaitForFrame(int64_t timeout_ms) {
642 return encoded_frame_event_.Wait(timeout_ms);
643 }
644
perkj26091b12016-09-01 01:17:40 -0700645 void SetExpectNoFrames() {
646 rtc::CritScope lock(&crit_);
647 expect_frames_ = false;
648 }
649
asaperssonfab67072017-04-04 05:51:49 -0700650 int number_of_reconfigurations() const {
Per512ecb32016-09-23 15:52:06 +0200651 rtc::CritScope lock(&crit_);
652 return number_of_reconfigurations_;
653 }
654
asaperssonfab67072017-04-04 05:51:49 -0700655 int last_min_transmit_bitrate() const {
Per512ecb32016-09-23 15:52:06 +0200656 rtc::CritScope lock(&crit_);
657 return min_transmit_bitrate_bps_;
658 }
659
perkj26091b12016-09-01 01:17:40 -0700660 private:
sergeyu2cb155a2016-11-04 11:39:29 -0700661 Result OnEncodedImage(
662 const EncodedImage& encoded_image,
663 const CodecSpecificInfo* codec_specific_info,
664 const RTPFragmentationHeader* fragmentation) override {
Per512ecb32016-09-23 15:52:06 +0200665 rtc::CritScope lock(&crit_);
666 EXPECT_TRUE(expect_frames_);
Niels Möller23775882018-08-16 10:24:12 +0200667 last_timestamp_ = encoded_image.Timestamp();
sprangb1ca0732017-02-01 08:38:12 -0800668 last_width_ = encoded_image._encodedWidth;
669 last_height_ = encoded_image._encodedHeight;
Per512ecb32016-09-23 15:52:06 +0200670 encoded_frame_event_.Set();
sprangb1ca0732017-02-01 08:38:12 -0800671 return Result(Result::OK, last_timestamp_);
Per512ecb32016-09-23 15:52:06 +0200672 }
673
674 void OnEncoderConfigurationChanged(std::vector<VideoStream> streams,
675 int min_transmit_bitrate_bps) override {
676 rtc::CriticalSection crit_;
677 ++number_of_reconfigurations_;
678 min_transmit_bitrate_bps_ = min_transmit_bitrate_bps;
679 }
680
perkj26091b12016-09-01 01:17:40 -0700681 rtc::CriticalSection crit_;
682 TestEncoder* test_encoder_;
683 rtc::Event encoded_frame_event_;
sprangb1ca0732017-02-01 08:38:12 -0800684 uint32_t last_timestamp_ = 0;
685 uint32_t last_height_ = 0;
686 uint32_t last_width_ = 0;
perkj26091b12016-09-01 01:17:40 -0700687 bool expect_frames_ = true;
Per512ecb32016-09-23 15:52:06 +0200688 int number_of_reconfigurations_ = 0;
689 int min_transmit_bitrate_bps_ = 0;
perkj26091b12016-09-01 01:17:40 -0700690 };
691
692 VideoSendStream::Config video_send_config_;
Erik Språng08127a92016-11-16 16:41:30 +0100693 VideoEncoderConfig video_encoder_config_;
Per512ecb32016-09-23 15:52:06 +0200694 int codec_width_;
695 int codec_height_;
sprang4847ae62017-06-27 07:06:52 -0700696 int max_framerate_;
perkj26091b12016-09-01 01:17:40 -0700697 TestEncoder fake_encoder_;
Niels Möllercbcbc222018-09-28 09:07:24 +0200698 test::VideoEncoderProxyFactory encoder_factory_;
sprangc5d62e22017-04-02 23:53:04 -0700699 std::unique_ptr<MockableSendStatisticsProxy> stats_proxy_;
perkj26091b12016-09-01 01:17:40 -0700700 TestSink sink_;
sprangb1ca0732017-02-01 08:38:12 -0800701 AdaptingFrameForwarder video_source_;
mflodmancc3d4422017-08-03 08:27:51 -0700702 std::unique_ptr<VideoStreamEncoderUnderTest> video_stream_encoder_;
sprang4847ae62017-06-27 07:06:52 -0700703 rtc::ScopedFakeClock fake_clock_;
perkj26091b12016-09-01 01:17:40 -0700704};
705
mflodmancc3d4422017-08-03 08:27:51 -0700706TEST_F(VideoStreamEncoderTest, EncodeOneFrame) {
707 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
Niels Möllerc572ff32018-11-07 08:43:50 +0100708 rtc::Event frame_destroyed_event;
perkja49cbd32016-09-16 07:53:41 -0700709 video_source_.IncomingCapturedFrame(CreateFrame(1, &frame_destroyed_event));
sprang4847ae62017-06-27 07:06:52 -0700710 WaitForEncodedFrame(1);
perkja49cbd32016-09-16 07:53:41 -0700711 EXPECT_TRUE(frame_destroyed_event.Wait(kDefaultTimeoutMs));
mflodmancc3d4422017-08-03 08:27:51 -0700712 video_stream_encoder_->Stop();
perkj26091b12016-09-01 01:17:40 -0700713}
714
mflodmancc3d4422017-08-03 08:27:51 -0700715TEST_F(VideoStreamEncoderTest, DropsFramesBeforeFirstOnBitrateUpdated) {
perkj26091b12016-09-01 01:17:40 -0700716 // Dropped since no target bitrate has been set.
Niels Möllerc572ff32018-11-07 08:43:50 +0100717 rtc::Event frame_destroyed_event;
Sebastian Janssona3177052018-04-10 13:05:49 +0200718 // The encoder will cache up to one frame for a short duration. Adding two
719 // frames means that the first frame will be dropped and the second frame will
720 // be sent when the encoder is enabled.
perkja49cbd32016-09-16 07:53:41 -0700721 video_source_.IncomingCapturedFrame(CreateFrame(1, &frame_destroyed_event));
Sebastian Janssona3177052018-04-10 13:05:49 +0200722 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
perkja49cbd32016-09-16 07:53:41 -0700723 EXPECT_TRUE(frame_destroyed_event.Wait(kDefaultTimeoutMs));
perkj26091b12016-09-01 01:17:40 -0700724
mflodmancc3d4422017-08-03 08:27:51 -0700725 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkj26091b12016-09-01 01:17:40 -0700726
Sebastian Janssona3177052018-04-10 13:05:49 +0200727 // The pending frame should be received.
sprang4847ae62017-06-27 07:06:52 -0700728 WaitForEncodedFrame(2);
Sebastian Janssona3177052018-04-10 13:05:49 +0200729 video_source_.IncomingCapturedFrame(CreateFrame(3, nullptr));
730
731 WaitForEncodedFrame(3);
mflodmancc3d4422017-08-03 08:27:51 -0700732 video_stream_encoder_->Stop();
perkj26091b12016-09-01 01:17:40 -0700733}
734
mflodmancc3d4422017-08-03 08:27:51 -0700735TEST_F(VideoStreamEncoderTest, DropsFramesWhenRateSetToZero) {
736 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkja49cbd32016-09-16 07:53:41 -0700737 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700738 WaitForEncodedFrame(1);
perkj26091b12016-09-01 01:17:40 -0700739
mflodmancc3d4422017-08-03 08:27:51 -0700740 video_stream_encoder_->OnBitrateUpdated(0, 0, 0);
Sebastian Janssona3177052018-04-10 13:05:49 +0200741 // The encoder will cache up to one frame for a short duration. Adding two
742 // frames means that the first frame will be dropped and the second frame will
743 // be sent when the encoder is resumed.
perkja49cbd32016-09-16 07:53:41 -0700744 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
Sebastian Janssona3177052018-04-10 13:05:49 +0200745 video_source_.IncomingCapturedFrame(CreateFrame(3, nullptr));
perkj26091b12016-09-01 01:17:40 -0700746
mflodmancc3d4422017-08-03 08:27:51 -0700747 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
sprang4847ae62017-06-27 07:06:52 -0700748 WaitForEncodedFrame(3);
Sebastian Janssona3177052018-04-10 13:05:49 +0200749 video_source_.IncomingCapturedFrame(CreateFrame(4, nullptr));
750 WaitForEncodedFrame(4);
mflodmancc3d4422017-08-03 08:27:51 -0700751 video_stream_encoder_->Stop();
perkj26091b12016-09-01 01:17:40 -0700752}
753
mflodmancc3d4422017-08-03 08:27:51 -0700754TEST_F(VideoStreamEncoderTest, DropsFramesWithSameOrOldNtpTimestamp) {
755 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkja49cbd32016-09-16 07:53:41 -0700756 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700757 WaitForEncodedFrame(1);
perkj26091b12016-09-01 01:17:40 -0700758
759 // This frame will be dropped since it has the same ntp timestamp.
perkja49cbd32016-09-16 07:53:41 -0700760 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
perkj26091b12016-09-01 01:17:40 -0700761
perkja49cbd32016-09-16 07:53:41 -0700762 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700763 WaitForEncodedFrame(2);
mflodmancc3d4422017-08-03 08:27:51 -0700764 video_stream_encoder_->Stop();
perkj26091b12016-09-01 01:17:40 -0700765}
766
mflodmancc3d4422017-08-03 08:27:51 -0700767TEST_F(VideoStreamEncoderTest, DropsFrameAfterStop) {
768 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkj26091b12016-09-01 01:17:40 -0700769
perkja49cbd32016-09-16 07:53:41 -0700770 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700771 WaitForEncodedFrame(1);
perkj26091b12016-09-01 01:17:40 -0700772
mflodmancc3d4422017-08-03 08:27:51 -0700773 video_stream_encoder_->Stop();
perkj26091b12016-09-01 01:17:40 -0700774 sink_.SetExpectNoFrames();
Niels Möllerc572ff32018-11-07 08:43:50 +0100775 rtc::Event frame_destroyed_event;
perkja49cbd32016-09-16 07:53:41 -0700776 video_source_.IncomingCapturedFrame(CreateFrame(2, &frame_destroyed_event));
777 EXPECT_TRUE(frame_destroyed_event.Wait(kDefaultTimeoutMs));
perkj26091b12016-09-01 01:17:40 -0700778}
779
mflodmancc3d4422017-08-03 08:27:51 -0700780TEST_F(VideoStreamEncoderTest, DropsPendingFramesOnSlowEncode) {
781 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkj26091b12016-09-01 01:17:40 -0700782
783 fake_encoder_.BlockNextEncode();
perkja49cbd32016-09-16 07:53:41 -0700784 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700785 WaitForEncodedFrame(1);
perkj26091b12016-09-01 01:17:40 -0700786 // Here, the encoder thread will be blocked in the TestEncoder waiting for a
787 // call to ContinueEncode.
perkja49cbd32016-09-16 07:53:41 -0700788 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
789 video_source_.IncomingCapturedFrame(CreateFrame(3, nullptr));
perkj26091b12016-09-01 01:17:40 -0700790 fake_encoder_.ContinueEncode();
sprang4847ae62017-06-27 07:06:52 -0700791 WaitForEncodedFrame(3);
perkj26091b12016-09-01 01:17:40 -0700792
mflodmancc3d4422017-08-03 08:27:51 -0700793 video_stream_encoder_->Stop();
perkj26091b12016-09-01 01:17:40 -0700794}
795
mflodmancc3d4422017-08-03 08:27:51 -0700796TEST_F(VideoStreamEncoderTest,
797 ConfigureEncoderTriggersOnEncoderConfigurationChanged) {
798 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
Per21d45d22016-10-30 21:37:57 +0100799 EXPECT_EQ(0, sink_.number_of_reconfigurations());
Per512ecb32016-09-23 15:52:06 +0200800
801 // Capture a frame and wait for it to synchronize with the encoder thread.
Perf8c5f2b2016-09-23 16:24:55 +0200802 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700803 WaitForEncodedFrame(1);
Per21d45d22016-10-30 21:37:57 +0100804 // The encoder will have been configured once when the first frame is
805 // received.
806 EXPECT_EQ(1, sink_.number_of_reconfigurations());
Per512ecb32016-09-23 15:52:06 +0200807
808 VideoEncoderConfig video_encoder_config;
Niels Möller259a4972018-04-05 15:36:51 +0200809 test::FillEncoderConfiguration(kVideoCodecVP8, 1, &video_encoder_config);
Per512ecb32016-09-23 15:52:06 +0200810 video_encoder_config.min_transmit_bitrate_bps = 9999;
mflodmancc3d4422017-08-03 08:27:51 -0700811 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
Niels Möllerf1338562018-04-26 09:51:47 +0200812 kMaxPayloadLength);
Per512ecb32016-09-23 15:52:06 +0200813
814 // Capture a frame and wait for it to synchronize with the encoder thread.
Perf8c5f2b2016-09-23 16:24:55 +0200815 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700816 WaitForEncodedFrame(2);
Per21d45d22016-10-30 21:37:57 +0100817 EXPECT_EQ(2, sink_.number_of_reconfigurations());
perkj3b703ed2016-09-29 23:25:40 -0700818 EXPECT_EQ(9999, sink_.last_min_transmit_bitrate());
perkj26105b42016-09-29 22:39:10 -0700819
mflodmancc3d4422017-08-03 08:27:51 -0700820 video_stream_encoder_->Stop();
perkj26105b42016-09-29 22:39:10 -0700821}
822
mflodmancc3d4422017-08-03 08:27:51 -0700823TEST_F(VideoStreamEncoderTest, FrameResolutionChangeReconfigureEncoder) {
824 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkjfa10b552016-10-02 23:45:26 -0700825
826 // Capture a frame and wait for it to synchronize with the encoder thread.
827 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700828 WaitForEncodedFrame(1);
Per21d45d22016-10-30 21:37:57 +0100829 // The encoder will have been configured once.
830 EXPECT_EQ(1, sink_.number_of_reconfigurations());
perkjfa10b552016-10-02 23:45:26 -0700831 EXPECT_EQ(codec_width_, fake_encoder_.codec_config().width);
832 EXPECT_EQ(codec_height_, fake_encoder_.codec_config().height);
833
834 codec_width_ *= 2;
835 codec_height_ *= 2;
836 // Capture a frame with a higher resolution and wait for it to synchronize
837 // with the encoder thread.
838 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700839 WaitForEncodedFrame(2);
perkjfa10b552016-10-02 23:45:26 -0700840 EXPECT_EQ(codec_width_, fake_encoder_.codec_config().width);
841 EXPECT_EQ(codec_height_, fake_encoder_.codec_config().height);
Per21d45d22016-10-30 21:37:57 +0100842 EXPECT_EQ(2, sink_.number_of_reconfigurations());
perkjfa10b552016-10-02 23:45:26 -0700843
mflodmancc3d4422017-08-03 08:27:51 -0700844 video_stream_encoder_->Stop();
perkjfa10b552016-10-02 23:45:26 -0700845}
846
mflodmancc3d4422017-08-03 08:27:51 -0700847TEST_F(VideoStreamEncoderTest, SwitchSourceDeregisterEncoderAsSink) {
perkj803d97f2016-11-01 11:45:46 -0700848 EXPECT_TRUE(video_source_.has_sinks());
849 test::FrameForwarder new_video_source;
mflodmancc3d4422017-08-03 08:27:51 -0700850 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -0700851 &new_video_source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
perkj803d97f2016-11-01 11:45:46 -0700852 EXPECT_FALSE(video_source_.has_sinks());
853 EXPECT_TRUE(new_video_source.has_sinks());
854
mflodmancc3d4422017-08-03 08:27:51 -0700855 video_stream_encoder_->Stop();
perkj803d97f2016-11-01 11:45:46 -0700856}
857
mflodmancc3d4422017-08-03 08:27:51 -0700858TEST_F(VideoStreamEncoderTest, SinkWantsRotationApplied) {
perkj803d97f2016-11-01 11:45:46 -0700859 EXPECT_FALSE(video_source_.sink_wants().rotation_applied);
mflodmancc3d4422017-08-03 08:27:51 -0700860 video_stream_encoder_->SetSink(&sink_, true /*rotation_applied*/);
perkj803d97f2016-11-01 11:45:46 -0700861 EXPECT_TRUE(video_source_.sink_wants().rotation_applied);
mflodmancc3d4422017-08-03 08:27:51 -0700862 video_stream_encoder_->Stop();
perkj803d97f2016-11-01 11:45:46 -0700863}
864
Jonathan Yubc771b72017-12-08 17:04:29 -0800865TEST_F(VideoStreamEncoderTest, TestCpuDowngrades_BalancedMode) {
866 const int kFramerateFps = 30;
asaperssonf7e294d2017-06-13 23:25:22 -0700867 const int kWidth = 1280;
868 const int kHeight = 720;
Jonathan Yubc771b72017-12-08 17:04:29 -0800869
870 // We rely on the automatic resolution adaptation, but we handle framerate
871 // adaptation manually by mocking the stats proxy.
872 video_source_.set_adaptation_enabled(true);
asaperssonf7e294d2017-06-13 23:25:22 -0700873
Taylor Brandstetter49fcc102018-05-16 14:20:41 -0700874 // Enable BALANCED preference, no initial limitation.
Jonathan Yubc771b72017-12-08 17:04:29 -0800875 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
Taylor Brandstetter49fcc102018-05-16 14:20:41 -0700876 video_stream_encoder_->SetSource(&video_source_,
877 webrtc::DegradationPreference::BALANCED);
Jonathan Yubc771b72017-12-08 17:04:29 -0800878 VerifyNoLimitation(video_source_.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -0700879 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
Jonathan Yubc771b72017-12-08 17:04:29 -0800880 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
asaperssonf7e294d2017-06-13 23:25:22 -0700881 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
882
Jonathan Yubc771b72017-12-08 17:04:29 -0800883 // Adapt down as far as possible.
884 rtc::VideoSinkWants last_wants;
885 int64_t t = 1;
886 int loop_count = 0;
887 do {
888 ++loop_count;
889 last_wants = video_source_.sink_wants();
890
891 // Simulate the framerate we've been asked to adapt to.
892 const int fps = std::min(kFramerateFps, last_wants.max_framerate_fps);
893 const int frame_interval_ms = rtc::kNumMillisecsPerSec / fps;
894 VideoSendStream::Stats mock_stats = stats_proxy_->GetStats();
895 mock_stats.input_frame_rate = fps;
896 stats_proxy_->SetMockStats(mock_stats);
897
898 video_source_.IncomingCapturedFrame(CreateFrame(t, kWidth, kHeight));
899 sink_.WaitForEncodedFrame(t);
900 t += frame_interval_ms;
901
mflodmancc3d4422017-08-03 08:27:51 -0700902 video_stream_encoder_->TriggerCpuOveruse();
Jonathan Yubc771b72017-12-08 17:04:29 -0800903 VerifyBalancedModeFpsRange(
904 video_source_.sink_wants(),
905 *video_source_.last_sent_width() * *video_source_.last_sent_height());
906 } while (video_source_.sink_wants().max_pixel_count <
907 last_wants.max_pixel_count ||
908 video_source_.sink_wants().max_framerate_fps <
909 last_wants.max_framerate_fps);
asaperssonf7e294d2017-06-13 23:25:22 -0700910
Jonathan Yubc771b72017-12-08 17:04:29 -0800911 // Verify that we've adapted all the way down.
912 stats_proxy_->ResetMockStats();
asaperssonf7e294d2017-06-13 23:25:22 -0700913 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
Jonathan Yubc771b72017-12-08 17:04:29 -0800914 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_framerate);
915 EXPECT_EQ(loop_count - 1,
asaperssonf7e294d2017-06-13 23:25:22 -0700916 stats_proxy_->GetStats().number_of_cpu_adapt_changes);
Jonathan Yubc771b72017-12-08 17:04:29 -0800917 EXPECT_EQ(kMinPixelsPerFrame, *video_source_.last_sent_width() *
918 *video_source_.last_sent_height());
919 EXPECT_EQ(kMinBalancedFramerateFps,
920 video_source_.sink_wants().max_framerate_fps);
asaperssonf7e294d2017-06-13 23:25:22 -0700921
Jonathan Yubc771b72017-12-08 17:04:29 -0800922 // Adapt back up the same number of times we adapted down.
923 for (int i = 0; i < loop_count - 1; ++i) {
924 last_wants = video_source_.sink_wants();
925
926 // Simulate the framerate we've been asked to adapt to.
927 const int fps = std::min(kFramerateFps, last_wants.max_framerate_fps);
928 const int frame_interval_ms = rtc::kNumMillisecsPerSec / fps;
929 VideoSendStream::Stats mock_stats = stats_proxy_->GetStats();
930 mock_stats.input_frame_rate = fps;
931 stats_proxy_->SetMockStats(mock_stats);
932
933 video_source_.IncomingCapturedFrame(CreateFrame(t, kWidth, kHeight));
934 sink_.WaitForEncodedFrame(t);
935 t += frame_interval_ms;
936
mflodmancc3d4422017-08-03 08:27:51 -0700937 video_stream_encoder_->TriggerCpuNormalUsage();
Jonathan Yubc771b72017-12-08 17:04:29 -0800938 VerifyBalancedModeFpsRange(
939 video_source_.sink_wants(),
940 *video_source_.last_sent_width() * *video_source_.last_sent_height());
941 EXPECT_TRUE(video_source_.sink_wants().max_pixel_count >
942 last_wants.max_pixel_count ||
943 video_source_.sink_wants().max_framerate_fps >
944 last_wants.max_framerate_fps);
asaperssonf7e294d2017-06-13 23:25:22 -0700945 }
946
Åsa Persson8c1bf952018-09-13 10:42:19 +0200947 VerifyFpsMaxResolutionMax(video_source_.sink_wants());
Jonathan Yubc771b72017-12-08 17:04:29 -0800948 stats_proxy_->ResetMockStats();
asaperssonf7e294d2017-06-13 23:25:22 -0700949 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
Jonathan Yubc771b72017-12-08 17:04:29 -0800950 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
951 EXPECT_EQ((loop_count - 1) * 2,
952 stats_proxy_->GetStats().number_of_cpu_adapt_changes);
asaperssonf7e294d2017-06-13 23:25:22 -0700953
mflodmancc3d4422017-08-03 08:27:51 -0700954 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -0700955}
mflodmancc3d4422017-08-03 08:27:51 -0700956TEST_F(VideoStreamEncoderTest, SinkWantsStoredByDegradationPreference) {
957 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson02465b82017-04-10 01:12:52 -0700958 VerifyNoLimitation(video_source_.sink_wants());
perkj803d97f2016-11-01 11:45:46 -0700959
sprangc5d62e22017-04-02 23:53:04 -0700960 const int kFrameWidth = 1280;
961 const int kFrameHeight = 720;
sprangc5d62e22017-04-02 23:53:04 -0700962
Åsa Persson8c1bf952018-09-13 10:42:19 +0200963 int64_t frame_timestamp = 1;
perkj803d97f2016-11-01 11:45:46 -0700964
kthelgason5e13d412016-12-01 03:59:51 -0800965 video_source_.IncomingCapturedFrame(
sprangc5d62e22017-04-02 23:53:04 -0700966 CreateFrame(frame_timestamp, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -0700967 WaitForEncodedFrame(frame_timestamp);
sprangc5d62e22017-04-02 23:53:04 -0700968 frame_timestamp += kFrameIntervalMs;
969
perkj803d97f2016-11-01 11:45:46 -0700970 // Trigger CPU overuse.
mflodmancc3d4422017-08-03 08:27:51 -0700971 video_stream_encoder_->TriggerCpuOveruse();
perkj803d97f2016-11-01 11:45:46 -0700972 video_source_.IncomingCapturedFrame(
sprangc5d62e22017-04-02 23:53:04 -0700973 CreateFrame(frame_timestamp, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -0700974 WaitForEncodedFrame(frame_timestamp);
sprangc5d62e22017-04-02 23:53:04 -0700975 frame_timestamp += kFrameIntervalMs;
sprang3ea3c772017-03-30 07:23:48 -0700976
asapersson0944a802017-04-07 00:57:58 -0700977 // Default degradation preference is maintain-framerate, so will lower max
sprangc5d62e22017-04-02 23:53:04 -0700978 // wanted resolution.
979 EXPECT_FALSE(video_source_.sink_wants().target_pixel_count);
980 EXPECT_LT(video_source_.sink_wants().max_pixel_count,
981 kFrameWidth * kFrameHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +0200982 EXPECT_EQ(kDefaultFramerate, video_source_.sink_wants().max_framerate_fps);
sprangc5d62e22017-04-02 23:53:04 -0700983
984 // Set new source, switch to maintain-resolution.
perkj803d97f2016-11-01 11:45:46 -0700985 test::FrameForwarder new_video_source;
mflodmancc3d4422017-08-03 08:27:51 -0700986 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -0700987 &new_video_source, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
perkj803d97f2016-11-01 11:45:46 -0700988
sprangc5d62e22017-04-02 23:53:04 -0700989 // Initially no degradation registered.
Åsa Persson8c1bf952018-09-13 10:42:19 +0200990 VerifyFpsMaxResolutionMax(new_video_source.sink_wants());
perkj803d97f2016-11-01 11:45:46 -0700991
sprangc5d62e22017-04-02 23:53:04 -0700992 // Force an input frame rate to be available, or the adaptation call won't
993 // know what framerate to adapt form.
asapersson02465b82017-04-10 01:12:52 -0700994 const int kInputFps = 30;
sprangc5d62e22017-04-02 23:53:04 -0700995 VideoSendStream::Stats stats = stats_proxy_->GetStats();
asapersson02465b82017-04-10 01:12:52 -0700996 stats.input_frame_rate = kInputFps;
sprangc5d62e22017-04-02 23:53:04 -0700997 stats_proxy_->SetMockStats(stats);
998
mflodmancc3d4422017-08-03 08:27:51 -0700999 video_stream_encoder_->TriggerCpuOveruse();
perkj803d97f2016-11-01 11:45:46 -07001000 new_video_source.IncomingCapturedFrame(
sprangc5d62e22017-04-02 23:53:04 -07001001 CreateFrame(frame_timestamp, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07001002 WaitForEncodedFrame(frame_timestamp);
sprangc5d62e22017-04-02 23:53:04 -07001003 frame_timestamp += kFrameIntervalMs;
1004
1005 // Some framerate constraint should be set.
sprang84a37592017-02-10 07:04:27 -08001006 EXPECT_FALSE(new_video_source.sink_wants().target_pixel_count);
sprangc5d62e22017-04-02 23:53:04 -07001007 EXPECT_EQ(std::numeric_limits<int>::max(),
1008 new_video_source.sink_wants().max_pixel_count);
asapersson02465b82017-04-10 01:12:52 -07001009 EXPECT_LT(new_video_source.sink_wants().max_framerate_fps, kInputFps);
sprangc5d62e22017-04-02 23:53:04 -07001010
asapersson02465b82017-04-10 01:12:52 -07001011 // Turn off degradation completely.
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001012 video_stream_encoder_->SetSource(&new_video_source,
1013 webrtc::DegradationPreference::DISABLED);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001014 VerifyFpsMaxResolutionMax(new_video_source.sink_wants());
sprangc5d62e22017-04-02 23:53:04 -07001015
mflodmancc3d4422017-08-03 08:27:51 -07001016 video_stream_encoder_->TriggerCpuOveruse();
sprangc5d62e22017-04-02 23:53:04 -07001017 new_video_source.IncomingCapturedFrame(
1018 CreateFrame(frame_timestamp, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07001019 WaitForEncodedFrame(frame_timestamp);
sprangc5d62e22017-04-02 23:53:04 -07001020 frame_timestamp += kFrameIntervalMs;
1021
1022 // Still no degradation.
Åsa Persson8c1bf952018-09-13 10:42:19 +02001023 VerifyFpsMaxResolutionMax(new_video_source.sink_wants());
perkj803d97f2016-11-01 11:45:46 -07001024
1025 // Calling SetSource with resolution scaling enabled apply the old SinkWants.
mflodmancc3d4422017-08-03 08:27:51 -07001026 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001027 &new_video_source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
sprangc5d62e22017-04-02 23:53:04 -07001028 EXPECT_LT(new_video_source.sink_wants().max_pixel_count,
1029 kFrameWidth * kFrameHeight);
sprang84a37592017-02-10 07:04:27 -08001030 EXPECT_FALSE(new_video_source.sink_wants().target_pixel_count);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001031 EXPECT_EQ(kDefaultFramerate, new_video_source.sink_wants().max_framerate_fps);
sprangc5d62e22017-04-02 23:53:04 -07001032
1033 // Calling SetSource with framerate scaling enabled apply the old SinkWants.
mflodmancc3d4422017-08-03 08:27:51 -07001034 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001035 &new_video_source, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
sprangc5d62e22017-04-02 23:53:04 -07001036 EXPECT_FALSE(new_video_source.sink_wants().target_pixel_count);
1037 EXPECT_EQ(std::numeric_limits<int>::max(),
1038 new_video_source.sink_wants().max_pixel_count);
asapersson02465b82017-04-10 01:12:52 -07001039 EXPECT_LT(new_video_source.sink_wants().max_framerate_fps, kInputFps);
perkj803d97f2016-11-01 11:45:46 -07001040
mflodmancc3d4422017-08-03 08:27:51 -07001041 video_stream_encoder_->Stop();
perkj803d97f2016-11-01 11:45:46 -07001042}
1043
mflodmancc3d4422017-08-03 08:27:51 -07001044TEST_F(VideoStreamEncoderTest, StatsTracksQualityAdaptationStats) {
1045 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkj803d97f2016-11-01 11:45:46 -07001046
asaperssonfab67072017-04-04 05:51:49 -07001047 const int kWidth = 1280;
1048 const int kHeight = 720;
asaperssonfab67072017-04-04 05:51:49 -07001049 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001050 WaitForEncodedFrame(1);
asaperssonfab67072017-04-04 05:51:49 -07001051 VideoSendStream::Stats stats = stats_proxy_->GetStats();
1052 EXPECT_FALSE(stats.bw_limited_resolution);
1053 EXPECT_EQ(0, stats.number_of_quality_adapt_changes);
1054
1055 // Trigger adapt down.
mflodmancc3d4422017-08-03 08:27:51 -07001056 video_stream_encoder_->TriggerQualityLow();
asaperssonfab67072017-04-04 05:51:49 -07001057 video_source_.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001058 WaitForEncodedFrame(2);
asaperssonfab67072017-04-04 05:51:49 -07001059
1060 stats = stats_proxy_->GetStats();
1061 EXPECT_TRUE(stats.bw_limited_resolution);
1062 EXPECT_EQ(1, stats.number_of_quality_adapt_changes);
1063
1064 // Trigger adapt up.
mflodmancc3d4422017-08-03 08:27:51 -07001065 video_stream_encoder_->TriggerQualityHigh();
asaperssonfab67072017-04-04 05:51:49 -07001066 video_source_.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001067 WaitForEncodedFrame(3);
asaperssonfab67072017-04-04 05:51:49 -07001068
1069 stats = stats_proxy_->GetStats();
1070 EXPECT_FALSE(stats.bw_limited_resolution);
1071 EXPECT_EQ(2, stats.number_of_quality_adapt_changes);
1072 EXPECT_EQ(0, stats.number_of_cpu_adapt_changes);
1073
mflodmancc3d4422017-08-03 08:27:51 -07001074 video_stream_encoder_->Stop();
asaperssonfab67072017-04-04 05:51:49 -07001075}
1076
mflodmancc3d4422017-08-03 08:27:51 -07001077TEST_F(VideoStreamEncoderTest, StatsTracksCpuAdaptationStats) {
1078 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonfab67072017-04-04 05:51:49 -07001079
1080 const int kWidth = 1280;
1081 const int kHeight = 720;
asaperssonfab67072017-04-04 05:51:49 -07001082 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001083 WaitForEncodedFrame(1);
perkj803d97f2016-11-01 11:45:46 -07001084 VideoSendStream::Stats stats = stats_proxy_->GetStats();
1085 EXPECT_FALSE(stats.cpu_limited_resolution);
1086 EXPECT_EQ(0, stats.number_of_cpu_adapt_changes);
1087
1088 // Trigger CPU overuse.
mflodmancc3d4422017-08-03 08:27:51 -07001089 video_stream_encoder_->TriggerCpuOveruse();
asaperssonfab67072017-04-04 05:51:49 -07001090 video_source_.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001091 WaitForEncodedFrame(2);
perkj803d97f2016-11-01 11:45:46 -07001092
1093 stats = stats_proxy_->GetStats();
1094 EXPECT_TRUE(stats.cpu_limited_resolution);
1095 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1096
1097 // Trigger CPU normal use.
mflodmancc3d4422017-08-03 08:27:51 -07001098 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssonfab67072017-04-04 05:51:49 -07001099 video_source_.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001100 WaitForEncodedFrame(3);
perkj803d97f2016-11-01 11:45:46 -07001101
1102 stats = stats_proxy_->GetStats();
1103 EXPECT_FALSE(stats.cpu_limited_resolution);
1104 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
asaperssonfab67072017-04-04 05:51:49 -07001105 EXPECT_EQ(0, stats.number_of_quality_adapt_changes);
perkj803d97f2016-11-01 11:45:46 -07001106
mflodmancc3d4422017-08-03 08:27:51 -07001107 video_stream_encoder_->Stop();
perkj803d97f2016-11-01 11:45:46 -07001108}
1109
mflodmancc3d4422017-08-03 08:27:51 -07001110TEST_F(VideoStreamEncoderTest, SwitchingSourceKeepsCpuAdaptation) {
1111 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
kthelgason876222f2016-11-29 01:44:11 -08001112
asaperssonfab67072017-04-04 05:51:49 -07001113 const int kWidth = 1280;
1114 const int kHeight = 720;
1115 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001116 WaitForEncodedFrame(1);
kthelgason876222f2016-11-29 01:44:11 -08001117 VideoSendStream::Stats stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001118 EXPECT_FALSE(stats.bw_limited_resolution);
kthelgason876222f2016-11-29 01:44:11 -08001119 EXPECT_FALSE(stats.cpu_limited_resolution);
1120 EXPECT_EQ(0, stats.number_of_cpu_adapt_changes);
1121
asaperssonfab67072017-04-04 05:51:49 -07001122 // Trigger CPU overuse.
mflodmancc3d4422017-08-03 08:27:51 -07001123 video_stream_encoder_->TriggerCpuOveruse();
asaperssonfab67072017-04-04 05:51:49 -07001124 video_source_.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001125 WaitForEncodedFrame(2);
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 new source with adaptation still enabled.
1132 test::FrameForwarder new_video_source;
mflodmancc3d4422017-08-03 08:27:51 -07001133 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001134 &new_video_source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
kthelgason876222f2016-11-29 01:44:11 -08001135
asaperssonfab67072017-04-04 05:51:49 -07001136 new_video_source.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001137 WaitForEncodedFrame(3);
kthelgason876222f2016-11-29 01:44:11 -08001138 stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001139 EXPECT_FALSE(stats.bw_limited_resolution);
kthelgason876222f2016-11-29 01:44:11 -08001140 EXPECT_TRUE(stats.cpu_limited_resolution);
1141 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1142
1143 // Set adaptation disabled.
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001144 video_stream_encoder_->SetSource(&new_video_source,
1145 webrtc::DegradationPreference::DISABLED);
kthelgason876222f2016-11-29 01:44:11 -08001146
asaperssonfab67072017-04-04 05:51:49 -07001147 new_video_source.IncomingCapturedFrame(CreateFrame(4, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001148 WaitForEncodedFrame(4);
kthelgason876222f2016-11-29 01:44:11 -08001149 stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001150 EXPECT_FALSE(stats.bw_limited_resolution);
kthelgason876222f2016-11-29 01:44:11 -08001151 EXPECT_FALSE(stats.cpu_limited_resolution);
1152 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1153
1154 // Set adaptation back to enabled.
mflodmancc3d4422017-08-03 08:27:51 -07001155 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001156 &new_video_source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
kthelgason876222f2016-11-29 01:44:11 -08001157
asaperssonfab67072017-04-04 05:51:49 -07001158 new_video_source.IncomingCapturedFrame(CreateFrame(5, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001159 WaitForEncodedFrame(5);
kthelgason876222f2016-11-29 01:44:11 -08001160 stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001161 EXPECT_FALSE(stats.bw_limited_resolution);
kthelgason876222f2016-11-29 01:44:11 -08001162 EXPECT_TRUE(stats.cpu_limited_resolution);
1163 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1164
asaperssonfab67072017-04-04 05:51:49 -07001165 // Trigger CPU normal use.
mflodmancc3d4422017-08-03 08:27:51 -07001166 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssonfab67072017-04-04 05:51:49 -07001167 new_video_source.IncomingCapturedFrame(CreateFrame(6, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001168 WaitForEncodedFrame(6);
kthelgason876222f2016-11-29 01:44:11 -08001169 stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001170 EXPECT_FALSE(stats.bw_limited_resolution);
kthelgason876222f2016-11-29 01:44:11 -08001171 EXPECT_FALSE(stats.cpu_limited_resolution);
1172 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
asapersson02465b82017-04-10 01:12:52 -07001173 EXPECT_EQ(0, stats.number_of_quality_adapt_changes);
kthelgason876222f2016-11-29 01:44:11 -08001174
mflodmancc3d4422017-08-03 08:27:51 -07001175 video_stream_encoder_->Stop();
kthelgason876222f2016-11-29 01:44:11 -08001176}
1177
mflodmancc3d4422017-08-03 08:27:51 -07001178TEST_F(VideoStreamEncoderTest, SwitchingSourceKeepsQualityAdaptation) {
1179 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
kthelgason876222f2016-11-29 01:44:11 -08001180
asaperssonfab67072017-04-04 05:51:49 -07001181 const int kWidth = 1280;
1182 const int kHeight = 720;
1183 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001184 WaitForEncodedFrame(1);
kthelgason876222f2016-11-29 01:44:11 -08001185 VideoSendStream::Stats 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
1190 // Set new source with adaptation still enabled.
1191 test::FrameForwarder new_video_source;
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001192 video_stream_encoder_->SetSource(&new_video_source,
1193 webrtc::DegradationPreference::BALANCED);
kthelgason876222f2016-11-29 01:44:11 -08001194
asaperssonfab67072017-04-04 05:51:49 -07001195 new_video_source.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001196 WaitForEncodedFrame(2);
kthelgason876222f2016-11-29 01:44:11 -08001197 stats = stats_proxy_->GetStats();
kthelgason876222f2016-11-29 01:44:11 -08001198 EXPECT_FALSE(stats.bw_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001199 EXPECT_FALSE(stats.bw_limited_framerate);
asaperssonfab67072017-04-04 05:51:49 -07001200 EXPECT_EQ(0, stats.number_of_quality_adapt_changes);
kthelgason876222f2016-11-29 01:44:11 -08001201
asaperssonfab67072017-04-04 05:51:49 -07001202 // Trigger adapt down.
mflodmancc3d4422017-08-03 08:27:51 -07001203 video_stream_encoder_->TriggerQualityLow();
asaperssonfab67072017-04-04 05:51:49 -07001204 new_video_source.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001205 WaitForEncodedFrame(3);
kthelgason876222f2016-11-29 01:44:11 -08001206 stats = stats_proxy_->GetStats();
kthelgason876222f2016-11-29 01:44:11 -08001207 EXPECT_TRUE(stats.bw_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001208 EXPECT_FALSE(stats.bw_limited_framerate);
asaperssonfab67072017-04-04 05:51:49 -07001209 EXPECT_EQ(1, stats.number_of_quality_adapt_changes);
kthelgason876222f2016-11-29 01:44:11 -08001210
asaperssonfab67072017-04-04 05:51:49 -07001211 // Set new source with adaptation still enabled.
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001212 video_stream_encoder_->SetSource(&new_video_source,
1213 webrtc::DegradationPreference::BALANCED);
kthelgason876222f2016-11-29 01:44:11 -08001214
asaperssonfab67072017-04-04 05:51:49 -07001215 new_video_source.IncomingCapturedFrame(CreateFrame(4, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001216 WaitForEncodedFrame(4);
kthelgason876222f2016-11-29 01:44:11 -08001217 stats = stats_proxy_->GetStats();
kthelgason876222f2016-11-29 01:44:11 -08001218 EXPECT_TRUE(stats.bw_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001219 EXPECT_FALSE(stats.bw_limited_framerate);
asaperssonfab67072017-04-04 05:51:49 -07001220 EXPECT_EQ(1, stats.number_of_quality_adapt_changes);
kthelgason876222f2016-11-29 01:44:11 -08001221
asapersson02465b82017-04-10 01:12:52 -07001222 // Disable resolution scaling.
mflodmancc3d4422017-08-03 08:27:51 -07001223 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001224 &new_video_source, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
kthelgason876222f2016-11-29 01:44:11 -08001225
asaperssonfab67072017-04-04 05:51:49 -07001226 new_video_source.IncomingCapturedFrame(CreateFrame(5, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001227 WaitForEncodedFrame(5);
kthelgason876222f2016-11-29 01:44:11 -08001228 stats = stats_proxy_->GetStats();
kthelgason876222f2016-11-29 01:44:11 -08001229 EXPECT_FALSE(stats.bw_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001230 EXPECT_FALSE(stats.bw_limited_framerate);
asaperssonfab67072017-04-04 05:51:49 -07001231 EXPECT_EQ(1, stats.number_of_quality_adapt_changes);
1232 EXPECT_EQ(0, stats.number_of_cpu_adapt_changes);
kthelgason876222f2016-11-29 01:44:11 -08001233
mflodmancc3d4422017-08-03 08:27:51 -07001234 video_stream_encoder_->Stop();
kthelgason876222f2016-11-29 01:44:11 -08001235}
1236
mflodmancc3d4422017-08-03 08:27:51 -07001237TEST_F(VideoStreamEncoderTest,
1238 QualityAdaptationStatsAreResetWhenScalerIsDisabled) {
1239 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson36e9eb42017-03-31 05:29:12 -07001240
1241 const int kWidth = 1280;
1242 const int kHeight = 720;
Åsa Persson8c1bf952018-09-13 10:42:19 +02001243 int64_t timestamp_ms = kFrameIntervalMs;
asapersson36e9eb42017-03-31 05:29:12 -07001244 video_source_.set_adaptation_enabled(true);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001245 video_source_.IncomingCapturedFrame(
1246 CreateFrame(timestamp_ms, kWidth, kHeight));
1247 WaitForEncodedFrame(timestamp_ms);
asapersson36e9eb42017-03-31 05:29:12 -07001248 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1249 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1250 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1251
1252 // Trigger adapt down.
mflodmancc3d4422017-08-03 08:27:51 -07001253 video_stream_encoder_->TriggerQualityLow();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001254 timestamp_ms += kFrameIntervalMs;
1255 video_source_.IncomingCapturedFrame(
1256 CreateFrame(timestamp_ms, kWidth, kHeight));
1257 WaitForEncodedFrame(timestamp_ms);
asapersson36e9eb42017-03-31 05:29:12 -07001258 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1259 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1260 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1261
1262 // Trigger overuse.
mflodmancc3d4422017-08-03 08:27:51 -07001263 video_stream_encoder_->TriggerCpuOveruse();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001264 timestamp_ms += kFrameIntervalMs;
1265 video_source_.IncomingCapturedFrame(
1266 CreateFrame(timestamp_ms, kWidth, kHeight));
1267 WaitForEncodedFrame(timestamp_ms);
asapersson36e9eb42017-03-31 05:29:12 -07001268 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1269 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1270 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1271
Niels Möller4db138e2018-04-19 09:04:13 +02001272 // Leave source unchanged, but disable quality scaler.
asapersson36e9eb42017-03-31 05:29:12 -07001273 fake_encoder_.SetQualityScaling(false);
Niels Möller4db138e2018-04-19 09:04:13 +02001274
1275 VideoEncoderConfig video_encoder_config;
1276 test::FillEncoderConfiguration(kVideoCodecVP8, 1, &video_encoder_config);
1277 // Make format different, to force recreation of encoder.
1278 video_encoder_config.video_format.parameters["foo"] = "foo";
1279 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
Niels Möllerf1338562018-04-26 09:51:47 +02001280 kMaxPayloadLength);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001281 timestamp_ms += kFrameIntervalMs;
1282 video_source_.IncomingCapturedFrame(
1283 CreateFrame(timestamp_ms, kWidth, kHeight));
1284 WaitForEncodedFrame(timestamp_ms);
asapersson36e9eb42017-03-31 05:29:12 -07001285 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1286 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1287 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1288
mflodmancc3d4422017-08-03 08:27:51 -07001289 video_stream_encoder_->Stop();
asapersson36e9eb42017-03-31 05:29:12 -07001290}
1291
mflodmancc3d4422017-08-03 08:27:51 -07001292TEST_F(VideoStreamEncoderTest,
1293 StatsTracksCpuAdaptationStatsWhenSwitchingSource) {
1294 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkj803d97f2016-11-01 11:45:46 -07001295
asapersson0944a802017-04-07 00:57:58 -07001296 const int kWidth = 1280;
1297 const int kHeight = 720;
sprang84a37592017-02-10 07:04:27 -08001298 int sequence = 1;
perkj803d97f2016-11-01 11:45:46 -07001299
asaperssonfab67072017-04-04 05:51:49 -07001300 video_source_.IncomingCapturedFrame(CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001301 WaitForEncodedFrame(sequence++);
perkj803d97f2016-11-01 11:45:46 -07001302 VideoSendStream::Stats stats = stats_proxy_->GetStats();
sprang84a37592017-02-10 07:04:27 -08001303 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001304 EXPECT_FALSE(stats.cpu_limited_framerate);
sprang84a37592017-02-10 07:04:27 -08001305 EXPECT_EQ(0, stats.number_of_cpu_adapt_changes);
1306
asapersson02465b82017-04-10 01:12:52 -07001307 // Trigger CPU overuse, should now adapt down.
mflodmancc3d4422017-08-03 08:27:51 -07001308 video_stream_encoder_->TriggerCpuOveruse();
asaperssonfab67072017-04-04 05:51:49 -07001309 video_source_.IncomingCapturedFrame(CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001310 WaitForEncodedFrame(sequence++);
sprang84a37592017-02-10 07:04:27 -08001311 stats = stats_proxy_->GetStats();
perkj803d97f2016-11-01 11:45:46 -07001312 EXPECT_TRUE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001313 EXPECT_FALSE(stats.cpu_limited_framerate);
perkj803d97f2016-11-01 11:45:46 -07001314 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1315
1316 // Set new source with adaptation still enabled.
1317 test::FrameForwarder new_video_source;
mflodmancc3d4422017-08-03 08:27:51 -07001318 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001319 &new_video_source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
perkj803d97f2016-11-01 11:45:46 -07001320
1321 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001322 CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001323 WaitForEncodedFrame(sequence++);
perkj803d97f2016-11-01 11:45:46 -07001324 stats = stats_proxy_->GetStats();
1325 EXPECT_TRUE(stats.cpu_limited_resolution);
asapersson09f05612017-05-15 23:40:18 -07001326 EXPECT_FALSE(stats.cpu_limited_framerate);
perkj803d97f2016-11-01 11:45:46 -07001327 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1328
sprangc5d62e22017-04-02 23:53:04 -07001329 // Set cpu adaptation by frame dropping.
mflodmancc3d4422017-08-03 08:27:51 -07001330 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001331 &new_video_source, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
perkj803d97f2016-11-01 11:45:46 -07001332 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001333 CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001334 WaitForEncodedFrame(sequence++);
perkj803d97f2016-11-01 11:45:46 -07001335 stats = stats_proxy_->GetStats();
sprangc5d62e22017-04-02 23:53:04 -07001336 // Not adapted at first.
perkj803d97f2016-11-01 11:45:46 -07001337 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson09f05612017-05-15 23:40:18 -07001338 EXPECT_FALSE(stats.cpu_limited_framerate);
perkj803d97f2016-11-01 11:45:46 -07001339 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1340
sprangc5d62e22017-04-02 23:53:04 -07001341 // Force an input frame rate to be available, or the adaptation call won't
asapersson09f05612017-05-15 23:40:18 -07001342 // know what framerate to adapt from.
sprangc5d62e22017-04-02 23:53:04 -07001343 VideoSendStream::Stats mock_stats = stats_proxy_->GetStats();
1344 mock_stats.input_frame_rate = 30;
1345 stats_proxy_->SetMockStats(mock_stats);
mflodmancc3d4422017-08-03 08:27:51 -07001346 video_stream_encoder_->TriggerCpuOveruse();
sprangc5d62e22017-04-02 23:53:04 -07001347 stats_proxy_->ResetMockStats();
1348
1349 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001350 CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001351 WaitForEncodedFrame(sequence++);
sprangc5d62e22017-04-02 23:53:04 -07001352
1353 // Framerate now adapted.
1354 stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001355 EXPECT_FALSE(stats.cpu_limited_resolution);
1356 EXPECT_TRUE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001357 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
1358
1359 // Disable CPU adaptation.
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001360 video_stream_encoder_->SetSource(&new_video_source,
1361 webrtc::DegradationPreference::DISABLED);
sprangc5d62e22017-04-02 23:53:04 -07001362 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001363 CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001364 WaitForEncodedFrame(sequence++);
sprangc5d62e22017-04-02 23:53:04 -07001365
1366 stats = stats_proxy_->GetStats();
1367 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001368 EXPECT_FALSE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001369 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
1370
1371 // Try to trigger overuse. Should not succeed.
1372 stats_proxy_->SetMockStats(mock_stats);
mflodmancc3d4422017-08-03 08:27:51 -07001373 video_stream_encoder_->TriggerCpuOveruse();
sprangc5d62e22017-04-02 23:53:04 -07001374 stats_proxy_->ResetMockStats();
1375
1376 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(2, stats.number_of_cpu_adapt_changes);
1380
1381 // Switch back the source with resolution adaptation enabled.
mflodmancc3d4422017-08-03 08:27:51 -07001382 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001383 &video_source_, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
asaperssonfab67072017-04-04 05:51:49 -07001384 video_source_.IncomingCapturedFrame(CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001385 WaitForEncodedFrame(sequence++);
perkj803d97f2016-11-01 11:45:46 -07001386 stats = stats_proxy_->GetStats();
1387 EXPECT_TRUE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001388 EXPECT_FALSE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001389 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
perkj803d97f2016-11-01 11:45:46 -07001390
1391 // Trigger CPU normal usage.
mflodmancc3d4422017-08-03 08:27:51 -07001392 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssonfab67072017-04-04 05:51:49 -07001393 video_source_.IncomingCapturedFrame(CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001394 WaitForEncodedFrame(sequence++);
perkj803d97f2016-11-01 11:45:46 -07001395 stats = stats_proxy_->GetStats();
1396 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001397 EXPECT_FALSE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001398 EXPECT_EQ(3, stats.number_of_cpu_adapt_changes);
1399
1400 // Back to the source with adaptation off, set it back to maintain-resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001401 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001402 &new_video_source, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
sprangc5d62e22017-04-02 23:53:04 -07001403 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001404 CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001405 WaitForEncodedFrame(sequence++);
sprangc5d62e22017-04-02 23:53:04 -07001406 stats = stats_proxy_->GetStats();
asapersson13874762017-06-07 00:01:02 -07001407 // Disabled, since we previously switched the source to disabled.
sprangc5d62e22017-04-02 23:53:04 -07001408 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001409 EXPECT_TRUE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001410 EXPECT_EQ(3, stats.number_of_cpu_adapt_changes);
1411
1412 // Trigger CPU normal usage.
mflodmancc3d4422017-08-03 08:27:51 -07001413 video_stream_encoder_->TriggerCpuNormalUsage();
sprangc5d62e22017-04-02 23:53:04 -07001414 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001415 CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001416 WaitForEncodedFrame(sequence++);
sprangc5d62e22017-04-02 23:53:04 -07001417 stats = stats_proxy_->GetStats();
1418 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001419 EXPECT_FALSE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001420 EXPECT_EQ(4, stats.number_of_cpu_adapt_changes);
asapersson02465b82017-04-10 01:12:52 -07001421 EXPECT_EQ(0, stats.number_of_quality_adapt_changes);
perkj803d97f2016-11-01 11:45:46 -07001422
mflodmancc3d4422017-08-03 08:27:51 -07001423 video_stream_encoder_->Stop();
perkj803d97f2016-11-01 11:45:46 -07001424}
1425
mflodmancc3d4422017-08-03 08:27:51 -07001426TEST_F(VideoStreamEncoderTest,
1427 ScalingUpAndDownDoesNothingWithMaintainResolution) {
asaperssonfab67072017-04-04 05:51:49 -07001428 const int kWidth = 1280;
1429 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001430 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
kthelgason876222f2016-11-29 01:44:11 -08001431
asaperssonfab67072017-04-04 05:51:49 -07001432 // Expect no scaling to begin with.
asapersson02465b82017-04-10 01:12:52 -07001433 VerifyNoLimitation(video_source_.sink_wants());
kthelgason876222f2016-11-29 01:44:11 -08001434
asaperssonfab67072017-04-04 05:51:49 -07001435 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001436 WaitForEncodedFrame(1);
kthelgason876222f2016-11-29 01:44:11 -08001437
asaperssonfab67072017-04-04 05:51:49 -07001438 // Trigger scale down.
mflodmancc3d4422017-08-03 08:27:51 -07001439 video_stream_encoder_->TriggerQualityLow();
kthelgason5e13d412016-12-01 03:59:51 -08001440
asaperssonfab67072017-04-04 05:51:49 -07001441 video_source_.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001442 WaitForEncodedFrame(2);
kthelgason5e13d412016-12-01 03:59:51 -08001443
kthelgason876222f2016-11-29 01:44:11 -08001444 // Expect a scale down.
1445 EXPECT_TRUE(video_source_.sink_wants().max_pixel_count);
asaperssonfab67072017-04-04 05:51:49 -07001446 EXPECT_LT(video_source_.sink_wants().max_pixel_count, kWidth * kHeight);
kthelgason876222f2016-11-29 01:44:11 -08001447
asapersson02465b82017-04-10 01:12:52 -07001448 // Set resolution scaling disabled.
kthelgason876222f2016-11-29 01:44:11 -08001449 test::FrameForwarder new_video_source;
mflodmancc3d4422017-08-03 08:27:51 -07001450 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001451 &new_video_source, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
kthelgason876222f2016-11-29 01:44:11 -08001452
asaperssonfab67072017-04-04 05:51:49 -07001453 // Trigger scale down.
mflodmancc3d4422017-08-03 08:27:51 -07001454 video_stream_encoder_->TriggerQualityLow();
asaperssonfab67072017-04-04 05:51:49 -07001455 new_video_source.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001456 WaitForEncodedFrame(3);
kthelgason876222f2016-11-29 01:44:11 -08001457
asaperssonfab67072017-04-04 05:51:49 -07001458 // Expect no scaling.
sprangc5d62e22017-04-02 23:53:04 -07001459 EXPECT_EQ(std::numeric_limits<int>::max(),
1460 new_video_source.sink_wants().max_pixel_count);
kthelgason876222f2016-11-29 01:44:11 -08001461
asaperssonfab67072017-04-04 05:51:49 -07001462 // Trigger scale up.
mflodmancc3d4422017-08-03 08:27:51 -07001463 video_stream_encoder_->TriggerQualityHigh();
asaperssonfab67072017-04-04 05:51:49 -07001464 new_video_source.IncomingCapturedFrame(CreateFrame(4, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001465 WaitForEncodedFrame(4);
kthelgason876222f2016-11-29 01:44:11 -08001466
asapersson02465b82017-04-10 01:12:52 -07001467 // Expect nothing to change, still no scaling.
sprangc5d62e22017-04-02 23:53:04 -07001468 EXPECT_EQ(std::numeric_limits<int>::max(),
1469 new_video_source.sink_wants().max_pixel_count);
kthelgason876222f2016-11-29 01:44:11 -08001470
mflodmancc3d4422017-08-03 08:27:51 -07001471 video_stream_encoder_->Stop();
kthelgason876222f2016-11-29 01:44:11 -08001472}
1473
mflodmancc3d4422017-08-03 08:27:51 -07001474TEST_F(VideoStreamEncoderTest,
1475 SkipsSameAdaptDownRequest_MaintainFramerateMode) {
asapersson02465b82017-04-10 01:12:52 -07001476 const int kWidth = 1280;
1477 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001478 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson02465b82017-04-10 01:12:52 -07001479
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001480 // Enable MAINTAIN_FRAMERATE preference, no initial limitation.
asapersson02465b82017-04-10 01:12:52 -07001481 test::FrameForwarder source;
mflodmancc3d4422017-08-03 08:27:51 -07001482 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001483 &source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
asapersson02465b82017-04-10 01:12:52 -07001484
1485 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001486 WaitForEncodedFrame(1);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001487 VerifyFpsMaxResolutionMax(source.sink_wants());
asapersson02465b82017-04-10 01:12:52 -07001488 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1489 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1490
1491 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001492 video_stream_encoder_->TriggerCpuOveruse();
asapersson09f05612017-05-15 23:40:18 -07001493 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
asapersson02465b82017-04-10 01:12:52 -07001494 const int kLastMaxPixelCount = source.sink_wants().max_pixel_count;
1495 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1496 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1497
1498 // Trigger adapt down for same input resolution, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07001499 video_stream_encoder_->TriggerCpuOveruse();
asapersson02465b82017-04-10 01:12:52 -07001500 EXPECT_EQ(kLastMaxPixelCount, source.sink_wants().max_pixel_count);
1501 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1502 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1503
mflodmancc3d4422017-08-03 08:27:51 -07001504 video_stream_encoder_->Stop();
asapersson02465b82017-04-10 01:12:52 -07001505}
1506
mflodmancc3d4422017-08-03 08:27:51 -07001507TEST_F(VideoStreamEncoderTest, SkipsSameOrLargerAdaptDownRequest_BalancedMode) {
asaperssonf7e294d2017-06-13 23:25:22 -07001508 const int kWidth = 1280;
1509 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001510 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -07001511
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001512 // Enable BALANCED preference, no initial limitation.
asaperssonf7e294d2017-06-13 23:25:22 -07001513 test::FrameForwarder source;
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001514 video_stream_encoder_->SetSource(&source,
1515 webrtc::DegradationPreference::BALANCED);
asaperssonf7e294d2017-06-13 23:25:22 -07001516 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
1517 sink_.WaitForEncodedFrame(1);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001518 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07001519
1520 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001521 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07001522 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
1523 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1524 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1525 const int kLastMaxPixelCount = source.sink_wants().max_pixel_count;
1526
1527 // Trigger adapt down for same input resolution, expect no change.
1528 source.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
1529 sink_.WaitForEncodedFrame(2);
mflodmancc3d4422017-08-03 08:27:51 -07001530 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07001531 EXPECT_EQ(kLastMaxPixelCount, source.sink_wants().max_pixel_count);
1532 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1533 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1534
1535 // Trigger adapt down for larger input resolution, expect no change.
1536 source.IncomingCapturedFrame(CreateFrame(3, kWidth + 1, kHeight + 1));
1537 sink_.WaitForEncodedFrame(3);
mflodmancc3d4422017-08-03 08:27:51 -07001538 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07001539 EXPECT_EQ(kLastMaxPixelCount, source.sink_wants().max_pixel_count);
1540 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1541 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1542
mflodmancc3d4422017-08-03 08:27:51 -07001543 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07001544}
1545
mflodmancc3d4422017-08-03 08:27:51 -07001546TEST_F(VideoStreamEncoderTest,
1547 NoChangeForInitialNormalUsage_MaintainFramerateMode) {
asapersson02465b82017-04-10 01:12:52 -07001548 const int kWidth = 1280;
1549 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001550 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson02465b82017-04-10 01:12:52 -07001551
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001552 // Enable MAINTAIN_FRAMERATE preference, no initial limitation.
asapersson02465b82017-04-10 01:12:52 -07001553 test::FrameForwarder source;
mflodmancc3d4422017-08-03 08:27:51 -07001554 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001555 &source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
asapersson02465b82017-04-10 01:12:52 -07001556
1557 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001558 WaitForEncodedFrame(kWidth, kHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001559 VerifyFpsMaxResolutionMax(source.sink_wants());
asapersson02465b82017-04-10 01:12:52 -07001560 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1561 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1562
1563 // Trigger adapt up, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07001564 video_stream_encoder_->TriggerCpuNormalUsage();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001565 VerifyFpsMaxResolutionMax(source.sink_wants());
asapersson02465b82017-04-10 01:12:52 -07001566 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1567 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1568
mflodmancc3d4422017-08-03 08:27:51 -07001569 video_stream_encoder_->Stop();
asapersson02465b82017-04-10 01:12:52 -07001570}
1571
mflodmancc3d4422017-08-03 08:27:51 -07001572TEST_F(VideoStreamEncoderTest,
1573 NoChangeForInitialNormalUsage_MaintainResolutionMode) {
asapersson02465b82017-04-10 01:12:52 -07001574 const int kWidth = 1280;
1575 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001576 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson02465b82017-04-10 01:12:52 -07001577
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001578 // Enable MAINTAIN_RESOLUTION preference, no initial limitation.
asapersson02465b82017-04-10 01:12:52 -07001579 test::FrameForwarder source;
mflodmancc3d4422017-08-03 08:27:51 -07001580 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001581 &source, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
asapersson02465b82017-04-10 01:12:52 -07001582
1583 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001584 WaitForEncodedFrame(kWidth, kHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001585 VerifyFpsMaxResolutionMax(source.sink_wants());
asapersson09f05612017-05-15 23:40:18 -07001586 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
asapersson02465b82017-04-10 01:12:52 -07001587 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1588
1589 // Trigger adapt up, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07001590 video_stream_encoder_->TriggerCpuNormalUsage();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001591 VerifyFpsMaxResolutionMax(source.sink_wants());
asapersson09f05612017-05-15 23:40:18 -07001592 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
asapersson02465b82017-04-10 01:12:52 -07001593 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1594
mflodmancc3d4422017-08-03 08:27:51 -07001595 video_stream_encoder_->Stop();
asapersson02465b82017-04-10 01:12:52 -07001596}
1597
mflodmancc3d4422017-08-03 08:27:51 -07001598TEST_F(VideoStreamEncoderTest, NoChangeForInitialNormalUsage_BalancedMode) {
asaperssonf7e294d2017-06-13 23:25:22 -07001599 const int kWidth = 1280;
1600 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001601 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -07001602
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001603 // Enable BALANCED preference, no initial limitation.
asaperssonf7e294d2017-06-13 23:25:22 -07001604 test::FrameForwarder source;
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001605 video_stream_encoder_->SetSource(&source,
1606 webrtc::DegradationPreference::BALANCED);
asaperssonf7e294d2017-06-13 23:25:22 -07001607
1608 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
1609 sink_.WaitForEncodedFrame(kWidth, kHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001610 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07001611 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1612 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
1613 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1614
1615 // Trigger adapt up, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07001616 video_stream_encoder_->TriggerQualityHigh();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001617 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07001618 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1619 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
1620 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1621
mflodmancc3d4422017-08-03 08:27:51 -07001622 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07001623}
1624
mflodmancc3d4422017-08-03 08:27:51 -07001625TEST_F(VideoStreamEncoderTest, NoChangeForInitialNormalUsage_DisabledMode) {
asapersson09f05612017-05-15 23:40:18 -07001626 const int kWidth = 1280;
1627 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001628 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson09f05612017-05-15 23:40:18 -07001629
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001630 // Enable DISABLED preference, no initial limitation.
asapersson09f05612017-05-15 23:40:18 -07001631 test::FrameForwarder source;
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001632 video_stream_encoder_->SetSource(&source,
1633 webrtc::DegradationPreference::DISABLED);
asapersson09f05612017-05-15 23:40:18 -07001634
1635 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
1636 sink_.WaitForEncodedFrame(kWidth, kHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001637 VerifyFpsMaxResolutionMax(source.sink_wants());
asapersson09f05612017-05-15 23:40:18 -07001638 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1639 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
1640 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1641
1642 // Trigger adapt up, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07001643 video_stream_encoder_->TriggerQualityHigh();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001644 VerifyFpsMaxResolutionMax(source.sink_wants());
asapersson09f05612017-05-15 23:40:18 -07001645 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1646 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
1647 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1648
mflodmancc3d4422017-08-03 08:27:51 -07001649 video_stream_encoder_->Stop();
asapersson09f05612017-05-15 23:40:18 -07001650}
1651
mflodmancc3d4422017-08-03 08:27:51 -07001652TEST_F(VideoStreamEncoderTest,
1653 AdaptsResolutionForLowQuality_MaintainFramerateMode) {
asapersson02465b82017-04-10 01:12:52 -07001654 const int kWidth = 1280;
1655 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001656 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson02465b82017-04-10 01:12:52 -07001657
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001658 // Enable MAINTAIN_FRAMERATE preference, no initial limitation.
asapersson02465b82017-04-10 01:12:52 -07001659 AdaptingFrameForwarder source;
1660 source.set_adaptation_enabled(true);
mflodmancc3d4422017-08-03 08:27:51 -07001661 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001662 &source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
asapersson02465b82017-04-10 01:12:52 -07001663
1664 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001665 WaitForEncodedFrame(1);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001666 VerifyFpsMaxResolutionMax(source.sink_wants());
asapersson02465b82017-04-10 01:12:52 -07001667 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1668 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1669
1670 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001671 video_stream_encoder_->TriggerQualityLow();
asapersson02465b82017-04-10 01:12:52 -07001672 source.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001673 WaitForEncodedFrame(2);
asapersson09f05612017-05-15 23:40:18 -07001674 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
asapersson02465b82017-04-10 01:12:52 -07001675 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1676 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1677
1678 // Trigger adapt up, expect no restriction.
mflodmancc3d4422017-08-03 08:27:51 -07001679 video_stream_encoder_->TriggerQualityHigh();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001680 VerifyFpsMaxResolutionMax(source.sink_wants());
asapersson02465b82017-04-10 01:12:52 -07001681 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1682 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1683 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1684
mflodmancc3d4422017-08-03 08:27:51 -07001685 video_stream_encoder_->Stop();
asapersson02465b82017-04-10 01:12:52 -07001686}
1687
mflodmancc3d4422017-08-03 08:27:51 -07001688TEST_F(VideoStreamEncoderTest,
1689 AdaptsFramerateForLowQuality_MaintainResolutionMode) {
asapersson09f05612017-05-15 23:40:18 -07001690 const int kWidth = 1280;
1691 const int kHeight = 720;
1692 const int kInputFps = 30;
mflodmancc3d4422017-08-03 08:27:51 -07001693 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson09f05612017-05-15 23:40:18 -07001694
1695 VideoSendStream::Stats stats = stats_proxy_->GetStats();
1696 stats.input_frame_rate = kInputFps;
1697 stats_proxy_->SetMockStats(stats);
1698
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001699 // Expect no scaling to begin with (preference: MAINTAIN_FRAMERATE).
asapersson09f05612017-05-15 23:40:18 -07001700 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
1701 sink_.WaitForEncodedFrame(1);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001702 VerifyFpsMaxResolutionMax(video_source_.sink_wants());
asapersson09f05612017-05-15 23:40:18 -07001703
1704 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001705 video_stream_encoder_->TriggerQualityLow();
asapersson09f05612017-05-15 23:40:18 -07001706 video_source_.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
1707 sink_.WaitForEncodedFrame(2);
1708 VerifyFpsMaxResolutionLt(video_source_.sink_wants(), kWidth * kHeight);
1709
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001710 // Enable MAINTAIN_RESOLUTION preference.
asapersson09f05612017-05-15 23:40:18 -07001711 test::FrameForwarder new_video_source;
mflodmancc3d4422017-08-03 08:27:51 -07001712 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001713 &new_video_source, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001714 VerifyFpsMaxResolutionMax(new_video_source.sink_wants());
asapersson09f05612017-05-15 23:40:18 -07001715
1716 // Trigger adapt down, expect reduced framerate.
mflodmancc3d4422017-08-03 08:27:51 -07001717 video_stream_encoder_->TriggerQualityLow();
asapersson09f05612017-05-15 23:40:18 -07001718 new_video_source.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
1719 sink_.WaitForEncodedFrame(3);
1720 VerifyFpsLtResolutionMax(new_video_source.sink_wants(), kInputFps);
1721
1722 // Trigger adapt up, expect no restriction.
mflodmancc3d4422017-08-03 08:27:51 -07001723 video_stream_encoder_->TriggerQualityHigh();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001724 VerifyFpsMaxResolutionMax(new_video_source.sink_wants());
asapersson09f05612017-05-15 23:40:18 -07001725
mflodmancc3d4422017-08-03 08:27:51 -07001726 video_stream_encoder_->Stop();
asapersson09f05612017-05-15 23:40:18 -07001727}
1728
mflodmancc3d4422017-08-03 08:27:51 -07001729TEST_F(VideoStreamEncoderTest, DoesNotScaleBelowSetResolutionLimit) {
asaperssond0de2952017-04-21 01:47:31 -07001730 const int kWidth = 1280;
1731 const int kHeight = 720;
1732 const size_t kNumFrames = 10;
1733
mflodmancc3d4422017-08-03 08:27:51 -07001734 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
kthelgason5e13d412016-12-01 03:59:51 -08001735
asaperssond0de2952017-04-21 01:47:31 -07001736 // Enable adapter, expected input resolutions when downscaling:
asapersson142fcc92017-08-17 08:58:54 -07001737 // 1280x720 -> 960x540 -> 640x360 -> 480x270 -> 320x180 (kMinPixelsPerFrame)
asaperssond0de2952017-04-21 01:47:31 -07001738 video_source_.set_adaptation_enabled(true);
1739
1740 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1741 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1742
1743 int downscales = 0;
1744 for (size_t i = 1; i <= kNumFrames; i++) {
Åsa Persson8c1bf952018-09-13 10:42:19 +02001745 video_source_.IncomingCapturedFrame(
1746 CreateFrame(i * kFrameIntervalMs, kWidth, kHeight));
1747 WaitForEncodedFrame(i * kFrameIntervalMs);
asaperssond0de2952017-04-21 01:47:31 -07001748
asaperssonfab67072017-04-04 05:51:49 -07001749 // Trigger scale down.
asaperssond0de2952017-04-21 01:47:31 -07001750 rtc::VideoSinkWants last_wants = video_source_.sink_wants();
mflodmancc3d4422017-08-03 08:27:51 -07001751 video_stream_encoder_->TriggerQualityLow();
sprangc5d62e22017-04-02 23:53:04 -07001752 EXPECT_GE(video_source_.sink_wants().max_pixel_count, kMinPixelsPerFrame);
asaperssond0de2952017-04-21 01:47:31 -07001753
1754 if (video_source_.sink_wants().max_pixel_count < last_wants.max_pixel_count)
1755 ++downscales;
1756
1757 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1758 EXPECT_EQ(downscales,
1759 stats_proxy_->GetStats().number_of_quality_adapt_changes);
1760 EXPECT_GT(downscales, 0);
kthelgason5e13d412016-12-01 03:59:51 -08001761 }
mflodmancc3d4422017-08-03 08:27:51 -07001762 video_stream_encoder_->Stop();
asaperssond0de2952017-04-21 01:47:31 -07001763}
1764
mflodmancc3d4422017-08-03 08:27:51 -07001765TEST_F(VideoStreamEncoderTest,
asaperssond0de2952017-04-21 01:47:31 -07001766 AdaptsResolutionUpAndDownTwiceOnOveruse_MaintainFramerateMode) {
1767 const int kWidth = 1280;
1768 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001769 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssond0de2952017-04-21 01:47:31 -07001770
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001771 // Enable MAINTAIN_FRAMERATE preference, no initial limitation.
asaperssond0de2952017-04-21 01:47:31 -07001772 AdaptingFrameForwarder source;
1773 source.set_adaptation_enabled(true);
mflodmancc3d4422017-08-03 08:27:51 -07001774 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001775 &source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
asaperssond0de2952017-04-21 01:47:31 -07001776
Åsa Persson8c1bf952018-09-13 10:42:19 +02001777 int64_t timestamp_ms = kFrameIntervalMs;
1778 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001779 WaitForEncodedFrame(kWidth, kHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001780 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssond0de2952017-04-21 01:47:31 -07001781 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1782 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1783
1784 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001785 video_stream_encoder_->TriggerCpuOveruse();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001786 timestamp_ms += kFrameIntervalMs;
1787 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
1788 WaitForEncodedFrame(timestamp_ms);
asapersson09f05612017-05-15 23:40:18 -07001789 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
asaperssond0de2952017-04-21 01:47:31 -07001790 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1791 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1792
1793 // Trigger adapt up, expect no restriction.
mflodmancc3d4422017-08-03 08:27:51 -07001794 video_stream_encoder_->TriggerCpuNormalUsage();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001795 timestamp_ms += kFrameIntervalMs;
1796 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001797 WaitForEncodedFrame(kWidth, kHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001798 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssond0de2952017-04-21 01:47:31 -07001799 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1800 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1801
1802 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001803 video_stream_encoder_->TriggerCpuOveruse();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001804 timestamp_ms += kFrameIntervalMs;
1805 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
1806 WaitForEncodedFrame(timestamp_ms);
asapersson09f05612017-05-15 23:40:18 -07001807 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
asaperssond0de2952017-04-21 01:47:31 -07001808 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1809 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1810
1811 // Trigger adapt up, expect no restriction.
mflodmancc3d4422017-08-03 08:27:51 -07001812 video_stream_encoder_->TriggerCpuNormalUsage();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001813 timestamp_ms += kFrameIntervalMs;
1814 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
asapersson09f05612017-05-15 23:40:18 -07001815 sink_.WaitForEncodedFrame(kWidth, kHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001816 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssond0de2952017-04-21 01:47:31 -07001817 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1818 EXPECT_EQ(4, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1819
mflodmancc3d4422017-08-03 08:27:51 -07001820 video_stream_encoder_->Stop();
asaperssond0de2952017-04-21 01:47:31 -07001821}
1822
mflodmancc3d4422017-08-03 08:27:51 -07001823TEST_F(VideoStreamEncoderTest,
asaperssonf7e294d2017-06-13 23:25:22 -07001824 AdaptsResolutionUpAndDownTwiceForLowQuality_BalancedMode_NoFpsLimit) {
1825 const int kWidth = 1280;
1826 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001827 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -07001828
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001829 // Enable BALANCED preference, no initial limitation.
asaperssonf7e294d2017-06-13 23:25:22 -07001830 AdaptingFrameForwarder source;
1831 source.set_adaptation_enabled(true);
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001832 video_stream_encoder_->SetSource(&source,
1833 webrtc::DegradationPreference::BALANCED);
asaperssonf7e294d2017-06-13 23:25:22 -07001834
Åsa Persson8c1bf952018-09-13 10:42:19 +02001835 int64_t timestamp_ms = kFrameIntervalMs;
1836 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
asaperssonf7e294d2017-06-13 23:25:22 -07001837 sink_.WaitForEncodedFrame(kWidth, kHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001838 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07001839 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1840 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1841
1842 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001843 video_stream_encoder_->TriggerQualityLow();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001844 timestamp_ms += kFrameIntervalMs;
1845 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
1846 sink_.WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07001847 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
1848 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1849 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1850
1851 // Trigger adapt up, expect no restriction.
mflodmancc3d4422017-08-03 08:27:51 -07001852 video_stream_encoder_->TriggerQualityHigh();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001853 timestamp_ms += kFrameIntervalMs;
1854 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
asaperssonf7e294d2017-06-13 23:25:22 -07001855 sink_.WaitForEncodedFrame(kWidth, kHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001856 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07001857 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1858 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1859
1860 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001861 video_stream_encoder_->TriggerQualityLow();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001862 timestamp_ms += kFrameIntervalMs;
1863 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
1864 sink_.WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07001865 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
1866 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1867 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1868
1869 // Trigger adapt up, expect no restriction.
mflodmancc3d4422017-08-03 08:27:51 -07001870 video_stream_encoder_->TriggerQualityHigh();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001871 timestamp_ms += kFrameIntervalMs;
1872 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
asaperssonf7e294d2017-06-13 23:25:22 -07001873 sink_.WaitForEncodedFrame(kWidth, kHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001874 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07001875 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1876 EXPECT_EQ(4, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1877
mflodmancc3d4422017-08-03 08:27:51 -07001878 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07001879}
1880
mflodmancc3d4422017-08-03 08:27:51 -07001881TEST_F(VideoStreamEncoderTest,
asaperssond0de2952017-04-21 01:47:31 -07001882 AdaptsResolutionOnOveruseAndLowQuality_MaintainFramerateMode) {
1883 const int kWidth = 1280;
1884 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001885 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssond0de2952017-04-21 01:47:31 -07001886
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001887 // Enable MAINTAIN_FRAMERATE preference, no initial limitation.
asaperssond0de2952017-04-21 01:47:31 -07001888 AdaptingFrameForwarder source;
1889 source.set_adaptation_enabled(true);
mflodmancc3d4422017-08-03 08:27:51 -07001890 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001891 &source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
asaperssond0de2952017-04-21 01:47:31 -07001892
Åsa Persson8c1bf952018-09-13 10:42:19 +02001893 int64_t timestamp_ms = kFrameIntervalMs;
1894 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001895 WaitForEncodedFrame(kWidth, kHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001896 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssond0de2952017-04-21 01:47:31 -07001897 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1898 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1899 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1900 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1901
1902 // Trigger cpu adapt down, expect scaled down resolution (960x540).
mflodmancc3d4422017-08-03 08:27:51 -07001903 video_stream_encoder_->TriggerCpuOveruse();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001904 timestamp_ms += kFrameIntervalMs;
1905 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
1906 WaitForEncodedFrame(timestamp_ms);
asapersson09f05612017-05-15 23:40:18 -07001907 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
asaperssond0de2952017-04-21 01:47:31 -07001908 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1909 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1910 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1911 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1912
1913 // Trigger cpu adapt down, expect scaled down resolution (640x360).
mflodmancc3d4422017-08-03 08:27:51 -07001914 video_stream_encoder_->TriggerCpuOveruse();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001915 timestamp_ms += kFrameIntervalMs;
1916 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
1917 WaitForEncodedFrame(timestamp_ms);
asapersson09f05612017-05-15 23:40:18 -07001918 VerifyFpsMaxResolutionLt(source.sink_wants(), source.last_wants());
asaperssond0de2952017-04-21 01:47:31 -07001919 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1920 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1921 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1922 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1923
Jonathan Yubc771b72017-12-08 17:04:29 -08001924 // Trigger cpu adapt down, expect scaled down resolution (480x270).
mflodmancc3d4422017-08-03 08:27:51 -07001925 video_stream_encoder_->TriggerCpuOveruse();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001926 timestamp_ms += kFrameIntervalMs;
1927 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
1928 WaitForEncodedFrame(timestamp_ms);
Jonathan Yubc771b72017-12-08 17:04:29 -08001929 VerifyFpsMaxResolutionLt(source.sink_wants(), source.last_wants());
asaperssond0de2952017-04-21 01:47:31 -07001930 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1931 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
Jonathan Yubc771b72017-12-08 17:04:29 -08001932 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
asaperssond0de2952017-04-21 01:47:31 -07001933 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1934
Jonathan Yubc771b72017-12-08 17:04:29 -08001935 // Trigger quality adapt down, expect scaled down resolution (320x180).
mflodmancc3d4422017-08-03 08:27:51 -07001936 video_stream_encoder_->TriggerQualityLow();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001937 timestamp_ms += kFrameIntervalMs;
1938 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
1939 WaitForEncodedFrame(timestamp_ms);
asapersson09f05612017-05-15 23:40:18 -07001940 VerifyFpsMaxResolutionLt(source.sink_wants(), source.last_wants());
Jonathan Yubc771b72017-12-08 17:04:29 -08001941 rtc::VideoSinkWants last_wants = source.sink_wants();
asaperssond0de2952017-04-21 01:47:31 -07001942 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1943 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1944 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1945 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1946
Jonathan Yubc771b72017-12-08 17:04:29 -08001947 // Trigger quality adapt down, expect no change (min resolution reached).
1948 video_stream_encoder_->TriggerQualityLow();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001949 timestamp_ms += kFrameIntervalMs;
1950 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
1951 WaitForEncodedFrame(timestamp_ms);
Jonathan Yubc771b72017-12-08 17:04:29 -08001952 VerifyFpsMaxResolutionEq(source.sink_wants(), last_wants);
1953 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1954 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1955 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1956 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1957
1958 // Trigger cpu adapt up, expect upscaled resolution (480x270).
mflodmancc3d4422017-08-03 08:27:51 -07001959 video_stream_encoder_->TriggerCpuNormalUsage();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001960 timestamp_ms += kFrameIntervalMs;
1961 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
1962 WaitForEncodedFrame(timestamp_ms);
asapersson09f05612017-05-15 23:40:18 -07001963 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
Jonathan Yubc771b72017-12-08 17:04:29 -08001964 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1965 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1966 EXPECT_EQ(4, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1967 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1968
1969 // Trigger cpu adapt up, expect upscaled resolution (640x360).
1970 video_stream_encoder_->TriggerCpuNormalUsage();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001971 timestamp_ms += kFrameIntervalMs;
1972 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
1973 WaitForEncodedFrame(timestamp_ms);
Jonathan Yubc771b72017-12-08 17:04:29 -08001974 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
1975 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1976 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1977 EXPECT_EQ(5, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1978 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1979
1980 // Trigger cpu adapt up, expect upscaled resolution (960x540).
1981 video_stream_encoder_->TriggerCpuNormalUsage();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001982 timestamp_ms += kFrameIntervalMs;
1983 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
1984 WaitForEncodedFrame(timestamp_ms);
Jonathan Yubc771b72017-12-08 17:04:29 -08001985 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
asaperssond0de2952017-04-21 01:47:31 -07001986 last_wants = source.sink_wants();
1987 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1988 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
Jonathan Yubc771b72017-12-08 17:04:29 -08001989 EXPECT_EQ(6, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
asaperssond0de2952017-04-21 01:47:31 -07001990 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1991
1992 // Trigger cpu adapt up, no cpu downgrades, expect no change (960x540).
mflodmancc3d4422017-08-03 08:27:51 -07001993 video_stream_encoder_->TriggerCpuNormalUsage();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001994 timestamp_ms += kFrameIntervalMs;
1995 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
1996 WaitForEncodedFrame(timestamp_ms);
asapersson09f05612017-05-15 23:40:18 -07001997 VerifyFpsEqResolutionEq(source.sink_wants(), last_wants);
asaperssond0de2952017-04-21 01:47:31 -07001998 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1999 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
Jonathan Yubc771b72017-12-08 17:04:29 -08002000 EXPECT_EQ(6, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
asaperssond0de2952017-04-21 01:47:31 -07002001 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2002
2003 // Trigger quality adapt up, expect no restriction (1280x720).
mflodmancc3d4422017-08-03 08:27:51 -07002004 video_stream_encoder_->TriggerQualityHigh();
Åsa Persson8c1bf952018-09-13 10:42:19 +02002005 timestamp_ms += kFrameIntervalMs;
2006 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002007 WaitForEncodedFrame(kWidth, kHeight);
asapersson09f05612017-05-15 23:40:18 -07002008 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
Åsa Persson8c1bf952018-09-13 10:42:19 +02002009 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssond0de2952017-04-21 01:47:31 -07002010 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2011 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
Jonathan Yubc771b72017-12-08 17:04:29 -08002012 EXPECT_EQ(6, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
asaperssond0de2952017-04-21 01:47:31 -07002013 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
kthelgason5e13d412016-12-01 03:59:51 -08002014
mflodmancc3d4422017-08-03 08:27:51 -07002015 video_stream_encoder_->Stop();
kthelgason5e13d412016-12-01 03:59:51 -08002016}
2017
mflodmancc3d4422017-08-03 08:27:51 -07002018TEST_F(VideoStreamEncoderTest, CpuLimitedHistogramIsReported) {
asaperssonfab67072017-04-04 05:51:49 -07002019 const int kWidth = 640;
2020 const int kHeight = 360;
perkj803d97f2016-11-01 11:45:46 -07002021
mflodmancc3d4422017-08-03 08:27:51 -07002022 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
sprang4847ae62017-06-27 07:06:52 -07002023
perkj803d97f2016-11-01 11:45:46 -07002024 for (int i = 1; i <= SendStatisticsProxy::kMinRequiredMetricsSamples; ++i) {
asaperssonfab67072017-04-04 05:51:49 -07002025 video_source_.IncomingCapturedFrame(CreateFrame(i, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002026 WaitForEncodedFrame(i);
perkj803d97f2016-11-01 11:45:46 -07002027 }
2028
mflodmancc3d4422017-08-03 08:27:51 -07002029 video_stream_encoder_->TriggerCpuOveruse();
perkj803d97f2016-11-01 11:45:46 -07002030 for (int i = 1; i <= SendStatisticsProxy::kMinRequiredMetricsSamples; ++i) {
asaperssonfab67072017-04-04 05:51:49 -07002031 video_source_.IncomingCapturedFrame(CreateFrame(
2032 SendStatisticsProxy::kMinRequiredMetricsSamples + i, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002033 WaitForEncodedFrame(SendStatisticsProxy::kMinRequiredMetricsSamples + i);
perkj803d97f2016-11-01 11:45:46 -07002034 }
2035
mflodmancc3d4422017-08-03 08:27:51 -07002036 video_stream_encoder_->Stop();
2037 video_stream_encoder_.reset();
perkj803d97f2016-11-01 11:45:46 -07002038 stats_proxy_.reset();
sprangf8ee65e2017-02-28 08:49:33 -08002039
perkj803d97f2016-11-01 11:45:46 -07002040 EXPECT_EQ(1,
2041 metrics::NumSamples("WebRTC.Video.CpuLimitedResolutionInPercent"));
2042 EXPECT_EQ(
2043 1, metrics::NumEvents("WebRTC.Video.CpuLimitedResolutionInPercent", 50));
2044}
2045
mflodmancc3d4422017-08-03 08:27:51 -07002046TEST_F(VideoStreamEncoderTest,
2047 CpuLimitedHistogramIsNotReportedForDisabledDegradation) {
2048 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonf4e44af2017-04-19 02:01:06 -07002049 const int kWidth = 640;
2050 const int kHeight = 360;
2051
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002052 video_stream_encoder_->SetSource(&video_source_,
2053 webrtc::DegradationPreference::DISABLED);
asaperssonf4e44af2017-04-19 02:01:06 -07002054
2055 for (int i = 1; i <= SendStatisticsProxy::kMinRequiredMetricsSamples; ++i) {
2056 video_source_.IncomingCapturedFrame(CreateFrame(i, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002057 WaitForEncodedFrame(i);
asaperssonf4e44af2017-04-19 02:01:06 -07002058 }
2059
mflodmancc3d4422017-08-03 08:27:51 -07002060 video_stream_encoder_->Stop();
2061 video_stream_encoder_.reset();
asaperssonf4e44af2017-04-19 02:01:06 -07002062 stats_proxy_.reset();
2063
2064 EXPECT_EQ(0,
2065 metrics::NumSamples("WebRTC.Video.CpuLimitedResolutionInPercent"));
2066}
2067
mflodmancc3d4422017-08-03 08:27:51 -07002068TEST_F(VideoStreamEncoderTest, CallsBitrateObserver) {
sprang4847ae62017-06-27 07:06:52 -07002069 MockBitrateObserver bitrate_observer;
Niels Möller0327c2d2018-05-21 14:09:31 +02002070 video_stream_encoder_->SetBitrateAllocationObserver(&bitrate_observer);
sprang57c2fff2017-01-16 06:24:02 -08002071
2072 const int kDefaultFps = 30;
Erik Språng566124a2018-04-23 12:32:22 +02002073 const VideoBitrateAllocation expected_bitrate =
sprang57c2fff2017-01-16 06:24:02 -08002074 DefaultVideoBitrateAllocator(fake_encoder_.codec_config())
kthelgason2bc68642017-02-07 07:02:22 -08002075 .GetAllocation(kLowTargetBitrateBps, kDefaultFps);
sprang57c2fff2017-01-16 06:24:02 -08002076
2077 // First called on bitrate updated, then again on first frame.
2078 EXPECT_CALL(bitrate_observer, OnBitrateAllocationUpdated(expected_bitrate))
2079 .Times(2);
mflodmancc3d4422017-08-03 08:27:51 -07002080 video_stream_encoder_->OnBitrateUpdated(kLowTargetBitrateBps, 0, 0);
sprang57c2fff2017-01-16 06:24:02 -08002081
2082 const int64_t kStartTimeMs = 1;
2083 video_source_.IncomingCapturedFrame(
2084 CreateFrame(kStartTimeMs, codec_width_, codec_height_));
sprang4847ae62017-06-27 07:06:52 -07002085 WaitForEncodedFrame(kStartTimeMs);
sprang57c2fff2017-01-16 06:24:02 -08002086
2087 // Not called on second frame.
2088 EXPECT_CALL(bitrate_observer, OnBitrateAllocationUpdated(expected_bitrate))
2089 .Times(0);
2090 video_source_.IncomingCapturedFrame(
2091 CreateFrame(kStartTimeMs + 1, codec_width_, codec_height_));
sprang4847ae62017-06-27 07:06:52 -07002092 WaitForEncodedFrame(kStartTimeMs + 1);
sprang57c2fff2017-01-16 06:24:02 -08002093
2094 // Called after a process interval.
2095 const int64_t kProcessIntervalMs =
2096 vcm::VCMProcessTimer::kDefaultProcessIntervalMs;
sprang4847ae62017-06-27 07:06:52 -07002097 fake_clock_.AdvanceTimeMicros(rtc::kNumMicrosecsPerMillisec *
2098 (kProcessIntervalMs + (1000 / kDefaultFps)));
sprang57c2fff2017-01-16 06:24:02 -08002099 EXPECT_CALL(bitrate_observer, OnBitrateAllocationUpdated(expected_bitrate))
2100 .Times(1);
2101 video_source_.IncomingCapturedFrame(CreateFrame(
2102 kStartTimeMs + kProcessIntervalMs, codec_width_, codec_height_));
sprang4847ae62017-06-27 07:06:52 -07002103 WaitForEncodedFrame(kStartTimeMs + kProcessIntervalMs);
sprang57c2fff2017-01-16 06:24:02 -08002104
mflodmancc3d4422017-08-03 08:27:51 -07002105 video_stream_encoder_->Stop();
sprang57c2fff2017-01-16 06:24:02 -08002106}
2107
Niels Möller7dc26b72017-12-06 10:27:48 +01002108TEST_F(VideoStreamEncoderTest, OveruseDetectorUpdatedOnReconfigureAndAdaption) {
2109 const int kFrameWidth = 1280;
2110 const int kFrameHeight = 720;
2111 const int kFramerate = 24;
2112
2113 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
2114 test::FrameForwarder source;
2115 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002116 &source, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
Niels Möller7dc26b72017-12-06 10:27:48 +01002117
2118 // Insert a single frame, triggering initial configuration.
2119 source.IncomingCapturedFrame(CreateFrame(1, kFrameWidth, kFrameHeight));
2120 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2121
2122 EXPECT_EQ(
2123 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2124 kDefaultFramerate);
2125
2126 // Trigger reconfigure encoder (without resetting the entire instance).
2127 VideoEncoderConfig video_encoder_config;
Niels Möller259a4972018-04-05 15:36:51 +02002128 video_encoder_config.codec_type = kVideoCodecVP8;
Niels Möller7dc26b72017-12-06 10:27:48 +01002129 video_encoder_config.max_bitrate_bps = kTargetBitrateBps;
2130 video_encoder_config.number_of_streams = 1;
2131 video_encoder_config.video_stream_factory =
2132 new rtc::RefCountedObject<VideoStreamFactory>(1, kFramerate);
2133 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
Niels Möllerf1338562018-04-26 09:51:47 +02002134 kMaxPayloadLength);
Niels Möller7dc26b72017-12-06 10:27:48 +01002135 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2136
2137 // Detector should be updated with fps limit from codec config.
2138 EXPECT_EQ(
2139 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2140 kFramerate);
2141
2142 // Trigger overuse, max framerate should be reduced.
2143 VideoSendStream::Stats stats = stats_proxy_->GetStats();
2144 stats.input_frame_rate = kFramerate;
2145 stats_proxy_->SetMockStats(stats);
2146 video_stream_encoder_->TriggerCpuOveruse();
2147 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2148 int adapted_framerate =
2149 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate();
2150 EXPECT_LT(adapted_framerate, kFramerate);
2151
2152 // Trigger underuse, max framerate should go back to codec configured fps.
2153 // Set extra low fps, to make sure it's actually reset, not just incremented.
2154 stats = stats_proxy_->GetStats();
2155 stats.input_frame_rate = adapted_framerate / 2;
2156 stats_proxy_->SetMockStats(stats);
2157 video_stream_encoder_->TriggerCpuNormalUsage();
2158 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2159 EXPECT_EQ(
2160 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2161 kFramerate);
2162
2163 video_stream_encoder_->Stop();
2164}
2165
2166TEST_F(VideoStreamEncoderTest,
2167 OveruseDetectorUpdatedRespectsFramerateAfterUnderuse) {
2168 const int kFrameWidth = 1280;
2169 const int kFrameHeight = 720;
2170 const int kLowFramerate = 15;
2171 const int kHighFramerate = 25;
2172
2173 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
2174 test::FrameForwarder source;
2175 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002176 &source, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
Niels Möller7dc26b72017-12-06 10:27:48 +01002177
2178 // Trigger initial configuration.
2179 VideoEncoderConfig video_encoder_config;
Niels Möller259a4972018-04-05 15:36:51 +02002180 video_encoder_config.codec_type = kVideoCodecVP8;
Niels Möller7dc26b72017-12-06 10:27:48 +01002181 video_encoder_config.max_bitrate_bps = kTargetBitrateBps;
2182 video_encoder_config.number_of_streams = 1;
2183 video_encoder_config.video_stream_factory =
2184 new rtc::RefCountedObject<VideoStreamFactory>(1, kLowFramerate);
2185 source.IncomingCapturedFrame(CreateFrame(1, kFrameWidth, kFrameHeight));
2186 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
Niels Möllerf1338562018-04-26 09:51:47 +02002187 kMaxPayloadLength);
Niels Möller7dc26b72017-12-06 10:27:48 +01002188 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2189
2190 EXPECT_EQ(
2191 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2192 kLowFramerate);
2193
2194 // Trigger overuse, max framerate should be reduced.
2195 VideoSendStream::Stats stats = stats_proxy_->GetStats();
2196 stats.input_frame_rate = kLowFramerate;
2197 stats_proxy_->SetMockStats(stats);
2198 video_stream_encoder_->TriggerCpuOveruse();
2199 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2200 int adapted_framerate =
2201 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate();
2202 EXPECT_LT(adapted_framerate, kLowFramerate);
2203
2204 // Reconfigure the encoder with a new (higher max framerate), max fps should
2205 // still respect the adaptation.
2206 video_encoder_config.video_stream_factory =
2207 new rtc::RefCountedObject<VideoStreamFactory>(1, kHighFramerate);
2208 source.IncomingCapturedFrame(CreateFrame(1, kFrameWidth, kFrameHeight));
2209 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
Niels Möllerf1338562018-04-26 09:51:47 +02002210 kMaxPayloadLength);
Niels Möller7dc26b72017-12-06 10:27:48 +01002211 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2212
2213 EXPECT_EQ(
2214 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2215 adapted_framerate);
2216
2217 // Trigger underuse, max framerate should go back to codec configured fps.
2218 stats = stats_proxy_->GetStats();
2219 stats.input_frame_rate = adapted_framerate;
2220 stats_proxy_->SetMockStats(stats);
2221 video_stream_encoder_->TriggerCpuNormalUsage();
2222 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2223 EXPECT_EQ(
2224 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2225 kHighFramerate);
2226
2227 video_stream_encoder_->Stop();
2228}
2229
mflodmancc3d4422017-08-03 08:27:51 -07002230TEST_F(VideoStreamEncoderTest,
2231 OveruseDetectorUpdatedOnDegradationPreferenceChange) {
sprangfda496a2017-06-15 04:21:07 -07002232 const int kFrameWidth = 1280;
2233 const int kFrameHeight = 720;
2234 const int kFramerate = 24;
2235
mflodmancc3d4422017-08-03 08:27:51 -07002236 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
sprangfda496a2017-06-15 04:21:07 -07002237 test::FrameForwarder source;
mflodmancc3d4422017-08-03 08:27:51 -07002238 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002239 &source, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
sprangfda496a2017-06-15 04:21:07 -07002240
2241 // Trigger initial configuration.
2242 VideoEncoderConfig video_encoder_config;
Niels Möller259a4972018-04-05 15:36:51 +02002243 video_encoder_config.codec_type = kVideoCodecVP8;
sprangfda496a2017-06-15 04:21:07 -07002244 video_encoder_config.max_bitrate_bps = kTargetBitrateBps;
2245 video_encoder_config.number_of_streams = 1;
2246 video_encoder_config.video_stream_factory =
2247 new rtc::RefCountedObject<VideoStreamFactory>(1, kFramerate);
2248 source.IncomingCapturedFrame(CreateFrame(1, kFrameWidth, kFrameHeight));
mflodmancc3d4422017-08-03 08:27:51 -07002249 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
Niels Möllerf1338562018-04-26 09:51:47 +02002250 kMaxPayloadLength);
mflodmancc3d4422017-08-03 08:27:51 -07002251 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
sprangfda496a2017-06-15 04:21:07 -07002252
Niels Möller7dc26b72017-12-06 10:27:48 +01002253 EXPECT_EQ(
2254 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2255 kFramerate);
sprangfda496a2017-06-15 04:21:07 -07002256
2257 // Trigger overuse, max framerate should be reduced.
2258 VideoSendStream::Stats stats = stats_proxy_->GetStats();
2259 stats.input_frame_rate = kFramerate;
2260 stats_proxy_->SetMockStats(stats);
mflodmancc3d4422017-08-03 08:27:51 -07002261 video_stream_encoder_->TriggerCpuOveruse();
2262 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
Niels Möller7dc26b72017-12-06 10:27:48 +01002263 int adapted_framerate =
2264 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate();
sprangfda496a2017-06-15 04:21:07 -07002265 EXPECT_LT(adapted_framerate, kFramerate);
2266
2267 // Change degradation preference to not enable framerate scaling. Target
2268 // framerate should be changed to codec defined limit.
mflodmancc3d4422017-08-03 08:27:51 -07002269 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002270 &source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
mflodmancc3d4422017-08-03 08:27:51 -07002271 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
Niels Möller7dc26b72017-12-06 10:27:48 +01002272 EXPECT_EQ(
2273 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2274 kFramerate);
sprangfda496a2017-06-15 04:21:07 -07002275
mflodmancc3d4422017-08-03 08:27:51 -07002276 video_stream_encoder_->Stop();
sprangfda496a2017-06-15 04:21:07 -07002277}
2278
mflodmancc3d4422017-08-03 08:27:51 -07002279TEST_F(VideoStreamEncoderTest, DropsFramesAndScalesWhenBitrateIsTooLow) {
asaperssonfab67072017-04-04 05:51:49 -07002280 const int kTooLowBitrateForFrameSizeBps = 10000;
mflodmancc3d4422017-08-03 08:27:51 -07002281 video_stream_encoder_->OnBitrateUpdated(kTooLowBitrateForFrameSizeBps, 0, 0);
asaperssonfab67072017-04-04 05:51:49 -07002282 const int kWidth = 640;
2283 const int kHeight = 360;
kthelgason2bc68642017-02-07 07:02:22 -08002284
asaperssonfab67072017-04-04 05:51:49 -07002285 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
kthelgason2bc68642017-02-07 07:02:22 -08002286
2287 // Expect to drop this frame, the wait should time out.
sprang4847ae62017-06-27 07:06:52 -07002288 ExpectDroppedFrame();
kthelgason2bc68642017-02-07 07:02:22 -08002289
2290 // Expect the sink_wants to specify a scaled frame.
asapersson0944a802017-04-07 00:57:58 -07002291 EXPECT_LT(video_source_.sink_wants().max_pixel_count, kWidth * kHeight);
kthelgason2bc68642017-02-07 07:02:22 -08002292
sprangc5d62e22017-04-02 23:53:04 -07002293 int last_pixel_count = video_source_.sink_wants().max_pixel_count;
kthelgason2bc68642017-02-07 07:02:22 -08002294
asaperssonfab67072017-04-04 05:51:49 -07002295 // Next frame is scaled.
kthelgason2bc68642017-02-07 07:02:22 -08002296 video_source_.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07002297 CreateFrame(2, kWidth * 3 / 4, kHeight * 3 / 4));
kthelgason2bc68642017-02-07 07:02:22 -08002298
2299 // Expect to drop this frame, the wait should time out.
sprang4847ae62017-06-27 07:06:52 -07002300 ExpectDroppedFrame();
kthelgason2bc68642017-02-07 07:02:22 -08002301
sprangc5d62e22017-04-02 23:53:04 -07002302 EXPECT_LT(video_source_.sink_wants().max_pixel_count, last_pixel_count);
kthelgason2bc68642017-02-07 07:02:22 -08002303
mflodmancc3d4422017-08-03 08:27:51 -07002304 video_stream_encoder_->Stop();
kthelgason2bc68642017-02-07 07:02:22 -08002305}
2306
mflodmancc3d4422017-08-03 08:27:51 -07002307TEST_F(VideoStreamEncoderTest,
2308 NumberOfDroppedFramesLimitedWhenBitrateIsTooLow) {
asaperssonfab67072017-04-04 05:51:49 -07002309 const int kTooLowBitrateForFrameSizeBps = 10000;
mflodmancc3d4422017-08-03 08:27:51 -07002310 video_stream_encoder_->OnBitrateUpdated(kTooLowBitrateForFrameSizeBps, 0, 0);
asaperssonfab67072017-04-04 05:51:49 -07002311 const int kWidth = 640;
2312 const int kHeight = 360;
kthelgason2bc68642017-02-07 07:02:22 -08002313
2314 // We expect the n initial frames to get dropped.
2315 int i;
2316 for (i = 1; i <= kMaxInitialFramedrop; ++i) {
asaperssonfab67072017-04-04 05:51:49 -07002317 video_source_.IncomingCapturedFrame(CreateFrame(i, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002318 ExpectDroppedFrame();
kthelgason2bc68642017-02-07 07:02:22 -08002319 }
2320 // The n+1th frame should not be dropped, even though it's size is too large.
asaperssonfab67072017-04-04 05:51:49 -07002321 video_source_.IncomingCapturedFrame(CreateFrame(i, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002322 WaitForEncodedFrame(i);
kthelgason2bc68642017-02-07 07:02:22 -08002323
2324 // Expect the sink_wants to specify a scaled frame.
asaperssonfab67072017-04-04 05:51:49 -07002325 EXPECT_LT(video_source_.sink_wants().max_pixel_count, kWidth * kHeight);
kthelgason2bc68642017-02-07 07:02:22 -08002326
mflodmancc3d4422017-08-03 08:27:51 -07002327 video_stream_encoder_->Stop();
kthelgason2bc68642017-02-07 07:02:22 -08002328}
2329
mflodmancc3d4422017-08-03 08:27:51 -07002330TEST_F(VideoStreamEncoderTest,
2331 InitialFrameDropOffWithMaintainResolutionPreference) {
asaperssonfab67072017-04-04 05:51:49 -07002332 const int kWidth = 640;
2333 const int kHeight = 360;
mflodmancc3d4422017-08-03 08:27:51 -07002334 video_stream_encoder_->OnBitrateUpdated(kLowTargetBitrateBps, 0, 0);
kthelgason2bc68642017-02-07 07:02:22 -08002335
2336 // Set degradation preference.
mflodmancc3d4422017-08-03 08:27:51 -07002337 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002338 &video_source_, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
kthelgason2bc68642017-02-07 07:02:22 -08002339
asaperssonfab67072017-04-04 05:51:49 -07002340 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
kthelgason2bc68642017-02-07 07:02:22 -08002341 // Frame should not be dropped, even if it's too large.
sprang4847ae62017-06-27 07:06:52 -07002342 WaitForEncodedFrame(1);
kthelgason2bc68642017-02-07 07:02:22 -08002343
mflodmancc3d4422017-08-03 08:27:51 -07002344 video_stream_encoder_->Stop();
kthelgason2bc68642017-02-07 07:02:22 -08002345}
2346
mflodmancc3d4422017-08-03 08:27:51 -07002347TEST_F(VideoStreamEncoderTest, InitialFrameDropOffWhenEncoderDisabledScaling) {
asaperssonfab67072017-04-04 05:51:49 -07002348 const int kWidth = 640;
2349 const int kHeight = 360;
kthelgasonad9010c2017-02-14 00:46:51 -08002350 fake_encoder_.SetQualityScaling(false);
Niels Möller4db138e2018-04-19 09:04:13 +02002351
2352 VideoEncoderConfig video_encoder_config;
2353 test::FillEncoderConfiguration(kVideoCodecVP8, 1, &video_encoder_config);
2354 // Make format different, to force recreation of encoder.
2355 video_encoder_config.video_format.parameters["foo"] = "foo";
2356 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
Niels Möllerf1338562018-04-26 09:51:47 +02002357 kMaxPayloadLength);
mflodmancc3d4422017-08-03 08:27:51 -07002358 video_stream_encoder_->OnBitrateUpdated(kLowTargetBitrateBps, 0, 0);
asapersson09f05612017-05-15 23:40:18 -07002359
kthelgasonb83797b2017-02-14 11:57:25 -08002360 // Force quality scaler reconfiguration by resetting the source.
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002361 video_stream_encoder_->SetSource(&video_source_,
2362 webrtc::DegradationPreference::BALANCED);
kthelgasonad9010c2017-02-14 00:46:51 -08002363
asaperssonfab67072017-04-04 05:51:49 -07002364 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
kthelgasonad9010c2017-02-14 00:46:51 -08002365 // Frame should not be dropped, even if it's too large.
sprang4847ae62017-06-27 07:06:52 -07002366 WaitForEncodedFrame(1);
kthelgasonad9010c2017-02-14 00:46:51 -08002367
mflodmancc3d4422017-08-03 08:27:51 -07002368 video_stream_encoder_->Stop();
kthelgasonad9010c2017-02-14 00:46:51 -08002369 fake_encoder_.SetQualityScaling(true);
2370}
2371
Kári Tristan Helgason639602a2018-08-02 10:51:40 +02002372TEST_F(VideoStreamEncoderTest, InitialFrameDropActivatesWhenBWEstimateReady) {
2373 webrtc::test::ScopedFieldTrials field_trials(
2374 "WebRTC-InitialFramedrop/Enabled/");
2375 // Reset encoder for field trials to take effect.
2376 ConfigureEncoder(video_encoder_config_.Copy());
2377 const int kTooLowBitrateForFrameSizeBps = 10000;
2378 const int kWidth = 640;
2379 const int kHeight = 360;
2380
2381 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
2382 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
2383 // Frame should not be dropped.
2384 WaitForEncodedFrame(1);
2385
2386 video_stream_encoder_->OnBitrateUpdated(kTooLowBitrateForFrameSizeBps, 0, 0);
2387 video_source_.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
2388 // Expect to drop this frame, the wait should time out.
2389 ExpectDroppedFrame();
2390
2391 // Expect the sink_wants to specify a scaled frame.
2392 EXPECT_LT(video_source_.sink_wants().max_pixel_count, kWidth * kHeight);
2393 video_stream_encoder_->Stop();
2394}
2395
mflodmancc3d4422017-08-03 08:27:51 -07002396TEST_F(VideoStreamEncoderTest,
asaperssond0de2952017-04-21 01:47:31 -07002397 ResolutionNotAdaptedForTooSmallFrame_MaintainFramerateMode) {
2398 const int kTooSmallWidth = 10;
2399 const int kTooSmallHeight = 10;
mflodmancc3d4422017-08-03 08:27:51 -07002400 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssond0de2952017-04-21 01:47:31 -07002401
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002402 // Enable MAINTAIN_FRAMERATE preference, no initial limitation.
asaperssond0de2952017-04-21 01:47:31 -07002403 test::FrameForwarder source;
mflodmancc3d4422017-08-03 08:27:51 -07002404 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002405 &source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
asaperssond0de2952017-04-21 01:47:31 -07002406 VerifyNoLimitation(source.sink_wants());
2407 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2408
2409 // Trigger adapt down, too small frame, expect no change.
2410 source.IncomingCapturedFrame(CreateFrame(1, kTooSmallWidth, kTooSmallHeight));
sprang4847ae62017-06-27 07:06:52 -07002411 WaitForEncodedFrame(1);
mflodmancc3d4422017-08-03 08:27:51 -07002412 video_stream_encoder_->TriggerCpuOveruse();
Åsa Persson8c1bf952018-09-13 10:42:19 +02002413 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssond0de2952017-04-21 01:47:31 -07002414 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2415 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2416
mflodmancc3d4422017-08-03 08:27:51 -07002417 video_stream_encoder_->Stop();
asaperssond0de2952017-04-21 01:47:31 -07002418}
2419
mflodmancc3d4422017-08-03 08:27:51 -07002420TEST_F(VideoStreamEncoderTest,
2421 ResolutionNotAdaptedForTooSmallFrame_BalancedMode) {
asaperssonf7e294d2017-06-13 23:25:22 -07002422 const int kTooSmallWidth = 10;
2423 const int kTooSmallHeight = 10;
2424 const int kFpsLimit = 7;
mflodmancc3d4422017-08-03 08:27:51 -07002425 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -07002426
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002427 // Enable BALANCED preference, no initial limitation.
asaperssonf7e294d2017-06-13 23:25:22 -07002428 test::FrameForwarder source;
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002429 video_stream_encoder_->SetSource(&source,
2430 webrtc::DegradationPreference::BALANCED);
asaperssonf7e294d2017-06-13 23:25:22 -07002431 VerifyNoLimitation(source.sink_wants());
2432 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2433 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2434
2435 // Trigger adapt down, expect limited framerate.
2436 source.IncomingCapturedFrame(CreateFrame(1, kTooSmallWidth, kTooSmallHeight));
sprang4847ae62017-06-27 07:06:52 -07002437 WaitForEncodedFrame(1);
mflodmancc3d4422017-08-03 08:27:51 -07002438 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002439 VerifyFpsEqResolutionMax(source.sink_wants(), kFpsLimit);
2440 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2441 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2442 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2443
2444 // Trigger adapt down, too small frame, expect no change.
2445 source.IncomingCapturedFrame(CreateFrame(2, kTooSmallWidth, kTooSmallHeight));
sprang4847ae62017-06-27 07:06:52 -07002446 WaitForEncodedFrame(2);
mflodmancc3d4422017-08-03 08:27:51 -07002447 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002448 VerifyFpsEqResolutionMax(source.sink_wants(), kFpsLimit);
2449 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2450 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2451 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2452
mflodmancc3d4422017-08-03 08:27:51 -07002453 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07002454}
2455
mflodmancc3d4422017-08-03 08:27:51 -07002456TEST_F(VideoStreamEncoderTest, FailingInitEncodeDoesntCauseCrash) {
asapersson02465b82017-04-10 01:12:52 -07002457 fake_encoder_.ForceInitEncodeFailure(true);
mflodmancc3d4422017-08-03 08:27:51 -07002458 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
Niels Möllerf1338562018-04-26 09:51:47 +02002459 ResetEncoder("VP8", 2, 1, 1, false);
asapersson02465b82017-04-10 01:12:52 -07002460 const int kFrameWidth = 1280;
2461 const int kFrameHeight = 720;
2462 video_source_.IncomingCapturedFrame(
2463 CreateFrame(1, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002464 ExpectDroppedFrame();
mflodmancc3d4422017-08-03 08:27:51 -07002465 video_stream_encoder_->Stop();
asapersson02465b82017-04-10 01:12:52 -07002466}
2467
sprangb1ca0732017-02-01 08:38:12 -08002468// TODO(sprang): Extend this with fps throttling and any "balanced" extensions.
mflodmancc3d4422017-08-03 08:27:51 -07002469TEST_F(VideoStreamEncoderTest,
2470 AdaptsResolutionOnOveruse_MaintainFramerateMode) {
2471 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
sprangb1ca0732017-02-01 08:38:12 -08002472
2473 const int kFrameWidth = 1280;
2474 const int kFrameHeight = 720;
2475 // Enabled default VideoAdapter downscaling. First step is 3/4, not 3/5 as
mflodmancc3d4422017-08-03 08:27:51 -07002476 // requested by
2477 // VideoStreamEncoder::VideoSourceProxy::RequestResolutionLowerThan().
sprangb1ca0732017-02-01 08:38:12 -08002478 video_source_.set_adaptation_enabled(true);
2479
2480 video_source_.IncomingCapturedFrame(
Åsa Persson8c1bf952018-09-13 10:42:19 +02002481 CreateFrame(1 * kFrameIntervalMs, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002482 WaitForEncodedFrame(kFrameWidth, kFrameHeight);
sprangb1ca0732017-02-01 08:38:12 -08002483
2484 // Trigger CPU overuse, downscale by 3/4.
mflodmancc3d4422017-08-03 08:27:51 -07002485 video_stream_encoder_->TriggerCpuOveruse();
sprangb1ca0732017-02-01 08:38:12 -08002486 video_source_.IncomingCapturedFrame(
Åsa Persson8c1bf952018-09-13 10:42:19 +02002487 CreateFrame(2 * kFrameIntervalMs, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002488 WaitForEncodedFrame((kFrameWidth * 3) / 4, (kFrameHeight * 3) / 4);
sprangb1ca0732017-02-01 08:38:12 -08002489
asaperssonfab67072017-04-04 05:51:49 -07002490 // Trigger CPU normal use, return to original resolution.
mflodmancc3d4422017-08-03 08:27:51 -07002491 video_stream_encoder_->TriggerCpuNormalUsage();
sprangb1ca0732017-02-01 08:38:12 -08002492 video_source_.IncomingCapturedFrame(
Åsa Persson8c1bf952018-09-13 10:42:19 +02002493 CreateFrame(3 * kFrameIntervalMs, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002494 WaitForEncodedFrame(kFrameWidth, kFrameHeight);
sprangb1ca0732017-02-01 08:38:12 -08002495
mflodmancc3d4422017-08-03 08:27:51 -07002496 video_stream_encoder_->Stop();
sprangb1ca0732017-02-01 08:38:12 -08002497}
sprangfe627f32017-03-29 08:24:59 -07002498
mflodmancc3d4422017-08-03 08:27:51 -07002499TEST_F(VideoStreamEncoderTest,
2500 AdaptsFramerateOnOveruse_MaintainResolutionMode) {
sprangc5d62e22017-04-02 23:53:04 -07002501 const int kFrameWidth = 1280;
2502 const int kFrameHeight = 720;
sprangc5d62e22017-04-02 23:53:04 -07002503
mflodmancc3d4422017-08-03 08:27:51 -07002504 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
2505 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002506 &video_source_, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
sprangc5d62e22017-04-02 23:53:04 -07002507 video_source_.set_adaptation_enabled(true);
2508
sprang4847ae62017-06-27 07:06:52 -07002509 int64_t timestamp_ms = fake_clock_.TimeNanos() / rtc::kNumNanosecsPerMillisec;
sprangc5d62e22017-04-02 23:53:04 -07002510
2511 video_source_.IncomingCapturedFrame(
2512 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002513 WaitForEncodedFrame(timestamp_ms);
sprangc5d62e22017-04-02 23:53:04 -07002514
2515 // Try to trigger overuse. No fps estimate available => no effect.
mflodmancc3d4422017-08-03 08:27:51 -07002516 video_stream_encoder_->TriggerCpuOveruse();
sprangc5d62e22017-04-02 23:53:04 -07002517
2518 // Insert frames for one second to get a stable estimate.
sprang4847ae62017-06-27 07:06:52 -07002519 for (int i = 0; i < max_framerate_; ++i) {
sprangc5d62e22017-04-02 23:53:04 -07002520 timestamp_ms += kFrameIntervalMs;
sprangc5d62e22017-04-02 23:53:04 -07002521 video_source_.IncomingCapturedFrame(
2522 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002523 WaitForEncodedFrame(timestamp_ms);
sprangc5d62e22017-04-02 23:53:04 -07002524 }
2525
2526 // Trigger CPU overuse, reduce framerate by 2/3.
mflodmancc3d4422017-08-03 08:27:51 -07002527 video_stream_encoder_->TriggerCpuOveruse();
sprangc5d62e22017-04-02 23:53:04 -07002528 int num_frames_dropped = 0;
sprang4847ae62017-06-27 07:06:52 -07002529 for (int i = 0; i < max_framerate_; ++i) {
sprangc5d62e22017-04-02 23:53:04 -07002530 timestamp_ms += kFrameIntervalMs;
sprangc5d62e22017-04-02 23:53:04 -07002531 video_source_.IncomingCapturedFrame(
2532 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002533 if (!WaitForFrame(kFrameTimeoutMs)) {
sprangc5d62e22017-04-02 23:53:04 -07002534 ++num_frames_dropped;
2535 } else {
Åsa Perssonc74d8da2017-12-04 14:13:56 +01002536 sink_.CheckLastFrameSizeMatches(kFrameWidth, kFrameHeight);
sprangc5d62e22017-04-02 23:53:04 -07002537 }
2538 }
2539
sprang4847ae62017-06-27 07:06:52 -07002540 // Add some slack to account for frames dropped by the frame dropper.
2541 const int kErrorMargin = 1;
2542 EXPECT_NEAR(num_frames_dropped, max_framerate_ - (max_framerate_ * 2 / 3),
sprangc5d62e22017-04-02 23:53:04 -07002543 kErrorMargin);
2544
2545 // Trigger CPU overuse, reduce framerate by 2/3 again.
mflodmancc3d4422017-08-03 08:27:51 -07002546 video_stream_encoder_->TriggerCpuOveruse();
sprangc5d62e22017-04-02 23:53:04 -07002547 num_frames_dropped = 0;
Åsa Persson8c1bf952018-09-13 10:42:19 +02002548 for (int i = 0; i <= max_framerate_; ++i) {
sprangc5d62e22017-04-02 23:53:04 -07002549 timestamp_ms += kFrameIntervalMs;
sprangc5d62e22017-04-02 23:53:04 -07002550 video_source_.IncomingCapturedFrame(
2551 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002552 if (!WaitForFrame(kFrameTimeoutMs)) {
sprangc5d62e22017-04-02 23:53:04 -07002553 ++num_frames_dropped;
2554 } else {
Åsa Perssonc74d8da2017-12-04 14:13:56 +01002555 sink_.CheckLastFrameSizeMatches(kFrameWidth, kFrameHeight);
sprangc5d62e22017-04-02 23:53:04 -07002556 }
2557 }
sprang4847ae62017-06-27 07:06:52 -07002558 EXPECT_NEAR(num_frames_dropped, max_framerate_ - (max_framerate_ * 4 / 9),
sprangc5d62e22017-04-02 23:53:04 -07002559 kErrorMargin);
2560
2561 // Go back up one step.
mflodmancc3d4422017-08-03 08:27:51 -07002562 video_stream_encoder_->TriggerCpuNormalUsage();
sprangc5d62e22017-04-02 23:53:04 -07002563 num_frames_dropped = 0;
sprang4847ae62017-06-27 07:06:52 -07002564 for (int i = 0; i < max_framerate_; ++i) {
sprangc5d62e22017-04-02 23:53:04 -07002565 timestamp_ms += kFrameIntervalMs;
sprangc5d62e22017-04-02 23:53:04 -07002566 video_source_.IncomingCapturedFrame(
2567 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002568 if (!WaitForFrame(kFrameTimeoutMs)) {
sprangc5d62e22017-04-02 23:53:04 -07002569 ++num_frames_dropped;
2570 } else {
Åsa Perssonc74d8da2017-12-04 14:13:56 +01002571 sink_.CheckLastFrameSizeMatches(kFrameWidth, kFrameHeight);
sprangc5d62e22017-04-02 23:53:04 -07002572 }
2573 }
sprang4847ae62017-06-27 07:06:52 -07002574 EXPECT_NEAR(num_frames_dropped, max_framerate_ - (max_framerate_ * 2 / 3),
sprangc5d62e22017-04-02 23:53:04 -07002575 kErrorMargin);
2576
2577 // Go back up to original mode.
mflodmancc3d4422017-08-03 08:27:51 -07002578 video_stream_encoder_->TriggerCpuNormalUsage();
sprangc5d62e22017-04-02 23:53:04 -07002579 num_frames_dropped = 0;
sprang4847ae62017-06-27 07:06:52 -07002580 for (int i = 0; i < max_framerate_; ++i) {
sprangc5d62e22017-04-02 23:53:04 -07002581 timestamp_ms += kFrameIntervalMs;
sprangc5d62e22017-04-02 23:53:04 -07002582 video_source_.IncomingCapturedFrame(
2583 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002584 if (!WaitForFrame(kFrameTimeoutMs)) {
sprangc5d62e22017-04-02 23:53:04 -07002585 ++num_frames_dropped;
2586 } else {
Åsa Perssonc74d8da2017-12-04 14:13:56 +01002587 sink_.CheckLastFrameSizeMatches(kFrameWidth, kFrameHeight);
sprangc5d62e22017-04-02 23:53:04 -07002588 }
2589 }
2590 EXPECT_NEAR(num_frames_dropped, 0, kErrorMargin);
2591
mflodmancc3d4422017-08-03 08:27:51 -07002592 video_stream_encoder_->Stop();
sprangc5d62e22017-04-02 23:53:04 -07002593}
2594
mflodmancc3d4422017-08-03 08:27:51 -07002595TEST_F(VideoStreamEncoderTest, DoesntAdaptDownPastMinFramerate) {
sprangc5d62e22017-04-02 23:53:04 -07002596 const int kFramerateFps = 5;
2597 const int kFrameIntervalMs = rtc::kNumMillisecsPerSec / kFramerateFps;
sprangc5d62e22017-04-02 23:53:04 -07002598 const int kFrameWidth = 1280;
2599 const int kFrameHeight = 720;
2600
sprang4847ae62017-06-27 07:06:52 -07002601 // Reconfigure encoder with two temporal layers and screensharing, which will
2602 // disable frame dropping and make testing easier.
Niels Möllerf1338562018-04-26 09:51:47 +02002603 ResetEncoder("VP8", 1, 2, 1, true);
sprang4847ae62017-06-27 07:06:52 -07002604
mflodmancc3d4422017-08-03 08:27:51 -07002605 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
2606 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002607 &video_source_, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
sprangc5d62e22017-04-02 23:53:04 -07002608 video_source_.set_adaptation_enabled(true);
2609
sprang4847ae62017-06-27 07:06:52 -07002610 int64_t timestamp_ms = fake_clock_.TimeNanos() / rtc::kNumNanosecsPerMillisec;
sprangc5d62e22017-04-02 23:53:04 -07002611
2612 // Trigger overuse as much as we can.
Jonathan Yubc771b72017-12-08 17:04:29 -08002613 rtc::VideoSinkWants last_wants;
2614 do {
2615 last_wants = video_source_.sink_wants();
2616
sprangc5d62e22017-04-02 23:53:04 -07002617 // Insert frames to get a new fps estimate...
2618 for (int j = 0; j < kFramerateFps; ++j) {
2619 video_source_.IncomingCapturedFrame(
2620 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
Jonathan Yubc771b72017-12-08 17:04:29 -08002621 if (video_source_.last_sent_width()) {
2622 sink_.WaitForEncodedFrame(timestamp_ms);
2623 }
sprangc5d62e22017-04-02 23:53:04 -07002624 timestamp_ms += kFrameIntervalMs;
Yves Gerey665174f2018-06-19 15:03:05 +02002625 fake_clock_.AdvanceTimeMicros(kFrameIntervalMs *
2626 rtc::kNumMicrosecsPerMillisec);
sprangc5d62e22017-04-02 23:53:04 -07002627 }
2628 // ...and then try to adapt again.
mflodmancc3d4422017-08-03 08:27:51 -07002629 video_stream_encoder_->TriggerCpuOveruse();
Jonathan Yubc771b72017-12-08 17:04:29 -08002630 } while (video_source_.sink_wants().max_framerate_fps <
2631 last_wants.max_framerate_fps);
sprangc5d62e22017-04-02 23:53:04 -07002632
Jonathan Yubc771b72017-12-08 17:04:29 -08002633 VerifyFpsEqResolutionMax(video_source_.sink_wants(), kMinFramerateFps);
asaperssonf7e294d2017-06-13 23:25:22 -07002634
mflodmancc3d4422017-08-03 08:27:51 -07002635 video_stream_encoder_->Stop();
sprangc5d62e22017-04-02 23:53:04 -07002636}
asaperssonf7e294d2017-06-13 23:25:22 -07002637
mflodmancc3d4422017-08-03 08:27:51 -07002638TEST_F(VideoStreamEncoderTest,
2639 AdaptsResolutionAndFramerateForLowQuality_BalancedMode) {
asaperssonf7e294d2017-06-13 23:25:22 -07002640 const int kWidth = 1280;
2641 const int kHeight = 720;
2642 const int64_t kFrameIntervalMs = 150;
2643 int64_t timestamp_ms = kFrameIntervalMs;
mflodmancc3d4422017-08-03 08:27:51 -07002644 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -07002645
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002646 // Enable BALANCED preference, no initial limitation.
asaperssonf7e294d2017-06-13 23:25:22 -07002647 AdaptingFrameForwarder source;
2648 source.set_adaptation_enabled(true);
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002649 video_stream_encoder_->SetSource(&source,
2650 webrtc::DegradationPreference::BALANCED);
asaperssonf7e294d2017-06-13 23:25:22 -07002651 timestamp_ms += kFrameIntervalMs;
2652 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002653 WaitForEncodedFrame(kWidth, kHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +02002654 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07002655 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2656 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2657 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2658
2659 // Trigger adapt down, expect scaled down resolution (960x540@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002660 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002661 timestamp_ms += kFrameIntervalMs;
2662 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002663 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002664 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
2665 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2666 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2667 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2668
2669 // Trigger adapt down, expect scaled down resolution (640x360@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002670 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002671 timestamp_ms += kFrameIntervalMs;
2672 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002673 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002674 VerifyFpsMaxResolutionLt(source.sink_wants(), source.last_wants());
2675 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2676 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2677 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2678
2679 // Trigger adapt down, expect reduced fps (640x360@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07002680 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002681 timestamp_ms += kFrameIntervalMs;
2682 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002683 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002684 VerifyFpsLtResolutionEq(source.sink_wants(), source.last_wants());
2685 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2686 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2687 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2688
2689 // Trigger adapt down, expect scaled down resolution (480x270@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07002690 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002691 timestamp_ms += kFrameIntervalMs;
2692 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002693 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002694 VerifyFpsEqResolutionLt(source.sink_wants(), source.last_wants());
2695 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2696 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2697 EXPECT_EQ(4, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2698
2699 // Restrict bitrate, trigger adapt down, expect reduced fps (480x270@10fps).
mflodmancc3d4422017-08-03 08:27:51 -07002700 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002701 timestamp_ms += kFrameIntervalMs;
2702 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002703 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002704 VerifyFpsLtResolutionEq(source.sink_wants(), source.last_wants());
2705 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2706 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2707 EXPECT_EQ(5, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2708
2709 // Trigger adapt down, expect scaled down resolution (320x180@10fps).
mflodmancc3d4422017-08-03 08:27:51 -07002710 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002711 timestamp_ms += kFrameIntervalMs;
2712 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002713 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002714 VerifyFpsEqResolutionLt(source.sink_wants(), source.last_wants());
2715 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2716 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2717 EXPECT_EQ(6, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2718
2719 // Trigger adapt down, expect reduced fps (320x180@7fps).
mflodmancc3d4422017-08-03 08:27:51 -07002720 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002721 timestamp_ms += kFrameIntervalMs;
2722 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002723 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002724 VerifyFpsLtResolutionEq(source.sink_wants(), source.last_wants());
2725 rtc::VideoSinkWants last_wants = source.sink_wants();
2726 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2727 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2728 EXPECT_EQ(7, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2729
2730 // Trigger adapt down, min resolution reached, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07002731 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002732 timestamp_ms += kFrameIntervalMs;
2733 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002734 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002735 VerifyFpsEqResolutionEq(source.sink_wants(), last_wants);
2736 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2737 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2738 EXPECT_EQ(7, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2739
2740 // Trigger adapt down, expect expect increased fps (320x180@10fps).
mflodmancc3d4422017-08-03 08:27:51 -07002741 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002742 timestamp_ms += kFrameIntervalMs;
2743 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002744 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002745 VerifyFpsGtResolutionEq(source.sink_wants(), source.last_wants());
2746 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2747 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2748 EXPECT_EQ(8, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2749
2750 // Trigger adapt up, expect upscaled resolution (480x270@10fps).
mflodmancc3d4422017-08-03 08:27:51 -07002751 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002752 timestamp_ms += kFrameIntervalMs;
2753 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002754 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002755 VerifyFpsEqResolutionGt(source.sink_wants(), source.last_wants());
2756 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2757 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2758 EXPECT_EQ(9, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2759
2760 // Increase bitrate, trigger adapt up, expect increased fps (480x270@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07002761 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002762 timestamp_ms += kFrameIntervalMs;
2763 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002764 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002765 VerifyFpsGtResolutionEq(source.sink_wants(), source.last_wants());
2766 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2767 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2768 EXPECT_EQ(10, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2769
2770 // Trigger adapt up, expect upscaled resolution (640x360@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07002771 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002772 timestamp_ms += kFrameIntervalMs;
2773 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002774 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002775 VerifyFpsEqResolutionGt(source.sink_wants(), source.last_wants());
2776 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2777 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2778 EXPECT_EQ(11, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2779
2780 // Trigger adapt up, expect increased fps (640x360@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002781 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002782 timestamp_ms += kFrameIntervalMs;
2783 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002784 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002785 VerifyFpsMaxResolutionEq(source.sink_wants(), source.last_wants());
2786 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2787 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2788 EXPECT_EQ(12, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2789
2790 // Trigger adapt up, expect upscaled resolution (960x540@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002791 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002792 timestamp_ms += kFrameIntervalMs;
2793 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002794 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002795 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
2796 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2797 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2798 EXPECT_EQ(13, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2799
2800 // Trigger adapt up, expect no restriction (1280x720fps@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002801 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002802 timestamp_ms += kFrameIntervalMs;
2803 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002804 WaitForEncodedFrame(kWidth, kHeight);
asaperssonf7e294d2017-06-13 23:25:22 -07002805 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
Åsa Persson8c1bf952018-09-13 10:42:19 +02002806 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07002807 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2808 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2809 EXPECT_EQ(14, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2810
2811 // Trigger adapt up, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07002812 video_stream_encoder_->TriggerQualityHigh();
Åsa Persson8c1bf952018-09-13 10:42:19 +02002813 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07002814 EXPECT_EQ(14, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2815
mflodmancc3d4422017-08-03 08:27:51 -07002816 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07002817}
2818
mflodmancc3d4422017-08-03 08:27:51 -07002819TEST_F(VideoStreamEncoderTest, AdaptWithTwoReasonsAndDifferentOrder_Framerate) {
asaperssonf7e294d2017-06-13 23:25:22 -07002820 const int kWidth = 1280;
2821 const int kHeight = 720;
2822 const int64_t kFrameIntervalMs = 150;
2823 int64_t timestamp_ms = kFrameIntervalMs;
mflodmancc3d4422017-08-03 08:27:51 -07002824 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -07002825
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002826 // Enable BALANCED preference, no initial limitation.
asaperssonf7e294d2017-06-13 23:25:22 -07002827 AdaptingFrameForwarder source;
2828 source.set_adaptation_enabled(true);
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002829 video_stream_encoder_->SetSource(&source,
2830 webrtc::DegradationPreference::BALANCED);
asaperssonf7e294d2017-06-13 23:25:22 -07002831 timestamp_ms += kFrameIntervalMs;
2832 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002833 WaitForEncodedFrame(kWidth, kHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +02002834 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07002835 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2836 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2837 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2838 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
2839 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2840 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2841
2842 // Trigger cpu adapt down, expect scaled down resolution (960x540@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002843 video_stream_encoder_->TriggerCpuOveruse();
asaperssonf7e294d2017-06-13 23:25:22 -07002844 timestamp_ms += kFrameIntervalMs;
2845 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002846 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002847 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
2848 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2849 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2850 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2851 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
2852 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2853 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2854
2855 // Trigger cpu adapt down, expect scaled down resolution (640x360@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002856 video_stream_encoder_->TriggerCpuOveruse();
asaperssonf7e294d2017-06-13 23:25:22 -07002857 timestamp_ms += kFrameIntervalMs;
2858 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002859 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002860 VerifyFpsMaxResolutionLt(source.sink_wants(), source.last_wants());
2861 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2862 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2863 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2864 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
2865 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2866 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2867
2868 // Trigger quality adapt down, expect reduced fps (640x360@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07002869 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002870 timestamp_ms += kFrameIntervalMs;
2871 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002872 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002873 VerifyFpsLtResolutionEq(source.sink_wants(), source.last_wants());
2874 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2875 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2876 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2877 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
2878 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2879 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2880
2881 // Trigger cpu adapt up, expect increased fps (640x360@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002882 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssonf7e294d2017-06-13 23:25:22 -07002883 timestamp_ms += kFrameIntervalMs;
2884 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002885 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002886 VerifyFpsMaxResolutionEq(source.sink_wants(), source.last_wants());
2887 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2888 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2889 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2890 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
2891 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2892 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2893
2894 // Trigger quality adapt up, expect upscaled resolution (960x540@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002895 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002896 timestamp_ms += kFrameIntervalMs;
2897 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002898 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002899 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
2900 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2901 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2902 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2903 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
2904 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2905 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2906
2907 // Trigger cpu adapt up, expect no restriction (1280x720fps@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002908 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssonf7e294d2017-06-13 23:25:22 -07002909 timestamp_ms += kFrameIntervalMs;
2910 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002911 WaitForEncodedFrame(kWidth, kHeight);
asaperssonf7e294d2017-06-13 23:25:22 -07002912 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
Åsa Persson8c1bf952018-09-13 10:42:19 +02002913 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07002914 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2915 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2916 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2917 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
2918 EXPECT_EQ(4, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2919 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2920
2921 // Trigger adapt up, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07002922 video_stream_encoder_->TriggerQualityHigh();
Åsa Persson8c1bf952018-09-13 10:42:19 +02002923 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07002924 EXPECT_EQ(4, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2925 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2926
mflodmancc3d4422017-08-03 08:27:51 -07002927 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07002928}
2929
mflodmancc3d4422017-08-03 08:27:51 -07002930TEST_F(VideoStreamEncoderTest,
2931 AdaptWithTwoReasonsAndDifferentOrder_Resolution) {
asaperssonf7e294d2017-06-13 23:25:22 -07002932 const int kWidth = 640;
2933 const int kHeight = 360;
2934 const int kFpsLimit = 15;
2935 const int64_t kFrameIntervalMs = 150;
2936 int64_t timestamp_ms = kFrameIntervalMs;
mflodmancc3d4422017-08-03 08:27:51 -07002937 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -07002938
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002939 // Enable BALANCED preference, no initial limitation.
asaperssonf7e294d2017-06-13 23:25:22 -07002940 AdaptingFrameForwarder source;
2941 source.set_adaptation_enabled(true);
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002942 video_stream_encoder_->SetSource(&source,
2943 webrtc::DegradationPreference::BALANCED);
asaperssonf7e294d2017-06-13 23:25:22 -07002944 timestamp_ms += kFrameIntervalMs;
2945 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002946 WaitForEncodedFrame(kWidth, kHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +02002947 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07002948 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2949 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2950 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2951 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
2952 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2953 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2954
2955 // Trigger cpu adapt down, expect scaled down framerate (640x360@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07002956 video_stream_encoder_->TriggerCpuOveruse();
asaperssonf7e294d2017-06-13 23:25:22 -07002957 timestamp_ms += kFrameIntervalMs;
2958 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002959 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002960 VerifyFpsEqResolutionMax(source.sink_wants(), kFpsLimit);
2961 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2962 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2963 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2964 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_framerate);
2965 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2966 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2967
2968 // Trigger quality adapt down, expect scaled down resolution (480x270@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07002969 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002970 timestamp_ms += kFrameIntervalMs;
2971 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002972 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002973 VerifyFpsEqResolutionLt(source.sink_wants(), source.last_wants());
2974 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2975 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2976 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2977 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_framerate);
2978 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2979 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2980
2981 // Trigger cpu adapt up, expect upscaled resolution (640x360@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07002982 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssonf7e294d2017-06-13 23:25:22 -07002983 timestamp_ms += kFrameIntervalMs;
2984 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002985 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002986 VerifyFpsEqResolutionGt(source.sink_wants(), source.last_wants());
2987 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2988 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2989 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2990 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
2991 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2992 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2993
2994 // Trigger quality adapt up, expect increased fps (640x360@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002995 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002996 timestamp_ms += kFrameIntervalMs;
2997 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002998 WaitForEncodedFrame(timestamp_ms);
Åsa Persson8c1bf952018-09-13 10:42:19 +02002999 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07003000 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
3001 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
3002 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
3003 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
3004 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
3005 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3006
3007 // Trigger adapt up, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07003008 video_stream_encoder_->TriggerQualityHigh();
Åsa Persson8c1bf952018-09-13 10:42:19 +02003009 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07003010 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
3011 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3012
mflodmancc3d4422017-08-03 08:27:51 -07003013 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07003014}
3015
mflodmancc3d4422017-08-03 08:27:51 -07003016TEST_F(VideoStreamEncoderTest, AcceptsFullHdAdaptedDownSimulcastFrames) {
ilnik6b826ef2017-06-16 06:53:48 -07003017 // Simulates simulcast behavior and makes highest stream resolutions divisible
3018 // by 4.
3019 class CroppingVideoStreamFactory
3020 : public VideoEncoderConfig::VideoStreamFactoryInterface {
3021 public:
3022 explicit CroppingVideoStreamFactory(size_t num_temporal_layers,
3023 int framerate)
3024 : num_temporal_layers_(num_temporal_layers), framerate_(framerate) {
3025 EXPECT_GT(num_temporal_layers, 0u);
3026 EXPECT_GT(framerate, 0);
3027 }
3028
3029 private:
3030 std::vector<VideoStream> CreateEncoderStreams(
3031 int width,
3032 int height,
3033 const VideoEncoderConfig& encoder_config) override {
Yves Gerey665174f2018-06-19 15:03:05 +02003034 std::vector<VideoStream> streams = test::CreateVideoStreams(
3035 width - width % 4, height - height % 4, encoder_config);
ilnik6b826ef2017-06-16 06:53:48 -07003036 for (VideoStream& stream : streams) {
Sergey Silkina796a7e2018-03-01 15:11:29 +01003037 stream.num_temporal_layers = num_temporal_layers_;
ilnik6b826ef2017-06-16 06:53:48 -07003038 stream.max_framerate = framerate_;
3039 }
3040 return streams;
3041 }
3042
3043 const size_t num_temporal_layers_;
3044 const int framerate_;
3045 };
3046
3047 const int kFrameWidth = 1920;
3048 const int kFrameHeight = 1080;
3049 // 3/4 of 1920.
3050 const int kAdaptedFrameWidth = 1440;
3051 // 3/4 of 1080 rounded down to multiple of 4.
3052 const int kAdaptedFrameHeight = 808;
3053 const int kFramerate = 24;
3054
mflodmancc3d4422017-08-03 08:27:51 -07003055 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
ilnik6b826ef2017-06-16 06:53:48 -07003056 // Trigger reconfigure encoder (without resetting the entire instance).
3057 VideoEncoderConfig video_encoder_config;
Niels Möller259a4972018-04-05 15:36:51 +02003058 video_encoder_config.codec_type = kVideoCodecVP8;
ilnik6b826ef2017-06-16 06:53:48 -07003059 video_encoder_config.max_bitrate_bps = kTargetBitrateBps;
3060 video_encoder_config.number_of_streams = 1;
3061 video_encoder_config.video_stream_factory =
3062 new rtc::RefCountedObject<CroppingVideoStreamFactory>(1, kFramerate);
mflodmancc3d4422017-08-03 08:27:51 -07003063 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
Niels Möllerf1338562018-04-26 09:51:47 +02003064 kMaxPayloadLength);
mflodmancc3d4422017-08-03 08:27:51 -07003065 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
ilnik6b826ef2017-06-16 06:53:48 -07003066
3067 video_source_.set_adaptation_enabled(true);
3068
3069 video_source_.IncomingCapturedFrame(
3070 CreateFrame(1, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07003071 WaitForEncodedFrame(kFrameWidth, kFrameHeight);
ilnik6b826ef2017-06-16 06:53:48 -07003072
3073 // Trigger CPU overuse, downscale by 3/4.
mflodmancc3d4422017-08-03 08:27:51 -07003074 video_stream_encoder_->TriggerCpuOveruse();
ilnik6b826ef2017-06-16 06:53:48 -07003075 video_source_.IncomingCapturedFrame(
3076 CreateFrame(2, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07003077 WaitForEncodedFrame(kAdaptedFrameWidth, kAdaptedFrameHeight);
ilnik6b826ef2017-06-16 06:53:48 -07003078
mflodmancc3d4422017-08-03 08:27:51 -07003079 video_stream_encoder_->Stop();
ilnik6b826ef2017-06-16 06:53:48 -07003080}
3081
mflodmancc3d4422017-08-03 08:27:51 -07003082TEST_F(VideoStreamEncoderTest, PeriodicallyUpdatesChannelParameters) {
sprang4847ae62017-06-27 07:06:52 -07003083 const int kFrameWidth = 1280;
3084 const int kFrameHeight = 720;
3085 const int kLowFps = 2;
3086 const int kHighFps = 30;
3087
mflodmancc3d4422017-08-03 08:27:51 -07003088 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
sprang4847ae62017-06-27 07:06:52 -07003089
3090 int64_t timestamp_ms = fake_clock_.TimeNanos() / rtc::kNumNanosecsPerMillisec;
3091 max_framerate_ = kLowFps;
3092
3093 // Insert 2 seconds of 2fps video.
3094 for (int i = 0; i < kLowFps * 2; ++i) {
3095 video_source_.IncomingCapturedFrame(
3096 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
3097 WaitForEncodedFrame(timestamp_ms);
3098 timestamp_ms += 1000 / kLowFps;
3099 }
3100
3101 // Make sure encoder is updated with new target.
mflodmancc3d4422017-08-03 08:27:51 -07003102 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
sprang4847ae62017-06-27 07:06:52 -07003103 video_source_.IncomingCapturedFrame(
3104 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
3105 WaitForEncodedFrame(timestamp_ms);
3106 timestamp_ms += 1000 / kLowFps;
3107
3108 EXPECT_EQ(kLowFps, fake_encoder_.GetConfiguredInputFramerate());
3109
3110 // Insert 30fps frames for just a little more than the forced update period.
3111 const int kVcmTimerIntervalFrames =
3112 (vcm::VCMProcessTimer::kDefaultProcessIntervalMs * kHighFps) / 1000;
3113 const int kFrameIntervalMs = 1000 / kHighFps;
3114 max_framerate_ = kHighFps;
3115 for (int i = 0; i < kVcmTimerIntervalFrames + 2; ++i) {
3116 video_source_.IncomingCapturedFrame(
3117 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
3118 // Wait for encoded frame, but skip ahead if it doesn't arrive as it might
3119 // be dropped if the encoder hans't been updated with the new higher target
3120 // framerate yet, causing it to overshoot the target bitrate and then
3121 // suffering the wrath of the media optimizer.
3122 TimedWaitForEncodedFrame(timestamp_ms, 2 * kFrameIntervalMs);
3123 timestamp_ms += kFrameIntervalMs;
3124 }
3125
3126 // Don expect correct measurement just yet, but it should be higher than
3127 // before.
3128 EXPECT_GT(fake_encoder_.GetConfiguredInputFramerate(), kLowFps);
3129
mflodmancc3d4422017-08-03 08:27:51 -07003130 video_stream_encoder_->Stop();
sprang4847ae62017-06-27 07:06:52 -07003131}
3132
mflodmancc3d4422017-08-03 08:27:51 -07003133TEST_F(VideoStreamEncoderTest, DoesNotUpdateBitrateAllocationWhenSuspended) {
sprang4847ae62017-06-27 07:06:52 -07003134 const int kFrameWidth = 1280;
3135 const int kFrameHeight = 720;
3136 const int kTargetBitrateBps = 1000000;
3137
3138 MockBitrateObserver bitrate_observer;
Niels Möller0327c2d2018-05-21 14:09:31 +02003139 video_stream_encoder_->SetBitrateAllocationObserver(&bitrate_observer);
sprang4847ae62017-06-27 07:06:52 -07003140
3141 EXPECT_CALL(bitrate_observer, OnBitrateAllocationUpdated(_)).Times(1);
3142 // Initial bitrate update.
mflodmancc3d4422017-08-03 08:27:51 -07003143 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
3144 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
sprang4847ae62017-06-27 07:06:52 -07003145
3146 // Insert a first video frame, causes another bitrate update.
3147 int64_t timestamp_ms = fake_clock_.TimeNanos() / rtc::kNumNanosecsPerMillisec;
3148 EXPECT_CALL(bitrate_observer, OnBitrateAllocationUpdated(_)).Times(1);
3149 video_source_.IncomingCapturedFrame(
3150 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
3151 WaitForEncodedFrame(timestamp_ms);
3152
3153 // Next, simulate video suspension due to pacer queue overrun.
mflodmancc3d4422017-08-03 08:27:51 -07003154 video_stream_encoder_->OnBitrateUpdated(0, 0, 1);
sprang4847ae62017-06-27 07:06:52 -07003155
3156 // Skip ahead until a new periodic parameter update should have occured.
3157 timestamp_ms += vcm::VCMProcessTimer::kDefaultProcessIntervalMs;
3158 fake_clock_.AdvanceTimeMicros(
3159 vcm::VCMProcessTimer::kDefaultProcessIntervalMs *
3160 rtc::kNumMicrosecsPerMillisec);
3161
3162 // Bitrate observer should not be called.
3163 EXPECT_CALL(bitrate_observer, OnBitrateAllocationUpdated(_)).Times(0);
3164 video_source_.IncomingCapturedFrame(
3165 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
3166 ExpectDroppedFrame();
3167
mflodmancc3d4422017-08-03 08:27:51 -07003168 video_stream_encoder_->Stop();
sprang4847ae62017-06-27 07:06:52 -07003169}
ilnik6b826ef2017-06-16 06:53:48 -07003170
Niels Möller4db138e2018-04-19 09:04:13 +02003171TEST_F(VideoStreamEncoderTest,
3172 DefaultCpuAdaptationThresholdsForSoftwareEncoder) {
3173 const int kFrameWidth = 1280;
3174 const int kFrameHeight = 720;
3175 const CpuOveruseOptions default_options;
3176 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
3177 video_source_.IncomingCapturedFrame(
3178 CreateFrame(1, kFrameWidth, kFrameHeight));
3179 WaitForEncodedFrame(1);
3180 EXPECT_EQ(video_stream_encoder_->overuse_detector_proxy_->GetOptions()
3181 .low_encode_usage_threshold_percent,
3182 default_options.low_encode_usage_threshold_percent);
3183 EXPECT_EQ(video_stream_encoder_->overuse_detector_proxy_->GetOptions()
3184 .high_encode_usage_threshold_percent,
3185 default_options.high_encode_usage_threshold_percent);
3186 video_stream_encoder_->Stop();
3187}
3188
3189TEST_F(VideoStreamEncoderTest,
3190 HigherCpuAdaptationThresholdsForHardwareEncoder) {
3191 const int kFrameWidth = 1280;
3192 const int kFrameHeight = 720;
3193 CpuOveruseOptions hardware_options;
3194 hardware_options.low_encode_usage_threshold_percent = 150;
3195 hardware_options.high_encode_usage_threshold_percent = 200;
3196 encoder_factory_.SetIsHardwareAccelerated(true);
3197
3198 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
3199 video_source_.IncomingCapturedFrame(
3200 CreateFrame(1, kFrameWidth, kFrameHeight));
3201 WaitForEncodedFrame(1);
3202 EXPECT_EQ(video_stream_encoder_->overuse_detector_proxy_->GetOptions()
3203 .low_encode_usage_threshold_percent,
3204 hardware_options.low_encode_usage_threshold_percent);
3205 EXPECT_EQ(video_stream_encoder_->overuse_detector_proxy_->GetOptions()
3206 .high_encode_usage_threshold_percent,
3207 hardware_options.high_encode_usage_threshold_percent);
3208 video_stream_encoder_->Stop();
3209}
3210
perkj26091b12016-09-01 01:17:40 -07003211} // namespace webrtc