blob: 4b9de7ba6093c5888e9e3538837af961c563706c [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) {
perkj803d97f2016-11-01 11:45:46 -0700107 rtc::Event event(false, false);
kthelgason876222f2016-11-29 01:44:11 -0800108 encoder_queue()->PostTask([this, &event, reason, down] {
sprangb1ca0732017-02-01 08:38:12 -0800109 down ? AdaptDown(reason) : AdaptUp(reason);
perkj803d97f2016-11-01 11:45:46 -0700110 event.Set();
111 });
perkj070ba852017-02-16 15:46:27 -0800112 ASSERT_TRUE(event.Wait(5000));
perkj803d97f2016-11-01 11:45:46 -0700113 }
114
kthelgason2fc52542017-03-03 00:24:41 -0800115 // This is used as a synchronisation mechanism, to make sure that the
116 // encoder queue is not blocked before we start sending it frames.
117 void WaitUntilTaskQueueIsIdle() {
118 rtc::Event event(false, false);
Yves Gerey665174f2018-06-19 15:03:05 +0200119 encoder_queue()->PostTask([&event] { event.Set(); });
kthelgason2fc52542017-03-03 00:24:41 -0800120 ASSERT_TRUE(event.Wait(5000));
121 }
122
sprangb1ca0732017-02-01 08:38:12 -0800123 void TriggerCpuOveruse() { PostTaskAndWait(true, AdaptReason::kCpu); }
kthelgason876222f2016-11-29 01:44:11 -0800124
sprangb1ca0732017-02-01 08:38:12 -0800125 void TriggerCpuNormalUsage() { PostTaskAndWait(false, AdaptReason::kCpu); }
kthelgason876222f2016-11-29 01:44:11 -0800126
sprangb1ca0732017-02-01 08:38:12 -0800127 void TriggerQualityLow() { PostTaskAndWait(true, AdaptReason::kQuality); }
kthelgason876222f2016-11-29 01:44:11 -0800128
sprangb1ca0732017-02-01 08:38:12 -0800129 void TriggerQualityHigh() { PostTaskAndWait(false, AdaptReason::kQuality); }
sprangfda496a2017-06-15 04:21:07 -0700130
Niels Möller7dc26b72017-12-06 10:27:48 +0100131 CpuOveruseDetectorProxy* overuse_detector_proxy_;
perkj803d97f2016-11-01 11:45:46 -0700132};
133
asapersson5f7226f2016-11-25 04:37:00 -0800134class VideoStreamFactory
135 : public VideoEncoderConfig::VideoStreamFactoryInterface {
136 public:
sprangfda496a2017-06-15 04:21:07 -0700137 explicit VideoStreamFactory(size_t num_temporal_layers, int framerate)
138 : num_temporal_layers_(num_temporal_layers), framerate_(framerate) {
asapersson5f7226f2016-11-25 04:37:00 -0800139 EXPECT_GT(num_temporal_layers, 0u);
sprangfda496a2017-06-15 04:21:07 -0700140 EXPECT_GT(framerate, 0);
asapersson5f7226f2016-11-25 04:37:00 -0800141 }
142
143 private:
144 std::vector<VideoStream> CreateEncoderStreams(
145 int width,
146 int height,
147 const VideoEncoderConfig& encoder_config) override {
148 std::vector<VideoStream> streams =
149 test::CreateVideoStreams(width, height, encoder_config);
150 for (VideoStream& stream : streams) {
Sergey Silkina796a7e2018-03-01 15:11:29 +0100151 stream.num_temporal_layers = num_temporal_layers_;
sprangfda496a2017-06-15 04:21:07 -0700152 stream.max_framerate = framerate_;
asapersson5f7226f2016-11-25 04:37:00 -0800153 }
154 return streams;
155 }
sprangfda496a2017-06-15 04:21:07 -0700156
asapersson5f7226f2016-11-25 04:37:00 -0800157 const size_t num_temporal_layers_;
sprangfda496a2017-06-15 04:21:07 -0700158 const int framerate_;
asapersson5f7226f2016-11-25 04:37:00 -0800159};
160
sprangb1ca0732017-02-01 08:38:12 -0800161class AdaptingFrameForwarder : public test::FrameForwarder {
162 public:
163 AdaptingFrameForwarder() : adaptation_enabled_(false) {}
asaperssonfab67072017-04-04 05:51:49 -0700164 ~AdaptingFrameForwarder() override {}
sprangb1ca0732017-02-01 08:38:12 -0800165
166 void set_adaptation_enabled(bool enabled) {
167 rtc::CritScope cs(&crit_);
168 adaptation_enabled_ = enabled;
169 }
170
asaperssonfab67072017-04-04 05:51:49 -0700171 bool adaption_enabled() const {
sprangb1ca0732017-02-01 08:38:12 -0800172 rtc::CritScope cs(&crit_);
173 return adaptation_enabled_;
174 }
175
asapersson09f05612017-05-15 23:40:18 -0700176 rtc::VideoSinkWants last_wants() const {
177 rtc::CritScope cs(&crit_);
178 return last_wants_;
179 }
180
Danil Chapovalovb9b146c2018-06-15 12:28:07 +0200181 absl::optional<int> last_sent_width() const { return last_width_; }
182 absl::optional<int> last_sent_height() const { return last_height_; }
Jonathan Yubc771b72017-12-08 17:04:29 -0800183
sprangb1ca0732017-02-01 08:38:12 -0800184 void IncomingCapturedFrame(const VideoFrame& video_frame) override {
185 int cropped_width = 0;
186 int cropped_height = 0;
187 int out_width = 0;
188 int out_height = 0;
sprangc5d62e22017-04-02 23:53:04 -0700189 if (adaption_enabled()) {
190 if (adapter_.AdaptFrameResolution(
191 video_frame.width(), video_frame.height(),
192 video_frame.timestamp_us() * 1000, &cropped_width,
193 &cropped_height, &out_width, &out_height)) {
194 VideoFrame adapted_frame(new rtc::RefCountedObject<TestBuffer>(
195 nullptr, out_width, out_height),
196 99, 99, kVideoRotation_0);
197 adapted_frame.set_ntp_time_ms(video_frame.ntp_time_ms());
198 test::FrameForwarder::IncomingCapturedFrame(adapted_frame);
Jonathan Yubc771b72017-12-08 17:04:29 -0800199 last_width_.emplace(adapted_frame.width());
200 last_height_.emplace(adapted_frame.height());
201 } else {
Danil Chapovalovb9b146c2018-06-15 12:28:07 +0200202 last_width_ = absl::nullopt;
203 last_height_ = absl::nullopt;
sprangc5d62e22017-04-02 23:53:04 -0700204 }
sprangb1ca0732017-02-01 08:38:12 -0800205 } else {
206 test::FrameForwarder::IncomingCapturedFrame(video_frame);
Jonathan Yubc771b72017-12-08 17:04:29 -0800207 last_width_.emplace(video_frame.width());
208 last_height_.emplace(video_frame.height());
sprangb1ca0732017-02-01 08:38:12 -0800209 }
210 }
211
212 void AddOrUpdateSink(rtc::VideoSinkInterface<VideoFrame>* sink,
213 const rtc::VideoSinkWants& wants) override {
214 rtc::CritScope cs(&crit_);
asapersson09f05612017-05-15 23:40:18 -0700215 last_wants_ = sink_wants();
sprangc5d62e22017-04-02 23:53:04 -0700216 adapter_.OnResolutionFramerateRequest(wants.target_pixel_count,
217 wants.max_pixel_count,
218 wants.max_framerate_fps);
sprangb1ca0732017-02-01 08:38:12 -0800219 test::FrameForwarder::AddOrUpdateSink(sink, wants);
220 }
sprangb1ca0732017-02-01 08:38:12 -0800221 cricket::VideoAdapter adapter_;
danilchapa37de392017-09-09 04:17:22 -0700222 bool adaptation_enabled_ RTC_GUARDED_BY(crit_);
223 rtc::VideoSinkWants last_wants_ RTC_GUARDED_BY(crit_);
Danil Chapovalovb9b146c2018-06-15 12:28:07 +0200224 absl::optional<int> last_width_;
225 absl::optional<int> last_height_;
sprangb1ca0732017-02-01 08:38:12 -0800226};
sprangc5d62e22017-04-02 23:53:04 -0700227
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:
497 TestEncoder()
498 : FakeEncoder(Clock::GetRealTimeClock()),
499 continue_encode_event_(false, false) {}
500
asaperssonfab67072017-04-04 05:51:49 -0700501 VideoCodec codec_config() const {
brandtre78d2662017-01-16 05:57:16 -0800502 rtc::CritScope lock(&crit_sect_);
perkjfa10b552016-10-02 23:45:26 -0700503 return config_;
504 }
505
506 void BlockNextEncode() {
brandtre78d2662017-01-16 05:57:16 -0800507 rtc::CritScope lock(&local_crit_sect_);
perkjfa10b552016-10-02 23:45:26 -0700508 block_next_encode_ = true;
509 }
510
kthelgason876222f2016-11-29 01:44:11 -0800511 VideoEncoder::ScalingSettings GetScalingSettings() const override {
kthelgason2fc52542017-03-03 00:24:41 -0800512 rtc::CritScope lock(&local_crit_sect_);
kthelgasonad9010c2017-02-14 00:46:51 -0800513 if (quality_scaling_)
Niels Möller225c7872018-02-22 15:03:53 +0100514 return VideoEncoder::ScalingSettings(1, 2, kMinPixelsPerFrame);
515 return VideoEncoder::ScalingSettings::kOff;
kthelgason876222f2016-11-29 01:44:11 -0800516 }
517
perkjfa10b552016-10-02 23:45:26 -0700518 void ContinueEncode() { continue_encode_event_.Set(); }
519
520 void CheckLastTimeStampsMatch(int64_t ntp_time_ms,
521 uint32_t timestamp) const {
brandtre78d2662017-01-16 05:57:16 -0800522 rtc::CritScope lock(&local_crit_sect_);
perkjfa10b552016-10-02 23:45:26 -0700523 EXPECT_EQ(timestamp_, timestamp);
524 EXPECT_EQ(ntp_time_ms_, ntp_time_ms);
525 }
526
kthelgason2fc52542017-03-03 00:24:41 -0800527 void SetQualityScaling(bool b) {
528 rtc::CritScope lock(&local_crit_sect_);
529 quality_scaling_ = b;
530 }
kthelgasonad9010c2017-02-14 00:46:51 -0800531
sprangfe627f32017-03-29 08:24:59 -0700532 void ForceInitEncodeFailure(bool force_failure) {
533 rtc::CritScope lock(&local_crit_sect_);
534 force_init_encode_failed_ = force_failure;
535 }
536
perkjfa10b552016-10-02 23:45:26 -0700537 private:
perkj26091b12016-09-01 01:17:40 -0700538 int32_t Encode(const VideoFrame& input_image,
539 const CodecSpecificInfo* codec_specific_info,
540 const std::vector<FrameType>* frame_types) override {
541 bool block_encode;
542 {
brandtre78d2662017-01-16 05:57:16 -0800543 rtc::CritScope lock(&local_crit_sect_);
perkj26091b12016-09-01 01:17:40 -0700544 EXPECT_GT(input_image.timestamp(), timestamp_);
545 EXPECT_GT(input_image.ntp_time_ms(), ntp_time_ms_);
546 EXPECT_EQ(input_image.timestamp(), input_image.ntp_time_ms() * 90);
547
548 timestamp_ = input_image.timestamp();
549 ntp_time_ms_ = input_image.ntp_time_ms();
perkj803d97f2016-11-01 11:45:46 -0700550 last_input_width_ = input_image.width();
551 last_input_height_ = input_image.height();
perkj26091b12016-09-01 01:17:40 -0700552 block_encode = block_next_encode_;
553 block_next_encode_ = false;
554 }
555 int32_t result =
556 FakeEncoder::Encode(input_image, codec_specific_info, frame_types);
557 if (block_encode)
perkja49cbd32016-09-16 07:53:41 -0700558 EXPECT_TRUE(continue_encode_event_.Wait(kDefaultTimeoutMs));
perkj26091b12016-09-01 01:17:40 -0700559 return result;
560 }
561
sprangfe627f32017-03-29 08:24:59 -0700562 int32_t InitEncode(const VideoCodec* config,
563 int32_t number_of_cores,
564 size_t max_payload_size) override {
565 int res =
566 FakeEncoder::InitEncode(config, number_of_cores, max_payload_size);
567 rtc::CritScope lock(&local_crit_sect_);
Erik Språng82fad3d2018-03-21 09:57:23 +0100568 if (config->codecType == kVideoCodecVP8) {
sprangfe627f32017-03-29 08:24:59 -0700569 // Simulate setting up temporal layers, in order to validate the life
570 // cycle of these objects.
571 int num_streams = std::max<int>(1, config->numberOfSimulcastStreams);
sprangfe627f32017-03-29 08:24:59 -0700572 for (int i = 0; i < num_streams; ++i) {
573 allocated_temporal_layers_.emplace_back(
Erik Språng4529fbc2018-10-12 10:30:31 +0200574 CreateVp8TemporalLayers(Vp8TemporalLayersType::kFixedPattern,
575 config->VP8().numberOfTemporalLayers));
sprangfe627f32017-03-29 08:24:59 -0700576 }
577 }
578 if (force_init_encode_failed_)
579 return -1;
580 return res;
581 }
582
brandtre78d2662017-01-16 05:57:16 -0800583 rtc::CriticalSection local_crit_sect_;
danilchapa37de392017-09-09 04:17:22 -0700584 bool block_next_encode_ RTC_GUARDED_BY(local_crit_sect_) = false;
perkj26091b12016-09-01 01:17:40 -0700585 rtc::Event continue_encode_event_;
danilchapa37de392017-09-09 04:17:22 -0700586 uint32_t timestamp_ RTC_GUARDED_BY(local_crit_sect_) = 0;
587 int64_t ntp_time_ms_ RTC_GUARDED_BY(local_crit_sect_) = 0;
588 int last_input_width_ RTC_GUARDED_BY(local_crit_sect_) = 0;
589 int last_input_height_ RTC_GUARDED_BY(local_crit_sect_) = 0;
590 bool quality_scaling_ RTC_GUARDED_BY(local_crit_sect_) = true;
Erik Språng4529fbc2018-10-12 10:30:31 +0200591 std::vector<std::unique_ptr<Vp8TemporalLayers>> allocated_temporal_layers_
danilchapa37de392017-09-09 04:17:22 -0700592 RTC_GUARDED_BY(local_crit_sect_);
593 bool force_init_encode_failed_ RTC_GUARDED_BY(local_crit_sect_) = false;
perkj26091b12016-09-01 01:17:40 -0700594 };
595
mflodmancc3d4422017-08-03 08:27:51 -0700596 class TestSink : public VideoStreamEncoder::EncoderSink {
perkj26091b12016-09-01 01:17:40 -0700597 public:
598 explicit TestSink(TestEncoder* test_encoder)
599 : test_encoder_(test_encoder), encoded_frame_event_(false, false) {}
600
perkj26091b12016-09-01 01:17:40 -0700601 void WaitForEncodedFrame(int64_t expected_ntp_time) {
sprang4847ae62017-06-27 07:06:52 -0700602 EXPECT_TRUE(
603 TimedWaitForEncodedFrame(expected_ntp_time, kDefaultTimeoutMs));
604 }
605
606 bool TimedWaitForEncodedFrame(int64_t expected_ntp_time,
607 int64_t timeout_ms) {
perkj26091b12016-09-01 01:17:40 -0700608 uint32_t timestamp = 0;
sprang4847ae62017-06-27 07:06:52 -0700609 if (!encoded_frame_event_.Wait(timeout_ms))
610 return false;
perkj26091b12016-09-01 01:17:40 -0700611 {
612 rtc::CritScope lock(&crit_);
sprangb1ca0732017-02-01 08:38:12 -0800613 timestamp = last_timestamp_;
perkj26091b12016-09-01 01:17:40 -0700614 }
615 test_encoder_->CheckLastTimeStampsMatch(expected_ntp_time, timestamp);
sprang4847ae62017-06-27 07:06:52 -0700616 return true;
perkj26091b12016-09-01 01:17:40 -0700617 }
618
sprangb1ca0732017-02-01 08:38:12 -0800619 void WaitForEncodedFrame(uint32_t expected_width,
620 uint32_t expected_height) {
sprangc5d62e22017-04-02 23:53:04 -0700621 EXPECT_TRUE(encoded_frame_event_.Wait(kDefaultTimeoutMs));
Åsa Perssonc74d8da2017-12-04 14:13:56 +0100622 CheckLastFrameSizeMatches(expected_width, expected_height);
sprangc5d62e22017-04-02 23:53:04 -0700623 }
624
Åsa Perssonc74d8da2017-12-04 14:13:56 +0100625 void CheckLastFrameSizeMatches(uint32_t expected_width,
sprangc5d62e22017-04-02 23:53:04 -0700626 uint32_t expected_height) {
sprangb1ca0732017-02-01 08:38:12 -0800627 uint32_t width = 0;
628 uint32_t height = 0;
sprangb1ca0732017-02-01 08:38:12 -0800629 {
630 rtc::CritScope lock(&crit_);
631 width = last_width_;
632 height = last_height_;
633 }
634 EXPECT_EQ(expected_height, height);
635 EXPECT_EQ(expected_width, width);
636 }
637
kthelgason2fc52542017-03-03 00:24:41 -0800638 void ExpectDroppedFrame() { EXPECT_FALSE(encoded_frame_event_.Wait(100)); }
kthelgason2bc68642017-02-07 07:02:22 -0800639
sprangc5d62e22017-04-02 23:53:04 -0700640 bool WaitForFrame(int64_t timeout_ms) {
641 return encoded_frame_event_.Wait(timeout_ms);
642 }
643
perkj26091b12016-09-01 01:17:40 -0700644 void SetExpectNoFrames() {
645 rtc::CritScope lock(&crit_);
646 expect_frames_ = false;
647 }
648
asaperssonfab67072017-04-04 05:51:49 -0700649 int number_of_reconfigurations() const {
Per512ecb32016-09-23 15:52:06 +0200650 rtc::CritScope lock(&crit_);
651 return number_of_reconfigurations_;
652 }
653
asaperssonfab67072017-04-04 05:51:49 -0700654 int last_min_transmit_bitrate() const {
Per512ecb32016-09-23 15:52:06 +0200655 rtc::CritScope lock(&crit_);
656 return min_transmit_bitrate_bps_;
657 }
658
perkj26091b12016-09-01 01:17:40 -0700659 private:
sergeyu2cb155a2016-11-04 11:39:29 -0700660 Result OnEncodedImage(
661 const EncodedImage& encoded_image,
662 const CodecSpecificInfo* codec_specific_info,
663 const RTPFragmentationHeader* fragmentation) override {
Per512ecb32016-09-23 15:52:06 +0200664 rtc::CritScope lock(&crit_);
665 EXPECT_TRUE(expect_frames_);
Niels Möller23775882018-08-16 10:24:12 +0200666 last_timestamp_ = encoded_image.Timestamp();
sprangb1ca0732017-02-01 08:38:12 -0800667 last_width_ = encoded_image._encodedWidth;
668 last_height_ = encoded_image._encodedHeight;
Per512ecb32016-09-23 15:52:06 +0200669 encoded_frame_event_.Set();
sprangb1ca0732017-02-01 08:38:12 -0800670 return Result(Result::OK, last_timestamp_);
Per512ecb32016-09-23 15:52:06 +0200671 }
672
673 void OnEncoderConfigurationChanged(std::vector<VideoStream> streams,
674 int min_transmit_bitrate_bps) override {
675 rtc::CriticalSection crit_;
676 ++number_of_reconfigurations_;
677 min_transmit_bitrate_bps_ = min_transmit_bitrate_bps;
678 }
679
perkj26091b12016-09-01 01:17:40 -0700680 rtc::CriticalSection crit_;
681 TestEncoder* test_encoder_;
682 rtc::Event encoded_frame_event_;
sprangb1ca0732017-02-01 08:38:12 -0800683 uint32_t last_timestamp_ = 0;
684 uint32_t last_height_ = 0;
685 uint32_t last_width_ = 0;
perkj26091b12016-09-01 01:17:40 -0700686 bool expect_frames_ = true;
Per512ecb32016-09-23 15:52:06 +0200687 int number_of_reconfigurations_ = 0;
688 int min_transmit_bitrate_bps_ = 0;
perkj26091b12016-09-01 01:17:40 -0700689 };
690
691 VideoSendStream::Config video_send_config_;
Erik Språng08127a92016-11-16 16:41:30 +0100692 VideoEncoderConfig video_encoder_config_;
Per512ecb32016-09-23 15:52:06 +0200693 int codec_width_;
694 int codec_height_;
sprang4847ae62017-06-27 07:06:52 -0700695 int max_framerate_;
perkj26091b12016-09-01 01:17:40 -0700696 TestEncoder fake_encoder_;
Niels Möllercbcbc222018-09-28 09:07:24 +0200697 test::VideoEncoderProxyFactory encoder_factory_;
sprangc5d62e22017-04-02 23:53:04 -0700698 std::unique_ptr<MockableSendStatisticsProxy> stats_proxy_;
perkj26091b12016-09-01 01:17:40 -0700699 TestSink sink_;
sprangb1ca0732017-02-01 08:38:12 -0800700 AdaptingFrameForwarder video_source_;
mflodmancc3d4422017-08-03 08:27:51 -0700701 std::unique_ptr<VideoStreamEncoderUnderTest> video_stream_encoder_;
sprang4847ae62017-06-27 07:06:52 -0700702 rtc::ScopedFakeClock fake_clock_;
perkj26091b12016-09-01 01:17:40 -0700703};
704
mflodmancc3d4422017-08-03 08:27:51 -0700705TEST_F(VideoStreamEncoderTest, EncodeOneFrame) {
706 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkj26091b12016-09-01 01:17:40 -0700707 rtc::Event frame_destroyed_event(false, false);
perkja49cbd32016-09-16 07:53:41 -0700708 video_source_.IncomingCapturedFrame(CreateFrame(1, &frame_destroyed_event));
sprang4847ae62017-06-27 07:06:52 -0700709 WaitForEncodedFrame(1);
perkja49cbd32016-09-16 07:53:41 -0700710 EXPECT_TRUE(frame_destroyed_event.Wait(kDefaultTimeoutMs));
mflodmancc3d4422017-08-03 08:27:51 -0700711 video_stream_encoder_->Stop();
perkj26091b12016-09-01 01:17:40 -0700712}
713
mflodmancc3d4422017-08-03 08:27:51 -0700714TEST_F(VideoStreamEncoderTest, DropsFramesBeforeFirstOnBitrateUpdated) {
perkj26091b12016-09-01 01:17:40 -0700715 // Dropped since no target bitrate has been set.
716 rtc::Event frame_destroyed_event(false, false);
Sebastian Janssona3177052018-04-10 13:05:49 +0200717 // The encoder will cache up to one frame for a short duration. Adding two
718 // frames means that the first frame will be dropped and the second frame will
719 // be sent when the encoder is enabled.
perkja49cbd32016-09-16 07:53:41 -0700720 video_source_.IncomingCapturedFrame(CreateFrame(1, &frame_destroyed_event));
Sebastian Janssona3177052018-04-10 13:05:49 +0200721 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
perkja49cbd32016-09-16 07:53:41 -0700722 EXPECT_TRUE(frame_destroyed_event.Wait(kDefaultTimeoutMs));
perkj26091b12016-09-01 01:17:40 -0700723
mflodmancc3d4422017-08-03 08:27:51 -0700724 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkj26091b12016-09-01 01:17:40 -0700725
Sebastian Janssona3177052018-04-10 13:05:49 +0200726 // The pending frame should be received.
sprang4847ae62017-06-27 07:06:52 -0700727 WaitForEncodedFrame(2);
Sebastian Janssona3177052018-04-10 13:05:49 +0200728 video_source_.IncomingCapturedFrame(CreateFrame(3, nullptr));
729
730 WaitForEncodedFrame(3);
mflodmancc3d4422017-08-03 08:27:51 -0700731 video_stream_encoder_->Stop();
perkj26091b12016-09-01 01:17:40 -0700732}
733
mflodmancc3d4422017-08-03 08:27:51 -0700734TEST_F(VideoStreamEncoderTest, DropsFramesWhenRateSetToZero) {
735 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkja49cbd32016-09-16 07:53:41 -0700736 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700737 WaitForEncodedFrame(1);
perkj26091b12016-09-01 01:17:40 -0700738
mflodmancc3d4422017-08-03 08:27:51 -0700739 video_stream_encoder_->OnBitrateUpdated(0, 0, 0);
Sebastian Janssona3177052018-04-10 13:05:49 +0200740 // The encoder will cache up to one frame for a short duration. Adding two
741 // frames means that the first frame will be dropped and the second frame will
742 // be sent when the encoder is resumed.
perkja49cbd32016-09-16 07:53:41 -0700743 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
Sebastian Janssona3177052018-04-10 13:05:49 +0200744 video_source_.IncomingCapturedFrame(CreateFrame(3, nullptr));
perkj26091b12016-09-01 01:17:40 -0700745
mflodmancc3d4422017-08-03 08:27:51 -0700746 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
sprang4847ae62017-06-27 07:06:52 -0700747 WaitForEncodedFrame(3);
Sebastian Janssona3177052018-04-10 13:05:49 +0200748 video_source_.IncomingCapturedFrame(CreateFrame(4, nullptr));
749 WaitForEncodedFrame(4);
mflodmancc3d4422017-08-03 08:27:51 -0700750 video_stream_encoder_->Stop();
perkj26091b12016-09-01 01:17:40 -0700751}
752
mflodmancc3d4422017-08-03 08:27:51 -0700753TEST_F(VideoStreamEncoderTest, DropsFramesWithSameOrOldNtpTimestamp) {
754 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkja49cbd32016-09-16 07:53:41 -0700755 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700756 WaitForEncodedFrame(1);
perkj26091b12016-09-01 01:17:40 -0700757
758 // This frame will be dropped since it has the same ntp timestamp.
perkja49cbd32016-09-16 07:53:41 -0700759 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
perkj26091b12016-09-01 01:17:40 -0700760
perkja49cbd32016-09-16 07:53:41 -0700761 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700762 WaitForEncodedFrame(2);
mflodmancc3d4422017-08-03 08:27:51 -0700763 video_stream_encoder_->Stop();
perkj26091b12016-09-01 01:17:40 -0700764}
765
mflodmancc3d4422017-08-03 08:27:51 -0700766TEST_F(VideoStreamEncoderTest, DropsFrameAfterStop) {
767 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkj26091b12016-09-01 01:17:40 -0700768
perkja49cbd32016-09-16 07:53:41 -0700769 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700770 WaitForEncodedFrame(1);
perkj26091b12016-09-01 01:17:40 -0700771
mflodmancc3d4422017-08-03 08:27:51 -0700772 video_stream_encoder_->Stop();
perkj26091b12016-09-01 01:17:40 -0700773 sink_.SetExpectNoFrames();
774 rtc::Event frame_destroyed_event(false, false);
perkja49cbd32016-09-16 07:53:41 -0700775 video_source_.IncomingCapturedFrame(CreateFrame(2, &frame_destroyed_event));
776 EXPECT_TRUE(frame_destroyed_event.Wait(kDefaultTimeoutMs));
perkj26091b12016-09-01 01:17:40 -0700777}
778
mflodmancc3d4422017-08-03 08:27:51 -0700779TEST_F(VideoStreamEncoderTest, DropsPendingFramesOnSlowEncode) {
780 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkj26091b12016-09-01 01:17:40 -0700781
782 fake_encoder_.BlockNextEncode();
perkja49cbd32016-09-16 07:53:41 -0700783 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700784 WaitForEncodedFrame(1);
perkj26091b12016-09-01 01:17:40 -0700785 // Here, the encoder thread will be blocked in the TestEncoder waiting for a
786 // call to ContinueEncode.
perkja49cbd32016-09-16 07:53:41 -0700787 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
788 video_source_.IncomingCapturedFrame(CreateFrame(3, nullptr));
perkj26091b12016-09-01 01:17:40 -0700789 fake_encoder_.ContinueEncode();
sprang4847ae62017-06-27 07:06:52 -0700790 WaitForEncodedFrame(3);
perkj26091b12016-09-01 01:17:40 -0700791
mflodmancc3d4422017-08-03 08:27:51 -0700792 video_stream_encoder_->Stop();
perkj26091b12016-09-01 01:17:40 -0700793}
794
mflodmancc3d4422017-08-03 08:27:51 -0700795TEST_F(VideoStreamEncoderTest,
796 ConfigureEncoderTriggersOnEncoderConfigurationChanged) {
797 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
Per21d45d22016-10-30 21:37:57 +0100798 EXPECT_EQ(0, sink_.number_of_reconfigurations());
Per512ecb32016-09-23 15:52:06 +0200799
800 // Capture a frame and wait for it to synchronize with the encoder thread.
Perf8c5f2b2016-09-23 16:24:55 +0200801 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700802 WaitForEncodedFrame(1);
Per21d45d22016-10-30 21:37:57 +0100803 // The encoder will have been configured once when the first frame is
804 // received.
805 EXPECT_EQ(1, sink_.number_of_reconfigurations());
Per512ecb32016-09-23 15:52:06 +0200806
807 VideoEncoderConfig video_encoder_config;
Niels Möller259a4972018-04-05 15:36:51 +0200808 test::FillEncoderConfiguration(kVideoCodecVP8, 1, &video_encoder_config);
Per512ecb32016-09-23 15:52:06 +0200809 video_encoder_config.min_transmit_bitrate_bps = 9999;
mflodmancc3d4422017-08-03 08:27:51 -0700810 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
Niels Möllerf1338562018-04-26 09:51:47 +0200811 kMaxPayloadLength);
Per512ecb32016-09-23 15:52:06 +0200812
813 // Capture a frame and wait for it to synchronize with the encoder thread.
Perf8c5f2b2016-09-23 16:24:55 +0200814 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700815 WaitForEncodedFrame(2);
Per21d45d22016-10-30 21:37:57 +0100816 EXPECT_EQ(2, sink_.number_of_reconfigurations());
perkj3b703ed2016-09-29 23:25:40 -0700817 EXPECT_EQ(9999, sink_.last_min_transmit_bitrate());
perkj26105b42016-09-29 22:39:10 -0700818
mflodmancc3d4422017-08-03 08:27:51 -0700819 video_stream_encoder_->Stop();
perkj26105b42016-09-29 22:39:10 -0700820}
821
mflodmancc3d4422017-08-03 08:27:51 -0700822TEST_F(VideoStreamEncoderTest, FrameResolutionChangeReconfigureEncoder) {
823 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkjfa10b552016-10-02 23:45:26 -0700824
825 // Capture a frame and wait for it to synchronize with the encoder thread.
826 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700827 WaitForEncodedFrame(1);
Per21d45d22016-10-30 21:37:57 +0100828 // The encoder will have been configured once.
829 EXPECT_EQ(1, sink_.number_of_reconfigurations());
perkjfa10b552016-10-02 23:45:26 -0700830 EXPECT_EQ(codec_width_, fake_encoder_.codec_config().width);
831 EXPECT_EQ(codec_height_, fake_encoder_.codec_config().height);
832
833 codec_width_ *= 2;
834 codec_height_ *= 2;
835 // Capture a frame with a higher resolution and wait for it to synchronize
836 // with the encoder thread.
837 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700838 WaitForEncodedFrame(2);
perkjfa10b552016-10-02 23:45:26 -0700839 EXPECT_EQ(codec_width_, fake_encoder_.codec_config().width);
840 EXPECT_EQ(codec_height_, fake_encoder_.codec_config().height);
Per21d45d22016-10-30 21:37:57 +0100841 EXPECT_EQ(2, sink_.number_of_reconfigurations());
perkjfa10b552016-10-02 23:45:26 -0700842
mflodmancc3d4422017-08-03 08:27:51 -0700843 video_stream_encoder_->Stop();
perkjfa10b552016-10-02 23:45:26 -0700844}
845
mflodmancc3d4422017-08-03 08:27:51 -0700846TEST_F(VideoStreamEncoderTest, SwitchSourceDeregisterEncoderAsSink) {
perkj803d97f2016-11-01 11:45:46 -0700847 EXPECT_TRUE(video_source_.has_sinks());
848 test::FrameForwarder new_video_source;
mflodmancc3d4422017-08-03 08:27:51 -0700849 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -0700850 &new_video_source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
perkj803d97f2016-11-01 11:45:46 -0700851 EXPECT_FALSE(video_source_.has_sinks());
852 EXPECT_TRUE(new_video_source.has_sinks());
853
mflodmancc3d4422017-08-03 08:27:51 -0700854 video_stream_encoder_->Stop();
perkj803d97f2016-11-01 11:45:46 -0700855}
856
mflodmancc3d4422017-08-03 08:27:51 -0700857TEST_F(VideoStreamEncoderTest, SinkWantsRotationApplied) {
perkj803d97f2016-11-01 11:45:46 -0700858 EXPECT_FALSE(video_source_.sink_wants().rotation_applied);
mflodmancc3d4422017-08-03 08:27:51 -0700859 video_stream_encoder_->SetSink(&sink_, true /*rotation_applied*/);
perkj803d97f2016-11-01 11:45:46 -0700860 EXPECT_TRUE(video_source_.sink_wants().rotation_applied);
mflodmancc3d4422017-08-03 08:27:51 -0700861 video_stream_encoder_->Stop();
perkj803d97f2016-11-01 11:45:46 -0700862}
863
Jonathan Yubc771b72017-12-08 17:04:29 -0800864TEST_F(VideoStreamEncoderTest, TestCpuDowngrades_BalancedMode) {
865 const int kFramerateFps = 30;
asaperssonf7e294d2017-06-13 23:25:22 -0700866 const int kWidth = 1280;
867 const int kHeight = 720;
Jonathan Yubc771b72017-12-08 17:04:29 -0800868
869 // We rely on the automatic resolution adaptation, but we handle framerate
870 // adaptation manually by mocking the stats proxy.
871 video_source_.set_adaptation_enabled(true);
asaperssonf7e294d2017-06-13 23:25:22 -0700872
Taylor Brandstetter49fcc102018-05-16 14:20:41 -0700873 // Enable BALANCED preference, no initial limitation.
Jonathan Yubc771b72017-12-08 17:04:29 -0800874 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
Taylor Brandstetter49fcc102018-05-16 14:20:41 -0700875 video_stream_encoder_->SetSource(&video_source_,
876 webrtc::DegradationPreference::BALANCED);
Jonathan Yubc771b72017-12-08 17:04:29 -0800877 VerifyNoLimitation(video_source_.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -0700878 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
Jonathan Yubc771b72017-12-08 17:04:29 -0800879 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
asaperssonf7e294d2017-06-13 23:25:22 -0700880 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
881
Jonathan Yubc771b72017-12-08 17:04:29 -0800882 // Adapt down as far as possible.
883 rtc::VideoSinkWants last_wants;
884 int64_t t = 1;
885 int loop_count = 0;
886 do {
887 ++loop_count;
888 last_wants = video_source_.sink_wants();
889
890 // Simulate the framerate we've been asked to adapt to.
891 const int fps = std::min(kFramerateFps, last_wants.max_framerate_fps);
892 const int frame_interval_ms = rtc::kNumMillisecsPerSec / fps;
893 VideoSendStream::Stats mock_stats = stats_proxy_->GetStats();
894 mock_stats.input_frame_rate = fps;
895 stats_proxy_->SetMockStats(mock_stats);
896
897 video_source_.IncomingCapturedFrame(CreateFrame(t, kWidth, kHeight));
898 sink_.WaitForEncodedFrame(t);
899 t += frame_interval_ms;
900
mflodmancc3d4422017-08-03 08:27:51 -0700901 video_stream_encoder_->TriggerCpuOveruse();
Jonathan Yubc771b72017-12-08 17:04:29 -0800902 VerifyBalancedModeFpsRange(
903 video_source_.sink_wants(),
904 *video_source_.last_sent_width() * *video_source_.last_sent_height());
905 } while (video_source_.sink_wants().max_pixel_count <
906 last_wants.max_pixel_count ||
907 video_source_.sink_wants().max_framerate_fps <
908 last_wants.max_framerate_fps);
asaperssonf7e294d2017-06-13 23:25:22 -0700909
Jonathan Yubc771b72017-12-08 17:04:29 -0800910 // Verify that we've adapted all the way down.
911 stats_proxy_->ResetMockStats();
asaperssonf7e294d2017-06-13 23:25:22 -0700912 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
Jonathan Yubc771b72017-12-08 17:04:29 -0800913 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_framerate);
914 EXPECT_EQ(loop_count - 1,
asaperssonf7e294d2017-06-13 23:25:22 -0700915 stats_proxy_->GetStats().number_of_cpu_adapt_changes);
Jonathan Yubc771b72017-12-08 17:04:29 -0800916 EXPECT_EQ(kMinPixelsPerFrame, *video_source_.last_sent_width() *
917 *video_source_.last_sent_height());
918 EXPECT_EQ(kMinBalancedFramerateFps,
919 video_source_.sink_wants().max_framerate_fps);
asaperssonf7e294d2017-06-13 23:25:22 -0700920
Jonathan Yubc771b72017-12-08 17:04:29 -0800921 // Adapt back up the same number of times we adapted down.
922 for (int i = 0; i < loop_count - 1; ++i) {
923 last_wants = video_source_.sink_wants();
924
925 // Simulate the framerate we've been asked to adapt to.
926 const int fps = std::min(kFramerateFps, last_wants.max_framerate_fps);
927 const int frame_interval_ms = rtc::kNumMillisecsPerSec / fps;
928 VideoSendStream::Stats mock_stats = stats_proxy_->GetStats();
929 mock_stats.input_frame_rate = fps;
930 stats_proxy_->SetMockStats(mock_stats);
931
932 video_source_.IncomingCapturedFrame(CreateFrame(t, kWidth, kHeight));
933 sink_.WaitForEncodedFrame(t);
934 t += frame_interval_ms;
935
mflodmancc3d4422017-08-03 08:27:51 -0700936 video_stream_encoder_->TriggerCpuNormalUsage();
Jonathan Yubc771b72017-12-08 17:04:29 -0800937 VerifyBalancedModeFpsRange(
938 video_source_.sink_wants(),
939 *video_source_.last_sent_width() * *video_source_.last_sent_height());
940 EXPECT_TRUE(video_source_.sink_wants().max_pixel_count >
941 last_wants.max_pixel_count ||
942 video_source_.sink_wants().max_framerate_fps >
943 last_wants.max_framerate_fps);
asaperssonf7e294d2017-06-13 23:25:22 -0700944 }
945
Åsa Persson8c1bf952018-09-13 10:42:19 +0200946 VerifyFpsMaxResolutionMax(video_source_.sink_wants());
Jonathan Yubc771b72017-12-08 17:04:29 -0800947 stats_proxy_->ResetMockStats();
asaperssonf7e294d2017-06-13 23:25:22 -0700948 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
Jonathan Yubc771b72017-12-08 17:04:29 -0800949 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
950 EXPECT_EQ((loop_count - 1) * 2,
951 stats_proxy_->GetStats().number_of_cpu_adapt_changes);
asaperssonf7e294d2017-06-13 23:25:22 -0700952
mflodmancc3d4422017-08-03 08:27:51 -0700953 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -0700954}
mflodmancc3d4422017-08-03 08:27:51 -0700955TEST_F(VideoStreamEncoderTest, SinkWantsStoredByDegradationPreference) {
956 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson02465b82017-04-10 01:12:52 -0700957 VerifyNoLimitation(video_source_.sink_wants());
perkj803d97f2016-11-01 11:45:46 -0700958
sprangc5d62e22017-04-02 23:53:04 -0700959 const int kFrameWidth = 1280;
960 const int kFrameHeight = 720;
sprangc5d62e22017-04-02 23:53:04 -0700961
Åsa Persson8c1bf952018-09-13 10:42:19 +0200962 int64_t frame_timestamp = 1;
perkj803d97f2016-11-01 11:45:46 -0700963
kthelgason5e13d412016-12-01 03:59:51 -0800964 video_source_.IncomingCapturedFrame(
sprangc5d62e22017-04-02 23:53:04 -0700965 CreateFrame(frame_timestamp, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -0700966 WaitForEncodedFrame(frame_timestamp);
sprangc5d62e22017-04-02 23:53:04 -0700967 frame_timestamp += kFrameIntervalMs;
968
perkj803d97f2016-11-01 11:45:46 -0700969 // Trigger CPU overuse.
mflodmancc3d4422017-08-03 08:27:51 -0700970 video_stream_encoder_->TriggerCpuOveruse();
perkj803d97f2016-11-01 11:45:46 -0700971 video_source_.IncomingCapturedFrame(
sprangc5d62e22017-04-02 23:53:04 -0700972 CreateFrame(frame_timestamp, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -0700973 WaitForEncodedFrame(frame_timestamp);
sprangc5d62e22017-04-02 23:53:04 -0700974 frame_timestamp += kFrameIntervalMs;
sprang3ea3c772017-03-30 07:23:48 -0700975
asapersson0944a802017-04-07 00:57:58 -0700976 // Default degradation preference is maintain-framerate, so will lower max
sprangc5d62e22017-04-02 23:53:04 -0700977 // wanted resolution.
978 EXPECT_FALSE(video_source_.sink_wants().target_pixel_count);
979 EXPECT_LT(video_source_.sink_wants().max_pixel_count,
980 kFrameWidth * kFrameHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +0200981 EXPECT_EQ(kDefaultFramerate, video_source_.sink_wants().max_framerate_fps);
sprangc5d62e22017-04-02 23:53:04 -0700982
983 // Set new source, switch to maintain-resolution.
perkj803d97f2016-11-01 11:45:46 -0700984 test::FrameForwarder new_video_source;
mflodmancc3d4422017-08-03 08:27:51 -0700985 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -0700986 &new_video_source, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
perkj803d97f2016-11-01 11:45:46 -0700987
sprangc5d62e22017-04-02 23:53:04 -0700988 // Initially no degradation registered.
Åsa Persson8c1bf952018-09-13 10:42:19 +0200989 VerifyFpsMaxResolutionMax(new_video_source.sink_wants());
perkj803d97f2016-11-01 11:45:46 -0700990
sprangc5d62e22017-04-02 23:53:04 -0700991 // Force an input frame rate to be available, or the adaptation call won't
992 // know what framerate to adapt form.
asapersson02465b82017-04-10 01:12:52 -0700993 const int kInputFps = 30;
sprangc5d62e22017-04-02 23:53:04 -0700994 VideoSendStream::Stats stats = stats_proxy_->GetStats();
asapersson02465b82017-04-10 01:12:52 -0700995 stats.input_frame_rate = kInputFps;
sprangc5d62e22017-04-02 23:53:04 -0700996 stats_proxy_->SetMockStats(stats);
997
mflodmancc3d4422017-08-03 08:27:51 -0700998 video_stream_encoder_->TriggerCpuOveruse();
perkj803d97f2016-11-01 11:45:46 -0700999 new_video_source.IncomingCapturedFrame(
sprangc5d62e22017-04-02 23:53:04 -07001000 CreateFrame(frame_timestamp, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07001001 WaitForEncodedFrame(frame_timestamp);
sprangc5d62e22017-04-02 23:53:04 -07001002 frame_timestamp += kFrameIntervalMs;
1003
1004 // Some framerate constraint should be set.
sprang84a37592017-02-10 07:04:27 -08001005 EXPECT_FALSE(new_video_source.sink_wants().target_pixel_count);
sprangc5d62e22017-04-02 23:53:04 -07001006 EXPECT_EQ(std::numeric_limits<int>::max(),
1007 new_video_source.sink_wants().max_pixel_count);
asapersson02465b82017-04-10 01:12:52 -07001008 EXPECT_LT(new_video_source.sink_wants().max_framerate_fps, kInputFps);
sprangc5d62e22017-04-02 23:53:04 -07001009
asapersson02465b82017-04-10 01:12:52 -07001010 // Turn off degradation completely.
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001011 video_stream_encoder_->SetSource(&new_video_source,
1012 webrtc::DegradationPreference::DISABLED);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001013 VerifyFpsMaxResolutionMax(new_video_source.sink_wants());
sprangc5d62e22017-04-02 23:53:04 -07001014
mflodmancc3d4422017-08-03 08:27:51 -07001015 video_stream_encoder_->TriggerCpuOveruse();
sprangc5d62e22017-04-02 23:53:04 -07001016 new_video_source.IncomingCapturedFrame(
1017 CreateFrame(frame_timestamp, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07001018 WaitForEncodedFrame(frame_timestamp);
sprangc5d62e22017-04-02 23:53:04 -07001019 frame_timestamp += kFrameIntervalMs;
1020
1021 // Still no degradation.
Åsa Persson8c1bf952018-09-13 10:42:19 +02001022 VerifyFpsMaxResolutionMax(new_video_source.sink_wants());
perkj803d97f2016-11-01 11:45:46 -07001023
1024 // Calling SetSource with resolution scaling enabled apply the old SinkWants.
mflodmancc3d4422017-08-03 08:27:51 -07001025 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001026 &new_video_source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
sprangc5d62e22017-04-02 23:53:04 -07001027 EXPECT_LT(new_video_source.sink_wants().max_pixel_count,
1028 kFrameWidth * kFrameHeight);
sprang84a37592017-02-10 07:04:27 -08001029 EXPECT_FALSE(new_video_source.sink_wants().target_pixel_count);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001030 EXPECT_EQ(kDefaultFramerate, new_video_source.sink_wants().max_framerate_fps);
sprangc5d62e22017-04-02 23:53:04 -07001031
1032 // Calling SetSource with framerate scaling enabled apply the old SinkWants.
mflodmancc3d4422017-08-03 08:27:51 -07001033 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001034 &new_video_source, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
sprangc5d62e22017-04-02 23:53:04 -07001035 EXPECT_FALSE(new_video_source.sink_wants().target_pixel_count);
1036 EXPECT_EQ(std::numeric_limits<int>::max(),
1037 new_video_source.sink_wants().max_pixel_count);
asapersson02465b82017-04-10 01:12:52 -07001038 EXPECT_LT(new_video_source.sink_wants().max_framerate_fps, kInputFps);
perkj803d97f2016-11-01 11:45:46 -07001039
mflodmancc3d4422017-08-03 08:27:51 -07001040 video_stream_encoder_->Stop();
perkj803d97f2016-11-01 11:45:46 -07001041}
1042
mflodmancc3d4422017-08-03 08:27:51 -07001043TEST_F(VideoStreamEncoderTest, StatsTracksQualityAdaptationStats) {
1044 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkj803d97f2016-11-01 11:45:46 -07001045
asaperssonfab67072017-04-04 05:51:49 -07001046 const int kWidth = 1280;
1047 const int kHeight = 720;
asaperssonfab67072017-04-04 05:51:49 -07001048 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001049 WaitForEncodedFrame(1);
asaperssonfab67072017-04-04 05:51:49 -07001050 VideoSendStream::Stats stats = stats_proxy_->GetStats();
1051 EXPECT_FALSE(stats.bw_limited_resolution);
1052 EXPECT_EQ(0, stats.number_of_quality_adapt_changes);
1053
1054 // Trigger adapt down.
mflodmancc3d4422017-08-03 08:27:51 -07001055 video_stream_encoder_->TriggerQualityLow();
asaperssonfab67072017-04-04 05:51:49 -07001056 video_source_.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001057 WaitForEncodedFrame(2);
asaperssonfab67072017-04-04 05:51:49 -07001058
1059 stats = stats_proxy_->GetStats();
1060 EXPECT_TRUE(stats.bw_limited_resolution);
1061 EXPECT_EQ(1, stats.number_of_quality_adapt_changes);
1062
1063 // Trigger adapt up.
mflodmancc3d4422017-08-03 08:27:51 -07001064 video_stream_encoder_->TriggerQualityHigh();
asaperssonfab67072017-04-04 05:51:49 -07001065 video_source_.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001066 WaitForEncodedFrame(3);
asaperssonfab67072017-04-04 05:51:49 -07001067
1068 stats = stats_proxy_->GetStats();
1069 EXPECT_FALSE(stats.bw_limited_resolution);
1070 EXPECT_EQ(2, stats.number_of_quality_adapt_changes);
1071 EXPECT_EQ(0, stats.number_of_cpu_adapt_changes);
1072
mflodmancc3d4422017-08-03 08:27:51 -07001073 video_stream_encoder_->Stop();
asaperssonfab67072017-04-04 05:51:49 -07001074}
1075
mflodmancc3d4422017-08-03 08:27:51 -07001076TEST_F(VideoStreamEncoderTest, StatsTracksCpuAdaptationStats) {
1077 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonfab67072017-04-04 05:51:49 -07001078
1079 const int kWidth = 1280;
1080 const int kHeight = 720;
asaperssonfab67072017-04-04 05:51:49 -07001081 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001082 WaitForEncodedFrame(1);
perkj803d97f2016-11-01 11:45:46 -07001083 VideoSendStream::Stats stats = stats_proxy_->GetStats();
1084 EXPECT_FALSE(stats.cpu_limited_resolution);
1085 EXPECT_EQ(0, stats.number_of_cpu_adapt_changes);
1086
1087 // Trigger CPU overuse.
mflodmancc3d4422017-08-03 08:27:51 -07001088 video_stream_encoder_->TriggerCpuOveruse();
asaperssonfab67072017-04-04 05:51:49 -07001089 video_source_.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001090 WaitForEncodedFrame(2);
perkj803d97f2016-11-01 11:45:46 -07001091
1092 stats = stats_proxy_->GetStats();
1093 EXPECT_TRUE(stats.cpu_limited_resolution);
1094 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1095
1096 // Trigger CPU normal use.
mflodmancc3d4422017-08-03 08:27:51 -07001097 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssonfab67072017-04-04 05:51:49 -07001098 video_source_.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001099 WaitForEncodedFrame(3);
perkj803d97f2016-11-01 11:45:46 -07001100
1101 stats = stats_proxy_->GetStats();
1102 EXPECT_FALSE(stats.cpu_limited_resolution);
1103 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
asaperssonfab67072017-04-04 05:51:49 -07001104 EXPECT_EQ(0, stats.number_of_quality_adapt_changes);
perkj803d97f2016-11-01 11:45:46 -07001105
mflodmancc3d4422017-08-03 08:27:51 -07001106 video_stream_encoder_->Stop();
perkj803d97f2016-11-01 11:45:46 -07001107}
1108
mflodmancc3d4422017-08-03 08:27:51 -07001109TEST_F(VideoStreamEncoderTest, SwitchingSourceKeepsCpuAdaptation) {
1110 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
kthelgason876222f2016-11-29 01:44:11 -08001111
asaperssonfab67072017-04-04 05:51:49 -07001112 const int kWidth = 1280;
1113 const int kHeight = 720;
1114 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001115 WaitForEncodedFrame(1);
kthelgason876222f2016-11-29 01:44:11 -08001116 VideoSendStream::Stats stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001117 EXPECT_FALSE(stats.bw_limited_resolution);
kthelgason876222f2016-11-29 01:44:11 -08001118 EXPECT_FALSE(stats.cpu_limited_resolution);
1119 EXPECT_EQ(0, stats.number_of_cpu_adapt_changes);
1120
asaperssonfab67072017-04-04 05:51:49 -07001121 // Trigger CPU overuse.
mflodmancc3d4422017-08-03 08:27:51 -07001122 video_stream_encoder_->TriggerCpuOveruse();
asaperssonfab67072017-04-04 05:51:49 -07001123 video_source_.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001124 WaitForEncodedFrame(2);
kthelgason876222f2016-11-29 01:44:11 -08001125 stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001126 EXPECT_FALSE(stats.bw_limited_resolution);
kthelgason876222f2016-11-29 01:44:11 -08001127 EXPECT_TRUE(stats.cpu_limited_resolution);
1128 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1129
1130 // Set new source with adaptation still enabled.
1131 test::FrameForwarder new_video_source;
mflodmancc3d4422017-08-03 08:27:51 -07001132 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001133 &new_video_source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
kthelgason876222f2016-11-29 01:44:11 -08001134
asaperssonfab67072017-04-04 05:51:49 -07001135 new_video_source.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001136 WaitForEncodedFrame(3);
kthelgason876222f2016-11-29 01:44:11 -08001137 stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001138 EXPECT_FALSE(stats.bw_limited_resolution);
kthelgason876222f2016-11-29 01:44:11 -08001139 EXPECT_TRUE(stats.cpu_limited_resolution);
1140 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1141
1142 // Set adaptation disabled.
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001143 video_stream_encoder_->SetSource(&new_video_source,
1144 webrtc::DegradationPreference::DISABLED);
kthelgason876222f2016-11-29 01:44:11 -08001145
asaperssonfab67072017-04-04 05:51:49 -07001146 new_video_source.IncomingCapturedFrame(CreateFrame(4, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001147 WaitForEncodedFrame(4);
kthelgason876222f2016-11-29 01:44:11 -08001148 stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001149 EXPECT_FALSE(stats.bw_limited_resolution);
kthelgason876222f2016-11-29 01:44:11 -08001150 EXPECT_FALSE(stats.cpu_limited_resolution);
1151 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1152
1153 // Set adaptation back to enabled.
mflodmancc3d4422017-08-03 08:27:51 -07001154 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001155 &new_video_source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
kthelgason876222f2016-11-29 01:44:11 -08001156
asaperssonfab67072017-04-04 05:51:49 -07001157 new_video_source.IncomingCapturedFrame(CreateFrame(5, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001158 WaitForEncodedFrame(5);
kthelgason876222f2016-11-29 01:44:11 -08001159 stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001160 EXPECT_FALSE(stats.bw_limited_resolution);
kthelgason876222f2016-11-29 01:44:11 -08001161 EXPECT_TRUE(stats.cpu_limited_resolution);
1162 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1163
asaperssonfab67072017-04-04 05:51:49 -07001164 // Trigger CPU normal use.
mflodmancc3d4422017-08-03 08:27:51 -07001165 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssonfab67072017-04-04 05:51:49 -07001166 new_video_source.IncomingCapturedFrame(CreateFrame(6, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001167 WaitForEncodedFrame(6);
kthelgason876222f2016-11-29 01:44:11 -08001168 stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001169 EXPECT_FALSE(stats.bw_limited_resolution);
kthelgason876222f2016-11-29 01:44:11 -08001170 EXPECT_FALSE(stats.cpu_limited_resolution);
1171 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
asapersson02465b82017-04-10 01:12:52 -07001172 EXPECT_EQ(0, stats.number_of_quality_adapt_changes);
kthelgason876222f2016-11-29 01:44:11 -08001173
mflodmancc3d4422017-08-03 08:27:51 -07001174 video_stream_encoder_->Stop();
kthelgason876222f2016-11-29 01:44:11 -08001175}
1176
mflodmancc3d4422017-08-03 08:27:51 -07001177TEST_F(VideoStreamEncoderTest, SwitchingSourceKeepsQualityAdaptation) {
1178 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
kthelgason876222f2016-11-29 01:44:11 -08001179
asaperssonfab67072017-04-04 05:51:49 -07001180 const int kWidth = 1280;
1181 const int kHeight = 720;
1182 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001183 WaitForEncodedFrame(1);
kthelgason876222f2016-11-29 01:44:11 -08001184 VideoSendStream::Stats stats = stats_proxy_->GetStats();
kthelgason876222f2016-11-29 01:44:11 -08001185 EXPECT_FALSE(stats.bw_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001186 EXPECT_FALSE(stats.bw_limited_framerate);
asaperssonfab67072017-04-04 05:51:49 -07001187 EXPECT_EQ(0, stats.number_of_quality_adapt_changes);
kthelgason876222f2016-11-29 01:44:11 -08001188
1189 // Set new source with adaptation still enabled.
1190 test::FrameForwarder new_video_source;
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001191 video_stream_encoder_->SetSource(&new_video_source,
1192 webrtc::DegradationPreference::BALANCED);
kthelgason876222f2016-11-29 01:44:11 -08001193
asaperssonfab67072017-04-04 05:51:49 -07001194 new_video_source.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001195 WaitForEncodedFrame(2);
kthelgason876222f2016-11-29 01:44:11 -08001196 stats = stats_proxy_->GetStats();
kthelgason876222f2016-11-29 01:44:11 -08001197 EXPECT_FALSE(stats.bw_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001198 EXPECT_FALSE(stats.bw_limited_framerate);
asaperssonfab67072017-04-04 05:51:49 -07001199 EXPECT_EQ(0, stats.number_of_quality_adapt_changes);
kthelgason876222f2016-11-29 01:44:11 -08001200
asaperssonfab67072017-04-04 05:51:49 -07001201 // Trigger adapt down.
mflodmancc3d4422017-08-03 08:27:51 -07001202 video_stream_encoder_->TriggerQualityLow();
asaperssonfab67072017-04-04 05:51:49 -07001203 new_video_source.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001204 WaitForEncodedFrame(3);
kthelgason876222f2016-11-29 01:44:11 -08001205 stats = stats_proxy_->GetStats();
kthelgason876222f2016-11-29 01:44:11 -08001206 EXPECT_TRUE(stats.bw_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001207 EXPECT_FALSE(stats.bw_limited_framerate);
asaperssonfab67072017-04-04 05:51:49 -07001208 EXPECT_EQ(1, stats.number_of_quality_adapt_changes);
kthelgason876222f2016-11-29 01:44:11 -08001209
asaperssonfab67072017-04-04 05:51:49 -07001210 // Set new source with adaptation still enabled.
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001211 video_stream_encoder_->SetSource(&new_video_source,
1212 webrtc::DegradationPreference::BALANCED);
kthelgason876222f2016-11-29 01:44:11 -08001213
asaperssonfab67072017-04-04 05:51:49 -07001214 new_video_source.IncomingCapturedFrame(CreateFrame(4, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001215 WaitForEncodedFrame(4);
kthelgason876222f2016-11-29 01:44:11 -08001216 stats = stats_proxy_->GetStats();
kthelgason876222f2016-11-29 01:44:11 -08001217 EXPECT_TRUE(stats.bw_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001218 EXPECT_FALSE(stats.bw_limited_framerate);
asaperssonfab67072017-04-04 05:51:49 -07001219 EXPECT_EQ(1, stats.number_of_quality_adapt_changes);
kthelgason876222f2016-11-29 01:44:11 -08001220
asapersson02465b82017-04-10 01:12:52 -07001221 // Disable resolution scaling.
mflodmancc3d4422017-08-03 08:27:51 -07001222 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001223 &new_video_source, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
kthelgason876222f2016-11-29 01:44:11 -08001224
asaperssonfab67072017-04-04 05:51:49 -07001225 new_video_source.IncomingCapturedFrame(CreateFrame(5, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001226 WaitForEncodedFrame(5);
kthelgason876222f2016-11-29 01:44:11 -08001227 stats = stats_proxy_->GetStats();
kthelgason876222f2016-11-29 01:44:11 -08001228 EXPECT_FALSE(stats.bw_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001229 EXPECT_FALSE(stats.bw_limited_framerate);
asaperssonfab67072017-04-04 05:51:49 -07001230 EXPECT_EQ(1, stats.number_of_quality_adapt_changes);
1231 EXPECT_EQ(0, stats.number_of_cpu_adapt_changes);
kthelgason876222f2016-11-29 01:44:11 -08001232
mflodmancc3d4422017-08-03 08:27:51 -07001233 video_stream_encoder_->Stop();
kthelgason876222f2016-11-29 01:44:11 -08001234}
1235
mflodmancc3d4422017-08-03 08:27:51 -07001236TEST_F(VideoStreamEncoderTest,
1237 QualityAdaptationStatsAreResetWhenScalerIsDisabled) {
1238 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson36e9eb42017-03-31 05:29:12 -07001239
1240 const int kWidth = 1280;
1241 const int kHeight = 720;
Åsa Persson8c1bf952018-09-13 10:42:19 +02001242 int64_t timestamp_ms = kFrameIntervalMs;
asapersson36e9eb42017-03-31 05:29:12 -07001243 video_source_.set_adaptation_enabled(true);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001244 video_source_.IncomingCapturedFrame(
1245 CreateFrame(timestamp_ms, kWidth, kHeight));
1246 WaitForEncodedFrame(timestamp_ms);
asapersson36e9eb42017-03-31 05:29:12 -07001247 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1248 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1249 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1250
1251 // Trigger adapt down.
mflodmancc3d4422017-08-03 08:27:51 -07001252 video_stream_encoder_->TriggerQualityLow();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001253 timestamp_ms += kFrameIntervalMs;
1254 video_source_.IncomingCapturedFrame(
1255 CreateFrame(timestamp_ms, kWidth, kHeight));
1256 WaitForEncodedFrame(timestamp_ms);
asapersson36e9eb42017-03-31 05:29:12 -07001257 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1258 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1259 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1260
1261 // Trigger overuse.
mflodmancc3d4422017-08-03 08:27:51 -07001262 video_stream_encoder_->TriggerCpuOveruse();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001263 timestamp_ms += kFrameIntervalMs;
1264 video_source_.IncomingCapturedFrame(
1265 CreateFrame(timestamp_ms, kWidth, kHeight));
1266 WaitForEncodedFrame(timestamp_ms);
asapersson36e9eb42017-03-31 05:29:12 -07001267 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1268 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1269 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1270
Niels Möller4db138e2018-04-19 09:04:13 +02001271 // Leave source unchanged, but disable quality scaler.
asapersson36e9eb42017-03-31 05:29:12 -07001272 fake_encoder_.SetQualityScaling(false);
Niels Möller4db138e2018-04-19 09:04:13 +02001273
1274 VideoEncoderConfig video_encoder_config;
1275 test::FillEncoderConfiguration(kVideoCodecVP8, 1, &video_encoder_config);
1276 // Make format different, to force recreation of encoder.
1277 video_encoder_config.video_format.parameters["foo"] = "foo";
1278 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
Niels Möllerf1338562018-04-26 09:51:47 +02001279 kMaxPayloadLength);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001280 timestamp_ms += kFrameIntervalMs;
1281 video_source_.IncomingCapturedFrame(
1282 CreateFrame(timestamp_ms, kWidth, kHeight));
1283 WaitForEncodedFrame(timestamp_ms);
asapersson36e9eb42017-03-31 05:29:12 -07001284 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1285 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1286 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1287
mflodmancc3d4422017-08-03 08:27:51 -07001288 video_stream_encoder_->Stop();
asapersson36e9eb42017-03-31 05:29:12 -07001289}
1290
mflodmancc3d4422017-08-03 08:27:51 -07001291TEST_F(VideoStreamEncoderTest,
1292 StatsTracksCpuAdaptationStatsWhenSwitchingSource) {
1293 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkj803d97f2016-11-01 11:45:46 -07001294
asapersson0944a802017-04-07 00:57:58 -07001295 const int kWidth = 1280;
1296 const int kHeight = 720;
sprang84a37592017-02-10 07:04:27 -08001297 int sequence = 1;
perkj803d97f2016-11-01 11:45:46 -07001298
asaperssonfab67072017-04-04 05:51:49 -07001299 video_source_.IncomingCapturedFrame(CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001300 WaitForEncodedFrame(sequence++);
perkj803d97f2016-11-01 11:45:46 -07001301 VideoSendStream::Stats stats = stats_proxy_->GetStats();
sprang84a37592017-02-10 07:04:27 -08001302 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001303 EXPECT_FALSE(stats.cpu_limited_framerate);
sprang84a37592017-02-10 07:04:27 -08001304 EXPECT_EQ(0, stats.number_of_cpu_adapt_changes);
1305
asapersson02465b82017-04-10 01:12:52 -07001306 // Trigger CPU overuse, should now adapt down.
mflodmancc3d4422017-08-03 08:27:51 -07001307 video_stream_encoder_->TriggerCpuOveruse();
asaperssonfab67072017-04-04 05:51:49 -07001308 video_source_.IncomingCapturedFrame(CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001309 WaitForEncodedFrame(sequence++);
sprang84a37592017-02-10 07:04:27 -08001310 stats = stats_proxy_->GetStats();
perkj803d97f2016-11-01 11:45:46 -07001311 EXPECT_TRUE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001312 EXPECT_FALSE(stats.cpu_limited_framerate);
perkj803d97f2016-11-01 11:45:46 -07001313 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1314
1315 // Set new source with adaptation still enabled.
1316 test::FrameForwarder new_video_source;
mflodmancc3d4422017-08-03 08:27:51 -07001317 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001318 &new_video_source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
perkj803d97f2016-11-01 11:45:46 -07001319
1320 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001321 CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001322 WaitForEncodedFrame(sequence++);
perkj803d97f2016-11-01 11:45:46 -07001323 stats = stats_proxy_->GetStats();
1324 EXPECT_TRUE(stats.cpu_limited_resolution);
asapersson09f05612017-05-15 23:40:18 -07001325 EXPECT_FALSE(stats.cpu_limited_framerate);
perkj803d97f2016-11-01 11:45:46 -07001326 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1327
sprangc5d62e22017-04-02 23:53:04 -07001328 // Set cpu adaptation by frame dropping.
mflodmancc3d4422017-08-03 08:27:51 -07001329 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001330 &new_video_source, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
perkj803d97f2016-11-01 11:45:46 -07001331 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001332 CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001333 WaitForEncodedFrame(sequence++);
perkj803d97f2016-11-01 11:45:46 -07001334 stats = stats_proxy_->GetStats();
sprangc5d62e22017-04-02 23:53:04 -07001335 // Not adapted at first.
perkj803d97f2016-11-01 11:45:46 -07001336 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson09f05612017-05-15 23:40:18 -07001337 EXPECT_FALSE(stats.cpu_limited_framerate);
perkj803d97f2016-11-01 11:45:46 -07001338 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1339
sprangc5d62e22017-04-02 23:53:04 -07001340 // Force an input frame rate to be available, or the adaptation call won't
asapersson09f05612017-05-15 23:40:18 -07001341 // know what framerate to adapt from.
sprangc5d62e22017-04-02 23:53:04 -07001342 VideoSendStream::Stats mock_stats = stats_proxy_->GetStats();
1343 mock_stats.input_frame_rate = 30;
1344 stats_proxy_->SetMockStats(mock_stats);
mflodmancc3d4422017-08-03 08:27:51 -07001345 video_stream_encoder_->TriggerCpuOveruse();
sprangc5d62e22017-04-02 23:53:04 -07001346 stats_proxy_->ResetMockStats();
1347
1348 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001349 CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001350 WaitForEncodedFrame(sequence++);
sprangc5d62e22017-04-02 23:53:04 -07001351
1352 // Framerate now adapted.
1353 stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001354 EXPECT_FALSE(stats.cpu_limited_resolution);
1355 EXPECT_TRUE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001356 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
1357
1358 // Disable CPU adaptation.
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001359 video_stream_encoder_->SetSource(&new_video_source,
1360 webrtc::DegradationPreference::DISABLED);
sprangc5d62e22017-04-02 23:53:04 -07001361 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001362 CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001363 WaitForEncodedFrame(sequence++);
sprangc5d62e22017-04-02 23:53:04 -07001364
1365 stats = stats_proxy_->GetStats();
1366 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001367 EXPECT_FALSE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001368 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
1369
1370 // Try to trigger overuse. Should not succeed.
1371 stats_proxy_->SetMockStats(mock_stats);
mflodmancc3d4422017-08-03 08:27:51 -07001372 video_stream_encoder_->TriggerCpuOveruse();
sprangc5d62e22017-04-02 23:53:04 -07001373 stats_proxy_->ResetMockStats();
1374
1375 stats = stats_proxy_->GetStats();
1376 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001377 EXPECT_FALSE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001378 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
1379
1380 // Switch back the source with resolution adaptation enabled.
mflodmancc3d4422017-08-03 08:27:51 -07001381 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001382 &video_source_, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
asaperssonfab67072017-04-04 05:51:49 -07001383 video_source_.IncomingCapturedFrame(CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001384 WaitForEncodedFrame(sequence++);
perkj803d97f2016-11-01 11:45:46 -07001385 stats = stats_proxy_->GetStats();
1386 EXPECT_TRUE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001387 EXPECT_FALSE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001388 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
perkj803d97f2016-11-01 11:45:46 -07001389
1390 // Trigger CPU normal usage.
mflodmancc3d4422017-08-03 08:27:51 -07001391 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssonfab67072017-04-04 05:51:49 -07001392 video_source_.IncomingCapturedFrame(CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001393 WaitForEncodedFrame(sequence++);
perkj803d97f2016-11-01 11:45:46 -07001394 stats = stats_proxy_->GetStats();
1395 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001396 EXPECT_FALSE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001397 EXPECT_EQ(3, stats.number_of_cpu_adapt_changes);
1398
1399 // Back to the source with adaptation off, set it back to maintain-resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001400 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001401 &new_video_source, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
sprangc5d62e22017-04-02 23:53:04 -07001402 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001403 CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001404 WaitForEncodedFrame(sequence++);
sprangc5d62e22017-04-02 23:53:04 -07001405 stats = stats_proxy_->GetStats();
asapersson13874762017-06-07 00:01:02 -07001406 // Disabled, since we previously switched the source to disabled.
sprangc5d62e22017-04-02 23:53:04 -07001407 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001408 EXPECT_TRUE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001409 EXPECT_EQ(3, stats.number_of_cpu_adapt_changes);
1410
1411 // Trigger CPU normal usage.
mflodmancc3d4422017-08-03 08:27:51 -07001412 video_stream_encoder_->TriggerCpuNormalUsage();
sprangc5d62e22017-04-02 23:53:04 -07001413 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001414 CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001415 WaitForEncodedFrame(sequence++);
sprangc5d62e22017-04-02 23:53:04 -07001416 stats = stats_proxy_->GetStats();
1417 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001418 EXPECT_FALSE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001419 EXPECT_EQ(4, stats.number_of_cpu_adapt_changes);
asapersson02465b82017-04-10 01:12:52 -07001420 EXPECT_EQ(0, stats.number_of_quality_adapt_changes);
perkj803d97f2016-11-01 11:45:46 -07001421
mflodmancc3d4422017-08-03 08:27:51 -07001422 video_stream_encoder_->Stop();
perkj803d97f2016-11-01 11:45:46 -07001423}
1424
mflodmancc3d4422017-08-03 08:27:51 -07001425TEST_F(VideoStreamEncoderTest,
1426 ScalingUpAndDownDoesNothingWithMaintainResolution) {
asaperssonfab67072017-04-04 05:51:49 -07001427 const int kWidth = 1280;
1428 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001429 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
kthelgason876222f2016-11-29 01:44:11 -08001430
asaperssonfab67072017-04-04 05:51:49 -07001431 // Expect no scaling to begin with.
asapersson02465b82017-04-10 01:12:52 -07001432 VerifyNoLimitation(video_source_.sink_wants());
kthelgason876222f2016-11-29 01:44:11 -08001433
asaperssonfab67072017-04-04 05:51:49 -07001434 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001435 WaitForEncodedFrame(1);
kthelgason876222f2016-11-29 01:44:11 -08001436
asaperssonfab67072017-04-04 05:51:49 -07001437 // Trigger scale down.
mflodmancc3d4422017-08-03 08:27:51 -07001438 video_stream_encoder_->TriggerQualityLow();
kthelgason5e13d412016-12-01 03:59:51 -08001439
asaperssonfab67072017-04-04 05:51:49 -07001440 video_source_.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001441 WaitForEncodedFrame(2);
kthelgason5e13d412016-12-01 03:59:51 -08001442
kthelgason876222f2016-11-29 01:44:11 -08001443 // Expect a scale down.
1444 EXPECT_TRUE(video_source_.sink_wants().max_pixel_count);
asaperssonfab67072017-04-04 05:51:49 -07001445 EXPECT_LT(video_source_.sink_wants().max_pixel_count, kWidth * kHeight);
kthelgason876222f2016-11-29 01:44:11 -08001446
asapersson02465b82017-04-10 01:12:52 -07001447 // Set resolution scaling disabled.
kthelgason876222f2016-11-29 01:44:11 -08001448 test::FrameForwarder new_video_source;
mflodmancc3d4422017-08-03 08:27:51 -07001449 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001450 &new_video_source, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
kthelgason876222f2016-11-29 01:44:11 -08001451
asaperssonfab67072017-04-04 05:51:49 -07001452 // Trigger scale down.
mflodmancc3d4422017-08-03 08:27:51 -07001453 video_stream_encoder_->TriggerQualityLow();
asaperssonfab67072017-04-04 05:51:49 -07001454 new_video_source.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001455 WaitForEncodedFrame(3);
kthelgason876222f2016-11-29 01:44:11 -08001456
asaperssonfab67072017-04-04 05:51:49 -07001457 // Expect no scaling.
sprangc5d62e22017-04-02 23:53:04 -07001458 EXPECT_EQ(std::numeric_limits<int>::max(),
1459 new_video_source.sink_wants().max_pixel_count);
kthelgason876222f2016-11-29 01:44:11 -08001460
asaperssonfab67072017-04-04 05:51:49 -07001461 // Trigger scale up.
mflodmancc3d4422017-08-03 08:27:51 -07001462 video_stream_encoder_->TriggerQualityHigh();
asaperssonfab67072017-04-04 05:51:49 -07001463 new_video_source.IncomingCapturedFrame(CreateFrame(4, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001464 WaitForEncodedFrame(4);
kthelgason876222f2016-11-29 01:44:11 -08001465
asapersson02465b82017-04-10 01:12:52 -07001466 // Expect nothing to change, still no scaling.
sprangc5d62e22017-04-02 23:53:04 -07001467 EXPECT_EQ(std::numeric_limits<int>::max(),
1468 new_video_source.sink_wants().max_pixel_count);
kthelgason876222f2016-11-29 01:44:11 -08001469
mflodmancc3d4422017-08-03 08:27:51 -07001470 video_stream_encoder_->Stop();
kthelgason876222f2016-11-29 01:44:11 -08001471}
1472
mflodmancc3d4422017-08-03 08:27:51 -07001473TEST_F(VideoStreamEncoderTest,
1474 SkipsSameAdaptDownRequest_MaintainFramerateMode) {
asapersson02465b82017-04-10 01:12:52 -07001475 const int kWidth = 1280;
1476 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001477 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson02465b82017-04-10 01:12:52 -07001478
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001479 // Enable MAINTAIN_FRAMERATE preference, no initial limitation.
asapersson02465b82017-04-10 01:12:52 -07001480 test::FrameForwarder source;
mflodmancc3d4422017-08-03 08:27:51 -07001481 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001482 &source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
asapersson02465b82017-04-10 01:12:52 -07001483
1484 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001485 WaitForEncodedFrame(1);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001486 VerifyFpsMaxResolutionMax(source.sink_wants());
asapersson02465b82017-04-10 01:12:52 -07001487 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1488 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1489
1490 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001491 video_stream_encoder_->TriggerCpuOveruse();
asapersson09f05612017-05-15 23:40:18 -07001492 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
asapersson02465b82017-04-10 01:12:52 -07001493 const int kLastMaxPixelCount = source.sink_wants().max_pixel_count;
1494 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1495 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1496
1497 // Trigger adapt down for same input resolution, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07001498 video_stream_encoder_->TriggerCpuOveruse();
asapersson02465b82017-04-10 01:12:52 -07001499 EXPECT_EQ(kLastMaxPixelCount, source.sink_wants().max_pixel_count);
1500 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1501 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1502
mflodmancc3d4422017-08-03 08:27:51 -07001503 video_stream_encoder_->Stop();
asapersson02465b82017-04-10 01:12:52 -07001504}
1505
mflodmancc3d4422017-08-03 08:27:51 -07001506TEST_F(VideoStreamEncoderTest, SkipsSameOrLargerAdaptDownRequest_BalancedMode) {
asaperssonf7e294d2017-06-13 23:25:22 -07001507 const int kWidth = 1280;
1508 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001509 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -07001510
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001511 // Enable BALANCED preference, no initial limitation.
asaperssonf7e294d2017-06-13 23:25:22 -07001512 test::FrameForwarder source;
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001513 video_stream_encoder_->SetSource(&source,
1514 webrtc::DegradationPreference::BALANCED);
asaperssonf7e294d2017-06-13 23:25:22 -07001515 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
1516 sink_.WaitForEncodedFrame(1);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001517 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07001518
1519 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001520 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07001521 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
1522 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1523 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1524 const int kLastMaxPixelCount = source.sink_wants().max_pixel_count;
1525
1526 // Trigger adapt down for same input resolution, expect no change.
1527 source.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
1528 sink_.WaitForEncodedFrame(2);
mflodmancc3d4422017-08-03 08:27:51 -07001529 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07001530 EXPECT_EQ(kLastMaxPixelCount, source.sink_wants().max_pixel_count);
1531 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1532 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1533
1534 // Trigger adapt down for larger input resolution, expect no change.
1535 source.IncomingCapturedFrame(CreateFrame(3, kWidth + 1, kHeight + 1));
1536 sink_.WaitForEncodedFrame(3);
mflodmancc3d4422017-08-03 08:27:51 -07001537 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07001538 EXPECT_EQ(kLastMaxPixelCount, source.sink_wants().max_pixel_count);
1539 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1540 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1541
mflodmancc3d4422017-08-03 08:27:51 -07001542 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07001543}
1544
mflodmancc3d4422017-08-03 08:27:51 -07001545TEST_F(VideoStreamEncoderTest,
1546 NoChangeForInitialNormalUsage_MaintainFramerateMode) {
asapersson02465b82017-04-10 01:12:52 -07001547 const int kWidth = 1280;
1548 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001549 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson02465b82017-04-10 01:12:52 -07001550
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001551 // Enable MAINTAIN_FRAMERATE preference, no initial limitation.
asapersson02465b82017-04-10 01:12:52 -07001552 test::FrameForwarder source;
mflodmancc3d4422017-08-03 08:27:51 -07001553 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001554 &source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
asapersson02465b82017-04-10 01:12:52 -07001555
1556 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001557 WaitForEncodedFrame(kWidth, kHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001558 VerifyFpsMaxResolutionMax(source.sink_wants());
asapersson02465b82017-04-10 01:12:52 -07001559 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1560 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1561
1562 // Trigger adapt up, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07001563 video_stream_encoder_->TriggerCpuNormalUsage();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001564 VerifyFpsMaxResolutionMax(source.sink_wants());
asapersson02465b82017-04-10 01:12:52 -07001565 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1566 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1567
mflodmancc3d4422017-08-03 08:27:51 -07001568 video_stream_encoder_->Stop();
asapersson02465b82017-04-10 01:12:52 -07001569}
1570
mflodmancc3d4422017-08-03 08:27:51 -07001571TEST_F(VideoStreamEncoderTest,
1572 NoChangeForInitialNormalUsage_MaintainResolutionMode) {
asapersson02465b82017-04-10 01:12:52 -07001573 const int kWidth = 1280;
1574 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001575 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson02465b82017-04-10 01:12:52 -07001576
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001577 // Enable MAINTAIN_RESOLUTION preference, no initial limitation.
asapersson02465b82017-04-10 01:12:52 -07001578 test::FrameForwarder source;
mflodmancc3d4422017-08-03 08:27:51 -07001579 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001580 &source, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
asapersson02465b82017-04-10 01:12:52 -07001581
1582 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001583 WaitForEncodedFrame(kWidth, kHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001584 VerifyFpsMaxResolutionMax(source.sink_wants());
asapersson09f05612017-05-15 23:40:18 -07001585 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
asapersson02465b82017-04-10 01:12:52 -07001586 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1587
1588 // Trigger adapt up, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07001589 video_stream_encoder_->TriggerCpuNormalUsage();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001590 VerifyFpsMaxResolutionMax(source.sink_wants());
asapersson09f05612017-05-15 23:40:18 -07001591 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
asapersson02465b82017-04-10 01:12:52 -07001592 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1593
mflodmancc3d4422017-08-03 08:27:51 -07001594 video_stream_encoder_->Stop();
asapersson02465b82017-04-10 01:12:52 -07001595}
1596
mflodmancc3d4422017-08-03 08:27:51 -07001597TEST_F(VideoStreamEncoderTest, NoChangeForInitialNormalUsage_BalancedMode) {
asaperssonf7e294d2017-06-13 23:25:22 -07001598 const int kWidth = 1280;
1599 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001600 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -07001601
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001602 // Enable BALANCED preference, no initial limitation.
asaperssonf7e294d2017-06-13 23:25:22 -07001603 test::FrameForwarder source;
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001604 video_stream_encoder_->SetSource(&source,
1605 webrtc::DegradationPreference::BALANCED);
asaperssonf7e294d2017-06-13 23:25:22 -07001606
1607 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
1608 sink_.WaitForEncodedFrame(kWidth, kHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001609 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07001610 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1611 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
1612 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1613
1614 // Trigger adapt up, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07001615 video_stream_encoder_->TriggerQualityHigh();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001616 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07001617 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1618 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
1619 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1620
mflodmancc3d4422017-08-03 08:27:51 -07001621 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07001622}
1623
mflodmancc3d4422017-08-03 08:27:51 -07001624TEST_F(VideoStreamEncoderTest, NoChangeForInitialNormalUsage_DisabledMode) {
asapersson09f05612017-05-15 23:40:18 -07001625 const int kWidth = 1280;
1626 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001627 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson09f05612017-05-15 23:40:18 -07001628
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001629 // Enable DISABLED preference, no initial limitation.
asapersson09f05612017-05-15 23:40:18 -07001630 test::FrameForwarder source;
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001631 video_stream_encoder_->SetSource(&source,
1632 webrtc::DegradationPreference::DISABLED);
asapersson09f05612017-05-15 23:40:18 -07001633
1634 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
1635 sink_.WaitForEncodedFrame(kWidth, kHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001636 VerifyFpsMaxResolutionMax(source.sink_wants());
asapersson09f05612017-05-15 23:40:18 -07001637 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1638 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
1639 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1640
1641 // Trigger adapt up, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07001642 video_stream_encoder_->TriggerQualityHigh();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001643 VerifyFpsMaxResolutionMax(source.sink_wants());
asapersson09f05612017-05-15 23:40:18 -07001644 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1645 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
1646 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1647
mflodmancc3d4422017-08-03 08:27:51 -07001648 video_stream_encoder_->Stop();
asapersson09f05612017-05-15 23:40:18 -07001649}
1650
mflodmancc3d4422017-08-03 08:27:51 -07001651TEST_F(VideoStreamEncoderTest,
1652 AdaptsResolutionForLowQuality_MaintainFramerateMode) {
asapersson02465b82017-04-10 01:12:52 -07001653 const int kWidth = 1280;
1654 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001655 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson02465b82017-04-10 01:12:52 -07001656
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001657 // Enable MAINTAIN_FRAMERATE preference, no initial limitation.
asapersson02465b82017-04-10 01:12:52 -07001658 AdaptingFrameForwarder source;
1659 source.set_adaptation_enabled(true);
mflodmancc3d4422017-08-03 08:27:51 -07001660 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001661 &source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
asapersson02465b82017-04-10 01:12:52 -07001662
1663 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001664 WaitForEncodedFrame(1);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001665 VerifyFpsMaxResolutionMax(source.sink_wants());
asapersson02465b82017-04-10 01:12:52 -07001666 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1667 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1668
1669 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001670 video_stream_encoder_->TriggerQualityLow();
asapersson02465b82017-04-10 01:12:52 -07001671 source.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001672 WaitForEncodedFrame(2);
asapersson09f05612017-05-15 23:40:18 -07001673 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
asapersson02465b82017-04-10 01:12:52 -07001674 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1675 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1676
1677 // Trigger adapt up, expect no restriction.
mflodmancc3d4422017-08-03 08:27:51 -07001678 video_stream_encoder_->TriggerQualityHigh();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001679 VerifyFpsMaxResolutionMax(source.sink_wants());
asapersson02465b82017-04-10 01:12:52 -07001680 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1681 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1682 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1683
mflodmancc3d4422017-08-03 08:27:51 -07001684 video_stream_encoder_->Stop();
asapersson02465b82017-04-10 01:12:52 -07001685}
1686
mflodmancc3d4422017-08-03 08:27:51 -07001687TEST_F(VideoStreamEncoderTest,
1688 AdaptsFramerateForLowQuality_MaintainResolutionMode) {
asapersson09f05612017-05-15 23:40:18 -07001689 const int kWidth = 1280;
1690 const int kHeight = 720;
1691 const int kInputFps = 30;
mflodmancc3d4422017-08-03 08:27:51 -07001692 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson09f05612017-05-15 23:40:18 -07001693
1694 VideoSendStream::Stats stats = stats_proxy_->GetStats();
1695 stats.input_frame_rate = kInputFps;
1696 stats_proxy_->SetMockStats(stats);
1697
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001698 // Expect no scaling to begin with (preference: MAINTAIN_FRAMERATE).
asapersson09f05612017-05-15 23:40:18 -07001699 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
1700 sink_.WaitForEncodedFrame(1);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001701 VerifyFpsMaxResolutionMax(video_source_.sink_wants());
asapersson09f05612017-05-15 23:40:18 -07001702
1703 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001704 video_stream_encoder_->TriggerQualityLow();
asapersson09f05612017-05-15 23:40:18 -07001705 video_source_.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
1706 sink_.WaitForEncodedFrame(2);
1707 VerifyFpsMaxResolutionLt(video_source_.sink_wants(), kWidth * kHeight);
1708
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001709 // Enable MAINTAIN_RESOLUTION preference.
asapersson09f05612017-05-15 23:40:18 -07001710 test::FrameForwarder new_video_source;
mflodmancc3d4422017-08-03 08:27:51 -07001711 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001712 &new_video_source, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001713 VerifyFpsMaxResolutionMax(new_video_source.sink_wants());
asapersson09f05612017-05-15 23:40:18 -07001714
1715 // Trigger adapt down, expect reduced framerate.
mflodmancc3d4422017-08-03 08:27:51 -07001716 video_stream_encoder_->TriggerQualityLow();
asapersson09f05612017-05-15 23:40:18 -07001717 new_video_source.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
1718 sink_.WaitForEncodedFrame(3);
1719 VerifyFpsLtResolutionMax(new_video_source.sink_wants(), kInputFps);
1720
1721 // Trigger adapt up, expect no restriction.
mflodmancc3d4422017-08-03 08:27:51 -07001722 video_stream_encoder_->TriggerQualityHigh();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001723 VerifyFpsMaxResolutionMax(new_video_source.sink_wants());
asapersson09f05612017-05-15 23:40:18 -07001724
mflodmancc3d4422017-08-03 08:27:51 -07001725 video_stream_encoder_->Stop();
asapersson09f05612017-05-15 23:40:18 -07001726}
1727
mflodmancc3d4422017-08-03 08:27:51 -07001728TEST_F(VideoStreamEncoderTest, DoesNotScaleBelowSetResolutionLimit) {
asaperssond0de2952017-04-21 01:47:31 -07001729 const int kWidth = 1280;
1730 const int kHeight = 720;
1731 const size_t kNumFrames = 10;
1732
mflodmancc3d4422017-08-03 08:27:51 -07001733 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
kthelgason5e13d412016-12-01 03:59:51 -08001734
asaperssond0de2952017-04-21 01:47:31 -07001735 // Enable adapter, expected input resolutions when downscaling:
asapersson142fcc92017-08-17 08:58:54 -07001736 // 1280x720 -> 960x540 -> 640x360 -> 480x270 -> 320x180 (kMinPixelsPerFrame)
asaperssond0de2952017-04-21 01:47:31 -07001737 video_source_.set_adaptation_enabled(true);
1738
1739 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1740 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1741
1742 int downscales = 0;
1743 for (size_t i = 1; i <= kNumFrames; i++) {
Åsa Persson8c1bf952018-09-13 10:42:19 +02001744 video_source_.IncomingCapturedFrame(
1745 CreateFrame(i * kFrameIntervalMs, kWidth, kHeight));
1746 WaitForEncodedFrame(i * kFrameIntervalMs);
asaperssond0de2952017-04-21 01:47:31 -07001747
asaperssonfab67072017-04-04 05:51:49 -07001748 // Trigger scale down.
asaperssond0de2952017-04-21 01:47:31 -07001749 rtc::VideoSinkWants last_wants = video_source_.sink_wants();
mflodmancc3d4422017-08-03 08:27:51 -07001750 video_stream_encoder_->TriggerQualityLow();
sprangc5d62e22017-04-02 23:53:04 -07001751 EXPECT_GE(video_source_.sink_wants().max_pixel_count, kMinPixelsPerFrame);
asaperssond0de2952017-04-21 01:47:31 -07001752
1753 if (video_source_.sink_wants().max_pixel_count < last_wants.max_pixel_count)
1754 ++downscales;
1755
1756 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1757 EXPECT_EQ(downscales,
1758 stats_proxy_->GetStats().number_of_quality_adapt_changes);
1759 EXPECT_GT(downscales, 0);
kthelgason5e13d412016-12-01 03:59:51 -08001760 }
mflodmancc3d4422017-08-03 08:27:51 -07001761 video_stream_encoder_->Stop();
asaperssond0de2952017-04-21 01:47:31 -07001762}
1763
mflodmancc3d4422017-08-03 08:27:51 -07001764TEST_F(VideoStreamEncoderTest,
asaperssond0de2952017-04-21 01:47:31 -07001765 AdaptsResolutionUpAndDownTwiceOnOveruse_MaintainFramerateMode) {
1766 const int kWidth = 1280;
1767 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001768 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssond0de2952017-04-21 01:47:31 -07001769
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001770 // Enable MAINTAIN_FRAMERATE preference, no initial limitation.
asaperssond0de2952017-04-21 01:47:31 -07001771 AdaptingFrameForwarder source;
1772 source.set_adaptation_enabled(true);
mflodmancc3d4422017-08-03 08:27:51 -07001773 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001774 &source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
asaperssond0de2952017-04-21 01:47:31 -07001775
Åsa Persson8c1bf952018-09-13 10:42:19 +02001776 int64_t timestamp_ms = kFrameIntervalMs;
1777 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001778 WaitForEncodedFrame(kWidth, kHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001779 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssond0de2952017-04-21 01:47:31 -07001780 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1781 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1782
1783 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001784 video_stream_encoder_->TriggerCpuOveruse();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001785 timestamp_ms += kFrameIntervalMs;
1786 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
1787 WaitForEncodedFrame(timestamp_ms);
asapersson09f05612017-05-15 23:40:18 -07001788 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
asaperssond0de2952017-04-21 01:47:31 -07001789 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1790 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1791
1792 // Trigger adapt up, expect no restriction.
mflodmancc3d4422017-08-03 08:27:51 -07001793 video_stream_encoder_->TriggerCpuNormalUsage();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001794 timestamp_ms += kFrameIntervalMs;
1795 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001796 WaitForEncodedFrame(kWidth, kHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001797 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssond0de2952017-04-21 01:47:31 -07001798 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1799 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1800
1801 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001802 video_stream_encoder_->TriggerCpuOveruse();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001803 timestamp_ms += kFrameIntervalMs;
1804 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
1805 WaitForEncodedFrame(timestamp_ms);
asapersson09f05612017-05-15 23:40:18 -07001806 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
asaperssond0de2952017-04-21 01:47:31 -07001807 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1808 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1809
1810 // Trigger adapt up, expect no restriction.
mflodmancc3d4422017-08-03 08:27:51 -07001811 video_stream_encoder_->TriggerCpuNormalUsage();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001812 timestamp_ms += kFrameIntervalMs;
1813 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
asapersson09f05612017-05-15 23:40:18 -07001814 sink_.WaitForEncodedFrame(kWidth, kHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001815 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssond0de2952017-04-21 01:47:31 -07001816 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1817 EXPECT_EQ(4, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1818
mflodmancc3d4422017-08-03 08:27:51 -07001819 video_stream_encoder_->Stop();
asaperssond0de2952017-04-21 01:47:31 -07001820}
1821
mflodmancc3d4422017-08-03 08:27:51 -07001822TEST_F(VideoStreamEncoderTest,
asaperssonf7e294d2017-06-13 23:25:22 -07001823 AdaptsResolutionUpAndDownTwiceForLowQuality_BalancedMode_NoFpsLimit) {
1824 const int kWidth = 1280;
1825 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001826 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -07001827
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001828 // Enable BALANCED preference, no initial limitation.
asaperssonf7e294d2017-06-13 23:25:22 -07001829 AdaptingFrameForwarder source;
1830 source.set_adaptation_enabled(true);
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001831 video_stream_encoder_->SetSource(&source,
1832 webrtc::DegradationPreference::BALANCED);
asaperssonf7e294d2017-06-13 23:25:22 -07001833
Åsa Persson8c1bf952018-09-13 10:42:19 +02001834 int64_t timestamp_ms = kFrameIntervalMs;
1835 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
asaperssonf7e294d2017-06-13 23:25:22 -07001836 sink_.WaitForEncodedFrame(kWidth, kHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001837 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07001838 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1839 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1840
1841 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001842 video_stream_encoder_->TriggerQualityLow();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001843 timestamp_ms += kFrameIntervalMs;
1844 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
1845 sink_.WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07001846 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
1847 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1848 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1849
1850 // Trigger adapt up, expect no restriction.
mflodmancc3d4422017-08-03 08:27:51 -07001851 video_stream_encoder_->TriggerQualityHigh();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001852 timestamp_ms += kFrameIntervalMs;
1853 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
asaperssonf7e294d2017-06-13 23:25:22 -07001854 sink_.WaitForEncodedFrame(kWidth, kHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001855 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07001856 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1857 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1858
1859 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001860 video_stream_encoder_->TriggerQualityLow();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001861 timestamp_ms += kFrameIntervalMs;
1862 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
1863 sink_.WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07001864 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
1865 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1866 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1867
1868 // Trigger adapt up, expect no restriction.
mflodmancc3d4422017-08-03 08:27:51 -07001869 video_stream_encoder_->TriggerQualityHigh();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001870 timestamp_ms += kFrameIntervalMs;
1871 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
asaperssonf7e294d2017-06-13 23:25:22 -07001872 sink_.WaitForEncodedFrame(kWidth, kHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001873 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07001874 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1875 EXPECT_EQ(4, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1876
mflodmancc3d4422017-08-03 08:27:51 -07001877 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07001878}
1879
mflodmancc3d4422017-08-03 08:27:51 -07001880TEST_F(VideoStreamEncoderTest,
asaperssond0de2952017-04-21 01:47:31 -07001881 AdaptsResolutionOnOveruseAndLowQuality_MaintainFramerateMode) {
1882 const int kWidth = 1280;
1883 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001884 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssond0de2952017-04-21 01:47:31 -07001885
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001886 // Enable MAINTAIN_FRAMERATE preference, no initial limitation.
asaperssond0de2952017-04-21 01:47:31 -07001887 AdaptingFrameForwarder source;
1888 source.set_adaptation_enabled(true);
mflodmancc3d4422017-08-03 08:27:51 -07001889 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001890 &source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
asaperssond0de2952017-04-21 01:47:31 -07001891
Åsa Persson8c1bf952018-09-13 10:42:19 +02001892 int64_t timestamp_ms = kFrameIntervalMs;
1893 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001894 WaitForEncodedFrame(kWidth, kHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001895 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssond0de2952017-04-21 01:47:31 -07001896 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1897 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1898 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1899 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1900
1901 // Trigger cpu adapt down, expect scaled down resolution (960x540).
mflodmancc3d4422017-08-03 08:27:51 -07001902 video_stream_encoder_->TriggerCpuOveruse();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001903 timestamp_ms += kFrameIntervalMs;
1904 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
1905 WaitForEncodedFrame(timestamp_ms);
asapersson09f05612017-05-15 23:40:18 -07001906 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
asaperssond0de2952017-04-21 01:47:31 -07001907 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1908 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1909 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1910 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1911
1912 // Trigger cpu adapt down, expect scaled down resolution (640x360).
mflodmancc3d4422017-08-03 08:27:51 -07001913 video_stream_encoder_->TriggerCpuOveruse();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001914 timestamp_ms += kFrameIntervalMs;
1915 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
1916 WaitForEncodedFrame(timestamp_ms);
asapersson09f05612017-05-15 23:40:18 -07001917 VerifyFpsMaxResolutionLt(source.sink_wants(), source.last_wants());
asaperssond0de2952017-04-21 01:47:31 -07001918 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1919 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1920 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1921 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1922
Jonathan Yubc771b72017-12-08 17:04:29 -08001923 // Trigger cpu adapt down, expect scaled down resolution (480x270).
mflodmancc3d4422017-08-03 08:27:51 -07001924 video_stream_encoder_->TriggerCpuOveruse();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001925 timestamp_ms += kFrameIntervalMs;
1926 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
1927 WaitForEncodedFrame(timestamp_ms);
Jonathan Yubc771b72017-12-08 17:04:29 -08001928 VerifyFpsMaxResolutionLt(source.sink_wants(), source.last_wants());
asaperssond0de2952017-04-21 01:47:31 -07001929 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1930 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
Jonathan Yubc771b72017-12-08 17:04:29 -08001931 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
asaperssond0de2952017-04-21 01:47:31 -07001932 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1933
Jonathan Yubc771b72017-12-08 17:04:29 -08001934 // Trigger quality adapt down, expect scaled down resolution (320x180).
mflodmancc3d4422017-08-03 08:27:51 -07001935 video_stream_encoder_->TriggerQualityLow();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001936 timestamp_ms += kFrameIntervalMs;
1937 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
1938 WaitForEncodedFrame(timestamp_ms);
asapersson09f05612017-05-15 23:40:18 -07001939 VerifyFpsMaxResolutionLt(source.sink_wants(), source.last_wants());
Jonathan Yubc771b72017-12-08 17:04:29 -08001940 rtc::VideoSinkWants last_wants = source.sink_wants();
asaperssond0de2952017-04-21 01:47:31 -07001941 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1942 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1943 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1944 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1945
Jonathan Yubc771b72017-12-08 17:04:29 -08001946 // Trigger quality adapt down, expect no change (min resolution reached).
1947 video_stream_encoder_->TriggerQualityLow();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001948 timestamp_ms += kFrameIntervalMs;
1949 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
1950 WaitForEncodedFrame(timestamp_ms);
Jonathan Yubc771b72017-12-08 17:04:29 -08001951 VerifyFpsMaxResolutionEq(source.sink_wants(), last_wants);
1952 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1953 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1954 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1955 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1956
1957 // Trigger cpu adapt up, expect upscaled resolution (480x270).
mflodmancc3d4422017-08-03 08:27:51 -07001958 video_stream_encoder_->TriggerCpuNormalUsage();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001959 timestamp_ms += kFrameIntervalMs;
1960 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
1961 WaitForEncodedFrame(timestamp_ms);
asapersson09f05612017-05-15 23:40:18 -07001962 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
Jonathan Yubc771b72017-12-08 17:04:29 -08001963 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1964 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1965 EXPECT_EQ(4, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1966 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1967
1968 // Trigger cpu adapt up, expect upscaled resolution (640x360).
1969 video_stream_encoder_->TriggerCpuNormalUsage();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001970 timestamp_ms += kFrameIntervalMs;
1971 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
1972 WaitForEncodedFrame(timestamp_ms);
Jonathan Yubc771b72017-12-08 17:04:29 -08001973 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
1974 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1975 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1976 EXPECT_EQ(5, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1977 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1978
1979 // Trigger cpu adapt up, expect upscaled resolution (960x540).
1980 video_stream_encoder_->TriggerCpuNormalUsage();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001981 timestamp_ms += kFrameIntervalMs;
1982 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
1983 WaitForEncodedFrame(timestamp_ms);
Jonathan Yubc771b72017-12-08 17:04:29 -08001984 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
asaperssond0de2952017-04-21 01:47:31 -07001985 last_wants = source.sink_wants();
1986 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1987 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
Jonathan Yubc771b72017-12-08 17:04:29 -08001988 EXPECT_EQ(6, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
asaperssond0de2952017-04-21 01:47:31 -07001989 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1990
1991 // Trigger cpu adapt up, no cpu downgrades, expect no change (960x540).
mflodmancc3d4422017-08-03 08:27:51 -07001992 video_stream_encoder_->TriggerCpuNormalUsage();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001993 timestamp_ms += kFrameIntervalMs;
1994 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
1995 WaitForEncodedFrame(timestamp_ms);
asapersson09f05612017-05-15 23:40:18 -07001996 VerifyFpsEqResolutionEq(source.sink_wants(), last_wants);
asaperssond0de2952017-04-21 01:47:31 -07001997 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1998 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
Jonathan Yubc771b72017-12-08 17:04:29 -08001999 EXPECT_EQ(6, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
asaperssond0de2952017-04-21 01:47:31 -07002000 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2001
2002 // Trigger quality adapt up, expect no restriction (1280x720).
mflodmancc3d4422017-08-03 08:27:51 -07002003 video_stream_encoder_->TriggerQualityHigh();
Åsa Persson8c1bf952018-09-13 10:42:19 +02002004 timestamp_ms += kFrameIntervalMs;
2005 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002006 WaitForEncodedFrame(kWidth, kHeight);
asapersson09f05612017-05-15 23:40:18 -07002007 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
Åsa Persson8c1bf952018-09-13 10:42:19 +02002008 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssond0de2952017-04-21 01:47:31 -07002009 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2010 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
Jonathan Yubc771b72017-12-08 17:04:29 -08002011 EXPECT_EQ(6, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
asaperssond0de2952017-04-21 01:47:31 -07002012 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
kthelgason5e13d412016-12-01 03:59:51 -08002013
mflodmancc3d4422017-08-03 08:27:51 -07002014 video_stream_encoder_->Stop();
kthelgason5e13d412016-12-01 03:59:51 -08002015}
2016
mflodmancc3d4422017-08-03 08:27:51 -07002017TEST_F(VideoStreamEncoderTest, CpuLimitedHistogramIsReported) {
asaperssonfab67072017-04-04 05:51:49 -07002018 const int kWidth = 640;
2019 const int kHeight = 360;
perkj803d97f2016-11-01 11:45:46 -07002020
mflodmancc3d4422017-08-03 08:27:51 -07002021 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
sprang4847ae62017-06-27 07:06:52 -07002022
perkj803d97f2016-11-01 11:45:46 -07002023 for (int i = 1; i <= SendStatisticsProxy::kMinRequiredMetricsSamples; ++i) {
asaperssonfab67072017-04-04 05:51:49 -07002024 video_source_.IncomingCapturedFrame(CreateFrame(i, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002025 WaitForEncodedFrame(i);
perkj803d97f2016-11-01 11:45:46 -07002026 }
2027
mflodmancc3d4422017-08-03 08:27:51 -07002028 video_stream_encoder_->TriggerCpuOveruse();
perkj803d97f2016-11-01 11:45:46 -07002029 for (int i = 1; i <= SendStatisticsProxy::kMinRequiredMetricsSamples; ++i) {
asaperssonfab67072017-04-04 05:51:49 -07002030 video_source_.IncomingCapturedFrame(CreateFrame(
2031 SendStatisticsProxy::kMinRequiredMetricsSamples + i, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002032 WaitForEncodedFrame(SendStatisticsProxy::kMinRequiredMetricsSamples + i);
perkj803d97f2016-11-01 11:45:46 -07002033 }
2034
mflodmancc3d4422017-08-03 08:27:51 -07002035 video_stream_encoder_->Stop();
2036 video_stream_encoder_.reset();
perkj803d97f2016-11-01 11:45:46 -07002037 stats_proxy_.reset();
sprangf8ee65e2017-02-28 08:49:33 -08002038
perkj803d97f2016-11-01 11:45:46 -07002039 EXPECT_EQ(1,
2040 metrics::NumSamples("WebRTC.Video.CpuLimitedResolutionInPercent"));
2041 EXPECT_EQ(
2042 1, metrics::NumEvents("WebRTC.Video.CpuLimitedResolutionInPercent", 50));
2043}
2044
mflodmancc3d4422017-08-03 08:27:51 -07002045TEST_F(VideoStreamEncoderTest,
2046 CpuLimitedHistogramIsNotReportedForDisabledDegradation) {
2047 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonf4e44af2017-04-19 02:01:06 -07002048 const int kWidth = 640;
2049 const int kHeight = 360;
2050
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002051 video_stream_encoder_->SetSource(&video_source_,
2052 webrtc::DegradationPreference::DISABLED);
asaperssonf4e44af2017-04-19 02:01:06 -07002053
2054 for (int i = 1; i <= SendStatisticsProxy::kMinRequiredMetricsSamples; ++i) {
2055 video_source_.IncomingCapturedFrame(CreateFrame(i, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002056 WaitForEncodedFrame(i);
asaperssonf4e44af2017-04-19 02:01:06 -07002057 }
2058
mflodmancc3d4422017-08-03 08:27:51 -07002059 video_stream_encoder_->Stop();
2060 video_stream_encoder_.reset();
asaperssonf4e44af2017-04-19 02:01:06 -07002061 stats_proxy_.reset();
2062
2063 EXPECT_EQ(0,
2064 metrics::NumSamples("WebRTC.Video.CpuLimitedResolutionInPercent"));
2065}
2066
mflodmancc3d4422017-08-03 08:27:51 -07002067TEST_F(VideoStreamEncoderTest, CallsBitrateObserver) {
sprang4847ae62017-06-27 07:06:52 -07002068 MockBitrateObserver bitrate_observer;
Niels Möller0327c2d2018-05-21 14:09:31 +02002069 video_stream_encoder_->SetBitrateAllocationObserver(&bitrate_observer);
sprang57c2fff2017-01-16 06:24:02 -08002070
2071 const int kDefaultFps = 30;
Erik Språng566124a2018-04-23 12:32:22 +02002072 const VideoBitrateAllocation expected_bitrate =
sprang57c2fff2017-01-16 06:24:02 -08002073 DefaultVideoBitrateAllocator(fake_encoder_.codec_config())
kthelgason2bc68642017-02-07 07:02:22 -08002074 .GetAllocation(kLowTargetBitrateBps, kDefaultFps);
sprang57c2fff2017-01-16 06:24:02 -08002075
2076 // First called on bitrate updated, then again on first frame.
2077 EXPECT_CALL(bitrate_observer, OnBitrateAllocationUpdated(expected_bitrate))
2078 .Times(2);
mflodmancc3d4422017-08-03 08:27:51 -07002079 video_stream_encoder_->OnBitrateUpdated(kLowTargetBitrateBps, 0, 0);
sprang57c2fff2017-01-16 06:24:02 -08002080
2081 const int64_t kStartTimeMs = 1;
2082 video_source_.IncomingCapturedFrame(
2083 CreateFrame(kStartTimeMs, codec_width_, codec_height_));
sprang4847ae62017-06-27 07:06:52 -07002084 WaitForEncodedFrame(kStartTimeMs);
sprang57c2fff2017-01-16 06:24:02 -08002085
2086 // Not called on second frame.
2087 EXPECT_CALL(bitrate_observer, OnBitrateAllocationUpdated(expected_bitrate))
2088 .Times(0);
2089 video_source_.IncomingCapturedFrame(
2090 CreateFrame(kStartTimeMs + 1, codec_width_, codec_height_));
sprang4847ae62017-06-27 07:06:52 -07002091 WaitForEncodedFrame(kStartTimeMs + 1);
sprang57c2fff2017-01-16 06:24:02 -08002092
2093 // Called after a process interval.
2094 const int64_t kProcessIntervalMs =
2095 vcm::VCMProcessTimer::kDefaultProcessIntervalMs;
sprang4847ae62017-06-27 07:06:52 -07002096 fake_clock_.AdvanceTimeMicros(rtc::kNumMicrosecsPerMillisec *
2097 (kProcessIntervalMs + (1000 / kDefaultFps)));
sprang57c2fff2017-01-16 06:24:02 -08002098 EXPECT_CALL(bitrate_observer, OnBitrateAllocationUpdated(expected_bitrate))
2099 .Times(1);
2100 video_source_.IncomingCapturedFrame(CreateFrame(
2101 kStartTimeMs + kProcessIntervalMs, codec_width_, codec_height_));
sprang4847ae62017-06-27 07:06:52 -07002102 WaitForEncodedFrame(kStartTimeMs + kProcessIntervalMs);
sprang57c2fff2017-01-16 06:24:02 -08002103
mflodmancc3d4422017-08-03 08:27:51 -07002104 video_stream_encoder_->Stop();
sprang57c2fff2017-01-16 06:24:02 -08002105}
2106
Niels Möller7dc26b72017-12-06 10:27:48 +01002107TEST_F(VideoStreamEncoderTest, OveruseDetectorUpdatedOnReconfigureAndAdaption) {
2108 const int kFrameWidth = 1280;
2109 const int kFrameHeight = 720;
2110 const int kFramerate = 24;
2111
2112 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
2113 test::FrameForwarder source;
2114 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002115 &source, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
Niels Möller7dc26b72017-12-06 10:27:48 +01002116
2117 // Insert a single frame, triggering initial configuration.
2118 source.IncomingCapturedFrame(CreateFrame(1, kFrameWidth, kFrameHeight));
2119 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2120
2121 EXPECT_EQ(
2122 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2123 kDefaultFramerate);
2124
2125 // Trigger reconfigure encoder (without resetting the entire instance).
2126 VideoEncoderConfig video_encoder_config;
Niels Möller259a4972018-04-05 15:36:51 +02002127 video_encoder_config.codec_type = kVideoCodecVP8;
Niels Möller7dc26b72017-12-06 10:27:48 +01002128 video_encoder_config.max_bitrate_bps = kTargetBitrateBps;
2129 video_encoder_config.number_of_streams = 1;
2130 video_encoder_config.video_stream_factory =
2131 new rtc::RefCountedObject<VideoStreamFactory>(1, kFramerate);
2132 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
Niels Möllerf1338562018-04-26 09:51:47 +02002133 kMaxPayloadLength);
Niels Möller7dc26b72017-12-06 10:27:48 +01002134 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2135
2136 // Detector should be updated with fps limit from codec config.
2137 EXPECT_EQ(
2138 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2139 kFramerate);
2140
2141 // Trigger overuse, max framerate should be reduced.
2142 VideoSendStream::Stats stats = stats_proxy_->GetStats();
2143 stats.input_frame_rate = kFramerate;
2144 stats_proxy_->SetMockStats(stats);
2145 video_stream_encoder_->TriggerCpuOveruse();
2146 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2147 int adapted_framerate =
2148 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate();
2149 EXPECT_LT(adapted_framerate, kFramerate);
2150
2151 // Trigger underuse, max framerate should go back to codec configured fps.
2152 // Set extra low fps, to make sure it's actually reset, not just incremented.
2153 stats = stats_proxy_->GetStats();
2154 stats.input_frame_rate = adapted_framerate / 2;
2155 stats_proxy_->SetMockStats(stats);
2156 video_stream_encoder_->TriggerCpuNormalUsage();
2157 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2158 EXPECT_EQ(
2159 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2160 kFramerate);
2161
2162 video_stream_encoder_->Stop();
2163}
2164
2165TEST_F(VideoStreamEncoderTest,
2166 OveruseDetectorUpdatedRespectsFramerateAfterUnderuse) {
2167 const int kFrameWidth = 1280;
2168 const int kFrameHeight = 720;
2169 const int kLowFramerate = 15;
2170 const int kHighFramerate = 25;
2171
2172 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
2173 test::FrameForwarder source;
2174 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002175 &source, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
Niels Möller7dc26b72017-12-06 10:27:48 +01002176
2177 // Trigger initial configuration.
2178 VideoEncoderConfig video_encoder_config;
Niels Möller259a4972018-04-05 15:36:51 +02002179 video_encoder_config.codec_type = kVideoCodecVP8;
Niels Möller7dc26b72017-12-06 10:27:48 +01002180 video_encoder_config.max_bitrate_bps = kTargetBitrateBps;
2181 video_encoder_config.number_of_streams = 1;
2182 video_encoder_config.video_stream_factory =
2183 new rtc::RefCountedObject<VideoStreamFactory>(1, kLowFramerate);
2184 source.IncomingCapturedFrame(CreateFrame(1, kFrameWidth, kFrameHeight));
2185 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
Niels Möllerf1338562018-04-26 09:51:47 +02002186 kMaxPayloadLength);
Niels Möller7dc26b72017-12-06 10:27:48 +01002187 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2188
2189 EXPECT_EQ(
2190 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2191 kLowFramerate);
2192
2193 // Trigger overuse, max framerate should be reduced.
2194 VideoSendStream::Stats stats = stats_proxy_->GetStats();
2195 stats.input_frame_rate = kLowFramerate;
2196 stats_proxy_->SetMockStats(stats);
2197 video_stream_encoder_->TriggerCpuOveruse();
2198 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2199 int adapted_framerate =
2200 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate();
2201 EXPECT_LT(adapted_framerate, kLowFramerate);
2202
2203 // Reconfigure the encoder with a new (higher max framerate), max fps should
2204 // still respect the adaptation.
2205 video_encoder_config.video_stream_factory =
2206 new rtc::RefCountedObject<VideoStreamFactory>(1, kHighFramerate);
2207 source.IncomingCapturedFrame(CreateFrame(1, kFrameWidth, kFrameHeight));
2208 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
Niels Möllerf1338562018-04-26 09:51:47 +02002209 kMaxPayloadLength);
Niels Möller7dc26b72017-12-06 10:27:48 +01002210 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2211
2212 EXPECT_EQ(
2213 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2214 adapted_framerate);
2215
2216 // Trigger underuse, max framerate should go back to codec configured fps.
2217 stats = stats_proxy_->GetStats();
2218 stats.input_frame_rate = adapted_framerate;
2219 stats_proxy_->SetMockStats(stats);
2220 video_stream_encoder_->TriggerCpuNormalUsage();
2221 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2222 EXPECT_EQ(
2223 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2224 kHighFramerate);
2225
2226 video_stream_encoder_->Stop();
2227}
2228
mflodmancc3d4422017-08-03 08:27:51 -07002229TEST_F(VideoStreamEncoderTest,
2230 OveruseDetectorUpdatedOnDegradationPreferenceChange) {
sprangfda496a2017-06-15 04:21:07 -07002231 const int kFrameWidth = 1280;
2232 const int kFrameHeight = 720;
2233 const int kFramerate = 24;
2234
mflodmancc3d4422017-08-03 08:27:51 -07002235 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
sprangfda496a2017-06-15 04:21:07 -07002236 test::FrameForwarder source;
mflodmancc3d4422017-08-03 08:27:51 -07002237 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002238 &source, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
sprangfda496a2017-06-15 04:21:07 -07002239
2240 // Trigger initial configuration.
2241 VideoEncoderConfig video_encoder_config;
Niels Möller259a4972018-04-05 15:36:51 +02002242 video_encoder_config.codec_type = kVideoCodecVP8;
sprangfda496a2017-06-15 04:21:07 -07002243 video_encoder_config.max_bitrate_bps = kTargetBitrateBps;
2244 video_encoder_config.number_of_streams = 1;
2245 video_encoder_config.video_stream_factory =
2246 new rtc::RefCountedObject<VideoStreamFactory>(1, kFramerate);
2247 source.IncomingCapturedFrame(CreateFrame(1, kFrameWidth, kFrameHeight));
mflodmancc3d4422017-08-03 08:27:51 -07002248 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
Niels Möllerf1338562018-04-26 09:51:47 +02002249 kMaxPayloadLength);
mflodmancc3d4422017-08-03 08:27:51 -07002250 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
sprangfda496a2017-06-15 04:21:07 -07002251
Niels Möller7dc26b72017-12-06 10:27:48 +01002252 EXPECT_EQ(
2253 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2254 kFramerate);
sprangfda496a2017-06-15 04:21:07 -07002255
2256 // Trigger overuse, max framerate should be reduced.
2257 VideoSendStream::Stats stats = stats_proxy_->GetStats();
2258 stats.input_frame_rate = kFramerate;
2259 stats_proxy_->SetMockStats(stats);
mflodmancc3d4422017-08-03 08:27:51 -07002260 video_stream_encoder_->TriggerCpuOveruse();
2261 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
Niels Möller7dc26b72017-12-06 10:27:48 +01002262 int adapted_framerate =
2263 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate();
sprangfda496a2017-06-15 04:21:07 -07002264 EXPECT_LT(adapted_framerate, kFramerate);
2265
2266 // Change degradation preference to not enable framerate scaling. Target
2267 // framerate should be changed to codec defined limit.
mflodmancc3d4422017-08-03 08:27:51 -07002268 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002269 &source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
mflodmancc3d4422017-08-03 08:27:51 -07002270 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
Niels Möller7dc26b72017-12-06 10:27:48 +01002271 EXPECT_EQ(
2272 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2273 kFramerate);
sprangfda496a2017-06-15 04:21:07 -07002274
mflodmancc3d4422017-08-03 08:27:51 -07002275 video_stream_encoder_->Stop();
sprangfda496a2017-06-15 04:21:07 -07002276}
2277
mflodmancc3d4422017-08-03 08:27:51 -07002278TEST_F(VideoStreamEncoderTest, DropsFramesAndScalesWhenBitrateIsTooLow) {
asaperssonfab67072017-04-04 05:51:49 -07002279 const int kTooLowBitrateForFrameSizeBps = 10000;
mflodmancc3d4422017-08-03 08:27:51 -07002280 video_stream_encoder_->OnBitrateUpdated(kTooLowBitrateForFrameSizeBps, 0, 0);
asaperssonfab67072017-04-04 05:51:49 -07002281 const int kWidth = 640;
2282 const int kHeight = 360;
kthelgason2bc68642017-02-07 07:02:22 -08002283
asaperssonfab67072017-04-04 05:51:49 -07002284 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
kthelgason2bc68642017-02-07 07:02:22 -08002285
2286 // Expect to drop this frame, the wait should time out.
sprang4847ae62017-06-27 07:06:52 -07002287 ExpectDroppedFrame();
kthelgason2bc68642017-02-07 07:02:22 -08002288
2289 // Expect the sink_wants to specify a scaled frame.
asapersson0944a802017-04-07 00:57:58 -07002290 EXPECT_LT(video_source_.sink_wants().max_pixel_count, kWidth * kHeight);
kthelgason2bc68642017-02-07 07:02:22 -08002291
sprangc5d62e22017-04-02 23:53:04 -07002292 int last_pixel_count = video_source_.sink_wants().max_pixel_count;
kthelgason2bc68642017-02-07 07:02:22 -08002293
asaperssonfab67072017-04-04 05:51:49 -07002294 // Next frame is scaled.
kthelgason2bc68642017-02-07 07:02:22 -08002295 video_source_.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07002296 CreateFrame(2, kWidth * 3 / 4, kHeight * 3 / 4));
kthelgason2bc68642017-02-07 07:02:22 -08002297
2298 // Expect to drop this frame, the wait should time out.
sprang4847ae62017-06-27 07:06:52 -07002299 ExpectDroppedFrame();
kthelgason2bc68642017-02-07 07:02:22 -08002300
sprangc5d62e22017-04-02 23:53:04 -07002301 EXPECT_LT(video_source_.sink_wants().max_pixel_count, last_pixel_count);
kthelgason2bc68642017-02-07 07:02:22 -08002302
mflodmancc3d4422017-08-03 08:27:51 -07002303 video_stream_encoder_->Stop();
kthelgason2bc68642017-02-07 07:02:22 -08002304}
2305
mflodmancc3d4422017-08-03 08:27:51 -07002306TEST_F(VideoStreamEncoderTest,
2307 NumberOfDroppedFramesLimitedWhenBitrateIsTooLow) {
asaperssonfab67072017-04-04 05:51:49 -07002308 const int kTooLowBitrateForFrameSizeBps = 10000;
mflodmancc3d4422017-08-03 08:27:51 -07002309 video_stream_encoder_->OnBitrateUpdated(kTooLowBitrateForFrameSizeBps, 0, 0);
asaperssonfab67072017-04-04 05:51:49 -07002310 const int kWidth = 640;
2311 const int kHeight = 360;
kthelgason2bc68642017-02-07 07:02:22 -08002312
2313 // We expect the n initial frames to get dropped.
2314 int i;
2315 for (i = 1; i <= kMaxInitialFramedrop; ++i) {
asaperssonfab67072017-04-04 05:51:49 -07002316 video_source_.IncomingCapturedFrame(CreateFrame(i, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002317 ExpectDroppedFrame();
kthelgason2bc68642017-02-07 07:02:22 -08002318 }
2319 // The n+1th frame should not be dropped, even though it's size is too large.
asaperssonfab67072017-04-04 05:51:49 -07002320 video_source_.IncomingCapturedFrame(CreateFrame(i, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002321 WaitForEncodedFrame(i);
kthelgason2bc68642017-02-07 07:02:22 -08002322
2323 // Expect the sink_wants to specify a scaled frame.
asaperssonfab67072017-04-04 05:51:49 -07002324 EXPECT_LT(video_source_.sink_wants().max_pixel_count, kWidth * kHeight);
kthelgason2bc68642017-02-07 07:02:22 -08002325
mflodmancc3d4422017-08-03 08:27:51 -07002326 video_stream_encoder_->Stop();
kthelgason2bc68642017-02-07 07:02:22 -08002327}
2328
mflodmancc3d4422017-08-03 08:27:51 -07002329TEST_F(VideoStreamEncoderTest,
2330 InitialFrameDropOffWithMaintainResolutionPreference) {
asaperssonfab67072017-04-04 05:51:49 -07002331 const int kWidth = 640;
2332 const int kHeight = 360;
mflodmancc3d4422017-08-03 08:27:51 -07002333 video_stream_encoder_->OnBitrateUpdated(kLowTargetBitrateBps, 0, 0);
kthelgason2bc68642017-02-07 07:02:22 -08002334
2335 // Set degradation preference.
mflodmancc3d4422017-08-03 08:27:51 -07002336 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002337 &video_source_, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
kthelgason2bc68642017-02-07 07:02:22 -08002338
asaperssonfab67072017-04-04 05:51:49 -07002339 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
kthelgason2bc68642017-02-07 07:02:22 -08002340 // Frame should not be dropped, even if it's too large.
sprang4847ae62017-06-27 07:06:52 -07002341 WaitForEncodedFrame(1);
kthelgason2bc68642017-02-07 07:02:22 -08002342
mflodmancc3d4422017-08-03 08:27:51 -07002343 video_stream_encoder_->Stop();
kthelgason2bc68642017-02-07 07:02:22 -08002344}
2345
mflodmancc3d4422017-08-03 08:27:51 -07002346TEST_F(VideoStreamEncoderTest, InitialFrameDropOffWhenEncoderDisabledScaling) {
asaperssonfab67072017-04-04 05:51:49 -07002347 const int kWidth = 640;
2348 const int kHeight = 360;
kthelgasonad9010c2017-02-14 00:46:51 -08002349 fake_encoder_.SetQualityScaling(false);
Niels Möller4db138e2018-04-19 09:04:13 +02002350
2351 VideoEncoderConfig video_encoder_config;
2352 test::FillEncoderConfiguration(kVideoCodecVP8, 1, &video_encoder_config);
2353 // Make format different, to force recreation of encoder.
2354 video_encoder_config.video_format.parameters["foo"] = "foo";
2355 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
Niels Möllerf1338562018-04-26 09:51:47 +02002356 kMaxPayloadLength);
mflodmancc3d4422017-08-03 08:27:51 -07002357 video_stream_encoder_->OnBitrateUpdated(kLowTargetBitrateBps, 0, 0);
asapersson09f05612017-05-15 23:40:18 -07002358
kthelgasonb83797b2017-02-14 11:57:25 -08002359 // Force quality scaler reconfiguration by resetting the source.
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002360 video_stream_encoder_->SetSource(&video_source_,
2361 webrtc::DegradationPreference::BALANCED);
kthelgasonad9010c2017-02-14 00:46:51 -08002362
asaperssonfab67072017-04-04 05:51:49 -07002363 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
kthelgasonad9010c2017-02-14 00:46:51 -08002364 // Frame should not be dropped, even if it's too large.
sprang4847ae62017-06-27 07:06:52 -07002365 WaitForEncodedFrame(1);
kthelgasonad9010c2017-02-14 00:46:51 -08002366
mflodmancc3d4422017-08-03 08:27:51 -07002367 video_stream_encoder_->Stop();
kthelgasonad9010c2017-02-14 00:46:51 -08002368 fake_encoder_.SetQualityScaling(true);
2369}
2370
Kári Tristan Helgason639602a2018-08-02 10:51:40 +02002371TEST_F(VideoStreamEncoderTest, InitialFrameDropActivatesWhenBWEstimateReady) {
2372 webrtc::test::ScopedFieldTrials field_trials(
2373 "WebRTC-InitialFramedrop/Enabled/");
2374 // Reset encoder for field trials to take effect.
2375 ConfigureEncoder(video_encoder_config_.Copy());
2376 const int kTooLowBitrateForFrameSizeBps = 10000;
2377 const int kWidth = 640;
2378 const int kHeight = 360;
2379
2380 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
2381 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
2382 // Frame should not be dropped.
2383 WaitForEncodedFrame(1);
2384
2385 video_stream_encoder_->OnBitrateUpdated(kTooLowBitrateForFrameSizeBps, 0, 0);
2386 video_source_.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
2387 // Expect to drop this frame, the wait should time out.
2388 ExpectDroppedFrame();
2389
2390 // Expect the sink_wants to specify a scaled frame.
2391 EXPECT_LT(video_source_.sink_wants().max_pixel_count, kWidth * kHeight);
2392 video_stream_encoder_->Stop();
2393}
2394
mflodmancc3d4422017-08-03 08:27:51 -07002395TEST_F(VideoStreamEncoderTest,
asaperssond0de2952017-04-21 01:47:31 -07002396 ResolutionNotAdaptedForTooSmallFrame_MaintainFramerateMode) {
2397 const int kTooSmallWidth = 10;
2398 const int kTooSmallHeight = 10;
mflodmancc3d4422017-08-03 08:27:51 -07002399 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssond0de2952017-04-21 01:47:31 -07002400
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002401 // Enable MAINTAIN_FRAMERATE preference, no initial limitation.
asaperssond0de2952017-04-21 01:47:31 -07002402 test::FrameForwarder source;
mflodmancc3d4422017-08-03 08:27:51 -07002403 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002404 &source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
asaperssond0de2952017-04-21 01:47:31 -07002405 VerifyNoLimitation(source.sink_wants());
2406 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2407
2408 // Trigger adapt down, too small frame, expect no change.
2409 source.IncomingCapturedFrame(CreateFrame(1, kTooSmallWidth, kTooSmallHeight));
sprang4847ae62017-06-27 07:06:52 -07002410 WaitForEncodedFrame(1);
mflodmancc3d4422017-08-03 08:27:51 -07002411 video_stream_encoder_->TriggerCpuOveruse();
Åsa Persson8c1bf952018-09-13 10:42:19 +02002412 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssond0de2952017-04-21 01:47:31 -07002413 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2414 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2415
mflodmancc3d4422017-08-03 08:27:51 -07002416 video_stream_encoder_->Stop();
asaperssond0de2952017-04-21 01:47:31 -07002417}
2418
mflodmancc3d4422017-08-03 08:27:51 -07002419TEST_F(VideoStreamEncoderTest,
2420 ResolutionNotAdaptedForTooSmallFrame_BalancedMode) {
asaperssonf7e294d2017-06-13 23:25:22 -07002421 const int kTooSmallWidth = 10;
2422 const int kTooSmallHeight = 10;
2423 const int kFpsLimit = 7;
mflodmancc3d4422017-08-03 08:27:51 -07002424 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -07002425
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002426 // Enable BALANCED preference, no initial limitation.
asaperssonf7e294d2017-06-13 23:25:22 -07002427 test::FrameForwarder source;
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002428 video_stream_encoder_->SetSource(&source,
2429 webrtc::DegradationPreference::BALANCED);
asaperssonf7e294d2017-06-13 23:25:22 -07002430 VerifyNoLimitation(source.sink_wants());
2431 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2432 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2433
2434 // Trigger adapt down, expect limited framerate.
2435 source.IncomingCapturedFrame(CreateFrame(1, kTooSmallWidth, kTooSmallHeight));
sprang4847ae62017-06-27 07:06:52 -07002436 WaitForEncodedFrame(1);
mflodmancc3d4422017-08-03 08:27:51 -07002437 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002438 VerifyFpsEqResolutionMax(source.sink_wants(), kFpsLimit);
2439 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2440 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2441 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2442
2443 // Trigger adapt down, too small frame, expect no change.
2444 source.IncomingCapturedFrame(CreateFrame(2, kTooSmallWidth, kTooSmallHeight));
sprang4847ae62017-06-27 07:06:52 -07002445 WaitForEncodedFrame(2);
mflodmancc3d4422017-08-03 08:27:51 -07002446 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002447 VerifyFpsEqResolutionMax(source.sink_wants(), kFpsLimit);
2448 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2449 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2450 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2451
mflodmancc3d4422017-08-03 08:27:51 -07002452 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07002453}
2454
mflodmancc3d4422017-08-03 08:27:51 -07002455TEST_F(VideoStreamEncoderTest, FailingInitEncodeDoesntCauseCrash) {
asapersson02465b82017-04-10 01:12:52 -07002456 fake_encoder_.ForceInitEncodeFailure(true);
mflodmancc3d4422017-08-03 08:27:51 -07002457 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
Niels Möllerf1338562018-04-26 09:51:47 +02002458 ResetEncoder("VP8", 2, 1, 1, false);
asapersson02465b82017-04-10 01:12:52 -07002459 const int kFrameWidth = 1280;
2460 const int kFrameHeight = 720;
2461 video_source_.IncomingCapturedFrame(
2462 CreateFrame(1, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002463 ExpectDroppedFrame();
mflodmancc3d4422017-08-03 08:27:51 -07002464 video_stream_encoder_->Stop();
asapersson02465b82017-04-10 01:12:52 -07002465}
2466
sprangb1ca0732017-02-01 08:38:12 -08002467// TODO(sprang): Extend this with fps throttling and any "balanced" extensions.
mflodmancc3d4422017-08-03 08:27:51 -07002468TEST_F(VideoStreamEncoderTest,
2469 AdaptsResolutionOnOveruse_MaintainFramerateMode) {
2470 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
sprangb1ca0732017-02-01 08:38:12 -08002471
2472 const int kFrameWidth = 1280;
2473 const int kFrameHeight = 720;
2474 // Enabled default VideoAdapter downscaling. First step is 3/4, not 3/5 as
mflodmancc3d4422017-08-03 08:27:51 -07002475 // requested by
2476 // VideoStreamEncoder::VideoSourceProxy::RequestResolutionLowerThan().
sprangb1ca0732017-02-01 08:38:12 -08002477 video_source_.set_adaptation_enabled(true);
2478
2479 video_source_.IncomingCapturedFrame(
Åsa Persson8c1bf952018-09-13 10:42:19 +02002480 CreateFrame(1 * kFrameIntervalMs, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002481 WaitForEncodedFrame(kFrameWidth, kFrameHeight);
sprangb1ca0732017-02-01 08:38:12 -08002482
2483 // Trigger CPU overuse, downscale by 3/4.
mflodmancc3d4422017-08-03 08:27:51 -07002484 video_stream_encoder_->TriggerCpuOveruse();
sprangb1ca0732017-02-01 08:38:12 -08002485 video_source_.IncomingCapturedFrame(
Åsa Persson8c1bf952018-09-13 10:42:19 +02002486 CreateFrame(2 * kFrameIntervalMs, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002487 WaitForEncodedFrame((kFrameWidth * 3) / 4, (kFrameHeight * 3) / 4);
sprangb1ca0732017-02-01 08:38:12 -08002488
asaperssonfab67072017-04-04 05:51:49 -07002489 // Trigger CPU normal use, return to original resolution.
mflodmancc3d4422017-08-03 08:27:51 -07002490 video_stream_encoder_->TriggerCpuNormalUsage();
sprangb1ca0732017-02-01 08:38:12 -08002491 video_source_.IncomingCapturedFrame(
Åsa Persson8c1bf952018-09-13 10:42:19 +02002492 CreateFrame(3 * kFrameIntervalMs, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002493 WaitForEncodedFrame(kFrameWidth, kFrameHeight);
sprangb1ca0732017-02-01 08:38:12 -08002494
mflodmancc3d4422017-08-03 08:27:51 -07002495 video_stream_encoder_->Stop();
sprangb1ca0732017-02-01 08:38:12 -08002496}
sprangfe627f32017-03-29 08:24:59 -07002497
mflodmancc3d4422017-08-03 08:27:51 -07002498TEST_F(VideoStreamEncoderTest,
2499 AdaptsFramerateOnOveruse_MaintainResolutionMode) {
sprangc5d62e22017-04-02 23:53:04 -07002500 const int kFrameWidth = 1280;
2501 const int kFrameHeight = 720;
sprangc5d62e22017-04-02 23:53:04 -07002502
mflodmancc3d4422017-08-03 08:27:51 -07002503 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
2504 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002505 &video_source_, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
sprangc5d62e22017-04-02 23:53:04 -07002506 video_source_.set_adaptation_enabled(true);
2507
sprang4847ae62017-06-27 07:06:52 -07002508 int64_t timestamp_ms = fake_clock_.TimeNanos() / rtc::kNumNanosecsPerMillisec;
sprangc5d62e22017-04-02 23:53:04 -07002509
2510 video_source_.IncomingCapturedFrame(
2511 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002512 WaitForEncodedFrame(timestamp_ms);
sprangc5d62e22017-04-02 23:53:04 -07002513
2514 // Try to trigger overuse. No fps estimate available => no effect.
mflodmancc3d4422017-08-03 08:27:51 -07002515 video_stream_encoder_->TriggerCpuOveruse();
sprangc5d62e22017-04-02 23:53:04 -07002516
2517 // Insert frames for one second to get a stable estimate.
sprang4847ae62017-06-27 07:06:52 -07002518 for (int i = 0; i < max_framerate_; ++i) {
sprangc5d62e22017-04-02 23:53:04 -07002519 timestamp_ms += kFrameIntervalMs;
sprangc5d62e22017-04-02 23:53:04 -07002520 video_source_.IncomingCapturedFrame(
2521 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002522 WaitForEncodedFrame(timestamp_ms);
sprangc5d62e22017-04-02 23:53:04 -07002523 }
2524
2525 // Trigger CPU overuse, reduce framerate by 2/3.
mflodmancc3d4422017-08-03 08:27:51 -07002526 video_stream_encoder_->TriggerCpuOveruse();
sprangc5d62e22017-04-02 23:53:04 -07002527 int num_frames_dropped = 0;
sprang4847ae62017-06-27 07:06:52 -07002528 for (int i = 0; i < max_framerate_; ++i) {
sprangc5d62e22017-04-02 23:53:04 -07002529 timestamp_ms += kFrameIntervalMs;
sprangc5d62e22017-04-02 23:53:04 -07002530 video_source_.IncomingCapturedFrame(
2531 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002532 if (!WaitForFrame(kFrameTimeoutMs)) {
sprangc5d62e22017-04-02 23:53:04 -07002533 ++num_frames_dropped;
2534 } else {
Åsa Perssonc74d8da2017-12-04 14:13:56 +01002535 sink_.CheckLastFrameSizeMatches(kFrameWidth, kFrameHeight);
sprangc5d62e22017-04-02 23:53:04 -07002536 }
2537 }
2538
sprang4847ae62017-06-27 07:06:52 -07002539 // Add some slack to account for frames dropped by the frame dropper.
2540 const int kErrorMargin = 1;
2541 EXPECT_NEAR(num_frames_dropped, max_framerate_ - (max_framerate_ * 2 / 3),
sprangc5d62e22017-04-02 23:53:04 -07002542 kErrorMargin);
2543
2544 // Trigger CPU overuse, reduce framerate by 2/3 again.
mflodmancc3d4422017-08-03 08:27:51 -07002545 video_stream_encoder_->TriggerCpuOveruse();
sprangc5d62e22017-04-02 23:53:04 -07002546 num_frames_dropped = 0;
Åsa Persson8c1bf952018-09-13 10:42:19 +02002547 for (int i = 0; i <= max_framerate_; ++i) {
sprangc5d62e22017-04-02 23:53:04 -07002548 timestamp_ms += kFrameIntervalMs;
sprangc5d62e22017-04-02 23:53:04 -07002549 video_source_.IncomingCapturedFrame(
2550 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002551 if (!WaitForFrame(kFrameTimeoutMs)) {
sprangc5d62e22017-04-02 23:53:04 -07002552 ++num_frames_dropped;
2553 } else {
Åsa Perssonc74d8da2017-12-04 14:13:56 +01002554 sink_.CheckLastFrameSizeMatches(kFrameWidth, kFrameHeight);
sprangc5d62e22017-04-02 23:53:04 -07002555 }
2556 }
sprang4847ae62017-06-27 07:06:52 -07002557 EXPECT_NEAR(num_frames_dropped, max_framerate_ - (max_framerate_ * 4 / 9),
sprangc5d62e22017-04-02 23:53:04 -07002558 kErrorMargin);
2559
2560 // Go back up one step.
mflodmancc3d4422017-08-03 08:27:51 -07002561 video_stream_encoder_->TriggerCpuNormalUsage();
sprangc5d62e22017-04-02 23:53:04 -07002562 num_frames_dropped = 0;
sprang4847ae62017-06-27 07:06:52 -07002563 for (int i = 0; i < max_framerate_; ++i) {
sprangc5d62e22017-04-02 23:53:04 -07002564 timestamp_ms += kFrameIntervalMs;
sprangc5d62e22017-04-02 23:53:04 -07002565 video_source_.IncomingCapturedFrame(
2566 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002567 if (!WaitForFrame(kFrameTimeoutMs)) {
sprangc5d62e22017-04-02 23:53:04 -07002568 ++num_frames_dropped;
2569 } else {
Åsa Perssonc74d8da2017-12-04 14:13:56 +01002570 sink_.CheckLastFrameSizeMatches(kFrameWidth, kFrameHeight);
sprangc5d62e22017-04-02 23:53:04 -07002571 }
2572 }
sprang4847ae62017-06-27 07:06:52 -07002573 EXPECT_NEAR(num_frames_dropped, max_framerate_ - (max_framerate_ * 2 / 3),
sprangc5d62e22017-04-02 23:53:04 -07002574 kErrorMargin);
2575
2576 // Go back up to original mode.
mflodmancc3d4422017-08-03 08:27:51 -07002577 video_stream_encoder_->TriggerCpuNormalUsage();
sprangc5d62e22017-04-02 23:53:04 -07002578 num_frames_dropped = 0;
sprang4847ae62017-06-27 07:06:52 -07002579 for (int i = 0; i < max_framerate_; ++i) {
sprangc5d62e22017-04-02 23:53:04 -07002580 timestamp_ms += kFrameIntervalMs;
sprangc5d62e22017-04-02 23:53:04 -07002581 video_source_.IncomingCapturedFrame(
2582 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002583 if (!WaitForFrame(kFrameTimeoutMs)) {
sprangc5d62e22017-04-02 23:53:04 -07002584 ++num_frames_dropped;
2585 } else {
Åsa Perssonc74d8da2017-12-04 14:13:56 +01002586 sink_.CheckLastFrameSizeMatches(kFrameWidth, kFrameHeight);
sprangc5d62e22017-04-02 23:53:04 -07002587 }
2588 }
2589 EXPECT_NEAR(num_frames_dropped, 0, kErrorMargin);
2590
mflodmancc3d4422017-08-03 08:27:51 -07002591 video_stream_encoder_->Stop();
sprangc5d62e22017-04-02 23:53:04 -07002592}
2593
mflodmancc3d4422017-08-03 08:27:51 -07002594TEST_F(VideoStreamEncoderTest, DoesntAdaptDownPastMinFramerate) {
sprangc5d62e22017-04-02 23:53:04 -07002595 const int kFramerateFps = 5;
2596 const int kFrameIntervalMs = rtc::kNumMillisecsPerSec / kFramerateFps;
sprangc5d62e22017-04-02 23:53:04 -07002597 const int kFrameWidth = 1280;
2598 const int kFrameHeight = 720;
2599
sprang4847ae62017-06-27 07:06:52 -07002600 // Reconfigure encoder with two temporal layers and screensharing, which will
2601 // disable frame dropping and make testing easier.
Niels Möllerf1338562018-04-26 09:51:47 +02002602 ResetEncoder("VP8", 1, 2, 1, true);
sprang4847ae62017-06-27 07:06:52 -07002603
mflodmancc3d4422017-08-03 08:27:51 -07002604 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
2605 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002606 &video_source_, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
sprangc5d62e22017-04-02 23:53:04 -07002607 video_source_.set_adaptation_enabled(true);
2608
sprang4847ae62017-06-27 07:06:52 -07002609 int64_t timestamp_ms = fake_clock_.TimeNanos() / rtc::kNumNanosecsPerMillisec;
sprangc5d62e22017-04-02 23:53:04 -07002610
2611 // Trigger overuse as much as we can.
Jonathan Yubc771b72017-12-08 17:04:29 -08002612 rtc::VideoSinkWants last_wants;
2613 do {
2614 last_wants = video_source_.sink_wants();
2615
sprangc5d62e22017-04-02 23:53:04 -07002616 // Insert frames to get a new fps estimate...
2617 for (int j = 0; j < kFramerateFps; ++j) {
2618 video_source_.IncomingCapturedFrame(
2619 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
Jonathan Yubc771b72017-12-08 17:04:29 -08002620 if (video_source_.last_sent_width()) {
2621 sink_.WaitForEncodedFrame(timestamp_ms);
2622 }
sprangc5d62e22017-04-02 23:53:04 -07002623 timestamp_ms += kFrameIntervalMs;
Yves Gerey665174f2018-06-19 15:03:05 +02002624 fake_clock_.AdvanceTimeMicros(kFrameIntervalMs *
2625 rtc::kNumMicrosecsPerMillisec);
sprangc5d62e22017-04-02 23:53:04 -07002626 }
2627 // ...and then try to adapt again.
mflodmancc3d4422017-08-03 08:27:51 -07002628 video_stream_encoder_->TriggerCpuOveruse();
Jonathan Yubc771b72017-12-08 17:04:29 -08002629 } while (video_source_.sink_wants().max_framerate_fps <
2630 last_wants.max_framerate_fps);
sprangc5d62e22017-04-02 23:53:04 -07002631
Jonathan Yubc771b72017-12-08 17:04:29 -08002632 VerifyFpsEqResolutionMax(video_source_.sink_wants(), kMinFramerateFps);
asaperssonf7e294d2017-06-13 23:25:22 -07002633
mflodmancc3d4422017-08-03 08:27:51 -07002634 video_stream_encoder_->Stop();
sprangc5d62e22017-04-02 23:53:04 -07002635}
asaperssonf7e294d2017-06-13 23:25:22 -07002636
mflodmancc3d4422017-08-03 08:27:51 -07002637TEST_F(VideoStreamEncoderTest,
2638 AdaptsResolutionAndFramerateForLowQuality_BalancedMode) {
asaperssonf7e294d2017-06-13 23:25:22 -07002639 const int kWidth = 1280;
2640 const int kHeight = 720;
2641 const int64_t kFrameIntervalMs = 150;
2642 int64_t timestamp_ms = kFrameIntervalMs;
mflodmancc3d4422017-08-03 08:27:51 -07002643 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -07002644
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002645 // Enable BALANCED preference, no initial limitation.
asaperssonf7e294d2017-06-13 23:25:22 -07002646 AdaptingFrameForwarder source;
2647 source.set_adaptation_enabled(true);
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002648 video_stream_encoder_->SetSource(&source,
2649 webrtc::DegradationPreference::BALANCED);
asaperssonf7e294d2017-06-13 23:25:22 -07002650 timestamp_ms += kFrameIntervalMs;
2651 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002652 WaitForEncodedFrame(kWidth, kHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +02002653 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07002654 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2655 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2656 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2657
2658 // Trigger adapt down, expect scaled down resolution (960x540@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002659 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002660 timestamp_ms += kFrameIntervalMs;
2661 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002662 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002663 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
2664 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2665 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2666 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2667
2668 // Trigger adapt down, expect scaled down resolution (640x360@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002669 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002670 timestamp_ms += kFrameIntervalMs;
2671 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002672 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002673 VerifyFpsMaxResolutionLt(source.sink_wants(), source.last_wants());
2674 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2675 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2676 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2677
2678 // Trigger adapt down, expect reduced fps (640x360@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07002679 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002680 timestamp_ms += kFrameIntervalMs;
2681 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002682 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002683 VerifyFpsLtResolutionEq(source.sink_wants(), source.last_wants());
2684 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2685 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2686 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2687
2688 // Trigger adapt down, expect scaled down resolution (480x270@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07002689 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002690 timestamp_ms += kFrameIntervalMs;
2691 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002692 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002693 VerifyFpsEqResolutionLt(source.sink_wants(), source.last_wants());
2694 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2695 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2696 EXPECT_EQ(4, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2697
2698 // Restrict bitrate, trigger adapt down, expect reduced fps (480x270@10fps).
mflodmancc3d4422017-08-03 08:27:51 -07002699 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002700 timestamp_ms += kFrameIntervalMs;
2701 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002702 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002703 VerifyFpsLtResolutionEq(source.sink_wants(), source.last_wants());
2704 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2705 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2706 EXPECT_EQ(5, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2707
2708 // Trigger adapt down, expect scaled down resolution (320x180@10fps).
mflodmancc3d4422017-08-03 08:27:51 -07002709 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002710 timestamp_ms += kFrameIntervalMs;
2711 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002712 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002713 VerifyFpsEqResolutionLt(source.sink_wants(), source.last_wants());
2714 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2715 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2716 EXPECT_EQ(6, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2717
2718 // Trigger adapt down, expect reduced fps (320x180@7fps).
mflodmancc3d4422017-08-03 08:27:51 -07002719 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002720 timestamp_ms += kFrameIntervalMs;
2721 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002722 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002723 VerifyFpsLtResolutionEq(source.sink_wants(), source.last_wants());
2724 rtc::VideoSinkWants last_wants = source.sink_wants();
2725 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2726 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2727 EXPECT_EQ(7, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2728
2729 // Trigger adapt down, min resolution reached, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07002730 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002731 timestamp_ms += kFrameIntervalMs;
2732 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002733 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002734 VerifyFpsEqResolutionEq(source.sink_wants(), last_wants);
2735 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2736 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2737 EXPECT_EQ(7, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2738
2739 // Trigger adapt down, expect expect increased fps (320x180@10fps).
mflodmancc3d4422017-08-03 08:27:51 -07002740 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002741 timestamp_ms += kFrameIntervalMs;
2742 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002743 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002744 VerifyFpsGtResolutionEq(source.sink_wants(), source.last_wants());
2745 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2746 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2747 EXPECT_EQ(8, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2748
2749 // Trigger adapt up, expect upscaled resolution (480x270@10fps).
mflodmancc3d4422017-08-03 08:27:51 -07002750 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002751 timestamp_ms += kFrameIntervalMs;
2752 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002753 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002754 VerifyFpsEqResolutionGt(source.sink_wants(), source.last_wants());
2755 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2756 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2757 EXPECT_EQ(9, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2758
2759 // Increase bitrate, trigger adapt up, expect increased fps (480x270@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07002760 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002761 timestamp_ms += kFrameIntervalMs;
2762 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002763 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002764 VerifyFpsGtResolutionEq(source.sink_wants(), source.last_wants());
2765 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2766 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2767 EXPECT_EQ(10, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2768
2769 // Trigger adapt up, expect upscaled resolution (640x360@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07002770 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002771 timestamp_ms += kFrameIntervalMs;
2772 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002773 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002774 VerifyFpsEqResolutionGt(source.sink_wants(), source.last_wants());
2775 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2776 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2777 EXPECT_EQ(11, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2778
2779 // Trigger adapt up, expect increased fps (640x360@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002780 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002781 timestamp_ms += kFrameIntervalMs;
2782 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002783 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002784 VerifyFpsMaxResolutionEq(source.sink_wants(), source.last_wants());
2785 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2786 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2787 EXPECT_EQ(12, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2788
2789 // Trigger adapt up, expect upscaled resolution (960x540@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002790 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002791 timestamp_ms += kFrameIntervalMs;
2792 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002793 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002794 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
2795 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2796 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2797 EXPECT_EQ(13, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2798
2799 // Trigger adapt up, expect no restriction (1280x720fps@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002800 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002801 timestamp_ms += kFrameIntervalMs;
2802 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002803 WaitForEncodedFrame(kWidth, kHeight);
asaperssonf7e294d2017-06-13 23:25:22 -07002804 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
Åsa Persson8c1bf952018-09-13 10:42:19 +02002805 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07002806 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2807 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2808 EXPECT_EQ(14, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2809
2810 // Trigger adapt up, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07002811 video_stream_encoder_->TriggerQualityHigh();
Åsa Persson8c1bf952018-09-13 10:42:19 +02002812 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07002813 EXPECT_EQ(14, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2814
mflodmancc3d4422017-08-03 08:27:51 -07002815 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07002816}
2817
mflodmancc3d4422017-08-03 08:27:51 -07002818TEST_F(VideoStreamEncoderTest, AdaptWithTwoReasonsAndDifferentOrder_Framerate) {
asaperssonf7e294d2017-06-13 23:25:22 -07002819 const int kWidth = 1280;
2820 const int kHeight = 720;
2821 const int64_t kFrameIntervalMs = 150;
2822 int64_t timestamp_ms = kFrameIntervalMs;
mflodmancc3d4422017-08-03 08:27:51 -07002823 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -07002824
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002825 // Enable BALANCED preference, no initial limitation.
asaperssonf7e294d2017-06-13 23:25:22 -07002826 AdaptingFrameForwarder source;
2827 source.set_adaptation_enabled(true);
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002828 video_stream_encoder_->SetSource(&source,
2829 webrtc::DegradationPreference::BALANCED);
asaperssonf7e294d2017-06-13 23:25:22 -07002830 timestamp_ms += kFrameIntervalMs;
2831 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002832 WaitForEncodedFrame(kWidth, kHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +02002833 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07002834 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2835 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2836 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2837 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
2838 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2839 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2840
2841 // Trigger cpu adapt down, expect scaled down resolution (960x540@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002842 video_stream_encoder_->TriggerCpuOveruse();
asaperssonf7e294d2017-06-13 23:25:22 -07002843 timestamp_ms += kFrameIntervalMs;
2844 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002845 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002846 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
2847 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2848 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2849 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2850 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
2851 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2852 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2853
2854 // Trigger cpu adapt down, expect scaled down resolution (640x360@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002855 video_stream_encoder_->TriggerCpuOveruse();
asaperssonf7e294d2017-06-13 23:25:22 -07002856 timestamp_ms += kFrameIntervalMs;
2857 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002858 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002859 VerifyFpsMaxResolutionLt(source.sink_wants(), source.last_wants());
2860 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2861 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2862 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2863 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
2864 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2865 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2866
2867 // Trigger quality adapt down, expect reduced fps (640x360@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07002868 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002869 timestamp_ms += kFrameIntervalMs;
2870 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002871 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002872 VerifyFpsLtResolutionEq(source.sink_wants(), source.last_wants());
2873 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2874 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2875 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2876 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
2877 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2878 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2879
2880 // Trigger cpu adapt up, expect increased fps (640x360@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002881 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssonf7e294d2017-06-13 23:25:22 -07002882 timestamp_ms += kFrameIntervalMs;
2883 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002884 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002885 VerifyFpsMaxResolutionEq(source.sink_wants(), source.last_wants());
2886 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2887 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2888 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2889 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
2890 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2891 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2892
2893 // Trigger quality adapt up, expect upscaled resolution (960x540@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002894 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002895 timestamp_ms += kFrameIntervalMs;
2896 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002897 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002898 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
2899 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2900 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2901 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2902 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
2903 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2904 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2905
2906 // Trigger cpu adapt up, expect no restriction (1280x720fps@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002907 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssonf7e294d2017-06-13 23:25:22 -07002908 timestamp_ms += kFrameIntervalMs;
2909 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002910 WaitForEncodedFrame(kWidth, kHeight);
asaperssonf7e294d2017-06-13 23:25:22 -07002911 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
Åsa Persson8c1bf952018-09-13 10:42:19 +02002912 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07002913 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2914 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2915 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2916 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
2917 EXPECT_EQ(4, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2918 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2919
2920 // Trigger adapt up, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07002921 video_stream_encoder_->TriggerQualityHigh();
Åsa Persson8c1bf952018-09-13 10:42:19 +02002922 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07002923 EXPECT_EQ(4, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2924 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2925
mflodmancc3d4422017-08-03 08:27:51 -07002926 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07002927}
2928
mflodmancc3d4422017-08-03 08:27:51 -07002929TEST_F(VideoStreamEncoderTest,
2930 AdaptWithTwoReasonsAndDifferentOrder_Resolution) {
asaperssonf7e294d2017-06-13 23:25:22 -07002931 const int kWidth = 640;
2932 const int kHeight = 360;
2933 const int kFpsLimit = 15;
2934 const int64_t kFrameIntervalMs = 150;
2935 int64_t timestamp_ms = kFrameIntervalMs;
mflodmancc3d4422017-08-03 08:27:51 -07002936 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -07002937
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002938 // Enable BALANCED preference, no initial limitation.
asaperssonf7e294d2017-06-13 23:25:22 -07002939 AdaptingFrameForwarder source;
2940 source.set_adaptation_enabled(true);
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002941 video_stream_encoder_->SetSource(&source,
2942 webrtc::DegradationPreference::BALANCED);
asaperssonf7e294d2017-06-13 23:25:22 -07002943 timestamp_ms += kFrameIntervalMs;
2944 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002945 WaitForEncodedFrame(kWidth, kHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +02002946 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07002947 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2948 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2949 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2950 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
2951 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2952 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2953
2954 // Trigger cpu adapt down, expect scaled down framerate (640x360@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07002955 video_stream_encoder_->TriggerCpuOveruse();
asaperssonf7e294d2017-06-13 23:25:22 -07002956 timestamp_ms += kFrameIntervalMs;
2957 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002958 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002959 VerifyFpsEqResolutionMax(source.sink_wants(), kFpsLimit);
2960 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2961 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2962 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2963 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_framerate);
2964 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2965 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2966
2967 // Trigger quality adapt down, expect scaled down resolution (480x270@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07002968 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002969 timestamp_ms += kFrameIntervalMs;
2970 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002971 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002972 VerifyFpsEqResolutionLt(source.sink_wants(), source.last_wants());
2973 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2974 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2975 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2976 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_framerate);
2977 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2978 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2979
2980 // Trigger cpu adapt up, expect upscaled resolution (640x360@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07002981 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssonf7e294d2017-06-13 23:25:22 -07002982 timestamp_ms += kFrameIntervalMs;
2983 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002984 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002985 VerifyFpsEqResolutionGt(source.sink_wants(), source.last_wants());
2986 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2987 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2988 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2989 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
2990 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2991 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2992
2993 // Trigger quality adapt up, expect increased fps (640x360@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002994 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002995 timestamp_ms += kFrameIntervalMs;
2996 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002997 WaitForEncodedFrame(timestamp_ms);
Åsa Persson8c1bf952018-09-13 10:42:19 +02002998 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07002999 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
3000 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
3001 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
3002 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
3003 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
3004 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3005
3006 // Trigger adapt up, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07003007 video_stream_encoder_->TriggerQualityHigh();
Åsa Persson8c1bf952018-09-13 10:42:19 +02003008 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07003009 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
3010 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3011
mflodmancc3d4422017-08-03 08:27:51 -07003012 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07003013}
3014
mflodmancc3d4422017-08-03 08:27:51 -07003015TEST_F(VideoStreamEncoderTest, AcceptsFullHdAdaptedDownSimulcastFrames) {
ilnik6b826ef2017-06-16 06:53:48 -07003016 // Simulates simulcast behavior and makes highest stream resolutions divisible
3017 // by 4.
3018 class CroppingVideoStreamFactory
3019 : public VideoEncoderConfig::VideoStreamFactoryInterface {
3020 public:
3021 explicit CroppingVideoStreamFactory(size_t num_temporal_layers,
3022 int framerate)
3023 : num_temporal_layers_(num_temporal_layers), framerate_(framerate) {
3024 EXPECT_GT(num_temporal_layers, 0u);
3025 EXPECT_GT(framerate, 0);
3026 }
3027
3028 private:
3029 std::vector<VideoStream> CreateEncoderStreams(
3030 int width,
3031 int height,
3032 const VideoEncoderConfig& encoder_config) override {
Yves Gerey665174f2018-06-19 15:03:05 +02003033 std::vector<VideoStream> streams = test::CreateVideoStreams(
3034 width - width % 4, height - height % 4, encoder_config);
ilnik6b826ef2017-06-16 06:53:48 -07003035 for (VideoStream& stream : streams) {
Sergey Silkina796a7e2018-03-01 15:11:29 +01003036 stream.num_temporal_layers = num_temporal_layers_;
ilnik6b826ef2017-06-16 06:53:48 -07003037 stream.max_framerate = framerate_;
3038 }
3039 return streams;
3040 }
3041
3042 const size_t num_temporal_layers_;
3043 const int framerate_;
3044 };
3045
3046 const int kFrameWidth = 1920;
3047 const int kFrameHeight = 1080;
3048 // 3/4 of 1920.
3049 const int kAdaptedFrameWidth = 1440;
3050 // 3/4 of 1080 rounded down to multiple of 4.
3051 const int kAdaptedFrameHeight = 808;
3052 const int kFramerate = 24;
3053
mflodmancc3d4422017-08-03 08:27:51 -07003054 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
ilnik6b826ef2017-06-16 06:53:48 -07003055 // Trigger reconfigure encoder (without resetting the entire instance).
3056 VideoEncoderConfig video_encoder_config;
Niels Möller259a4972018-04-05 15:36:51 +02003057 video_encoder_config.codec_type = kVideoCodecVP8;
ilnik6b826ef2017-06-16 06:53:48 -07003058 video_encoder_config.max_bitrate_bps = kTargetBitrateBps;
3059 video_encoder_config.number_of_streams = 1;
3060 video_encoder_config.video_stream_factory =
3061 new rtc::RefCountedObject<CroppingVideoStreamFactory>(1, kFramerate);
mflodmancc3d4422017-08-03 08:27:51 -07003062 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
Niels Möllerf1338562018-04-26 09:51:47 +02003063 kMaxPayloadLength);
mflodmancc3d4422017-08-03 08:27:51 -07003064 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
ilnik6b826ef2017-06-16 06:53:48 -07003065
3066 video_source_.set_adaptation_enabled(true);
3067
3068 video_source_.IncomingCapturedFrame(
3069 CreateFrame(1, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07003070 WaitForEncodedFrame(kFrameWidth, kFrameHeight);
ilnik6b826ef2017-06-16 06:53:48 -07003071
3072 // Trigger CPU overuse, downscale by 3/4.
mflodmancc3d4422017-08-03 08:27:51 -07003073 video_stream_encoder_->TriggerCpuOveruse();
ilnik6b826ef2017-06-16 06:53:48 -07003074 video_source_.IncomingCapturedFrame(
3075 CreateFrame(2, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07003076 WaitForEncodedFrame(kAdaptedFrameWidth, kAdaptedFrameHeight);
ilnik6b826ef2017-06-16 06:53:48 -07003077
mflodmancc3d4422017-08-03 08:27:51 -07003078 video_stream_encoder_->Stop();
ilnik6b826ef2017-06-16 06:53:48 -07003079}
3080
mflodmancc3d4422017-08-03 08:27:51 -07003081TEST_F(VideoStreamEncoderTest, PeriodicallyUpdatesChannelParameters) {
sprang4847ae62017-06-27 07:06:52 -07003082 const int kFrameWidth = 1280;
3083 const int kFrameHeight = 720;
3084 const int kLowFps = 2;
3085 const int kHighFps = 30;
3086
mflodmancc3d4422017-08-03 08:27:51 -07003087 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
sprang4847ae62017-06-27 07:06:52 -07003088
3089 int64_t timestamp_ms = fake_clock_.TimeNanos() / rtc::kNumNanosecsPerMillisec;
3090 max_framerate_ = kLowFps;
3091
3092 // Insert 2 seconds of 2fps video.
3093 for (int i = 0; i < kLowFps * 2; ++i) {
3094 video_source_.IncomingCapturedFrame(
3095 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
3096 WaitForEncodedFrame(timestamp_ms);
3097 timestamp_ms += 1000 / kLowFps;
3098 }
3099
3100 // Make sure encoder is updated with new target.
mflodmancc3d4422017-08-03 08:27:51 -07003101 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
sprang4847ae62017-06-27 07:06:52 -07003102 video_source_.IncomingCapturedFrame(
3103 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
3104 WaitForEncodedFrame(timestamp_ms);
3105 timestamp_ms += 1000 / kLowFps;
3106
3107 EXPECT_EQ(kLowFps, fake_encoder_.GetConfiguredInputFramerate());
3108
3109 // Insert 30fps frames for just a little more than the forced update period.
3110 const int kVcmTimerIntervalFrames =
3111 (vcm::VCMProcessTimer::kDefaultProcessIntervalMs * kHighFps) / 1000;
3112 const int kFrameIntervalMs = 1000 / kHighFps;
3113 max_framerate_ = kHighFps;
3114 for (int i = 0; i < kVcmTimerIntervalFrames + 2; ++i) {
3115 video_source_.IncomingCapturedFrame(
3116 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
3117 // Wait for encoded frame, but skip ahead if it doesn't arrive as it might
3118 // be dropped if the encoder hans't been updated with the new higher target
3119 // framerate yet, causing it to overshoot the target bitrate and then
3120 // suffering the wrath of the media optimizer.
3121 TimedWaitForEncodedFrame(timestamp_ms, 2 * kFrameIntervalMs);
3122 timestamp_ms += kFrameIntervalMs;
3123 }
3124
3125 // Don expect correct measurement just yet, but it should be higher than
3126 // before.
3127 EXPECT_GT(fake_encoder_.GetConfiguredInputFramerate(), kLowFps);
3128
mflodmancc3d4422017-08-03 08:27:51 -07003129 video_stream_encoder_->Stop();
sprang4847ae62017-06-27 07:06:52 -07003130}
3131
mflodmancc3d4422017-08-03 08:27:51 -07003132TEST_F(VideoStreamEncoderTest, DoesNotUpdateBitrateAllocationWhenSuspended) {
sprang4847ae62017-06-27 07:06:52 -07003133 const int kFrameWidth = 1280;
3134 const int kFrameHeight = 720;
3135 const int kTargetBitrateBps = 1000000;
3136
3137 MockBitrateObserver bitrate_observer;
Niels Möller0327c2d2018-05-21 14:09:31 +02003138 video_stream_encoder_->SetBitrateAllocationObserver(&bitrate_observer);
sprang4847ae62017-06-27 07:06:52 -07003139
3140 EXPECT_CALL(bitrate_observer, OnBitrateAllocationUpdated(_)).Times(1);
3141 // Initial bitrate update.
mflodmancc3d4422017-08-03 08:27:51 -07003142 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
3143 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
sprang4847ae62017-06-27 07:06:52 -07003144
3145 // Insert a first video frame, causes another bitrate update.
3146 int64_t timestamp_ms = fake_clock_.TimeNanos() / rtc::kNumNanosecsPerMillisec;
3147 EXPECT_CALL(bitrate_observer, OnBitrateAllocationUpdated(_)).Times(1);
3148 video_source_.IncomingCapturedFrame(
3149 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
3150 WaitForEncodedFrame(timestamp_ms);
3151
3152 // Next, simulate video suspension due to pacer queue overrun.
mflodmancc3d4422017-08-03 08:27:51 -07003153 video_stream_encoder_->OnBitrateUpdated(0, 0, 1);
sprang4847ae62017-06-27 07:06:52 -07003154
3155 // Skip ahead until a new periodic parameter update should have occured.
3156 timestamp_ms += vcm::VCMProcessTimer::kDefaultProcessIntervalMs;
3157 fake_clock_.AdvanceTimeMicros(
3158 vcm::VCMProcessTimer::kDefaultProcessIntervalMs *
3159 rtc::kNumMicrosecsPerMillisec);
3160
3161 // Bitrate observer should not be called.
3162 EXPECT_CALL(bitrate_observer, OnBitrateAllocationUpdated(_)).Times(0);
3163 video_source_.IncomingCapturedFrame(
3164 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
3165 ExpectDroppedFrame();
3166
mflodmancc3d4422017-08-03 08:27:51 -07003167 video_stream_encoder_->Stop();
sprang4847ae62017-06-27 07:06:52 -07003168}
ilnik6b826ef2017-06-16 06:53:48 -07003169
Niels Möller4db138e2018-04-19 09:04:13 +02003170TEST_F(VideoStreamEncoderTest,
3171 DefaultCpuAdaptationThresholdsForSoftwareEncoder) {
3172 const int kFrameWidth = 1280;
3173 const int kFrameHeight = 720;
3174 const CpuOveruseOptions default_options;
3175 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
3176 video_source_.IncomingCapturedFrame(
3177 CreateFrame(1, kFrameWidth, kFrameHeight));
3178 WaitForEncodedFrame(1);
3179 EXPECT_EQ(video_stream_encoder_->overuse_detector_proxy_->GetOptions()
3180 .low_encode_usage_threshold_percent,
3181 default_options.low_encode_usage_threshold_percent);
3182 EXPECT_EQ(video_stream_encoder_->overuse_detector_proxy_->GetOptions()
3183 .high_encode_usage_threshold_percent,
3184 default_options.high_encode_usage_threshold_percent);
3185 video_stream_encoder_->Stop();
3186}
3187
3188TEST_F(VideoStreamEncoderTest,
3189 HigherCpuAdaptationThresholdsForHardwareEncoder) {
3190 const int kFrameWidth = 1280;
3191 const int kFrameHeight = 720;
3192 CpuOveruseOptions hardware_options;
3193 hardware_options.low_encode_usage_threshold_percent = 150;
3194 hardware_options.high_encode_usage_threshold_percent = 200;
3195 encoder_factory_.SetIsHardwareAccelerated(true);
3196
3197 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
3198 video_source_.IncomingCapturedFrame(
3199 CreateFrame(1, kFrameWidth, kFrameHeight));
3200 WaitForEncodedFrame(1);
3201 EXPECT_EQ(video_stream_encoder_->overuse_detector_proxy_->GetOptions()
3202 .low_encode_usage_threshold_percent,
3203 hardware_options.low_encode_usage_threshold_percent);
3204 EXPECT_EQ(video_stream_encoder_->overuse_detector_proxy_->GetOptions()
3205 .high_encode_usage_threshold_percent,
3206 hardware_options.high_encode_usage_threshold_percent);
3207 video_stream_encoder_->Stop();
3208}
3209
perkj26091b12016-09-01 01:17:40 -07003210} // namespace webrtc