blob: 684b4323d66dae1e6914660c4854bcb31d136beb [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
Jiawei Ouc2ebe212018-11-08 10:02:56 -080017#include "api/video/builtin_video_bitrate_allocator_factory.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020018#include "api/video/i420_buffer.h"
Erik Språng4529fbc2018-10-12 10:30:31 +020019#include "api/video_codecs/create_vp8_temporal_layers.h"
20#include "api/video_codecs/vp8_temporal_layers.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020021#include "media/base/videoadapter.h"
Sergey Silkin86684962018-03-28 19:32:37 +020022#include "modules/video_coding/codecs/vp9/include/vp9_globals.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020023#include "modules/video_coding/utility/default_video_bitrate_allocator.h"
24#include "rtc_base/fakeclock.h"
25#include "rtc_base/logging.h"
Stefan Holmerdbdb3a02018-07-17 16:03:46 +020026#include "rtc_base/refcountedobject.h"
Mirko Bonadei17f48782018-09-28 08:51:10 +020027#include "system_wrappers/include/metrics.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020028#include "system_wrappers/include/sleep.h"
29#include "test/encoder_settings.h"
30#include "test/fake_encoder.h"
Kári Tristan Helgason639602a2018-08-02 10:51:40 +020031#include "test/field_trial.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020032#include "test/frame_generator.h"
33#include "test/gmock.h"
34#include "test/gtest.h"
Niels Möllercbcbc222018-09-28 09:07:24 +020035#include "test/video_encoder_proxy_factory.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020036#include "video/send_statistics_proxy.h"
perkj26091b12016-09-01 01:17:40 -070037
38namespace webrtc {
39
sprangb1ca0732017-02-01 08:38:12 -080040using ScaleReason = AdaptationObserverInterface::AdaptReason;
sprang57c2fff2017-01-16 06:24:02 -080041using ::testing::_;
42using ::testing::Return;
kthelgason876222f2016-11-29 01:44:11 -080043
perkj803d97f2016-11-01 11:45:46 -070044namespace {
Åsa Persson8c1bf952018-09-13 10:42:19 +020045const int kMinPixelsPerFrame = 320 * 180;
46const int kMinFramerateFps = 2;
47const int kMinBalancedFramerateFps = 7;
48const int64_t kFrameTimeoutMs = 100;
asapersson5f7226f2016-11-25 04:37:00 -080049const size_t kMaxPayloadLength = 1440;
kthelgason2bc68642017-02-07 07:02:22 -080050const int kTargetBitrateBps = 1000000;
51const int kLowTargetBitrateBps = kTargetBitrateBps / 10;
52const int kMaxInitialFramedrop = 4;
sprangfda496a2017-06-15 04:21:07 -070053const int kDefaultFramerate = 30;
Åsa Persson8c1bf952018-09-13 10:42:19 +020054const int64_t kFrameIntervalMs = rtc::kNumMillisecsPerSec / kDefaultFramerate;
asapersson5f7226f2016-11-25 04:37:00 -080055
perkj803d97f2016-11-01 11:45:46 -070056class TestBuffer : public webrtc::I420Buffer {
57 public:
58 TestBuffer(rtc::Event* event, int width, int height)
59 : I420Buffer(width, height), event_(event) {}
60
61 private:
62 friend class rtc::RefCountedObject<TestBuffer>;
63 ~TestBuffer() override {
64 if (event_)
65 event_->Set();
66 }
67 rtc::Event* const event_;
68};
69
Niels Möller7dc26b72017-12-06 10:27:48 +010070class CpuOveruseDetectorProxy : public OveruseFrameDetector {
71 public:
Niels Möllerd1f7eb62018-03-28 16:40:58 +020072 explicit CpuOveruseDetectorProxy(CpuOveruseMetricsObserver* metrics_observer)
73 : OveruseFrameDetector(metrics_observer),
Niels Möller7dc26b72017-12-06 10:27:48 +010074 last_target_framerate_fps_(-1) {}
75 virtual ~CpuOveruseDetectorProxy() {}
76
77 void OnTargetFramerateUpdated(int framerate_fps) override {
78 rtc::CritScope cs(&lock_);
79 last_target_framerate_fps_ = framerate_fps;
80 OveruseFrameDetector::OnTargetFramerateUpdated(framerate_fps);
81 }
82
83 int GetLastTargetFramerate() {
84 rtc::CritScope cs(&lock_);
85 return last_target_framerate_fps_;
86 }
87
Niels Möller4db138e2018-04-19 09:04:13 +020088 CpuOveruseOptions GetOptions() { return options_; }
89
Niels Möller7dc26b72017-12-06 10:27:48 +010090 private:
91 rtc::CriticalSection lock_;
92 int last_target_framerate_fps_ RTC_GUARDED_BY(lock_);
93};
94
mflodmancc3d4422017-08-03 08:27:51 -070095class VideoStreamEncoderUnderTest : public VideoStreamEncoder {
perkj803d97f2016-11-01 11:45:46 -070096 public:
Niels Möller213618e2018-07-24 09:29:58 +020097 VideoStreamEncoderUnderTest(SendStatisticsProxy* stats_proxy,
98 const VideoStreamEncoderSettings& settings)
Yves Gerey665174f2018-06-19 15:03:05 +020099 : VideoStreamEncoder(1 /* number_of_cores */,
100 stats_proxy,
101 settings,
102 nullptr /* pre_encode_callback */,
103 std::unique_ptr<OveruseFrameDetector>(
104 overuse_detector_proxy_ =
105 new CpuOveruseDetectorProxy(stats_proxy))) {}
perkj803d97f2016-11-01 11:45:46 -0700106
sprangb1ca0732017-02-01 08:38:12 -0800107 void PostTaskAndWait(bool down, AdaptReason reason) {
Niels Möllerc572ff32018-11-07 08:43:50 +0100108 rtc::Event event;
kthelgason876222f2016-11-29 01:44:11 -0800109 encoder_queue()->PostTask([this, &event, reason, down] {
sprangb1ca0732017-02-01 08:38:12 -0800110 down ? AdaptDown(reason) : AdaptUp(reason);
perkj803d97f2016-11-01 11:45:46 -0700111 event.Set();
112 });
perkj070ba852017-02-16 15:46:27 -0800113 ASSERT_TRUE(event.Wait(5000));
perkj803d97f2016-11-01 11:45:46 -0700114 }
115
kthelgason2fc52542017-03-03 00:24:41 -0800116 // This is used as a synchronisation mechanism, to make sure that the
117 // encoder queue is not blocked before we start sending it frames.
118 void WaitUntilTaskQueueIsIdle() {
Niels Möllerc572ff32018-11-07 08:43:50 +0100119 rtc::Event event;
Yves Gerey665174f2018-06-19 15:03:05 +0200120 encoder_queue()->PostTask([&event] { event.Set(); });
kthelgason2fc52542017-03-03 00:24:41 -0800121 ASSERT_TRUE(event.Wait(5000));
122 }
123
sprangb1ca0732017-02-01 08:38:12 -0800124 void TriggerCpuOveruse() { PostTaskAndWait(true, AdaptReason::kCpu); }
kthelgason876222f2016-11-29 01:44:11 -0800125
sprangb1ca0732017-02-01 08:38:12 -0800126 void TriggerCpuNormalUsage() { PostTaskAndWait(false, AdaptReason::kCpu); }
kthelgason876222f2016-11-29 01:44:11 -0800127
sprangb1ca0732017-02-01 08:38:12 -0800128 void TriggerQualityLow() { PostTaskAndWait(true, AdaptReason::kQuality); }
kthelgason876222f2016-11-29 01:44:11 -0800129
sprangb1ca0732017-02-01 08:38:12 -0800130 void TriggerQualityHigh() { PostTaskAndWait(false, AdaptReason::kQuality); }
sprangfda496a2017-06-15 04:21:07 -0700131
Niels Möller7dc26b72017-12-06 10:27:48 +0100132 CpuOveruseDetectorProxy* overuse_detector_proxy_;
perkj803d97f2016-11-01 11:45:46 -0700133};
134
asapersson5f7226f2016-11-25 04:37:00 -0800135class VideoStreamFactory
136 : public VideoEncoderConfig::VideoStreamFactoryInterface {
137 public:
sprangfda496a2017-06-15 04:21:07 -0700138 explicit VideoStreamFactory(size_t num_temporal_layers, int framerate)
139 : num_temporal_layers_(num_temporal_layers), framerate_(framerate) {
asapersson5f7226f2016-11-25 04:37:00 -0800140 EXPECT_GT(num_temporal_layers, 0u);
sprangfda496a2017-06-15 04:21:07 -0700141 EXPECT_GT(framerate, 0);
asapersson5f7226f2016-11-25 04:37:00 -0800142 }
143
144 private:
145 std::vector<VideoStream> CreateEncoderStreams(
146 int width,
147 int height,
148 const VideoEncoderConfig& encoder_config) override {
149 std::vector<VideoStream> streams =
150 test::CreateVideoStreams(width, height, encoder_config);
151 for (VideoStream& stream : streams) {
Sergey Silkina796a7e2018-03-01 15:11:29 +0100152 stream.num_temporal_layers = num_temporal_layers_;
sprangfda496a2017-06-15 04:21:07 -0700153 stream.max_framerate = framerate_;
asapersson5f7226f2016-11-25 04:37:00 -0800154 }
155 return streams;
156 }
sprangfda496a2017-06-15 04:21:07 -0700157
asapersson5f7226f2016-11-25 04:37:00 -0800158 const size_t num_temporal_layers_;
sprangfda496a2017-06-15 04:21:07 -0700159 const int framerate_;
asapersson5f7226f2016-11-25 04:37:00 -0800160};
161
sprangb1ca0732017-02-01 08:38:12 -0800162class AdaptingFrameForwarder : public test::FrameForwarder {
163 public:
164 AdaptingFrameForwarder() : adaptation_enabled_(false) {}
asaperssonfab67072017-04-04 05:51:49 -0700165 ~AdaptingFrameForwarder() override {}
sprangb1ca0732017-02-01 08:38:12 -0800166
167 void set_adaptation_enabled(bool enabled) {
168 rtc::CritScope cs(&crit_);
169 adaptation_enabled_ = enabled;
170 }
171
asaperssonfab67072017-04-04 05:51:49 -0700172 bool adaption_enabled() const {
sprangb1ca0732017-02-01 08:38:12 -0800173 rtc::CritScope cs(&crit_);
174 return adaptation_enabled_;
175 }
176
asapersson09f05612017-05-15 23:40:18 -0700177 rtc::VideoSinkWants last_wants() const {
178 rtc::CritScope cs(&crit_);
179 return last_wants_;
180 }
181
Danil Chapovalovb9b146c2018-06-15 12:28:07 +0200182 absl::optional<int> last_sent_width() const { return last_width_; }
183 absl::optional<int> last_sent_height() const { return last_height_; }
Jonathan Yubc771b72017-12-08 17:04:29 -0800184
sprangb1ca0732017-02-01 08:38:12 -0800185 void IncomingCapturedFrame(const VideoFrame& video_frame) override {
186 int cropped_width = 0;
187 int cropped_height = 0;
188 int out_width = 0;
189 int out_height = 0;
sprangc5d62e22017-04-02 23:53:04 -0700190 if (adaption_enabled()) {
191 if (adapter_.AdaptFrameResolution(
192 video_frame.width(), video_frame.height(),
193 video_frame.timestamp_us() * 1000, &cropped_width,
194 &cropped_height, &out_width, &out_height)) {
195 VideoFrame adapted_frame(new rtc::RefCountedObject<TestBuffer>(
196 nullptr, out_width, out_height),
197 99, 99, kVideoRotation_0);
198 adapted_frame.set_ntp_time_ms(video_frame.ntp_time_ms());
199 test::FrameForwarder::IncomingCapturedFrame(adapted_frame);
Jonathan Yubc771b72017-12-08 17:04:29 -0800200 last_width_.emplace(adapted_frame.width());
201 last_height_.emplace(adapted_frame.height());
202 } else {
Danil Chapovalovb9b146c2018-06-15 12:28:07 +0200203 last_width_ = absl::nullopt;
204 last_height_ = absl::nullopt;
sprangc5d62e22017-04-02 23:53:04 -0700205 }
sprangb1ca0732017-02-01 08:38:12 -0800206 } else {
207 test::FrameForwarder::IncomingCapturedFrame(video_frame);
Jonathan Yubc771b72017-12-08 17:04:29 -0800208 last_width_.emplace(video_frame.width());
209 last_height_.emplace(video_frame.height());
sprangb1ca0732017-02-01 08:38:12 -0800210 }
211 }
212
213 void AddOrUpdateSink(rtc::VideoSinkInterface<VideoFrame>* sink,
214 const rtc::VideoSinkWants& wants) override {
215 rtc::CritScope cs(&crit_);
asapersson09f05612017-05-15 23:40:18 -0700216 last_wants_ = sink_wants();
sprangc5d62e22017-04-02 23:53:04 -0700217 adapter_.OnResolutionFramerateRequest(wants.target_pixel_count,
218 wants.max_pixel_count,
219 wants.max_framerate_fps);
sprangb1ca0732017-02-01 08:38:12 -0800220 test::FrameForwarder::AddOrUpdateSink(sink, wants);
221 }
sprangb1ca0732017-02-01 08:38:12 -0800222 cricket::VideoAdapter adapter_;
danilchapa37de392017-09-09 04:17:22 -0700223 bool adaptation_enabled_ RTC_GUARDED_BY(crit_);
224 rtc::VideoSinkWants last_wants_ RTC_GUARDED_BY(crit_);
Danil Chapovalovb9b146c2018-06-15 12:28:07 +0200225 absl::optional<int> last_width_;
226 absl::optional<int> last_height_;
sprangb1ca0732017-02-01 08:38:12 -0800227};
sprangc5d62e22017-04-02 23:53:04 -0700228
Niels Möller213618e2018-07-24 09:29:58 +0200229// TODO(nisse): Mock only VideoStreamEncoderObserver.
sprangc5d62e22017-04-02 23:53:04 -0700230class MockableSendStatisticsProxy : public SendStatisticsProxy {
231 public:
232 MockableSendStatisticsProxy(Clock* clock,
233 const VideoSendStream::Config& config,
234 VideoEncoderConfig::ContentType content_type)
235 : SendStatisticsProxy(clock, config, content_type) {}
236
237 VideoSendStream::Stats GetStats() override {
238 rtc::CritScope cs(&lock_);
239 if (mock_stats_)
240 return *mock_stats_;
241 return SendStatisticsProxy::GetStats();
242 }
243
Niels Möller213618e2018-07-24 09:29:58 +0200244 int GetInputFrameRate() const override {
245 rtc::CritScope cs(&lock_);
246 if (mock_stats_)
247 return mock_stats_->input_frame_rate;
248 return SendStatisticsProxy::GetInputFrameRate();
249 }
sprangc5d62e22017-04-02 23:53:04 -0700250 void SetMockStats(const VideoSendStream::Stats& stats) {
251 rtc::CritScope cs(&lock_);
252 mock_stats_.emplace(stats);
253 }
254
255 void ResetMockStats() {
256 rtc::CritScope cs(&lock_);
257 mock_stats_.reset();
258 }
259
260 private:
261 rtc::CriticalSection lock_;
Danil Chapovalovb9b146c2018-06-15 12:28:07 +0200262 absl::optional<VideoSendStream::Stats> mock_stats_ RTC_GUARDED_BY(lock_);
sprangc5d62e22017-04-02 23:53:04 -0700263};
264
sprang4847ae62017-06-27 07:06:52 -0700265class MockBitrateObserver : public VideoBitrateAllocationObserver {
266 public:
Erik Språng566124a2018-04-23 12:32:22 +0200267 MOCK_METHOD1(OnBitrateAllocationUpdated, void(const VideoBitrateAllocation&));
sprang4847ae62017-06-27 07:06:52 -0700268};
269
perkj803d97f2016-11-01 11:45:46 -0700270} // namespace
271
mflodmancc3d4422017-08-03 08:27:51 -0700272class VideoStreamEncoderTest : public ::testing::Test {
perkj26091b12016-09-01 01:17:40 -0700273 public:
274 static const int kDefaultTimeoutMs = 30 * 1000;
275
mflodmancc3d4422017-08-03 08:27:51 -0700276 VideoStreamEncoderTest()
perkj26091b12016-09-01 01:17:40 -0700277 : video_send_config_(VideoSendStream::Config(nullptr)),
perkjfa10b552016-10-02 23:45:26 -0700278 codec_width_(320),
279 codec_height_(240),
Åsa Persson8c1bf952018-09-13 10:42:19 +0200280 max_framerate_(kDefaultFramerate),
perkj26091b12016-09-01 01:17:40 -0700281 fake_encoder_(),
Niels Möller4db138e2018-04-19 09:04:13 +0200282 encoder_factory_(&fake_encoder_),
Jiawei Ouc2ebe212018-11-08 10:02:56 -0800283 bitrate_allocator_factory_(CreateBuiltinVideoBitrateAllocatorFactory()),
sprangc5d62e22017-04-02 23:53:04 -0700284 stats_proxy_(new MockableSendStatisticsProxy(
perkj803d97f2016-11-01 11:45:46 -0700285 Clock::GetRealTimeClock(),
286 video_send_config_,
287 webrtc::VideoEncoderConfig::ContentType::kRealtimeVideo)),
perkj26091b12016-09-01 01:17:40 -0700288 sink_(&fake_encoder_) {}
289
290 void SetUp() override {
perkj803d97f2016-11-01 11:45:46 -0700291 metrics::Reset();
perkj26091b12016-09-01 01:17:40 -0700292 video_send_config_ = VideoSendStream::Config(nullptr);
Niels Möller4db138e2018-04-19 09:04:13 +0200293 video_send_config_.encoder_settings.encoder_factory = &encoder_factory_;
Jiawei Ouc2ebe212018-11-08 10:02:56 -0800294 video_send_config_.encoder_settings.bitrate_allocator_factory =
295 bitrate_allocator_factory_.get();
Niels Möller259a4972018-04-05 15:36:51 +0200296 video_send_config_.rtp.payload_name = "FAKE";
297 video_send_config_.rtp.payload_type = 125;
perkj26091b12016-09-01 01:17:40 -0700298
Per512ecb32016-09-23 15:52:06 +0200299 VideoEncoderConfig video_encoder_config;
Niels Möller259a4972018-04-05 15:36:51 +0200300 test::FillEncoderConfiguration(kVideoCodecVP8, 1, &video_encoder_config);
sprang4847ae62017-06-27 07:06:52 -0700301 video_encoder_config.video_stream_factory =
302 new rtc::RefCountedObject<VideoStreamFactory>(1, max_framerate_);
Erik Språng08127a92016-11-16 16:41:30 +0100303 video_encoder_config_ = video_encoder_config.Copy();
sprang4847ae62017-06-27 07:06:52 -0700304
305 // Framerate limit is specified by the VideoStreamFactory.
306 std::vector<VideoStream> streams =
307 video_encoder_config.video_stream_factory->CreateEncoderStreams(
308 codec_width_, codec_height_, video_encoder_config);
309 max_framerate_ = streams[0].max_framerate;
310 fake_clock_.SetTimeMicros(1234);
311
Niels Möllerf1338562018-04-26 09:51:47 +0200312 ConfigureEncoder(std::move(video_encoder_config));
asapersson5f7226f2016-11-25 04:37:00 -0800313 }
314
Niels Möllerf1338562018-04-26 09:51:47 +0200315 void ConfigureEncoder(VideoEncoderConfig video_encoder_config) {
mflodmancc3d4422017-08-03 08:27:51 -0700316 if (video_stream_encoder_)
317 video_stream_encoder_->Stop();
318 video_stream_encoder_.reset(new VideoStreamEncoderUnderTest(
perkj803d97f2016-11-01 11:45:46 -0700319 stats_proxy_.get(), video_send_config_.encoder_settings));
mflodmancc3d4422017-08-03 08:27:51 -0700320 video_stream_encoder_->SetSink(&sink_, false /* rotation_applied */);
321 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -0700322 &video_source_, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
mflodmancc3d4422017-08-03 08:27:51 -0700323 video_stream_encoder_->SetStartBitrate(kTargetBitrateBps);
324 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
Niels Möllerf1338562018-04-26 09:51:47 +0200325 kMaxPayloadLength);
mflodmancc3d4422017-08-03 08:27:51 -0700326 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
asapersson5f7226f2016-11-25 04:37:00 -0800327 }
328
329 void ResetEncoder(const std::string& payload_name,
330 size_t num_streams,
331 size_t num_temporal_layers,
emircanbbcc3562017-08-18 00:28:40 -0700332 unsigned char num_spatial_layers,
sprang4847ae62017-06-27 07:06:52 -0700333 bool screenshare) {
Niels Möller259a4972018-04-05 15:36:51 +0200334 video_send_config_.rtp.payload_name = payload_name;
asapersson5f7226f2016-11-25 04:37:00 -0800335
336 VideoEncoderConfig video_encoder_config;
Niels Möller259a4972018-04-05 15:36:51 +0200337 video_encoder_config.codec_type = PayloadStringToCodecType(payload_name);
asapersson5f7226f2016-11-25 04:37:00 -0800338 video_encoder_config.number_of_streams = num_streams;
kthelgason2bc68642017-02-07 07:02:22 -0800339 video_encoder_config.max_bitrate_bps = kTargetBitrateBps;
asapersson5f7226f2016-11-25 04:37:00 -0800340 video_encoder_config.video_stream_factory =
sprangfda496a2017-06-15 04:21:07 -0700341 new rtc::RefCountedObject<VideoStreamFactory>(num_temporal_layers,
342 kDefaultFramerate);
sprang4847ae62017-06-27 07:06:52 -0700343 video_encoder_config.content_type =
344 screenshare ? VideoEncoderConfig::ContentType::kScreen
345 : VideoEncoderConfig::ContentType::kRealtimeVideo;
emircanbbcc3562017-08-18 00:28:40 -0700346 if (payload_name == "VP9") {
347 VideoCodecVP9 vp9_settings = VideoEncoder::GetDefaultVp9Settings();
348 vp9_settings.numberOfSpatialLayers = num_spatial_layers;
349 video_encoder_config.encoder_specific_settings =
350 new rtc::RefCountedObject<
351 VideoEncoderConfig::Vp9EncoderSpecificSettings>(vp9_settings);
352 }
Niels Möllerf1338562018-04-26 09:51:47 +0200353 ConfigureEncoder(std::move(video_encoder_config));
perkj26091b12016-09-01 01:17:40 -0700354 }
355
sprang57c2fff2017-01-16 06:24:02 -0800356 VideoFrame CreateFrame(int64_t ntp_time_ms,
357 rtc::Event* destruction_event) const {
Per512ecb32016-09-23 15:52:06 +0200358 VideoFrame frame(new rtc::RefCountedObject<TestBuffer>(
359 destruction_event, codec_width_, codec_height_),
360 99, 99, kVideoRotation_0);
sprang57c2fff2017-01-16 06:24:02 -0800361 frame.set_ntp_time_ms(ntp_time_ms);
perkj26091b12016-09-01 01:17:40 -0700362 return frame;
363 }
364
sprang57c2fff2017-01-16 06:24:02 -0800365 VideoFrame CreateFrame(int64_t ntp_time_ms, int width, int height) const {
perkj803d97f2016-11-01 11:45:46 -0700366 VideoFrame frame(
367 new rtc::RefCountedObject<TestBuffer>(nullptr, width, height), 99, 99,
368 kVideoRotation_0);
sprang57c2fff2017-01-16 06:24:02 -0800369 frame.set_ntp_time_ms(ntp_time_ms);
sprangc5d62e22017-04-02 23:53:04 -0700370 frame.set_timestamp_us(ntp_time_ms * 1000);
perkj803d97f2016-11-01 11:45:46 -0700371 return frame;
372 }
373
asapersson02465b82017-04-10 01:12:52 -0700374 void VerifyNoLimitation(const rtc::VideoSinkWants& wants) {
asapersson02465b82017-04-10 01:12:52 -0700375 EXPECT_EQ(std::numeric_limits<int>::max(), wants.max_framerate_fps);
asapersson09f05612017-05-15 23:40:18 -0700376 EXPECT_EQ(std::numeric_limits<int>::max(), wants.max_pixel_count);
377 EXPECT_FALSE(wants.target_pixel_count);
asapersson02465b82017-04-10 01:12:52 -0700378 }
379
asapersson09f05612017-05-15 23:40:18 -0700380 void VerifyFpsEqResolutionEq(const rtc::VideoSinkWants& wants1,
381 const rtc::VideoSinkWants& wants2) {
382 EXPECT_EQ(wants1.max_framerate_fps, wants2.max_framerate_fps);
383 EXPECT_EQ(wants1.max_pixel_count, wants2.max_pixel_count);
384 }
385
Åsa Persson8c1bf952018-09-13 10:42:19 +0200386 void VerifyFpsMaxResolutionMax(const rtc::VideoSinkWants& wants) {
387 EXPECT_EQ(kDefaultFramerate, wants.max_framerate_fps);
388 EXPECT_EQ(std::numeric_limits<int>::max(), wants.max_pixel_count);
389 EXPECT_FALSE(wants.target_pixel_count);
390 }
391
asapersson09f05612017-05-15 23:40:18 -0700392 void VerifyFpsMaxResolutionLt(const rtc::VideoSinkWants& wants1,
393 const rtc::VideoSinkWants& wants2) {
Åsa Persson8c1bf952018-09-13 10:42:19 +0200394 EXPECT_EQ(kDefaultFramerate, wants1.max_framerate_fps);
asapersson09f05612017-05-15 23:40:18 -0700395 EXPECT_LT(wants1.max_pixel_count, wants2.max_pixel_count);
396 EXPECT_GT(wants1.max_pixel_count, 0);
397 }
398
399 void VerifyFpsMaxResolutionGt(const rtc::VideoSinkWants& wants1,
400 const rtc::VideoSinkWants& wants2) {
Åsa Persson8c1bf952018-09-13 10:42:19 +0200401 EXPECT_EQ(kDefaultFramerate, wants1.max_framerate_fps);
asapersson09f05612017-05-15 23:40:18 -0700402 EXPECT_GT(wants1.max_pixel_count, wants2.max_pixel_count);
403 }
404
asaperssonf7e294d2017-06-13 23:25:22 -0700405 void VerifyFpsMaxResolutionEq(const rtc::VideoSinkWants& wants1,
406 const rtc::VideoSinkWants& wants2) {
Åsa Persson8c1bf952018-09-13 10:42:19 +0200407 EXPECT_EQ(kDefaultFramerate, wants1.max_framerate_fps);
asaperssonf7e294d2017-06-13 23:25:22 -0700408 EXPECT_EQ(wants1.max_pixel_count, wants2.max_pixel_count);
409 }
410
411 void VerifyFpsLtResolutionEq(const rtc::VideoSinkWants& wants1,
412 const rtc::VideoSinkWants& wants2) {
413 EXPECT_LT(wants1.max_framerate_fps, wants2.max_framerate_fps);
414 EXPECT_EQ(wants1.max_pixel_count, wants2.max_pixel_count);
415 }
416
417 void VerifyFpsGtResolutionEq(const rtc::VideoSinkWants& wants1,
418 const rtc::VideoSinkWants& wants2) {
419 EXPECT_GT(wants1.max_framerate_fps, wants2.max_framerate_fps);
420 EXPECT_EQ(wants1.max_pixel_count, wants2.max_pixel_count);
421 }
422
423 void VerifyFpsEqResolutionLt(const rtc::VideoSinkWants& wants1,
424 const rtc::VideoSinkWants& wants2) {
425 EXPECT_EQ(wants1.max_framerate_fps, wants2.max_framerate_fps);
426 EXPECT_LT(wants1.max_pixel_count, wants2.max_pixel_count);
427 EXPECT_GT(wants1.max_pixel_count, 0);
428 }
429
430 void VerifyFpsEqResolutionGt(const rtc::VideoSinkWants& wants1,
431 const rtc::VideoSinkWants& wants2) {
432 EXPECT_EQ(wants1.max_framerate_fps, wants2.max_framerate_fps);
433 EXPECT_GT(wants1.max_pixel_count, wants2.max_pixel_count);
434 }
435
asapersson09f05612017-05-15 23:40:18 -0700436 void VerifyFpsMaxResolutionLt(const rtc::VideoSinkWants& wants,
437 int pixel_count) {
Åsa Persson8c1bf952018-09-13 10:42:19 +0200438 EXPECT_EQ(kDefaultFramerate, wants.max_framerate_fps);
asapersson02465b82017-04-10 01:12:52 -0700439 EXPECT_LT(wants.max_pixel_count, pixel_count);
440 EXPECT_GT(wants.max_pixel_count, 0);
asapersson09f05612017-05-15 23:40:18 -0700441 }
442
443 void VerifyFpsLtResolutionMax(const rtc::VideoSinkWants& wants, int fps) {
444 EXPECT_LT(wants.max_framerate_fps, fps);
445 EXPECT_EQ(std::numeric_limits<int>::max(), wants.max_pixel_count);
446 EXPECT_FALSE(wants.target_pixel_count);
asapersson02465b82017-04-10 01:12:52 -0700447 }
448
asaperssonf7e294d2017-06-13 23:25:22 -0700449 void VerifyFpsEqResolutionMax(const rtc::VideoSinkWants& wants,
450 int expected_fps) {
451 EXPECT_EQ(expected_fps, wants.max_framerate_fps);
452 EXPECT_EQ(std::numeric_limits<int>::max(), wants.max_pixel_count);
453 EXPECT_FALSE(wants.target_pixel_count);
454 }
455
Jonathan Yubc771b72017-12-08 17:04:29 -0800456 void VerifyBalancedModeFpsRange(const rtc::VideoSinkWants& wants,
457 int last_frame_pixels) {
458 // Balanced mode should always scale FPS to the desired range before
459 // attempting to scale resolution.
460 int fps_limit = wants.max_framerate_fps;
461 if (last_frame_pixels <= 320 * 240) {
462 EXPECT_TRUE(7 <= fps_limit && fps_limit <= 10);
463 } else if (last_frame_pixels <= 480 * 270) {
464 EXPECT_TRUE(10 <= fps_limit && fps_limit <= 15);
465 } else if (last_frame_pixels <= 640 * 480) {
466 EXPECT_LE(15, fps_limit);
467 } else {
Åsa Persson8c1bf952018-09-13 10:42:19 +0200468 EXPECT_EQ(kDefaultFramerate, fps_limit);
Jonathan Yubc771b72017-12-08 17:04:29 -0800469 }
470 }
471
sprang4847ae62017-06-27 07:06:52 -0700472 void WaitForEncodedFrame(int64_t expected_ntp_time) {
473 sink_.WaitForEncodedFrame(expected_ntp_time);
474 fake_clock_.AdvanceTimeMicros(rtc::kNumMicrosecsPerSec / max_framerate_);
475 }
476
477 bool TimedWaitForEncodedFrame(int64_t expected_ntp_time, int64_t timeout_ms) {
478 bool ok = sink_.TimedWaitForEncodedFrame(expected_ntp_time, timeout_ms);
479 fake_clock_.AdvanceTimeMicros(rtc::kNumMicrosecsPerSec / max_framerate_);
480 return ok;
481 }
482
483 void WaitForEncodedFrame(uint32_t expected_width, uint32_t expected_height) {
484 sink_.WaitForEncodedFrame(expected_width, expected_height);
485 fake_clock_.AdvanceTimeMicros(rtc::kNumMicrosecsPerSec / max_framerate_);
486 }
487
488 void ExpectDroppedFrame() {
489 sink_.ExpectDroppedFrame();
490 fake_clock_.AdvanceTimeMicros(rtc::kNumMicrosecsPerSec / max_framerate_);
491 }
492
493 bool WaitForFrame(int64_t timeout_ms) {
494 bool ok = sink_.WaitForFrame(timeout_ms);
495 fake_clock_.AdvanceTimeMicros(rtc::kNumMicrosecsPerSec / max_framerate_);
496 return ok;
497 }
498
perkj26091b12016-09-01 01:17:40 -0700499 class TestEncoder : public test::FakeEncoder {
500 public:
Niels Möllerc572ff32018-11-07 08:43:50 +0100501 TestEncoder() : FakeEncoder(Clock::GetRealTimeClock()) {}
perkj26091b12016-09-01 01:17:40 -0700502
asaperssonfab67072017-04-04 05:51:49 -0700503 VideoCodec codec_config() const {
brandtre78d2662017-01-16 05:57:16 -0800504 rtc::CritScope lock(&crit_sect_);
perkjfa10b552016-10-02 23:45:26 -0700505 return config_;
506 }
507
508 void BlockNextEncode() {
brandtre78d2662017-01-16 05:57:16 -0800509 rtc::CritScope lock(&local_crit_sect_);
perkjfa10b552016-10-02 23:45:26 -0700510 block_next_encode_ = true;
511 }
512
Erik Språngaed30702018-11-05 12:57:17 +0100513 VideoEncoder::EncoderInfo GetEncoderInfo() const override {
kthelgason2fc52542017-03-03 00:24:41 -0800514 rtc::CritScope lock(&local_crit_sect_);
Mirta Dvorniciccdc5eb02018-12-05 13:22:09 +0100515 EncoderInfo info = FakeEncoder::GetEncoderInfo();
Erik Språngaed30702018-11-05 12:57:17 +0100516 if (quality_scaling_) {
517 info.scaling_settings =
518 VideoEncoder::ScalingSettings(1, 2, kMinPixelsPerFrame);
519 }
520 return info;
kthelgason876222f2016-11-29 01:44:11 -0800521 }
522
perkjfa10b552016-10-02 23:45:26 -0700523 void ContinueEncode() { continue_encode_event_.Set(); }
524
525 void CheckLastTimeStampsMatch(int64_t ntp_time_ms,
526 uint32_t timestamp) const {
brandtre78d2662017-01-16 05:57:16 -0800527 rtc::CritScope lock(&local_crit_sect_);
perkjfa10b552016-10-02 23:45:26 -0700528 EXPECT_EQ(timestamp_, timestamp);
529 EXPECT_EQ(ntp_time_ms_, ntp_time_ms);
530 }
531
kthelgason2fc52542017-03-03 00:24:41 -0800532 void SetQualityScaling(bool b) {
533 rtc::CritScope lock(&local_crit_sect_);
534 quality_scaling_ = b;
535 }
kthelgasonad9010c2017-02-14 00:46:51 -0800536
sprangfe627f32017-03-29 08:24:59 -0700537 void ForceInitEncodeFailure(bool force_failure) {
538 rtc::CritScope lock(&local_crit_sect_);
539 force_init_encode_failed_ = force_failure;
540 }
541
perkjfa10b552016-10-02 23:45:26 -0700542 private:
perkj26091b12016-09-01 01:17:40 -0700543 int32_t Encode(const VideoFrame& input_image,
544 const CodecSpecificInfo* codec_specific_info,
545 const std::vector<FrameType>* frame_types) override {
546 bool block_encode;
547 {
brandtre78d2662017-01-16 05:57:16 -0800548 rtc::CritScope lock(&local_crit_sect_);
perkj26091b12016-09-01 01:17:40 -0700549 EXPECT_GT(input_image.timestamp(), timestamp_);
550 EXPECT_GT(input_image.ntp_time_ms(), ntp_time_ms_);
551 EXPECT_EQ(input_image.timestamp(), input_image.ntp_time_ms() * 90);
552
553 timestamp_ = input_image.timestamp();
554 ntp_time_ms_ = input_image.ntp_time_ms();
perkj803d97f2016-11-01 11:45:46 -0700555 last_input_width_ = input_image.width();
556 last_input_height_ = input_image.height();
perkj26091b12016-09-01 01:17:40 -0700557 block_encode = block_next_encode_;
558 block_next_encode_ = false;
559 }
560 int32_t result =
561 FakeEncoder::Encode(input_image, codec_specific_info, frame_types);
562 if (block_encode)
perkja49cbd32016-09-16 07:53:41 -0700563 EXPECT_TRUE(continue_encode_event_.Wait(kDefaultTimeoutMs));
perkj26091b12016-09-01 01:17:40 -0700564 return result;
565 }
566
sprangfe627f32017-03-29 08:24:59 -0700567 int32_t InitEncode(const VideoCodec* config,
568 int32_t number_of_cores,
569 size_t max_payload_size) override {
570 int res =
571 FakeEncoder::InitEncode(config, number_of_cores, max_payload_size);
572 rtc::CritScope lock(&local_crit_sect_);
Erik Språng82fad3d2018-03-21 09:57:23 +0100573 if (config->codecType == kVideoCodecVP8) {
sprangfe627f32017-03-29 08:24:59 -0700574 // Simulate setting up temporal layers, in order to validate the life
575 // cycle of these objects.
576 int num_streams = std::max<int>(1, config->numberOfSimulcastStreams);
sprangfe627f32017-03-29 08:24:59 -0700577 for (int i = 0; i < num_streams; ++i) {
578 allocated_temporal_layers_.emplace_back(
Erik Språng4529fbc2018-10-12 10:30:31 +0200579 CreateVp8TemporalLayers(Vp8TemporalLayersType::kFixedPattern,
580 config->VP8().numberOfTemporalLayers));
sprangfe627f32017-03-29 08:24:59 -0700581 }
582 }
583 if (force_init_encode_failed_)
584 return -1;
585 return res;
586 }
587
brandtre78d2662017-01-16 05:57:16 -0800588 rtc::CriticalSection local_crit_sect_;
danilchapa37de392017-09-09 04:17:22 -0700589 bool block_next_encode_ RTC_GUARDED_BY(local_crit_sect_) = false;
perkj26091b12016-09-01 01:17:40 -0700590 rtc::Event continue_encode_event_;
danilchapa37de392017-09-09 04:17:22 -0700591 uint32_t timestamp_ RTC_GUARDED_BY(local_crit_sect_) = 0;
592 int64_t ntp_time_ms_ RTC_GUARDED_BY(local_crit_sect_) = 0;
593 int last_input_width_ RTC_GUARDED_BY(local_crit_sect_) = 0;
594 int last_input_height_ RTC_GUARDED_BY(local_crit_sect_) = 0;
595 bool quality_scaling_ RTC_GUARDED_BY(local_crit_sect_) = true;
Erik Språng4529fbc2018-10-12 10:30:31 +0200596 std::vector<std::unique_ptr<Vp8TemporalLayers>> allocated_temporal_layers_
danilchapa37de392017-09-09 04:17:22 -0700597 RTC_GUARDED_BY(local_crit_sect_);
598 bool force_init_encode_failed_ RTC_GUARDED_BY(local_crit_sect_) = false;
perkj26091b12016-09-01 01:17:40 -0700599 };
600
mflodmancc3d4422017-08-03 08:27:51 -0700601 class TestSink : public VideoStreamEncoder::EncoderSink {
perkj26091b12016-09-01 01:17:40 -0700602 public:
603 explicit TestSink(TestEncoder* test_encoder)
Niels Möllerc572ff32018-11-07 08:43:50 +0100604 : test_encoder_(test_encoder) {}
perkj26091b12016-09-01 01:17:40 -0700605
perkj26091b12016-09-01 01:17:40 -0700606 void WaitForEncodedFrame(int64_t expected_ntp_time) {
sprang4847ae62017-06-27 07:06:52 -0700607 EXPECT_TRUE(
608 TimedWaitForEncodedFrame(expected_ntp_time, kDefaultTimeoutMs));
609 }
610
611 bool TimedWaitForEncodedFrame(int64_t expected_ntp_time,
612 int64_t timeout_ms) {
perkj26091b12016-09-01 01:17:40 -0700613 uint32_t timestamp = 0;
sprang4847ae62017-06-27 07:06:52 -0700614 if (!encoded_frame_event_.Wait(timeout_ms))
615 return false;
perkj26091b12016-09-01 01:17:40 -0700616 {
617 rtc::CritScope lock(&crit_);
sprangb1ca0732017-02-01 08:38:12 -0800618 timestamp = last_timestamp_;
perkj26091b12016-09-01 01:17:40 -0700619 }
620 test_encoder_->CheckLastTimeStampsMatch(expected_ntp_time, timestamp);
sprang4847ae62017-06-27 07:06:52 -0700621 return true;
perkj26091b12016-09-01 01:17:40 -0700622 }
623
sprangb1ca0732017-02-01 08:38:12 -0800624 void WaitForEncodedFrame(uint32_t expected_width,
625 uint32_t expected_height) {
sprangc5d62e22017-04-02 23:53:04 -0700626 EXPECT_TRUE(encoded_frame_event_.Wait(kDefaultTimeoutMs));
Åsa Perssonc74d8da2017-12-04 14:13:56 +0100627 CheckLastFrameSizeMatches(expected_width, expected_height);
sprangc5d62e22017-04-02 23:53:04 -0700628 }
629
Åsa Perssonc74d8da2017-12-04 14:13:56 +0100630 void CheckLastFrameSizeMatches(uint32_t expected_width,
sprangc5d62e22017-04-02 23:53:04 -0700631 uint32_t expected_height) {
sprangb1ca0732017-02-01 08:38:12 -0800632 uint32_t width = 0;
633 uint32_t height = 0;
sprangb1ca0732017-02-01 08:38:12 -0800634 {
635 rtc::CritScope lock(&crit_);
636 width = last_width_;
637 height = last_height_;
638 }
639 EXPECT_EQ(expected_height, height);
640 EXPECT_EQ(expected_width, width);
641 }
642
kthelgason2fc52542017-03-03 00:24:41 -0800643 void ExpectDroppedFrame() { EXPECT_FALSE(encoded_frame_event_.Wait(100)); }
kthelgason2bc68642017-02-07 07:02:22 -0800644
sprangc5d62e22017-04-02 23:53:04 -0700645 bool WaitForFrame(int64_t timeout_ms) {
646 return encoded_frame_event_.Wait(timeout_ms);
647 }
648
perkj26091b12016-09-01 01:17:40 -0700649 void SetExpectNoFrames() {
650 rtc::CritScope lock(&crit_);
651 expect_frames_ = false;
652 }
653
asaperssonfab67072017-04-04 05:51:49 -0700654 int number_of_reconfigurations() const {
Per512ecb32016-09-23 15:52:06 +0200655 rtc::CritScope lock(&crit_);
656 return number_of_reconfigurations_;
657 }
658
asaperssonfab67072017-04-04 05:51:49 -0700659 int last_min_transmit_bitrate() const {
Per512ecb32016-09-23 15:52:06 +0200660 rtc::CritScope lock(&crit_);
661 return min_transmit_bitrate_bps_;
662 }
663
perkj26091b12016-09-01 01:17:40 -0700664 private:
sergeyu2cb155a2016-11-04 11:39:29 -0700665 Result OnEncodedImage(
666 const EncodedImage& encoded_image,
667 const CodecSpecificInfo* codec_specific_info,
668 const RTPFragmentationHeader* fragmentation) override {
Per512ecb32016-09-23 15:52:06 +0200669 rtc::CritScope lock(&crit_);
670 EXPECT_TRUE(expect_frames_);
Niels Möller23775882018-08-16 10:24:12 +0200671 last_timestamp_ = encoded_image.Timestamp();
sprangb1ca0732017-02-01 08:38:12 -0800672 last_width_ = encoded_image._encodedWidth;
673 last_height_ = encoded_image._encodedHeight;
Per512ecb32016-09-23 15:52:06 +0200674 encoded_frame_event_.Set();
sprangb1ca0732017-02-01 08:38:12 -0800675 return Result(Result::OK, last_timestamp_);
Per512ecb32016-09-23 15:52:06 +0200676 }
677
678 void OnEncoderConfigurationChanged(std::vector<VideoStream> streams,
679 int min_transmit_bitrate_bps) override {
680 rtc::CriticalSection crit_;
681 ++number_of_reconfigurations_;
682 min_transmit_bitrate_bps_ = min_transmit_bitrate_bps;
683 }
684
perkj26091b12016-09-01 01:17:40 -0700685 rtc::CriticalSection crit_;
686 TestEncoder* test_encoder_;
687 rtc::Event encoded_frame_event_;
sprangb1ca0732017-02-01 08:38:12 -0800688 uint32_t last_timestamp_ = 0;
689 uint32_t last_height_ = 0;
690 uint32_t last_width_ = 0;
perkj26091b12016-09-01 01:17:40 -0700691 bool expect_frames_ = true;
Per512ecb32016-09-23 15:52:06 +0200692 int number_of_reconfigurations_ = 0;
693 int min_transmit_bitrate_bps_ = 0;
perkj26091b12016-09-01 01:17:40 -0700694 };
695
696 VideoSendStream::Config video_send_config_;
Erik Språng08127a92016-11-16 16:41:30 +0100697 VideoEncoderConfig video_encoder_config_;
Per512ecb32016-09-23 15:52:06 +0200698 int codec_width_;
699 int codec_height_;
sprang4847ae62017-06-27 07:06:52 -0700700 int max_framerate_;
perkj26091b12016-09-01 01:17:40 -0700701 TestEncoder fake_encoder_;
Niels Möllercbcbc222018-09-28 09:07:24 +0200702 test::VideoEncoderProxyFactory encoder_factory_;
Jiawei Ouc2ebe212018-11-08 10:02:56 -0800703 std::unique_ptr<VideoBitrateAllocatorFactory> bitrate_allocator_factory_;
sprangc5d62e22017-04-02 23:53:04 -0700704 std::unique_ptr<MockableSendStatisticsProxy> stats_proxy_;
perkj26091b12016-09-01 01:17:40 -0700705 TestSink sink_;
sprangb1ca0732017-02-01 08:38:12 -0800706 AdaptingFrameForwarder video_source_;
mflodmancc3d4422017-08-03 08:27:51 -0700707 std::unique_ptr<VideoStreamEncoderUnderTest> video_stream_encoder_;
sprang4847ae62017-06-27 07:06:52 -0700708 rtc::ScopedFakeClock fake_clock_;
perkj26091b12016-09-01 01:17:40 -0700709};
710
mflodmancc3d4422017-08-03 08:27:51 -0700711TEST_F(VideoStreamEncoderTest, EncodeOneFrame) {
712 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
Niels Möllerc572ff32018-11-07 08:43:50 +0100713 rtc::Event frame_destroyed_event;
perkja49cbd32016-09-16 07:53:41 -0700714 video_source_.IncomingCapturedFrame(CreateFrame(1, &frame_destroyed_event));
sprang4847ae62017-06-27 07:06:52 -0700715 WaitForEncodedFrame(1);
perkja49cbd32016-09-16 07:53:41 -0700716 EXPECT_TRUE(frame_destroyed_event.Wait(kDefaultTimeoutMs));
mflodmancc3d4422017-08-03 08:27:51 -0700717 video_stream_encoder_->Stop();
perkj26091b12016-09-01 01:17:40 -0700718}
719
mflodmancc3d4422017-08-03 08:27:51 -0700720TEST_F(VideoStreamEncoderTest, DropsFramesBeforeFirstOnBitrateUpdated) {
perkj26091b12016-09-01 01:17:40 -0700721 // Dropped since no target bitrate has been set.
Niels Möllerc572ff32018-11-07 08:43:50 +0100722 rtc::Event frame_destroyed_event;
Sebastian Janssona3177052018-04-10 13:05:49 +0200723 // The encoder will cache up to one frame for a short duration. Adding two
724 // frames means that the first frame will be dropped and the second frame will
725 // be sent when the encoder is enabled.
perkja49cbd32016-09-16 07:53:41 -0700726 video_source_.IncomingCapturedFrame(CreateFrame(1, &frame_destroyed_event));
Sebastian Janssona3177052018-04-10 13:05:49 +0200727 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
perkja49cbd32016-09-16 07:53:41 -0700728 EXPECT_TRUE(frame_destroyed_event.Wait(kDefaultTimeoutMs));
perkj26091b12016-09-01 01:17:40 -0700729
mflodmancc3d4422017-08-03 08:27:51 -0700730 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkj26091b12016-09-01 01:17:40 -0700731
Sebastian Janssona3177052018-04-10 13:05:49 +0200732 // The pending frame should be received.
sprang4847ae62017-06-27 07:06:52 -0700733 WaitForEncodedFrame(2);
Sebastian Janssona3177052018-04-10 13:05:49 +0200734 video_source_.IncomingCapturedFrame(CreateFrame(3, nullptr));
735
736 WaitForEncodedFrame(3);
mflodmancc3d4422017-08-03 08:27:51 -0700737 video_stream_encoder_->Stop();
perkj26091b12016-09-01 01:17:40 -0700738}
739
mflodmancc3d4422017-08-03 08:27:51 -0700740TEST_F(VideoStreamEncoderTest, DropsFramesWhenRateSetToZero) {
741 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkja49cbd32016-09-16 07:53:41 -0700742 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700743 WaitForEncodedFrame(1);
perkj26091b12016-09-01 01:17:40 -0700744
mflodmancc3d4422017-08-03 08:27:51 -0700745 video_stream_encoder_->OnBitrateUpdated(0, 0, 0);
Sebastian Janssona3177052018-04-10 13:05:49 +0200746 // The encoder will cache up to one frame for a short duration. Adding two
747 // frames means that the first frame will be dropped and the second frame will
748 // be sent when the encoder is resumed.
perkja49cbd32016-09-16 07:53:41 -0700749 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
Sebastian Janssona3177052018-04-10 13:05:49 +0200750 video_source_.IncomingCapturedFrame(CreateFrame(3, nullptr));
perkj26091b12016-09-01 01:17:40 -0700751
mflodmancc3d4422017-08-03 08:27:51 -0700752 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
sprang4847ae62017-06-27 07:06:52 -0700753 WaitForEncodedFrame(3);
Sebastian Janssona3177052018-04-10 13:05:49 +0200754 video_source_.IncomingCapturedFrame(CreateFrame(4, nullptr));
755 WaitForEncodedFrame(4);
mflodmancc3d4422017-08-03 08:27:51 -0700756 video_stream_encoder_->Stop();
perkj26091b12016-09-01 01:17:40 -0700757}
758
mflodmancc3d4422017-08-03 08:27:51 -0700759TEST_F(VideoStreamEncoderTest, DropsFramesWithSameOrOldNtpTimestamp) {
760 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkja49cbd32016-09-16 07:53:41 -0700761 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700762 WaitForEncodedFrame(1);
perkj26091b12016-09-01 01:17:40 -0700763
764 // This frame will be dropped since it has the same ntp timestamp.
perkja49cbd32016-09-16 07:53:41 -0700765 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
perkj26091b12016-09-01 01:17:40 -0700766
perkja49cbd32016-09-16 07:53:41 -0700767 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700768 WaitForEncodedFrame(2);
mflodmancc3d4422017-08-03 08:27:51 -0700769 video_stream_encoder_->Stop();
perkj26091b12016-09-01 01:17:40 -0700770}
771
mflodmancc3d4422017-08-03 08:27:51 -0700772TEST_F(VideoStreamEncoderTest, DropsFrameAfterStop) {
773 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkj26091b12016-09-01 01:17:40 -0700774
perkja49cbd32016-09-16 07:53:41 -0700775 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700776 WaitForEncodedFrame(1);
perkj26091b12016-09-01 01:17:40 -0700777
mflodmancc3d4422017-08-03 08:27:51 -0700778 video_stream_encoder_->Stop();
perkj26091b12016-09-01 01:17:40 -0700779 sink_.SetExpectNoFrames();
Niels Möllerc572ff32018-11-07 08:43:50 +0100780 rtc::Event frame_destroyed_event;
perkja49cbd32016-09-16 07:53:41 -0700781 video_source_.IncomingCapturedFrame(CreateFrame(2, &frame_destroyed_event));
782 EXPECT_TRUE(frame_destroyed_event.Wait(kDefaultTimeoutMs));
perkj26091b12016-09-01 01:17:40 -0700783}
784
mflodmancc3d4422017-08-03 08:27:51 -0700785TEST_F(VideoStreamEncoderTest, DropsPendingFramesOnSlowEncode) {
786 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkj26091b12016-09-01 01:17:40 -0700787
788 fake_encoder_.BlockNextEncode();
perkja49cbd32016-09-16 07:53:41 -0700789 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700790 WaitForEncodedFrame(1);
perkj26091b12016-09-01 01:17:40 -0700791 // Here, the encoder thread will be blocked in the TestEncoder waiting for a
792 // call to ContinueEncode.
perkja49cbd32016-09-16 07:53:41 -0700793 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
794 video_source_.IncomingCapturedFrame(CreateFrame(3, nullptr));
perkj26091b12016-09-01 01:17:40 -0700795 fake_encoder_.ContinueEncode();
sprang4847ae62017-06-27 07:06:52 -0700796 WaitForEncodedFrame(3);
perkj26091b12016-09-01 01:17:40 -0700797
mflodmancc3d4422017-08-03 08:27:51 -0700798 video_stream_encoder_->Stop();
perkj26091b12016-09-01 01:17:40 -0700799}
800
mflodmancc3d4422017-08-03 08:27:51 -0700801TEST_F(VideoStreamEncoderTest,
802 ConfigureEncoderTriggersOnEncoderConfigurationChanged) {
803 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
Per21d45d22016-10-30 21:37:57 +0100804 EXPECT_EQ(0, sink_.number_of_reconfigurations());
Per512ecb32016-09-23 15:52:06 +0200805
806 // Capture a frame and wait for it to synchronize with the encoder thread.
Perf8c5f2b2016-09-23 16:24:55 +0200807 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700808 WaitForEncodedFrame(1);
Per21d45d22016-10-30 21:37:57 +0100809 // The encoder will have been configured once when the first frame is
810 // received.
811 EXPECT_EQ(1, sink_.number_of_reconfigurations());
Per512ecb32016-09-23 15:52:06 +0200812
813 VideoEncoderConfig video_encoder_config;
Niels Möller259a4972018-04-05 15:36:51 +0200814 test::FillEncoderConfiguration(kVideoCodecVP8, 1, &video_encoder_config);
Per512ecb32016-09-23 15:52:06 +0200815 video_encoder_config.min_transmit_bitrate_bps = 9999;
mflodmancc3d4422017-08-03 08:27:51 -0700816 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
Niels Möllerf1338562018-04-26 09:51:47 +0200817 kMaxPayloadLength);
Per512ecb32016-09-23 15:52:06 +0200818
819 // Capture a frame and wait for it to synchronize with the encoder thread.
Perf8c5f2b2016-09-23 16:24:55 +0200820 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700821 WaitForEncodedFrame(2);
Per21d45d22016-10-30 21:37:57 +0100822 EXPECT_EQ(2, sink_.number_of_reconfigurations());
perkj3b703ed2016-09-29 23:25:40 -0700823 EXPECT_EQ(9999, sink_.last_min_transmit_bitrate());
perkj26105b42016-09-29 22:39:10 -0700824
mflodmancc3d4422017-08-03 08:27:51 -0700825 video_stream_encoder_->Stop();
perkj26105b42016-09-29 22:39:10 -0700826}
827
mflodmancc3d4422017-08-03 08:27:51 -0700828TEST_F(VideoStreamEncoderTest, FrameResolutionChangeReconfigureEncoder) {
829 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkjfa10b552016-10-02 23:45:26 -0700830
831 // Capture a frame and wait for it to synchronize with the encoder thread.
832 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700833 WaitForEncodedFrame(1);
Per21d45d22016-10-30 21:37:57 +0100834 // The encoder will have been configured once.
835 EXPECT_EQ(1, sink_.number_of_reconfigurations());
perkjfa10b552016-10-02 23:45:26 -0700836 EXPECT_EQ(codec_width_, fake_encoder_.codec_config().width);
837 EXPECT_EQ(codec_height_, fake_encoder_.codec_config().height);
838
839 codec_width_ *= 2;
840 codec_height_ *= 2;
841 // Capture a frame with a higher resolution and wait for it to synchronize
842 // with the encoder thread.
843 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700844 WaitForEncodedFrame(2);
perkjfa10b552016-10-02 23:45:26 -0700845 EXPECT_EQ(codec_width_, fake_encoder_.codec_config().width);
846 EXPECT_EQ(codec_height_, fake_encoder_.codec_config().height);
Per21d45d22016-10-30 21:37:57 +0100847 EXPECT_EQ(2, sink_.number_of_reconfigurations());
perkjfa10b552016-10-02 23:45:26 -0700848
mflodmancc3d4422017-08-03 08:27:51 -0700849 video_stream_encoder_->Stop();
perkjfa10b552016-10-02 23:45:26 -0700850}
851
mflodmancc3d4422017-08-03 08:27:51 -0700852TEST_F(VideoStreamEncoderTest, SwitchSourceDeregisterEncoderAsSink) {
perkj803d97f2016-11-01 11:45:46 -0700853 EXPECT_TRUE(video_source_.has_sinks());
854 test::FrameForwarder new_video_source;
mflodmancc3d4422017-08-03 08:27:51 -0700855 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -0700856 &new_video_source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
perkj803d97f2016-11-01 11:45:46 -0700857 EXPECT_FALSE(video_source_.has_sinks());
858 EXPECT_TRUE(new_video_source.has_sinks());
859
mflodmancc3d4422017-08-03 08:27:51 -0700860 video_stream_encoder_->Stop();
perkj803d97f2016-11-01 11:45:46 -0700861}
862
mflodmancc3d4422017-08-03 08:27:51 -0700863TEST_F(VideoStreamEncoderTest, SinkWantsRotationApplied) {
perkj803d97f2016-11-01 11:45:46 -0700864 EXPECT_FALSE(video_source_.sink_wants().rotation_applied);
mflodmancc3d4422017-08-03 08:27:51 -0700865 video_stream_encoder_->SetSink(&sink_, true /*rotation_applied*/);
perkj803d97f2016-11-01 11:45:46 -0700866 EXPECT_TRUE(video_source_.sink_wants().rotation_applied);
mflodmancc3d4422017-08-03 08:27:51 -0700867 video_stream_encoder_->Stop();
perkj803d97f2016-11-01 11:45:46 -0700868}
869
Jonathan Yubc771b72017-12-08 17:04:29 -0800870TEST_F(VideoStreamEncoderTest, TestCpuDowngrades_BalancedMode) {
871 const int kFramerateFps = 30;
asaperssonf7e294d2017-06-13 23:25:22 -0700872 const int kWidth = 1280;
873 const int kHeight = 720;
Jonathan Yubc771b72017-12-08 17:04:29 -0800874
875 // We rely on the automatic resolution adaptation, but we handle framerate
876 // adaptation manually by mocking the stats proxy.
877 video_source_.set_adaptation_enabled(true);
asaperssonf7e294d2017-06-13 23:25:22 -0700878
Taylor Brandstetter49fcc102018-05-16 14:20:41 -0700879 // Enable BALANCED preference, no initial limitation.
Jonathan Yubc771b72017-12-08 17:04:29 -0800880 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
Taylor Brandstetter49fcc102018-05-16 14:20:41 -0700881 video_stream_encoder_->SetSource(&video_source_,
882 webrtc::DegradationPreference::BALANCED);
Jonathan Yubc771b72017-12-08 17:04:29 -0800883 VerifyNoLimitation(video_source_.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -0700884 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
Jonathan Yubc771b72017-12-08 17:04:29 -0800885 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
asaperssonf7e294d2017-06-13 23:25:22 -0700886 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
887
Jonathan Yubc771b72017-12-08 17:04:29 -0800888 // Adapt down as far as possible.
889 rtc::VideoSinkWants last_wants;
890 int64_t t = 1;
891 int loop_count = 0;
892 do {
893 ++loop_count;
894 last_wants = video_source_.sink_wants();
895
896 // Simulate the framerate we've been asked to adapt to.
897 const int fps = std::min(kFramerateFps, last_wants.max_framerate_fps);
898 const int frame_interval_ms = rtc::kNumMillisecsPerSec / fps;
899 VideoSendStream::Stats mock_stats = stats_proxy_->GetStats();
900 mock_stats.input_frame_rate = fps;
901 stats_proxy_->SetMockStats(mock_stats);
902
903 video_source_.IncomingCapturedFrame(CreateFrame(t, kWidth, kHeight));
904 sink_.WaitForEncodedFrame(t);
905 t += frame_interval_ms;
906
mflodmancc3d4422017-08-03 08:27:51 -0700907 video_stream_encoder_->TriggerCpuOveruse();
Jonathan Yubc771b72017-12-08 17:04:29 -0800908 VerifyBalancedModeFpsRange(
909 video_source_.sink_wants(),
910 *video_source_.last_sent_width() * *video_source_.last_sent_height());
911 } while (video_source_.sink_wants().max_pixel_count <
912 last_wants.max_pixel_count ||
913 video_source_.sink_wants().max_framerate_fps <
914 last_wants.max_framerate_fps);
asaperssonf7e294d2017-06-13 23:25:22 -0700915
Jonathan Yubc771b72017-12-08 17:04:29 -0800916 // Verify that we've adapted all the way down.
917 stats_proxy_->ResetMockStats();
asaperssonf7e294d2017-06-13 23:25:22 -0700918 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
Jonathan Yubc771b72017-12-08 17:04:29 -0800919 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_framerate);
920 EXPECT_EQ(loop_count - 1,
asaperssonf7e294d2017-06-13 23:25:22 -0700921 stats_proxy_->GetStats().number_of_cpu_adapt_changes);
Jonathan Yubc771b72017-12-08 17:04:29 -0800922 EXPECT_EQ(kMinPixelsPerFrame, *video_source_.last_sent_width() *
923 *video_source_.last_sent_height());
924 EXPECT_EQ(kMinBalancedFramerateFps,
925 video_source_.sink_wants().max_framerate_fps);
asaperssonf7e294d2017-06-13 23:25:22 -0700926
Jonathan Yubc771b72017-12-08 17:04:29 -0800927 // Adapt back up the same number of times we adapted down.
928 for (int i = 0; i < loop_count - 1; ++i) {
929 last_wants = video_source_.sink_wants();
930
931 // Simulate the framerate we've been asked to adapt to.
932 const int fps = std::min(kFramerateFps, last_wants.max_framerate_fps);
933 const int frame_interval_ms = rtc::kNumMillisecsPerSec / fps;
934 VideoSendStream::Stats mock_stats = stats_proxy_->GetStats();
935 mock_stats.input_frame_rate = fps;
936 stats_proxy_->SetMockStats(mock_stats);
937
938 video_source_.IncomingCapturedFrame(CreateFrame(t, kWidth, kHeight));
939 sink_.WaitForEncodedFrame(t);
940 t += frame_interval_ms;
941
mflodmancc3d4422017-08-03 08:27:51 -0700942 video_stream_encoder_->TriggerCpuNormalUsage();
Jonathan Yubc771b72017-12-08 17:04:29 -0800943 VerifyBalancedModeFpsRange(
944 video_source_.sink_wants(),
945 *video_source_.last_sent_width() * *video_source_.last_sent_height());
946 EXPECT_TRUE(video_source_.sink_wants().max_pixel_count >
947 last_wants.max_pixel_count ||
948 video_source_.sink_wants().max_framerate_fps >
949 last_wants.max_framerate_fps);
asaperssonf7e294d2017-06-13 23:25:22 -0700950 }
951
Åsa Persson8c1bf952018-09-13 10:42:19 +0200952 VerifyFpsMaxResolutionMax(video_source_.sink_wants());
Jonathan Yubc771b72017-12-08 17:04:29 -0800953 stats_proxy_->ResetMockStats();
asaperssonf7e294d2017-06-13 23:25:22 -0700954 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
Jonathan Yubc771b72017-12-08 17:04:29 -0800955 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
956 EXPECT_EQ((loop_count - 1) * 2,
957 stats_proxy_->GetStats().number_of_cpu_adapt_changes);
asaperssonf7e294d2017-06-13 23:25:22 -0700958
mflodmancc3d4422017-08-03 08:27:51 -0700959 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -0700960}
mflodmancc3d4422017-08-03 08:27:51 -0700961TEST_F(VideoStreamEncoderTest, SinkWantsStoredByDegradationPreference) {
962 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson02465b82017-04-10 01:12:52 -0700963 VerifyNoLimitation(video_source_.sink_wants());
perkj803d97f2016-11-01 11:45:46 -0700964
sprangc5d62e22017-04-02 23:53:04 -0700965 const int kFrameWidth = 1280;
966 const int kFrameHeight = 720;
sprangc5d62e22017-04-02 23:53:04 -0700967
Åsa Persson8c1bf952018-09-13 10:42:19 +0200968 int64_t frame_timestamp = 1;
perkj803d97f2016-11-01 11:45:46 -0700969
kthelgason5e13d412016-12-01 03:59:51 -0800970 video_source_.IncomingCapturedFrame(
sprangc5d62e22017-04-02 23:53:04 -0700971 CreateFrame(frame_timestamp, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -0700972 WaitForEncodedFrame(frame_timestamp);
sprangc5d62e22017-04-02 23:53:04 -0700973 frame_timestamp += kFrameIntervalMs;
974
perkj803d97f2016-11-01 11:45:46 -0700975 // Trigger CPU overuse.
mflodmancc3d4422017-08-03 08:27:51 -0700976 video_stream_encoder_->TriggerCpuOveruse();
perkj803d97f2016-11-01 11:45:46 -0700977 video_source_.IncomingCapturedFrame(
sprangc5d62e22017-04-02 23:53:04 -0700978 CreateFrame(frame_timestamp, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -0700979 WaitForEncodedFrame(frame_timestamp);
sprangc5d62e22017-04-02 23:53:04 -0700980 frame_timestamp += kFrameIntervalMs;
sprang3ea3c772017-03-30 07:23:48 -0700981
asapersson0944a802017-04-07 00:57:58 -0700982 // Default degradation preference is maintain-framerate, so will lower max
sprangc5d62e22017-04-02 23:53:04 -0700983 // wanted resolution.
984 EXPECT_FALSE(video_source_.sink_wants().target_pixel_count);
985 EXPECT_LT(video_source_.sink_wants().max_pixel_count,
986 kFrameWidth * kFrameHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +0200987 EXPECT_EQ(kDefaultFramerate, video_source_.sink_wants().max_framerate_fps);
sprangc5d62e22017-04-02 23:53:04 -0700988
989 // Set new source, switch to maintain-resolution.
perkj803d97f2016-11-01 11:45:46 -0700990 test::FrameForwarder new_video_source;
mflodmancc3d4422017-08-03 08:27:51 -0700991 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -0700992 &new_video_source, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
perkj803d97f2016-11-01 11:45:46 -0700993
sprangc5d62e22017-04-02 23:53:04 -0700994 // Initially no degradation registered.
Åsa Persson8c1bf952018-09-13 10:42:19 +0200995 VerifyFpsMaxResolutionMax(new_video_source.sink_wants());
perkj803d97f2016-11-01 11:45:46 -0700996
sprangc5d62e22017-04-02 23:53:04 -0700997 // Force an input frame rate to be available, or the adaptation call won't
998 // know what framerate to adapt form.
asapersson02465b82017-04-10 01:12:52 -0700999 const int kInputFps = 30;
sprangc5d62e22017-04-02 23:53:04 -07001000 VideoSendStream::Stats stats = stats_proxy_->GetStats();
asapersson02465b82017-04-10 01:12:52 -07001001 stats.input_frame_rate = kInputFps;
sprangc5d62e22017-04-02 23:53:04 -07001002 stats_proxy_->SetMockStats(stats);
1003
mflodmancc3d4422017-08-03 08:27:51 -07001004 video_stream_encoder_->TriggerCpuOveruse();
perkj803d97f2016-11-01 11:45:46 -07001005 new_video_source.IncomingCapturedFrame(
sprangc5d62e22017-04-02 23:53:04 -07001006 CreateFrame(frame_timestamp, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07001007 WaitForEncodedFrame(frame_timestamp);
sprangc5d62e22017-04-02 23:53:04 -07001008 frame_timestamp += kFrameIntervalMs;
1009
1010 // Some framerate constraint should be set.
sprang84a37592017-02-10 07:04:27 -08001011 EXPECT_FALSE(new_video_source.sink_wants().target_pixel_count);
sprangc5d62e22017-04-02 23:53:04 -07001012 EXPECT_EQ(std::numeric_limits<int>::max(),
1013 new_video_source.sink_wants().max_pixel_count);
asapersson02465b82017-04-10 01:12:52 -07001014 EXPECT_LT(new_video_source.sink_wants().max_framerate_fps, kInputFps);
sprangc5d62e22017-04-02 23:53:04 -07001015
asapersson02465b82017-04-10 01:12:52 -07001016 // Turn off degradation completely.
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001017 video_stream_encoder_->SetSource(&new_video_source,
1018 webrtc::DegradationPreference::DISABLED);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001019 VerifyFpsMaxResolutionMax(new_video_source.sink_wants());
sprangc5d62e22017-04-02 23:53:04 -07001020
mflodmancc3d4422017-08-03 08:27:51 -07001021 video_stream_encoder_->TriggerCpuOveruse();
sprangc5d62e22017-04-02 23:53:04 -07001022 new_video_source.IncomingCapturedFrame(
1023 CreateFrame(frame_timestamp, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07001024 WaitForEncodedFrame(frame_timestamp);
sprangc5d62e22017-04-02 23:53:04 -07001025 frame_timestamp += kFrameIntervalMs;
1026
1027 // Still no degradation.
Åsa Persson8c1bf952018-09-13 10:42:19 +02001028 VerifyFpsMaxResolutionMax(new_video_source.sink_wants());
perkj803d97f2016-11-01 11:45:46 -07001029
1030 // Calling SetSource with resolution scaling enabled apply the old SinkWants.
mflodmancc3d4422017-08-03 08:27:51 -07001031 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001032 &new_video_source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
sprangc5d62e22017-04-02 23:53:04 -07001033 EXPECT_LT(new_video_source.sink_wants().max_pixel_count,
1034 kFrameWidth * kFrameHeight);
sprang84a37592017-02-10 07:04:27 -08001035 EXPECT_FALSE(new_video_source.sink_wants().target_pixel_count);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001036 EXPECT_EQ(kDefaultFramerate, new_video_source.sink_wants().max_framerate_fps);
sprangc5d62e22017-04-02 23:53:04 -07001037
1038 // Calling SetSource with framerate scaling enabled apply the old SinkWants.
mflodmancc3d4422017-08-03 08:27:51 -07001039 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001040 &new_video_source, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
sprangc5d62e22017-04-02 23:53:04 -07001041 EXPECT_FALSE(new_video_source.sink_wants().target_pixel_count);
1042 EXPECT_EQ(std::numeric_limits<int>::max(),
1043 new_video_source.sink_wants().max_pixel_count);
asapersson02465b82017-04-10 01:12:52 -07001044 EXPECT_LT(new_video_source.sink_wants().max_framerate_fps, kInputFps);
perkj803d97f2016-11-01 11:45:46 -07001045
mflodmancc3d4422017-08-03 08:27:51 -07001046 video_stream_encoder_->Stop();
perkj803d97f2016-11-01 11:45:46 -07001047}
1048
mflodmancc3d4422017-08-03 08:27:51 -07001049TEST_F(VideoStreamEncoderTest, StatsTracksQualityAdaptationStats) {
1050 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkj803d97f2016-11-01 11:45:46 -07001051
asaperssonfab67072017-04-04 05:51:49 -07001052 const int kWidth = 1280;
1053 const int kHeight = 720;
asaperssonfab67072017-04-04 05:51:49 -07001054 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001055 WaitForEncodedFrame(1);
asaperssonfab67072017-04-04 05:51:49 -07001056 VideoSendStream::Stats stats = stats_proxy_->GetStats();
1057 EXPECT_FALSE(stats.bw_limited_resolution);
1058 EXPECT_EQ(0, stats.number_of_quality_adapt_changes);
1059
1060 // Trigger adapt down.
mflodmancc3d4422017-08-03 08:27:51 -07001061 video_stream_encoder_->TriggerQualityLow();
asaperssonfab67072017-04-04 05:51:49 -07001062 video_source_.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001063 WaitForEncodedFrame(2);
asaperssonfab67072017-04-04 05:51:49 -07001064
1065 stats = stats_proxy_->GetStats();
1066 EXPECT_TRUE(stats.bw_limited_resolution);
1067 EXPECT_EQ(1, stats.number_of_quality_adapt_changes);
1068
1069 // Trigger adapt up.
mflodmancc3d4422017-08-03 08:27:51 -07001070 video_stream_encoder_->TriggerQualityHigh();
asaperssonfab67072017-04-04 05:51:49 -07001071 video_source_.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001072 WaitForEncodedFrame(3);
asaperssonfab67072017-04-04 05:51:49 -07001073
1074 stats = stats_proxy_->GetStats();
1075 EXPECT_FALSE(stats.bw_limited_resolution);
1076 EXPECT_EQ(2, stats.number_of_quality_adapt_changes);
1077 EXPECT_EQ(0, stats.number_of_cpu_adapt_changes);
1078
mflodmancc3d4422017-08-03 08:27:51 -07001079 video_stream_encoder_->Stop();
asaperssonfab67072017-04-04 05:51:49 -07001080}
1081
mflodmancc3d4422017-08-03 08:27:51 -07001082TEST_F(VideoStreamEncoderTest, StatsTracksCpuAdaptationStats) {
1083 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonfab67072017-04-04 05:51:49 -07001084
1085 const int kWidth = 1280;
1086 const int kHeight = 720;
asaperssonfab67072017-04-04 05:51:49 -07001087 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001088 WaitForEncodedFrame(1);
perkj803d97f2016-11-01 11:45:46 -07001089 VideoSendStream::Stats stats = stats_proxy_->GetStats();
1090 EXPECT_FALSE(stats.cpu_limited_resolution);
1091 EXPECT_EQ(0, stats.number_of_cpu_adapt_changes);
1092
1093 // Trigger CPU overuse.
mflodmancc3d4422017-08-03 08:27:51 -07001094 video_stream_encoder_->TriggerCpuOveruse();
asaperssonfab67072017-04-04 05:51:49 -07001095 video_source_.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001096 WaitForEncodedFrame(2);
perkj803d97f2016-11-01 11:45:46 -07001097
1098 stats = stats_proxy_->GetStats();
1099 EXPECT_TRUE(stats.cpu_limited_resolution);
1100 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1101
1102 // Trigger CPU normal use.
mflodmancc3d4422017-08-03 08:27:51 -07001103 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssonfab67072017-04-04 05:51:49 -07001104 video_source_.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001105 WaitForEncodedFrame(3);
perkj803d97f2016-11-01 11:45:46 -07001106
1107 stats = stats_proxy_->GetStats();
1108 EXPECT_FALSE(stats.cpu_limited_resolution);
1109 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
asaperssonfab67072017-04-04 05:51:49 -07001110 EXPECT_EQ(0, stats.number_of_quality_adapt_changes);
perkj803d97f2016-11-01 11:45:46 -07001111
mflodmancc3d4422017-08-03 08:27:51 -07001112 video_stream_encoder_->Stop();
perkj803d97f2016-11-01 11:45:46 -07001113}
1114
mflodmancc3d4422017-08-03 08:27:51 -07001115TEST_F(VideoStreamEncoderTest, SwitchingSourceKeepsCpuAdaptation) {
1116 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
kthelgason876222f2016-11-29 01:44:11 -08001117
asaperssonfab67072017-04-04 05:51:49 -07001118 const int kWidth = 1280;
1119 const int kHeight = 720;
1120 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001121 WaitForEncodedFrame(1);
kthelgason876222f2016-11-29 01:44:11 -08001122 VideoSendStream::Stats stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001123 EXPECT_FALSE(stats.bw_limited_resolution);
kthelgason876222f2016-11-29 01:44:11 -08001124 EXPECT_FALSE(stats.cpu_limited_resolution);
1125 EXPECT_EQ(0, stats.number_of_cpu_adapt_changes);
1126
asaperssonfab67072017-04-04 05:51:49 -07001127 // Trigger CPU overuse.
mflodmancc3d4422017-08-03 08:27:51 -07001128 video_stream_encoder_->TriggerCpuOveruse();
asaperssonfab67072017-04-04 05:51:49 -07001129 video_source_.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001130 WaitForEncodedFrame(2);
kthelgason876222f2016-11-29 01:44:11 -08001131 stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001132 EXPECT_FALSE(stats.bw_limited_resolution);
kthelgason876222f2016-11-29 01:44:11 -08001133 EXPECT_TRUE(stats.cpu_limited_resolution);
1134 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1135
1136 // Set new source with adaptation still enabled.
1137 test::FrameForwarder new_video_source;
mflodmancc3d4422017-08-03 08:27:51 -07001138 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001139 &new_video_source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
kthelgason876222f2016-11-29 01:44:11 -08001140
asaperssonfab67072017-04-04 05:51:49 -07001141 new_video_source.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001142 WaitForEncodedFrame(3);
kthelgason876222f2016-11-29 01:44:11 -08001143 stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001144 EXPECT_FALSE(stats.bw_limited_resolution);
kthelgason876222f2016-11-29 01:44:11 -08001145 EXPECT_TRUE(stats.cpu_limited_resolution);
1146 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1147
1148 // Set adaptation disabled.
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001149 video_stream_encoder_->SetSource(&new_video_source,
1150 webrtc::DegradationPreference::DISABLED);
kthelgason876222f2016-11-29 01:44:11 -08001151
asaperssonfab67072017-04-04 05:51:49 -07001152 new_video_source.IncomingCapturedFrame(CreateFrame(4, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001153 WaitForEncodedFrame(4);
kthelgason876222f2016-11-29 01:44:11 -08001154 stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001155 EXPECT_FALSE(stats.bw_limited_resolution);
kthelgason876222f2016-11-29 01:44:11 -08001156 EXPECT_FALSE(stats.cpu_limited_resolution);
1157 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1158
1159 // Set adaptation back to enabled.
mflodmancc3d4422017-08-03 08:27:51 -07001160 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001161 &new_video_source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
kthelgason876222f2016-11-29 01:44:11 -08001162
asaperssonfab67072017-04-04 05:51:49 -07001163 new_video_source.IncomingCapturedFrame(CreateFrame(5, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001164 WaitForEncodedFrame(5);
kthelgason876222f2016-11-29 01:44:11 -08001165 stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001166 EXPECT_FALSE(stats.bw_limited_resolution);
kthelgason876222f2016-11-29 01:44:11 -08001167 EXPECT_TRUE(stats.cpu_limited_resolution);
1168 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1169
asaperssonfab67072017-04-04 05:51:49 -07001170 // Trigger CPU normal use.
mflodmancc3d4422017-08-03 08:27:51 -07001171 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssonfab67072017-04-04 05:51:49 -07001172 new_video_source.IncomingCapturedFrame(CreateFrame(6, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001173 WaitForEncodedFrame(6);
kthelgason876222f2016-11-29 01:44:11 -08001174 stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001175 EXPECT_FALSE(stats.bw_limited_resolution);
kthelgason876222f2016-11-29 01:44:11 -08001176 EXPECT_FALSE(stats.cpu_limited_resolution);
1177 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
asapersson02465b82017-04-10 01:12:52 -07001178 EXPECT_EQ(0, stats.number_of_quality_adapt_changes);
kthelgason876222f2016-11-29 01:44:11 -08001179
mflodmancc3d4422017-08-03 08:27:51 -07001180 video_stream_encoder_->Stop();
kthelgason876222f2016-11-29 01:44:11 -08001181}
1182
mflodmancc3d4422017-08-03 08:27:51 -07001183TEST_F(VideoStreamEncoderTest, SwitchingSourceKeepsQualityAdaptation) {
1184 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
kthelgason876222f2016-11-29 01:44:11 -08001185
asaperssonfab67072017-04-04 05:51:49 -07001186 const int kWidth = 1280;
1187 const int kHeight = 720;
1188 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001189 WaitForEncodedFrame(1);
kthelgason876222f2016-11-29 01:44:11 -08001190 VideoSendStream::Stats stats = stats_proxy_->GetStats();
kthelgason876222f2016-11-29 01:44:11 -08001191 EXPECT_FALSE(stats.bw_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001192 EXPECT_FALSE(stats.bw_limited_framerate);
asaperssonfab67072017-04-04 05:51:49 -07001193 EXPECT_EQ(0, stats.number_of_quality_adapt_changes);
kthelgason876222f2016-11-29 01:44:11 -08001194
1195 // Set new source with adaptation still enabled.
1196 test::FrameForwarder new_video_source;
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001197 video_stream_encoder_->SetSource(&new_video_source,
1198 webrtc::DegradationPreference::BALANCED);
kthelgason876222f2016-11-29 01:44:11 -08001199
asaperssonfab67072017-04-04 05:51:49 -07001200 new_video_source.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001201 WaitForEncodedFrame(2);
kthelgason876222f2016-11-29 01:44:11 -08001202 stats = stats_proxy_->GetStats();
kthelgason876222f2016-11-29 01:44:11 -08001203 EXPECT_FALSE(stats.bw_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001204 EXPECT_FALSE(stats.bw_limited_framerate);
asaperssonfab67072017-04-04 05:51:49 -07001205 EXPECT_EQ(0, stats.number_of_quality_adapt_changes);
kthelgason876222f2016-11-29 01:44:11 -08001206
asaperssonfab67072017-04-04 05:51:49 -07001207 // Trigger adapt down.
mflodmancc3d4422017-08-03 08:27:51 -07001208 video_stream_encoder_->TriggerQualityLow();
asaperssonfab67072017-04-04 05:51:49 -07001209 new_video_source.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001210 WaitForEncodedFrame(3);
kthelgason876222f2016-11-29 01:44:11 -08001211 stats = stats_proxy_->GetStats();
kthelgason876222f2016-11-29 01:44:11 -08001212 EXPECT_TRUE(stats.bw_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001213 EXPECT_FALSE(stats.bw_limited_framerate);
asaperssonfab67072017-04-04 05:51:49 -07001214 EXPECT_EQ(1, stats.number_of_quality_adapt_changes);
kthelgason876222f2016-11-29 01:44:11 -08001215
asaperssonfab67072017-04-04 05:51:49 -07001216 // Set new source with adaptation still enabled.
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001217 video_stream_encoder_->SetSource(&new_video_source,
1218 webrtc::DegradationPreference::BALANCED);
kthelgason876222f2016-11-29 01:44:11 -08001219
asaperssonfab67072017-04-04 05:51:49 -07001220 new_video_source.IncomingCapturedFrame(CreateFrame(4, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001221 WaitForEncodedFrame(4);
kthelgason876222f2016-11-29 01:44:11 -08001222 stats = stats_proxy_->GetStats();
kthelgason876222f2016-11-29 01:44:11 -08001223 EXPECT_TRUE(stats.bw_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001224 EXPECT_FALSE(stats.bw_limited_framerate);
asaperssonfab67072017-04-04 05:51:49 -07001225 EXPECT_EQ(1, stats.number_of_quality_adapt_changes);
kthelgason876222f2016-11-29 01:44:11 -08001226
asapersson02465b82017-04-10 01:12:52 -07001227 // Disable resolution scaling.
mflodmancc3d4422017-08-03 08:27:51 -07001228 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001229 &new_video_source, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
kthelgason876222f2016-11-29 01:44:11 -08001230
asaperssonfab67072017-04-04 05:51:49 -07001231 new_video_source.IncomingCapturedFrame(CreateFrame(5, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001232 WaitForEncodedFrame(5);
kthelgason876222f2016-11-29 01:44:11 -08001233 stats = stats_proxy_->GetStats();
kthelgason876222f2016-11-29 01:44:11 -08001234 EXPECT_FALSE(stats.bw_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001235 EXPECT_FALSE(stats.bw_limited_framerate);
asaperssonfab67072017-04-04 05:51:49 -07001236 EXPECT_EQ(1, stats.number_of_quality_adapt_changes);
1237 EXPECT_EQ(0, stats.number_of_cpu_adapt_changes);
kthelgason876222f2016-11-29 01:44:11 -08001238
mflodmancc3d4422017-08-03 08:27:51 -07001239 video_stream_encoder_->Stop();
kthelgason876222f2016-11-29 01:44:11 -08001240}
1241
mflodmancc3d4422017-08-03 08:27:51 -07001242TEST_F(VideoStreamEncoderTest,
1243 QualityAdaptationStatsAreResetWhenScalerIsDisabled) {
1244 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson36e9eb42017-03-31 05:29:12 -07001245
1246 const int kWidth = 1280;
1247 const int kHeight = 720;
Åsa Persson8c1bf952018-09-13 10:42:19 +02001248 int64_t timestamp_ms = kFrameIntervalMs;
asapersson36e9eb42017-03-31 05:29:12 -07001249 video_source_.set_adaptation_enabled(true);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001250 video_source_.IncomingCapturedFrame(
1251 CreateFrame(timestamp_ms, kWidth, kHeight));
1252 WaitForEncodedFrame(timestamp_ms);
asapersson36e9eb42017-03-31 05:29:12 -07001253 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1254 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1255 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1256
1257 // Trigger adapt down.
mflodmancc3d4422017-08-03 08:27:51 -07001258 video_stream_encoder_->TriggerQualityLow();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001259 timestamp_ms += kFrameIntervalMs;
1260 video_source_.IncomingCapturedFrame(
1261 CreateFrame(timestamp_ms, kWidth, kHeight));
1262 WaitForEncodedFrame(timestamp_ms);
asapersson36e9eb42017-03-31 05:29:12 -07001263 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1264 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1265 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1266
1267 // Trigger overuse.
mflodmancc3d4422017-08-03 08:27:51 -07001268 video_stream_encoder_->TriggerCpuOveruse();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001269 timestamp_ms += kFrameIntervalMs;
1270 video_source_.IncomingCapturedFrame(
1271 CreateFrame(timestamp_ms, kWidth, kHeight));
1272 WaitForEncodedFrame(timestamp_ms);
asapersson36e9eb42017-03-31 05:29:12 -07001273 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1274 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1275 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1276
Niels Möller4db138e2018-04-19 09:04:13 +02001277 // Leave source unchanged, but disable quality scaler.
asapersson36e9eb42017-03-31 05:29:12 -07001278 fake_encoder_.SetQualityScaling(false);
Niels Möller4db138e2018-04-19 09:04:13 +02001279
1280 VideoEncoderConfig video_encoder_config;
1281 test::FillEncoderConfiguration(kVideoCodecVP8, 1, &video_encoder_config);
1282 // Make format different, to force recreation of encoder.
1283 video_encoder_config.video_format.parameters["foo"] = "foo";
1284 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
Niels Möllerf1338562018-04-26 09:51:47 +02001285 kMaxPayloadLength);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001286 timestamp_ms += kFrameIntervalMs;
1287 video_source_.IncomingCapturedFrame(
1288 CreateFrame(timestamp_ms, kWidth, kHeight));
1289 WaitForEncodedFrame(timestamp_ms);
asapersson36e9eb42017-03-31 05:29:12 -07001290 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1291 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1292 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1293
mflodmancc3d4422017-08-03 08:27:51 -07001294 video_stream_encoder_->Stop();
asapersson36e9eb42017-03-31 05:29:12 -07001295}
1296
mflodmancc3d4422017-08-03 08:27:51 -07001297TEST_F(VideoStreamEncoderTest,
1298 StatsTracksCpuAdaptationStatsWhenSwitchingSource) {
1299 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkj803d97f2016-11-01 11:45:46 -07001300
asapersson0944a802017-04-07 00:57:58 -07001301 const int kWidth = 1280;
1302 const int kHeight = 720;
sprang84a37592017-02-10 07:04:27 -08001303 int sequence = 1;
perkj803d97f2016-11-01 11:45:46 -07001304
asaperssonfab67072017-04-04 05:51:49 -07001305 video_source_.IncomingCapturedFrame(CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001306 WaitForEncodedFrame(sequence++);
perkj803d97f2016-11-01 11:45:46 -07001307 VideoSendStream::Stats stats = stats_proxy_->GetStats();
sprang84a37592017-02-10 07:04:27 -08001308 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001309 EXPECT_FALSE(stats.cpu_limited_framerate);
sprang84a37592017-02-10 07:04:27 -08001310 EXPECT_EQ(0, stats.number_of_cpu_adapt_changes);
1311
asapersson02465b82017-04-10 01:12:52 -07001312 // Trigger CPU overuse, should now adapt down.
mflodmancc3d4422017-08-03 08:27:51 -07001313 video_stream_encoder_->TriggerCpuOveruse();
asaperssonfab67072017-04-04 05:51:49 -07001314 video_source_.IncomingCapturedFrame(CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001315 WaitForEncodedFrame(sequence++);
sprang84a37592017-02-10 07:04:27 -08001316 stats = stats_proxy_->GetStats();
perkj803d97f2016-11-01 11:45:46 -07001317 EXPECT_TRUE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001318 EXPECT_FALSE(stats.cpu_limited_framerate);
perkj803d97f2016-11-01 11:45:46 -07001319 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1320
1321 // Set new source with adaptation still enabled.
1322 test::FrameForwarder new_video_source;
mflodmancc3d4422017-08-03 08:27:51 -07001323 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001324 &new_video_source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
perkj803d97f2016-11-01 11:45:46 -07001325
1326 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001327 CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001328 WaitForEncodedFrame(sequence++);
perkj803d97f2016-11-01 11:45:46 -07001329 stats = stats_proxy_->GetStats();
1330 EXPECT_TRUE(stats.cpu_limited_resolution);
asapersson09f05612017-05-15 23:40:18 -07001331 EXPECT_FALSE(stats.cpu_limited_framerate);
perkj803d97f2016-11-01 11:45:46 -07001332 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1333
sprangc5d62e22017-04-02 23:53:04 -07001334 // Set cpu adaptation by frame dropping.
mflodmancc3d4422017-08-03 08:27:51 -07001335 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001336 &new_video_source, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
perkj803d97f2016-11-01 11:45:46 -07001337 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001338 CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001339 WaitForEncodedFrame(sequence++);
perkj803d97f2016-11-01 11:45:46 -07001340 stats = stats_proxy_->GetStats();
sprangc5d62e22017-04-02 23:53:04 -07001341 // Not adapted at first.
perkj803d97f2016-11-01 11:45:46 -07001342 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson09f05612017-05-15 23:40:18 -07001343 EXPECT_FALSE(stats.cpu_limited_framerate);
perkj803d97f2016-11-01 11:45:46 -07001344 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1345
sprangc5d62e22017-04-02 23:53:04 -07001346 // Force an input frame rate to be available, or the adaptation call won't
asapersson09f05612017-05-15 23:40:18 -07001347 // know what framerate to adapt from.
sprangc5d62e22017-04-02 23:53:04 -07001348 VideoSendStream::Stats mock_stats = stats_proxy_->GetStats();
1349 mock_stats.input_frame_rate = 30;
1350 stats_proxy_->SetMockStats(mock_stats);
mflodmancc3d4422017-08-03 08:27:51 -07001351 video_stream_encoder_->TriggerCpuOveruse();
sprangc5d62e22017-04-02 23:53:04 -07001352 stats_proxy_->ResetMockStats();
1353
1354 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001355 CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001356 WaitForEncodedFrame(sequence++);
sprangc5d62e22017-04-02 23:53:04 -07001357
1358 // Framerate now adapted.
1359 stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001360 EXPECT_FALSE(stats.cpu_limited_resolution);
1361 EXPECT_TRUE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001362 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
1363
1364 // Disable CPU adaptation.
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001365 video_stream_encoder_->SetSource(&new_video_source,
1366 webrtc::DegradationPreference::DISABLED);
sprangc5d62e22017-04-02 23:53:04 -07001367 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001368 CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001369 WaitForEncodedFrame(sequence++);
sprangc5d62e22017-04-02 23:53:04 -07001370
1371 stats = stats_proxy_->GetStats();
1372 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001373 EXPECT_FALSE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001374 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
1375
1376 // Try to trigger overuse. Should not succeed.
1377 stats_proxy_->SetMockStats(mock_stats);
mflodmancc3d4422017-08-03 08:27:51 -07001378 video_stream_encoder_->TriggerCpuOveruse();
sprangc5d62e22017-04-02 23:53:04 -07001379 stats_proxy_->ResetMockStats();
1380
1381 stats = stats_proxy_->GetStats();
1382 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001383 EXPECT_FALSE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001384 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
1385
1386 // Switch back the source with resolution adaptation enabled.
mflodmancc3d4422017-08-03 08:27:51 -07001387 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001388 &video_source_, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
asaperssonfab67072017-04-04 05:51:49 -07001389 video_source_.IncomingCapturedFrame(CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001390 WaitForEncodedFrame(sequence++);
perkj803d97f2016-11-01 11:45:46 -07001391 stats = stats_proxy_->GetStats();
1392 EXPECT_TRUE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001393 EXPECT_FALSE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001394 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
perkj803d97f2016-11-01 11:45:46 -07001395
1396 // Trigger CPU normal usage.
mflodmancc3d4422017-08-03 08:27:51 -07001397 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssonfab67072017-04-04 05:51:49 -07001398 video_source_.IncomingCapturedFrame(CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001399 WaitForEncodedFrame(sequence++);
perkj803d97f2016-11-01 11:45:46 -07001400 stats = stats_proxy_->GetStats();
1401 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001402 EXPECT_FALSE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001403 EXPECT_EQ(3, stats.number_of_cpu_adapt_changes);
1404
1405 // Back to the source with adaptation off, set it back to maintain-resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001406 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001407 &new_video_source, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
sprangc5d62e22017-04-02 23:53:04 -07001408 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001409 CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001410 WaitForEncodedFrame(sequence++);
sprangc5d62e22017-04-02 23:53:04 -07001411 stats = stats_proxy_->GetStats();
asapersson13874762017-06-07 00:01:02 -07001412 // Disabled, since we previously switched the source to disabled.
sprangc5d62e22017-04-02 23:53:04 -07001413 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001414 EXPECT_TRUE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001415 EXPECT_EQ(3, stats.number_of_cpu_adapt_changes);
1416
1417 // Trigger CPU normal usage.
mflodmancc3d4422017-08-03 08:27:51 -07001418 video_stream_encoder_->TriggerCpuNormalUsage();
sprangc5d62e22017-04-02 23:53:04 -07001419 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001420 CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001421 WaitForEncodedFrame(sequence++);
sprangc5d62e22017-04-02 23:53:04 -07001422 stats = stats_proxy_->GetStats();
1423 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001424 EXPECT_FALSE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001425 EXPECT_EQ(4, stats.number_of_cpu_adapt_changes);
asapersson02465b82017-04-10 01:12:52 -07001426 EXPECT_EQ(0, stats.number_of_quality_adapt_changes);
perkj803d97f2016-11-01 11:45:46 -07001427
mflodmancc3d4422017-08-03 08:27:51 -07001428 video_stream_encoder_->Stop();
perkj803d97f2016-11-01 11:45:46 -07001429}
1430
mflodmancc3d4422017-08-03 08:27:51 -07001431TEST_F(VideoStreamEncoderTest,
1432 ScalingUpAndDownDoesNothingWithMaintainResolution) {
asaperssonfab67072017-04-04 05:51:49 -07001433 const int kWidth = 1280;
1434 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001435 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
kthelgason876222f2016-11-29 01:44:11 -08001436
asaperssonfab67072017-04-04 05:51:49 -07001437 // Expect no scaling to begin with.
asapersson02465b82017-04-10 01:12:52 -07001438 VerifyNoLimitation(video_source_.sink_wants());
kthelgason876222f2016-11-29 01:44:11 -08001439
asaperssonfab67072017-04-04 05:51:49 -07001440 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001441 WaitForEncodedFrame(1);
kthelgason876222f2016-11-29 01:44:11 -08001442
asaperssonfab67072017-04-04 05:51:49 -07001443 // Trigger scale down.
mflodmancc3d4422017-08-03 08:27:51 -07001444 video_stream_encoder_->TriggerQualityLow();
kthelgason5e13d412016-12-01 03:59:51 -08001445
asaperssonfab67072017-04-04 05:51:49 -07001446 video_source_.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001447 WaitForEncodedFrame(2);
kthelgason5e13d412016-12-01 03:59:51 -08001448
kthelgason876222f2016-11-29 01:44:11 -08001449 // Expect a scale down.
1450 EXPECT_TRUE(video_source_.sink_wants().max_pixel_count);
asaperssonfab67072017-04-04 05:51:49 -07001451 EXPECT_LT(video_source_.sink_wants().max_pixel_count, kWidth * kHeight);
kthelgason876222f2016-11-29 01:44:11 -08001452
asapersson02465b82017-04-10 01:12:52 -07001453 // Set resolution scaling disabled.
kthelgason876222f2016-11-29 01:44:11 -08001454 test::FrameForwarder new_video_source;
mflodmancc3d4422017-08-03 08:27:51 -07001455 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001456 &new_video_source, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
kthelgason876222f2016-11-29 01:44:11 -08001457
asaperssonfab67072017-04-04 05:51:49 -07001458 // Trigger scale down.
mflodmancc3d4422017-08-03 08:27:51 -07001459 video_stream_encoder_->TriggerQualityLow();
asaperssonfab67072017-04-04 05:51:49 -07001460 new_video_source.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001461 WaitForEncodedFrame(3);
kthelgason876222f2016-11-29 01:44:11 -08001462
asaperssonfab67072017-04-04 05:51:49 -07001463 // Expect no scaling.
sprangc5d62e22017-04-02 23:53:04 -07001464 EXPECT_EQ(std::numeric_limits<int>::max(),
1465 new_video_source.sink_wants().max_pixel_count);
kthelgason876222f2016-11-29 01:44:11 -08001466
asaperssonfab67072017-04-04 05:51:49 -07001467 // Trigger scale up.
mflodmancc3d4422017-08-03 08:27:51 -07001468 video_stream_encoder_->TriggerQualityHigh();
asaperssonfab67072017-04-04 05:51:49 -07001469 new_video_source.IncomingCapturedFrame(CreateFrame(4, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001470 WaitForEncodedFrame(4);
kthelgason876222f2016-11-29 01:44:11 -08001471
asapersson02465b82017-04-10 01:12:52 -07001472 // Expect nothing to change, still no scaling.
sprangc5d62e22017-04-02 23:53:04 -07001473 EXPECT_EQ(std::numeric_limits<int>::max(),
1474 new_video_source.sink_wants().max_pixel_count);
kthelgason876222f2016-11-29 01:44:11 -08001475
mflodmancc3d4422017-08-03 08:27:51 -07001476 video_stream_encoder_->Stop();
kthelgason876222f2016-11-29 01:44:11 -08001477}
1478
mflodmancc3d4422017-08-03 08:27:51 -07001479TEST_F(VideoStreamEncoderTest,
1480 SkipsSameAdaptDownRequest_MaintainFramerateMode) {
asapersson02465b82017-04-10 01:12:52 -07001481 const int kWidth = 1280;
1482 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001483 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson02465b82017-04-10 01:12:52 -07001484
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001485 // Enable MAINTAIN_FRAMERATE preference, no initial limitation.
asapersson02465b82017-04-10 01:12:52 -07001486 test::FrameForwarder source;
mflodmancc3d4422017-08-03 08:27:51 -07001487 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001488 &source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
asapersson02465b82017-04-10 01:12:52 -07001489
1490 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001491 WaitForEncodedFrame(1);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001492 VerifyFpsMaxResolutionMax(source.sink_wants());
asapersson02465b82017-04-10 01:12:52 -07001493 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1494 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1495
1496 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001497 video_stream_encoder_->TriggerCpuOveruse();
asapersson09f05612017-05-15 23:40:18 -07001498 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
asapersson02465b82017-04-10 01:12:52 -07001499 const int 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
1503 // Trigger adapt down for same input resolution, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07001504 video_stream_encoder_->TriggerCpuOveruse();
asapersson02465b82017-04-10 01:12:52 -07001505 EXPECT_EQ(kLastMaxPixelCount, source.sink_wants().max_pixel_count);
1506 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1507 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1508
mflodmancc3d4422017-08-03 08:27:51 -07001509 video_stream_encoder_->Stop();
asapersson02465b82017-04-10 01:12:52 -07001510}
1511
mflodmancc3d4422017-08-03 08:27:51 -07001512TEST_F(VideoStreamEncoderTest, SkipsSameOrLargerAdaptDownRequest_BalancedMode) {
asaperssonf7e294d2017-06-13 23:25:22 -07001513 const int kWidth = 1280;
1514 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001515 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -07001516
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001517 // Enable BALANCED preference, no initial limitation.
asaperssonf7e294d2017-06-13 23:25:22 -07001518 test::FrameForwarder source;
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001519 video_stream_encoder_->SetSource(&source,
1520 webrtc::DegradationPreference::BALANCED);
asaperssonf7e294d2017-06-13 23:25:22 -07001521 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
1522 sink_.WaitForEncodedFrame(1);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001523 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07001524
1525 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001526 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07001527 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
1528 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1529 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1530 const int kLastMaxPixelCount = source.sink_wants().max_pixel_count;
1531
1532 // Trigger adapt down for same input resolution, expect no change.
1533 source.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
1534 sink_.WaitForEncodedFrame(2);
mflodmancc3d4422017-08-03 08:27:51 -07001535 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07001536 EXPECT_EQ(kLastMaxPixelCount, source.sink_wants().max_pixel_count);
1537 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1538 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1539
1540 // Trigger adapt down for larger input resolution, expect no change.
1541 source.IncomingCapturedFrame(CreateFrame(3, kWidth + 1, kHeight + 1));
1542 sink_.WaitForEncodedFrame(3);
mflodmancc3d4422017-08-03 08:27:51 -07001543 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07001544 EXPECT_EQ(kLastMaxPixelCount, source.sink_wants().max_pixel_count);
1545 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1546 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1547
mflodmancc3d4422017-08-03 08:27:51 -07001548 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07001549}
1550
mflodmancc3d4422017-08-03 08:27:51 -07001551TEST_F(VideoStreamEncoderTest,
1552 NoChangeForInitialNormalUsage_MaintainFramerateMode) {
asapersson02465b82017-04-10 01:12:52 -07001553 const int kWidth = 1280;
1554 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001555 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson02465b82017-04-10 01:12:52 -07001556
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001557 // Enable MAINTAIN_FRAMERATE preference, no initial limitation.
asapersson02465b82017-04-10 01:12:52 -07001558 test::FrameForwarder source;
mflodmancc3d4422017-08-03 08:27:51 -07001559 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001560 &source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
asapersson02465b82017-04-10 01:12:52 -07001561
1562 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001563 WaitForEncodedFrame(kWidth, kHeight);
Å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
1568 // Trigger adapt up, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07001569 video_stream_encoder_->TriggerCpuNormalUsage();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001570 VerifyFpsMaxResolutionMax(source.sink_wants());
asapersson02465b82017-04-10 01:12:52 -07001571 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1572 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1573
mflodmancc3d4422017-08-03 08:27:51 -07001574 video_stream_encoder_->Stop();
asapersson02465b82017-04-10 01:12:52 -07001575}
1576
mflodmancc3d4422017-08-03 08:27:51 -07001577TEST_F(VideoStreamEncoderTest,
1578 NoChangeForInitialNormalUsage_MaintainResolutionMode) {
asapersson02465b82017-04-10 01:12:52 -07001579 const int kWidth = 1280;
1580 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001581 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson02465b82017-04-10 01:12:52 -07001582
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001583 // Enable MAINTAIN_RESOLUTION preference, no initial limitation.
asapersson02465b82017-04-10 01:12:52 -07001584 test::FrameForwarder source;
mflodmancc3d4422017-08-03 08:27:51 -07001585 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001586 &source, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
asapersson02465b82017-04-10 01:12:52 -07001587
1588 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001589 WaitForEncodedFrame(kWidth, kHeight);
Å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
1594 // Trigger adapt up, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07001595 video_stream_encoder_->TriggerCpuNormalUsage();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001596 VerifyFpsMaxResolutionMax(source.sink_wants());
asapersson09f05612017-05-15 23:40:18 -07001597 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
asapersson02465b82017-04-10 01:12:52 -07001598 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1599
mflodmancc3d4422017-08-03 08:27:51 -07001600 video_stream_encoder_->Stop();
asapersson02465b82017-04-10 01:12:52 -07001601}
1602
mflodmancc3d4422017-08-03 08:27:51 -07001603TEST_F(VideoStreamEncoderTest, NoChangeForInitialNormalUsage_BalancedMode) {
asaperssonf7e294d2017-06-13 23:25:22 -07001604 const int kWidth = 1280;
1605 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001606 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -07001607
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001608 // Enable BALANCED preference, no initial limitation.
asaperssonf7e294d2017-06-13 23:25:22 -07001609 test::FrameForwarder source;
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001610 video_stream_encoder_->SetSource(&source,
1611 webrtc::DegradationPreference::BALANCED);
asaperssonf7e294d2017-06-13 23:25:22 -07001612
1613 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
1614 sink_.WaitForEncodedFrame(kWidth, kHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001615 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07001616 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1617 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
1618 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1619
1620 // Trigger adapt up, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07001621 video_stream_encoder_->TriggerQualityHigh();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001622 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07001623 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1624 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
1625 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1626
mflodmancc3d4422017-08-03 08:27:51 -07001627 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07001628}
1629
mflodmancc3d4422017-08-03 08:27:51 -07001630TEST_F(VideoStreamEncoderTest, NoChangeForInitialNormalUsage_DisabledMode) {
asapersson09f05612017-05-15 23:40:18 -07001631 const int kWidth = 1280;
1632 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001633 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson09f05612017-05-15 23:40:18 -07001634
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001635 // Enable DISABLED preference, no initial limitation.
asapersson09f05612017-05-15 23:40:18 -07001636 test::FrameForwarder source;
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001637 video_stream_encoder_->SetSource(&source,
1638 webrtc::DegradationPreference::DISABLED);
asapersson09f05612017-05-15 23:40:18 -07001639
1640 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
1641 sink_.WaitForEncodedFrame(kWidth, kHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001642 VerifyFpsMaxResolutionMax(source.sink_wants());
asapersson09f05612017-05-15 23:40:18 -07001643 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1644 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
1645 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1646
1647 // Trigger adapt up, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07001648 video_stream_encoder_->TriggerQualityHigh();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001649 VerifyFpsMaxResolutionMax(source.sink_wants());
asapersson09f05612017-05-15 23:40:18 -07001650 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1651 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
1652 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1653
mflodmancc3d4422017-08-03 08:27:51 -07001654 video_stream_encoder_->Stop();
asapersson09f05612017-05-15 23:40:18 -07001655}
1656
mflodmancc3d4422017-08-03 08:27:51 -07001657TEST_F(VideoStreamEncoderTest,
1658 AdaptsResolutionForLowQuality_MaintainFramerateMode) {
asapersson02465b82017-04-10 01:12:52 -07001659 const int kWidth = 1280;
1660 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001661 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson02465b82017-04-10 01:12:52 -07001662
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001663 // Enable MAINTAIN_FRAMERATE preference, no initial limitation.
asapersson02465b82017-04-10 01:12:52 -07001664 AdaptingFrameForwarder source;
1665 source.set_adaptation_enabled(true);
mflodmancc3d4422017-08-03 08:27:51 -07001666 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001667 &source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
asapersson02465b82017-04-10 01:12:52 -07001668
1669 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001670 WaitForEncodedFrame(1);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001671 VerifyFpsMaxResolutionMax(source.sink_wants());
asapersson02465b82017-04-10 01:12:52 -07001672 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1673 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1674
1675 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001676 video_stream_encoder_->TriggerQualityLow();
asapersson02465b82017-04-10 01:12:52 -07001677 source.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001678 WaitForEncodedFrame(2);
asapersson09f05612017-05-15 23:40:18 -07001679 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
asapersson02465b82017-04-10 01:12:52 -07001680 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1681 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1682
1683 // Trigger adapt up, expect no restriction.
mflodmancc3d4422017-08-03 08:27:51 -07001684 video_stream_encoder_->TriggerQualityHigh();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001685 VerifyFpsMaxResolutionMax(source.sink_wants());
asapersson02465b82017-04-10 01:12:52 -07001686 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1687 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1688 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1689
mflodmancc3d4422017-08-03 08:27:51 -07001690 video_stream_encoder_->Stop();
asapersson02465b82017-04-10 01:12:52 -07001691}
1692
mflodmancc3d4422017-08-03 08:27:51 -07001693TEST_F(VideoStreamEncoderTest,
1694 AdaptsFramerateForLowQuality_MaintainResolutionMode) {
asapersson09f05612017-05-15 23:40:18 -07001695 const int kWidth = 1280;
1696 const int kHeight = 720;
1697 const int kInputFps = 30;
mflodmancc3d4422017-08-03 08:27:51 -07001698 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson09f05612017-05-15 23:40:18 -07001699
1700 VideoSendStream::Stats stats = stats_proxy_->GetStats();
1701 stats.input_frame_rate = kInputFps;
1702 stats_proxy_->SetMockStats(stats);
1703
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001704 // Expect no scaling to begin with (preference: MAINTAIN_FRAMERATE).
asapersson09f05612017-05-15 23:40:18 -07001705 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
1706 sink_.WaitForEncodedFrame(1);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001707 VerifyFpsMaxResolutionMax(video_source_.sink_wants());
asapersson09f05612017-05-15 23:40:18 -07001708
1709 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001710 video_stream_encoder_->TriggerQualityLow();
asapersson09f05612017-05-15 23:40:18 -07001711 video_source_.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
1712 sink_.WaitForEncodedFrame(2);
1713 VerifyFpsMaxResolutionLt(video_source_.sink_wants(), kWidth * kHeight);
1714
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001715 // Enable MAINTAIN_RESOLUTION preference.
asapersson09f05612017-05-15 23:40:18 -07001716 test::FrameForwarder new_video_source;
mflodmancc3d4422017-08-03 08:27:51 -07001717 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001718 &new_video_source, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001719 VerifyFpsMaxResolutionMax(new_video_source.sink_wants());
asapersson09f05612017-05-15 23:40:18 -07001720
1721 // Trigger adapt down, expect reduced framerate.
mflodmancc3d4422017-08-03 08:27:51 -07001722 video_stream_encoder_->TriggerQualityLow();
asapersson09f05612017-05-15 23:40:18 -07001723 new_video_source.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
1724 sink_.WaitForEncodedFrame(3);
1725 VerifyFpsLtResolutionMax(new_video_source.sink_wants(), kInputFps);
1726
1727 // Trigger adapt up, expect no restriction.
mflodmancc3d4422017-08-03 08:27:51 -07001728 video_stream_encoder_->TriggerQualityHigh();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001729 VerifyFpsMaxResolutionMax(new_video_source.sink_wants());
asapersson09f05612017-05-15 23:40:18 -07001730
mflodmancc3d4422017-08-03 08:27:51 -07001731 video_stream_encoder_->Stop();
asapersson09f05612017-05-15 23:40:18 -07001732}
1733
mflodmancc3d4422017-08-03 08:27:51 -07001734TEST_F(VideoStreamEncoderTest, DoesNotScaleBelowSetResolutionLimit) {
asaperssond0de2952017-04-21 01:47:31 -07001735 const int kWidth = 1280;
1736 const int kHeight = 720;
1737 const size_t kNumFrames = 10;
1738
mflodmancc3d4422017-08-03 08:27:51 -07001739 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
kthelgason5e13d412016-12-01 03:59:51 -08001740
asaperssond0de2952017-04-21 01:47:31 -07001741 // Enable adapter, expected input resolutions when downscaling:
asapersson142fcc92017-08-17 08:58:54 -07001742 // 1280x720 -> 960x540 -> 640x360 -> 480x270 -> 320x180 (kMinPixelsPerFrame)
asaperssond0de2952017-04-21 01:47:31 -07001743 video_source_.set_adaptation_enabled(true);
1744
1745 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1746 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1747
1748 int downscales = 0;
1749 for (size_t i = 1; i <= kNumFrames; i++) {
Åsa Persson8c1bf952018-09-13 10:42:19 +02001750 video_source_.IncomingCapturedFrame(
1751 CreateFrame(i * kFrameIntervalMs, kWidth, kHeight));
1752 WaitForEncodedFrame(i * kFrameIntervalMs);
asaperssond0de2952017-04-21 01:47:31 -07001753
asaperssonfab67072017-04-04 05:51:49 -07001754 // Trigger scale down.
asaperssond0de2952017-04-21 01:47:31 -07001755 rtc::VideoSinkWants last_wants = video_source_.sink_wants();
mflodmancc3d4422017-08-03 08:27:51 -07001756 video_stream_encoder_->TriggerQualityLow();
sprangc5d62e22017-04-02 23:53:04 -07001757 EXPECT_GE(video_source_.sink_wants().max_pixel_count, kMinPixelsPerFrame);
asaperssond0de2952017-04-21 01:47:31 -07001758
1759 if (video_source_.sink_wants().max_pixel_count < last_wants.max_pixel_count)
1760 ++downscales;
1761
1762 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1763 EXPECT_EQ(downscales,
1764 stats_proxy_->GetStats().number_of_quality_adapt_changes);
1765 EXPECT_GT(downscales, 0);
kthelgason5e13d412016-12-01 03:59:51 -08001766 }
mflodmancc3d4422017-08-03 08:27:51 -07001767 video_stream_encoder_->Stop();
asaperssond0de2952017-04-21 01:47:31 -07001768}
1769
mflodmancc3d4422017-08-03 08:27:51 -07001770TEST_F(VideoStreamEncoderTest,
asaperssond0de2952017-04-21 01:47:31 -07001771 AdaptsResolutionUpAndDownTwiceOnOveruse_MaintainFramerateMode) {
1772 const int kWidth = 1280;
1773 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001774 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssond0de2952017-04-21 01:47:31 -07001775
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001776 // Enable MAINTAIN_FRAMERATE preference, no initial limitation.
asaperssond0de2952017-04-21 01:47:31 -07001777 AdaptingFrameForwarder source;
1778 source.set_adaptation_enabled(true);
mflodmancc3d4422017-08-03 08:27:51 -07001779 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001780 &source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
asaperssond0de2952017-04-21 01:47:31 -07001781
Åsa Persson8c1bf952018-09-13 10:42:19 +02001782 int64_t timestamp_ms = kFrameIntervalMs;
1783 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001784 WaitForEncodedFrame(kWidth, kHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001785 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssond0de2952017-04-21 01:47:31 -07001786 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1787 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1788
1789 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001790 video_stream_encoder_->TriggerCpuOveruse();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001791 timestamp_ms += kFrameIntervalMs;
1792 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
1793 WaitForEncodedFrame(timestamp_ms);
asapersson09f05612017-05-15 23:40:18 -07001794 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
asaperssond0de2952017-04-21 01:47:31 -07001795 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1796 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1797
1798 // Trigger adapt up, expect no restriction.
mflodmancc3d4422017-08-03 08:27:51 -07001799 video_stream_encoder_->TriggerCpuNormalUsage();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001800 timestamp_ms += kFrameIntervalMs;
1801 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001802 WaitForEncodedFrame(kWidth, kHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001803 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssond0de2952017-04-21 01:47:31 -07001804 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1805 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1806
1807 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001808 video_stream_encoder_->TriggerCpuOveruse();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001809 timestamp_ms += kFrameIntervalMs;
1810 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
1811 WaitForEncodedFrame(timestamp_ms);
asapersson09f05612017-05-15 23:40:18 -07001812 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
asaperssond0de2952017-04-21 01:47:31 -07001813 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1814 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1815
1816 // Trigger adapt up, expect no restriction.
mflodmancc3d4422017-08-03 08:27:51 -07001817 video_stream_encoder_->TriggerCpuNormalUsage();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001818 timestamp_ms += kFrameIntervalMs;
1819 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
asapersson09f05612017-05-15 23:40:18 -07001820 sink_.WaitForEncodedFrame(kWidth, kHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001821 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssond0de2952017-04-21 01:47:31 -07001822 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1823 EXPECT_EQ(4, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1824
mflodmancc3d4422017-08-03 08:27:51 -07001825 video_stream_encoder_->Stop();
asaperssond0de2952017-04-21 01:47:31 -07001826}
1827
mflodmancc3d4422017-08-03 08:27:51 -07001828TEST_F(VideoStreamEncoderTest,
asaperssonf7e294d2017-06-13 23:25:22 -07001829 AdaptsResolutionUpAndDownTwiceForLowQuality_BalancedMode_NoFpsLimit) {
1830 const int kWidth = 1280;
1831 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001832 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -07001833
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001834 // Enable BALANCED preference, no initial limitation.
asaperssonf7e294d2017-06-13 23:25:22 -07001835 AdaptingFrameForwarder source;
1836 source.set_adaptation_enabled(true);
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001837 video_stream_encoder_->SetSource(&source,
1838 webrtc::DegradationPreference::BALANCED);
asaperssonf7e294d2017-06-13 23:25:22 -07001839
Åsa Persson8c1bf952018-09-13 10:42:19 +02001840 int64_t timestamp_ms = kFrameIntervalMs;
1841 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
asaperssonf7e294d2017-06-13 23:25:22 -07001842 sink_.WaitForEncodedFrame(kWidth, kHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001843 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07001844 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1845 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1846
1847 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001848 video_stream_encoder_->TriggerQualityLow();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001849 timestamp_ms += kFrameIntervalMs;
1850 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
1851 sink_.WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07001852 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
1853 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1854 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1855
1856 // Trigger adapt up, expect no restriction.
mflodmancc3d4422017-08-03 08:27:51 -07001857 video_stream_encoder_->TriggerQualityHigh();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001858 timestamp_ms += kFrameIntervalMs;
1859 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
asaperssonf7e294d2017-06-13 23:25:22 -07001860 sink_.WaitForEncodedFrame(kWidth, kHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001861 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07001862 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1863 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1864
1865 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001866 video_stream_encoder_->TriggerQualityLow();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001867 timestamp_ms += kFrameIntervalMs;
1868 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
1869 sink_.WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07001870 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
1871 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1872 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1873
1874 // Trigger adapt up, expect no restriction.
mflodmancc3d4422017-08-03 08:27:51 -07001875 video_stream_encoder_->TriggerQualityHigh();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001876 timestamp_ms += kFrameIntervalMs;
1877 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
asaperssonf7e294d2017-06-13 23:25:22 -07001878 sink_.WaitForEncodedFrame(kWidth, kHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001879 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07001880 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1881 EXPECT_EQ(4, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1882
mflodmancc3d4422017-08-03 08:27:51 -07001883 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07001884}
1885
mflodmancc3d4422017-08-03 08:27:51 -07001886TEST_F(VideoStreamEncoderTest,
asaperssond0de2952017-04-21 01:47:31 -07001887 AdaptsResolutionOnOveruseAndLowQuality_MaintainFramerateMode) {
1888 const int kWidth = 1280;
1889 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001890 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssond0de2952017-04-21 01:47:31 -07001891
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001892 // Enable MAINTAIN_FRAMERATE preference, no initial limitation.
asaperssond0de2952017-04-21 01:47:31 -07001893 AdaptingFrameForwarder source;
1894 source.set_adaptation_enabled(true);
mflodmancc3d4422017-08-03 08:27:51 -07001895 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001896 &source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
asaperssond0de2952017-04-21 01:47:31 -07001897
Åsa Persson8c1bf952018-09-13 10:42:19 +02001898 int64_t timestamp_ms = kFrameIntervalMs;
1899 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001900 WaitForEncodedFrame(kWidth, kHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001901 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssond0de2952017-04-21 01:47:31 -07001902 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1903 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1904 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1905 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1906
1907 // Trigger cpu adapt down, expect scaled down resolution (960x540).
mflodmancc3d4422017-08-03 08:27:51 -07001908 video_stream_encoder_->TriggerCpuOveruse();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001909 timestamp_ms += kFrameIntervalMs;
1910 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
1911 WaitForEncodedFrame(timestamp_ms);
asapersson09f05612017-05-15 23:40:18 -07001912 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
asaperssond0de2952017-04-21 01:47:31 -07001913 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1914 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1915 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1916 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1917
1918 // Trigger cpu adapt down, expect scaled down resolution (640x360).
mflodmancc3d4422017-08-03 08:27:51 -07001919 video_stream_encoder_->TriggerCpuOveruse();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001920 timestamp_ms += kFrameIntervalMs;
1921 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
1922 WaitForEncodedFrame(timestamp_ms);
asapersson09f05612017-05-15 23:40:18 -07001923 VerifyFpsMaxResolutionLt(source.sink_wants(), source.last_wants());
asaperssond0de2952017-04-21 01:47:31 -07001924 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1925 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1926 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1927 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1928
Jonathan Yubc771b72017-12-08 17:04:29 -08001929 // Trigger cpu adapt down, expect scaled down resolution (480x270).
mflodmancc3d4422017-08-03 08:27:51 -07001930 video_stream_encoder_->TriggerCpuOveruse();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001931 timestamp_ms += kFrameIntervalMs;
1932 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
1933 WaitForEncodedFrame(timestamp_ms);
Jonathan Yubc771b72017-12-08 17:04:29 -08001934 VerifyFpsMaxResolutionLt(source.sink_wants(), source.last_wants());
asaperssond0de2952017-04-21 01:47:31 -07001935 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1936 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
Jonathan Yubc771b72017-12-08 17:04:29 -08001937 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
asaperssond0de2952017-04-21 01:47:31 -07001938 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1939
Jonathan Yubc771b72017-12-08 17:04:29 -08001940 // Trigger quality adapt down, expect scaled down resolution (320x180).
mflodmancc3d4422017-08-03 08:27:51 -07001941 video_stream_encoder_->TriggerQualityLow();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001942 timestamp_ms += kFrameIntervalMs;
1943 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
1944 WaitForEncodedFrame(timestamp_ms);
asapersson09f05612017-05-15 23:40:18 -07001945 VerifyFpsMaxResolutionLt(source.sink_wants(), source.last_wants());
Jonathan Yubc771b72017-12-08 17:04:29 -08001946 rtc::VideoSinkWants last_wants = source.sink_wants();
asaperssond0de2952017-04-21 01:47:31 -07001947 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1948 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1949 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1950 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1951
Jonathan Yubc771b72017-12-08 17:04:29 -08001952 // Trigger quality adapt down, expect no change (min resolution reached).
1953 video_stream_encoder_->TriggerQualityLow();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001954 timestamp_ms += kFrameIntervalMs;
1955 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
1956 WaitForEncodedFrame(timestamp_ms);
Jonathan Yubc771b72017-12-08 17:04:29 -08001957 VerifyFpsMaxResolutionEq(source.sink_wants(), last_wants);
1958 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1959 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1960 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1961 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1962
1963 // Trigger cpu adapt up, expect upscaled resolution (480x270).
mflodmancc3d4422017-08-03 08:27:51 -07001964 video_stream_encoder_->TriggerCpuNormalUsage();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001965 timestamp_ms += kFrameIntervalMs;
1966 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
1967 WaitForEncodedFrame(timestamp_ms);
asapersson09f05612017-05-15 23:40:18 -07001968 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
Jonathan Yubc771b72017-12-08 17:04:29 -08001969 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1970 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1971 EXPECT_EQ(4, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1972 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1973
1974 // Trigger cpu adapt up, expect upscaled resolution (640x360).
1975 video_stream_encoder_->TriggerCpuNormalUsage();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001976 timestamp_ms += kFrameIntervalMs;
1977 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
1978 WaitForEncodedFrame(timestamp_ms);
Jonathan Yubc771b72017-12-08 17:04:29 -08001979 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
1980 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1981 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1982 EXPECT_EQ(5, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1983 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1984
1985 // Trigger cpu adapt up, expect upscaled resolution (960x540).
1986 video_stream_encoder_->TriggerCpuNormalUsage();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001987 timestamp_ms += kFrameIntervalMs;
1988 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
1989 WaitForEncodedFrame(timestamp_ms);
Jonathan Yubc771b72017-12-08 17:04:29 -08001990 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
asaperssond0de2952017-04-21 01:47:31 -07001991 last_wants = source.sink_wants();
1992 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1993 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
Jonathan Yubc771b72017-12-08 17:04:29 -08001994 EXPECT_EQ(6, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
asaperssond0de2952017-04-21 01:47:31 -07001995 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1996
1997 // Trigger cpu adapt up, no cpu downgrades, expect no change (960x540).
mflodmancc3d4422017-08-03 08:27:51 -07001998 video_stream_encoder_->TriggerCpuNormalUsage();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001999 timestamp_ms += kFrameIntervalMs;
2000 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
2001 WaitForEncodedFrame(timestamp_ms);
asapersson09f05612017-05-15 23:40:18 -07002002 VerifyFpsEqResolutionEq(source.sink_wants(), last_wants);
asaperssond0de2952017-04-21 01:47:31 -07002003 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2004 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
Jonathan Yubc771b72017-12-08 17:04:29 -08002005 EXPECT_EQ(6, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
asaperssond0de2952017-04-21 01:47:31 -07002006 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2007
2008 // Trigger quality adapt up, expect no restriction (1280x720).
mflodmancc3d4422017-08-03 08:27:51 -07002009 video_stream_encoder_->TriggerQualityHigh();
Åsa Persson8c1bf952018-09-13 10:42:19 +02002010 timestamp_ms += kFrameIntervalMs;
2011 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002012 WaitForEncodedFrame(kWidth, kHeight);
asapersson09f05612017-05-15 23:40:18 -07002013 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
Åsa Persson8c1bf952018-09-13 10:42:19 +02002014 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssond0de2952017-04-21 01:47:31 -07002015 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2016 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
Jonathan Yubc771b72017-12-08 17:04:29 -08002017 EXPECT_EQ(6, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
asaperssond0de2952017-04-21 01:47:31 -07002018 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
kthelgason5e13d412016-12-01 03:59:51 -08002019
mflodmancc3d4422017-08-03 08:27:51 -07002020 video_stream_encoder_->Stop();
kthelgason5e13d412016-12-01 03:59:51 -08002021}
2022
mflodmancc3d4422017-08-03 08:27:51 -07002023TEST_F(VideoStreamEncoderTest, CpuLimitedHistogramIsReported) {
asaperssonfab67072017-04-04 05:51:49 -07002024 const int kWidth = 640;
2025 const int kHeight = 360;
perkj803d97f2016-11-01 11:45:46 -07002026
mflodmancc3d4422017-08-03 08:27:51 -07002027 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
sprang4847ae62017-06-27 07:06:52 -07002028
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(i, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002031 WaitForEncodedFrame(i);
perkj803d97f2016-11-01 11:45:46 -07002032 }
2033
mflodmancc3d4422017-08-03 08:27:51 -07002034 video_stream_encoder_->TriggerCpuOveruse();
perkj803d97f2016-11-01 11:45:46 -07002035 for (int i = 1; i <= SendStatisticsProxy::kMinRequiredMetricsSamples; ++i) {
asaperssonfab67072017-04-04 05:51:49 -07002036 video_source_.IncomingCapturedFrame(CreateFrame(
2037 SendStatisticsProxy::kMinRequiredMetricsSamples + i, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002038 WaitForEncodedFrame(SendStatisticsProxy::kMinRequiredMetricsSamples + i);
perkj803d97f2016-11-01 11:45:46 -07002039 }
2040
mflodmancc3d4422017-08-03 08:27:51 -07002041 video_stream_encoder_->Stop();
2042 video_stream_encoder_.reset();
perkj803d97f2016-11-01 11:45:46 -07002043 stats_proxy_.reset();
sprangf8ee65e2017-02-28 08:49:33 -08002044
perkj803d97f2016-11-01 11:45:46 -07002045 EXPECT_EQ(1,
2046 metrics::NumSamples("WebRTC.Video.CpuLimitedResolutionInPercent"));
2047 EXPECT_EQ(
2048 1, metrics::NumEvents("WebRTC.Video.CpuLimitedResolutionInPercent", 50));
2049}
2050
mflodmancc3d4422017-08-03 08:27:51 -07002051TEST_F(VideoStreamEncoderTest,
2052 CpuLimitedHistogramIsNotReportedForDisabledDegradation) {
2053 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonf4e44af2017-04-19 02:01:06 -07002054 const int kWidth = 640;
2055 const int kHeight = 360;
2056
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002057 video_stream_encoder_->SetSource(&video_source_,
2058 webrtc::DegradationPreference::DISABLED);
asaperssonf4e44af2017-04-19 02:01:06 -07002059
2060 for (int i = 1; i <= SendStatisticsProxy::kMinRequiredMetricsSamples; ++i) {
2061 video_source_.IncomingCapturedFrame(CreateFrame(i, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002062 WaitForEncodedFrame(i);
asaperssonf4e44af2017-04-19 02:01:06 -07002063 }
2064
mflodmancc3d4422017-08-03 08:27:51 -07002065 video_stream_encoder_->Stop();
2066 video_stream_encoder_.reset();
asaperssonf4e44af2017-04-19 02:01:06 -07002067 stats_proxy_.reset();
2068
2069 EXPECT_EQ(0,
2070 metrics::NumSamples("WebRTC.Video.CpuLimitedResolutionInPercent"));
2071}
2072
mflodmancc3d4422017-08-03 08:27:51 -07002073TEST_F(VideoStreamEncoderTest, CallsBitrateObserver) {
sprang4847ae62017-06-27 07:06:52 -07002074 MockBitrateObserver bitrate_observer;
Niels Möller0327c2d2018-05-21 14:09:31 +02002075 video_stream_encoder_->SetBitrateAllocationObserver(&bitrate_observer);
sprang57c2fff2017-01-16 06:24:02 -08002076
2077 const int kDefaultFps = 30;
Erik Språng566124a2018-04-23 12:32:22 +02002078 const VideoBitrateAllocation expected_bitrate =
sprang57c2fff2017-01-16 06:24:02 -08002079 DefaultVideoBitrateAllocator(fake_encoder_.codec_config())
kthelgason2bc68642017-02-07 07:02:22 -08002080 .GetAllocation(kLowTargetBitrateBps, kDefaultFps);
sprang57c2fff2017-01-16 06:24:02 -08002081
2082 // First called on bitrate updated, then again on first frame.
2083 EXPECT_CALL(bitrate_observer, OnBitrateAllocationUpdated(expected_bitrate))
2084 .Times(2);
mflodmancc3d4422017-08-03 08:27:51 -07002085 video_stream_encoder_->OnBitrateUpdated(kLowTargetBitrateBps, 0, 0);
sprang57c2fff2017-01-16 06:24:02 -08002086
2087 const int64_t kStartTimeMs = 1;
2088 video_source_.IncomingCapturedFrame(
2089 CreateFrame(kStartTimeMs, codec_width_, codec_height_));
sprang4847ae62017-06-27 07:06:52 -07002090 WaitForEncodedFrame(kStartTimeMs);
sprang57c2fff2017-01-16 06:24:02 -08002091
2092 // Not called on second frame.
2093 EXPECT_CALL(bitrate_observer, OnBitrateAllocationUpdated(expected_bitrate))
2094 .Times(0);
2095 video_source_.IncomingCapturedFrame(
2096 CreateFrame(kStartTimeMs + 1, codec_width_, codec_height_));
sprang4847ae62017-06-27 07:06:52 -07002097 WaitForEncodedFrame(kStartTimeMs + 1);
sprang57c2fff2017-01-16 06:24:02 -08002098
2099 // Called after a process interval.
2100 const int64_t kProcessIntervalMs =
2101 vcm::VCMProcessTimer::kDefaultProcessIntervalMs;
sprang4847ae62017-06-27 07:06:52 -07002102 fake_clock_.AdvanceTimeMicros(rtc::kNumMicrosecsPerMillisec *
2103 (kProcessIntervalMs + (1000 / kDefaultFps)));
sprang57c2fff2017-01-16 06:24:02 -08002104 EXPECT_CALL(bitrate_observer, OnBitrateAllocationUpdated(expected_bitrate))
2105 .Times(1);
2106 video_source_.IncomingCapturedFrame(CreateFrame(
2107 kStartTimeMs + kProcessIntervalMs, codec_width_, codec_height_));
sprang4847ae62017-06-27 07:06:52 -07002108 WaitForEncodedFrame(kStartTimeMs + kProcessIntervalMs);
sprang57c2fff2017-01-16 06:24:02 -08002109
mflodmancc3d4422017-08-03 08:27:51 -07002110 video_stream_encoder_->Stop();
sprang57c2fff2017-01-16 06:24:02 -08002111}
2112
Niels Möller7dc26b72017-12-06 10:27:48 +01002113TEST_F(VideoStreamEncoderTest, OveruseDetectorUpdatedOnReconfigureAndAdaption) {
2114 const int kFrameWidth = 1280;
2115 const int kFrameHeight = 720;
2116 const int kFramerate = 24;
2117
2118 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
2119 test::FrameForwarder source;
2120 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002121 &source, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
Niels Möller7dc26b72017-12-06 10:27:48 +01002122
2123 // Insert a single frame, triggering initial configuration.
2124 source.IncomingCapturedFrame(CreateFrame(1, kFrameWidth, kFrameHeight));
2125 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2126
2127 EXPECT_EQ(
2128 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2129 kDefaultFramerate);
2130
2131 // Trigger reconfigure encoder (without resetting the entire instance).
2132 VideoEncoderConfig video_encoder_config;
Niels Möller259a4972018-04-05 15:36:51 +02002133 video_encoder_config.codec_type = kVideoCodecVP8;
Niels Möller7dc26b72017-12-06 10:27:48 +01002134 video_encoder_config.max_bitrate_bps = kTargetBitrateBps;
2135 video_encoder_config.number_of_streams = 1;
2136 video_encoder_config.video_stream_factory =
2137 new rtc::RefCountedObject<VideoStreamFactory>(1, kFramerate);
2138 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
Niels Möllerf1338562018-04-26 09:51:47 +02002139 kMaxPayloadLength);
Niels Möller7dc26b72017-12-06 10:27:48 +01002140 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2141
2142 // Detector should be updated with fps limit from codec config.
2143 EXPECT_EQ(
2144 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2145 kFramerate);
2146
2147 // Trigger overuse, max framerate should be reduced.
2148 VideoSendStream::Stats stats = stats_proxy_->GetStats();
2149 stats.input_frame_rate = kFramerate;
2150 stats_proxy_->SetMockStats(stats);
2151 video_stream_encoder_->TriggerCpuOveruse();
2152 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2153 int adapted_framerate =
2154 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate();
2155 EXPECT_LT(adapted_framerate, kFramerate);
2156
2157 // Trigger underuse, max framerate should go back to codec configured fps.
2158 // Set extra low fps, to make sure it's actually reset, not just incremented.
2159 stats = stats_proxy_->GetStats();
2160 stats.input_frame_rate = adapted_framerate / 2;
2161 stats_proxy_->SetMockStats(stats);
2162 video_stream_encoder_->TriggerCpuNormalUsage();
2163 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2164 EXPECT_EQ(
2165 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2166 kFramerate);
2167
2168 video_stream_encoder_->Stop();
2169}
2170
2171TEST_F(VideoStreamEncoderTest,
2172 OveruseDetectorUpdatedRespectsFramerateAfterUnderuse) {
2173 const int kFrameWidth = 1280;
2174 const int kFrameHeight = 720;
2175 const int kLowFramerate = 15;
2176 const int kHighFramerate = 25;
2177
2178 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
2179 test::FrameForwarder source;
2180 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002181 &source, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
Niels Möller7dc26b72017-12-06 10:27:48 +01002182
2183 // Trigger initial configuration.
2184 VideoEncoderConfig video_encoder_config;
Niels Möller259a4972018-04-05 15:36:51 +02002185 video_encoder_config.codec_type = kVideoCodecVP8;
Niels Möller7dc26b72017-12-06 10:27:48 +01002186 video_encoder_config.max_bitrate_bps = kTargetBitrateBps;
2187 video_encoder_config.number_of_streams = 1;
2188 video_encoder_config.video_stream_factory =
2189 new rtc::RefCountedObject<VideoStreamFactory>(1, kLowFramerate);
2190 source.IncomingCapturedFrame(CreateFrame(1, kFrameWidth, kFrameHeight));
2191 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
Niels Möllerf1338562018-04-26 09:51:47 +02002192 kMaxPayloadLength);
Niels Möller7dc26b72017-12-06 10:27:48 +01002193 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2194
2195 EXPECT_EQ(
2196 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2197 kLowFramerate);
2198
2199 // Trigger overuse, max framerate should be reduced.
2200 VideoSendStream::Stats stats = stats_proxy_->GetStats();
2201 stats.input_frame_rate = kLowFramerate;
2202 stats_proxy_->SetMockStats(stats);
2203 video_stream_encoder_->TriggerCpuOveruse();
2204 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2205 int adapted_framerate =
2206 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate();
2207 EXPECT_LT(adapted_framerate, kLowFramerate);
2208
2209 // Reconfigure the encoder with a new (higher max framerate), max fps should
2210 // still respect the adaptation.
2211 video_encoder_config.video_stream_factory =
2212 new rtc::RefCountedObject<VideoStreamFactory>(1, kHighFramerate);
2213 source.IncomingCapturedFrame(CreateFrame(1, kFrameWidth, kFrameHeight));
2214 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
Niels Möllerf1338562018-04-26 09:51:47 +02002215 kMaxPayloadLength);
Niels Möller7dc26b72017-12-06 10:27:48 +01002216 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2217
2218 EXPECT_EQ(
2219 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2220 adapted_framerate);
2221
2222 // Trigger underuse, max framerate should go back to codec configured fps.
2223 stats = stats_proxy_->GetStats();
2224 stats.input_frame_rate = adapted_framerate;
2225 stats_proxy_->SetMockStats(stats);
2226 video_stream_encoder_->TriggerCpuNormalUsage();
2227 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2228 EXPECT_EQ(
2229 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2230 kHighFramerate);
2231
2232 video_stream_encoder_->Stop();
2233}
2234
mflodmancc3d4422017-08-03 08:27:51 -07002235TEST_F(VideoStreamEncoderTest,
2236 OveruseDetectorUpdatedOnDegradationPreferenceChange) {
sprangfda496a2017-06-15 04:21:07 -07002237 const int kFrameWidth = 1280;
2238 const int kFrameHeight = 720;
2239 const int kFramerate = 24;
2240
mflodmancc3d4422017-08-03 08:27:51 -07002241 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
sprangfda496a2017-06-15 04:21:07 -07002242 test::FrameForwarder source;
mflodmancc3d4422017-08-03 08:27:51 -07002243 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002244 &source, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
sprangfda496a2017-06-15 04:21:07 -07002245
2246 // Trigger initial configuration.
2247 VideoEncoderConfig video_encoder_config;
Niels Möller259a4972018-04-05 15:36:51 +02002248 video_encoder_config.codec_type = kVideoCodecVP8;
sprangfda496a2017-06-15 04:21:07 -07002249 video_encoder_config.max_bitrate_bps = kTargetBitrateBps;
2250 video_encoder_config.number_of_streams = 1;
2251 video_encoder_config.video_stream_factory =
2252 new rtc::RefCountedObject<VideoStreamFactory>(1, kFramerate);
2253 source.IncomingCapturedFrame(CreateFrame(1, kFrameWidth, kFrameHeight));
mflodmancc3d4422017-08-03 08:27:51 -07002254 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
Niels Möllerf1338562018-04-26 09:51:47 +02002255 kMaxPayloadLength);
mflodmancc3d4422017-08-03 08:27:51 -07002256 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
sprangfda496a2017-06-15 04:21:07 -07002257
Niels Möller7dc26b72017-12-06 10:27:48 +01002258 EXPECT_EQ(
2259 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2260 kFramerate);
sprangfda496a2017-06-15 04:21:07 -07002261
2262 // Trigger overuse, max framerate should be reduced.
2263 VideoSendStream::Stats stats = stats_proxy_->GetStats();
2264 stats.input_frame_rate = kFramerate;
2265 stats_proxy_->SetMockStats(stats);
mflodmancc3d4422017-08-03 08:27:51 -07002266 video_stream_encoder_->TriggerCpuOveruse();
2267 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
Niels Möller7dc26b72017-12-06 10:27:48 +01002268 int adapted_framerate =
2269 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate();
sprangfda496a2017-06-15 04:21:07 -07002270 EXPECT_LT(adapted_framerate, kFramerate);
2271
2272 // Change degradation preference to not enable framerate scaling. Target
2273 // framerate should be changed to codec defined limit.
mflodmancc3d4422017-08-03 08:27:51 -07002274 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002275 &source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
mflodmancc3d4422017-08-03 08:27:51 -07002276 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
Niels Möller7dc26b72017-12-06 10:27:48 +01002277 EXPECT_EQ(
2278 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2279 kFramerate);
sprangfda496a2017-06-15 04:21:07 -07002280
mflodmancc3d4422017-08-03 08:27:51 -07002281 video_stream_encoder_->Stop();
sprangfda496a2017-06-15 04:21:07 -07002282}
2283
mflodmancc3d4422017-08-03 08:27:51 -07002284TEST_F(VideoStreamEncoderTest, DropsFramesAndScalesWhenBitrateIsTooLow) {
asaperssonfab67072017-04-04 05:51:49 -07002285 const int kTooLowBitrateForFrameSizeBps = 10000;
mflodmancc3d4422017-08-03 08:27:51 -07002286 video_stream_encoder_->OnBitrateUpdated(kTooLowBitrateForFrameSizeBps, 0, 0);
asaperssonfab67072017-04-04 05:51:49 -07002287 const int kWidth = 640;
2288 const int kHeight = 360;
kthelgason2bc68642017-02-07 07:02:22 -08002289
asaperssonfab67072017-04-04 05:51:49 -07002290 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
kthelgason2bc68642017-02-07 07:02:22 -08002291
2292 // Expect to drop this frame, the wait should time out.
sprang4847ae62017-06-27 07:06:52 -07002293 ExpectDroppedFrame();
kthelgason2bc68642017-02-07 07:02:22 -08002294
2295 // Expect the sink_wants to specify a scaled frame.
asapersson0944a802017-04-07 00:57:58 -07002296 EXPECT_LT(video_source_.sink_wants().max_pixel_count, kWidth * kHeight);
kthelgason2bc68642017-02-07 07:02:22 -08002297
sprangc5d62e22017-04-02 23:53:04 -07002298 int last_pixel_count = video_source_.sink_wants().max_pixel_count;
kthelgason2bc68642017-02-07 07:02:22 -08002299
asaperssonfab67072017-04-04 05:51:49 -07002300 // Next frame is scaled.
kthelgason2bc68642017-02-07 07:02:22 -08002301 video_source_.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07002302 CreateFrame(2, kWidth * 3 / 4, kHeight * 3 / 4));
kthelgason2bc68642017-02-07 07:02:22 -08002303
2304 // Expect to drop this frame, the wait should time out.
sprang4847ae62017-06-27 07:06:52 -07002305 ExpectDroppedFrame();
kthelgason2bc68642017-02-07 07:02:22 -08002306
sprangc5d62e22017-04-02 23:53:04 -07002307 EXPECT_LT(video_source_.sink_wants().max_pixel_count, last_pixel_count);
kthelgason2bc68642017-02-07 07:02:22 -08002308
mflodmancc3d4422017-08-03 08:27:51 -07002309 video_stream_encoder_->Stop();
kthelgason2bc68642017-02-07 07:02:22 -08002310}
2311
mflodmancc3d4422017-08-03 08:27:51 -07002312TEST_F(VideoStreamEncoderTest,
2313 NumberOfDroppedFramesLimitedWhenBitrateIsTooLow) {
asaperssonfab67072017-04-04 05:51:49 -07002314 const int kTooLowBitrateForFrameSizeBps = 10000;
mflodmancc3d4422017-08-03 08:27:51 -07002315 video_stream_encoder_->OnBitrateUpdated(kTooLowBitrateForFrameSizeBps, 0, 0);
asaperssonfab67072017-04-04 05:51:49 -07002316 const int kWidth = 640;
2317 const int kHeight = 360;
kthelgason2bc68642017-02-07 07:02:22 -08002318
2319 // We expect the n initial frames to get dropped.
2320 int i;
2321 for (i = 1; i <= kMaxInitialFramedrop; ++i) {
asaperssonfab67072017-04-04 05:51:49 -07002322 video_source_.IncomingCapturedFrame(CreateFrame(i, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002323 ExpectDroppedFrame();
kthelgason2bc68642017-02-07 07:02:22 -08002324 }
2325 // The n+1th frame should not be dropped, even though it's size is too large.
asaperssonfab67072017-04-04 05:51:49 -07002326 video_source_.IncomingCapturedFrame(CreateFrame(i, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002327 WaitForEncodedFrame(i);
kthelgason2bc68642017-02-07 07:02:22 -08002328
2329 // Expect the sink_wants to specify a scaled frame.
asaperssonfab67072017-04-04 05:51:49 -07002330 EXPECT_LT(video_source_.sink_wants().max_pixel_count, kWidth * kHeight);
kthelgason2bc68642017-02-07 07:02:22 -08002331
mflodmancc3d4422017-08-03 08:27:51 -07002332 video_stream_encoder_->Stop();
kthelgason2bc68642017-02-07 07:02:22 -08002333}
2334
mflodmancc3d4422017-08-03 08:27:51 -07002335TEST_F(VideoStreamEncoderTest,
2336 InitialFrameDropOffWithMaintainResolutionPreference) {
asaperssonfab67072017-04-04 05:51:49 -07002337 const int kWidth = 640;
2338 const int kHeight = 360;
mflodmancc3d4422017-08-03 08:27:51 -07002339 video_stream_encoder_->OnBitrateUpdated(kLowTargetBitrateBps, 0, 0);
kthelgason2bc68642017-02-07 07:02:22 -08002340
2341 // Set degradation preference.
mflodmancc3d4422017-08-03 08:27:51 -07002342 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002343 &video_source_, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
kthelgason2bc68642017-02-07 07:02:22 -08002344
asaperssonfab67072017-04-04 05:51:49 -07002345 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
kthelgason2bc68642017-02-07 07:02:22 -08002346 // Frame should not be dropped, even if it's too large.
sprang4847ae62017-06-27 07:06:52 -07002347 WaitForEncodedFrame(1);
kthelgason2bc68642017-02-07 07:02:22 -08002348
mflodmancc3d4422017-08-03 08:27:51 -07002349 video_stream_encoder_->Stop();
kthelgason2bc68642017-02-07 07:02:22 -08002350}
2351
mflodmancc3d4422017-08-03 08:27:51 -07002352TEST_F(VideoStreamEncoderTest, InitialFrameDropOffWhenEncoderDisabledScaling) {
asaperssonfab67072017-04-04 05:51:49 -07002353 const int kWidth = 640;
2354 const int kHeight = 360;
kthelgasonad9010c2017-02-14 00:46:51 -08002355 fake_encoder_.SetQualityScaling(false);
Niels Möller4db138e2018-04-19 09:04:13 +02002356
2357 VideoEncoderConfig video_encoder_config;
2358 test::FillEncoderConfiguration(kVideoCodecVP8, 1, &video_encoder_config);
2359 // Make format different, to force recreation of encoder.
2360 video_encoder_config.video_format.parameters["foo"] = "foo";
2361 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
Niels Möllerf1338562018-04-26 09:51:47 +02002362 kMaxPayloadLength);
mflodmancc3d4422017-08-03 08:27:51 -07002363 video_stream_encoder_->OnBitrateUpdated(kLowTargetBitrateBps, 0, 0);
asapersson09f05612017-05-15 23:40:18 -07002364
kthelgasonb83797b2017-02-14 11:57:25 -08002365 // Force quality scaler reconfiguration by resetting the source.
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002366 video_stream_encoder_->SetSource(&video_source_,
2367 webrtc::DegradationPreference::BALANCED);
kthelgasonad9010c2017-02-14 00:46:51 -08002368
asaperssonfab67072017-04-04 05:51:49 -07002369 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
kthelgasonad9010c2017-02-14 00:46:51 -08002370 // Frame should not be dropped, even if it's too large.
sprang4847ae62017-06-27 07:06:52 -07002371 WaitForEncodedFrame(1);
kthelgasonad9010c2017-02-14 00:46:51 -08002372
mflodmancc3d4422017-08-03 08:27:51 -07002373 video_stream_encoder_->Stop();
kthelgasonad9010c2017-02-14 00:46:51 -08002374 fake_encoder_.SetQualityScaling(true);
2375}
2376
Kári Tristan Helgason639602a2018-08-02 10:51:40 +02002377TEST_F(VideoStreamEncoderTest, InitialFrameDropActivatesWhenBWEstimateReady) {
2378 webrtc::test::ScopedFieldTrials field_trials(
2379 "WebRTC-InitialFramedrop/Enabled/");
2380 // Reset encoder for field trials to take effect.
2381 ConfigureEncoder(video_encoder_config_.Copy());
2382 const int kTooLowBitrateForFrameSizeBps = 10000;
2383 const int kWidth = 640;
2384 const int kHeight = 360;
2385
2386 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
2387 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
2388 // Frame should not be dropped.
2389 WaitForEncodedFrame(1);
2390
2391 video_stream_encoder_->OnBitrateUpdated(kTooLowBitrateForFrameSizeBps, 0, 0);
2392 video_source_.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
2393 // Expect to drop this frame, the wait should time out.
2394 ExpectDroppedFrame();
2395
2396 // Expect the sink_wants to specify a scaled frame.
2397 EXPECT_LT(video_source_.sink_wants().max_pixel_count, kWidth * kHeight);
2398 video_stream_encoder_->Stop();
2399}
2400
mflodmancc3d4422017-08-03 08:27:51 -07002401TEST_F(VideoStreamEncoderTest,
asaperssond0de2952017-04-21 01:47:31 -07002402 ResolutionNotAdaptedForTooSmallFrame_MaintainFramerateMode) {
2403 const int kTooSmallWidth = 10;
2404 const int kTooSmallHeight = 10;
mflodmancc3d4422017-08-03 08:27:51 -07002405 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssond0de2952017-04-21 01:47:31 -07002406
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002407 // Enable MAINTAIN_FRAMERATE preference, no initial limitation.
asaperssond0de2952017-04-21 01:47:31 -07002408 test::FrameForwarder source;
mflodmancc3d4422017-08-03 08:27:51 -07002409 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002410 &source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
asaperssond0de2952017-04-21 01:47:31 -07002411 VerifyNoLimitation(source.sink_wants());
2412 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2413
2414 // Trigger adapt down, too small frame, expect no change.
2415 source.IncomingCapturedFrame(CreateFrame(1, kTooSmallWidth, kTooSmallHeight));
sprang4847ae62017-06-27 07:06:52 -07002416 WaitForEncodedFrame(1);
mflodmancc3d4422017-08-03 08:27:51 -07002417 video_stream_encoder_->TriggerCpuOveruse();
Åsa Persson8c1bf952018-09-13 10:42:19 +02002418 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssond0de2952017-04-21 01:47:31 -07002419 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2420 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2421
mflodmancc3d4422017-08-03 08:27:51 -07002422 video_stream_encoder_->Stop();
asaperssond0de2952017-04-21 01:47:31 -07002423}
2424
mflodmancc3d4422017-08-03 08:27:51 -07002425TEST_F(VideoStreamEncoderTest,
2426 ResolutionNotAdaptedForTooSmallFrame_BalancedMode) {
asaperssonf7e294d2017-06-13 23:25:22 -07002427 const int kTooSmallWidth = 10;
2428 const int kTooSmallHeight = 10;
2429 const int kFpsLimit = 7;
mflodmancc3d4422017-08-03 08:27:51 -07002430 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -07002431
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002432 // Enable BALANCED preference, no initial limitation.
asaperssonf7e294d2017-06-13 23:25:22 -07002433 test::FrameForwarder source;
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002434 video_stream_encoder_->SetSource(&source,
2435 webrtc::DegradationPreference::BALANCED);
asaperssonf7e294d2017-06-13 23:25:22 -07002436 VerifyNoLimitation(source.sink_wants());
2437 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2438 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2439
2440 // Trigger adapt down, expect limited framerate.
2441 source.IncomingCapturedFrame(CreateFrame(1, kTooSmallWidth, kTooSmallHeight));
sprang4847ae62017-06-27 07:06:52 -07002442 WaitForEncodedFrame(1);
mflodmancc3d4422017-08-03 08:27:51 -07002443 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002444 VerifyFpsEqResolutionMax(source.sink_wants(), kFpsLimit);
2445 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2446 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2447 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2448
2449 // Trigger adapt down, too small frame, expect no change.
2450 source.IncomingCapturedFrame(CreateFrame(2, kTooSmallWidth, kTooSmallHeight));
sprang4847ae62017-06-27 07:06:52 -07002451 WaitForEncodedFrame(2);
mflodmancc3d4422017-08-03 08:27:51 -07002452 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002453 VerifyFpsEqResolutionMax(source.sink_wants(), kFpsLimit);
2454 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2455 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2456 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2457
mflodmancc3d4422017-08-03 08:27:51 -07002458 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07002459}
2460
mflodmancc3d4422017-08-03 08:27:51 -07002461TEST_F(VideoStreamEncoderTest, FailingInitEncodeDoesntCauseCrash) {
asapersson02465b82017-04-10 01:12:52 -07002462 fake_encoder_.ForceInitEncodeFailure(true);
mflodmancc3d4422017-08-03 08:27:51 -07002463 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
Niels Möllerf1338562018-04-26 09:51:47 +02002464 ResetEncoder("VP8", 2, 1, 1, false);
asapersson02465b82017-04-10 01:12:52 -07002465 const int kFrameWidth = 1280;
2466 const int kFrameHeight = 720;
2467 video_source_.IncomingCapturedFrame(
2468 CreateFrame(1, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002469 ExpectDroppedFrame();
mflodmancc3d4422017-08-03 08:27:51 -07002470 video_stream_encoder_->Stop();
asapersson02465b82017-04-10 01:12:52 -07002471}
2472
sprangb1ca0732017-02-01 08:38:12 -08002473// TODO(sprang): Extend this with fps throttling and any "balanced" extensions.
mflodmancc3d4422017-08-03 08:27:51 -07002474TEST_F(VideoStreamEncoderTest,
2475 AdaptsResolutionOnOveruse_MaintainFramerateMode) {
2476 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
sprangb1ca0732017-02-01 08:38:12 -08002477
2478 const int kFrameWidth = 1280;
2479 const int kFrameHeight = 720;
2480 // Enabled default VideoAdapter downscaling. First step is 3/4, not 3/5 as
mflodmancc3d4422017-08-03 08:27:51 -07002481 // requested by
2482 // VideoStreamEncoder::VideoSourceProxy::RequestResolutionLowerThan().
sprangb1ca0732017-02-01 08:38:12 -08002483 video_source_.set_adaptation_enabled(true);
2484
2485 video_source_.IncomingCapturedFrame(
Åsa Persson8c1bf952018-09-13 10:42:19 +02002486 CreateFrame(1 * kFrameIntervalMs, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002487 WaitForEncodedFrame(kFrameWidth, kFrameHeight);
sprangb1ca0732017-02-01 08:38:12 -08002488
2489 // Trigger CPU overuse, downscale by 3/4.
mflodmancc3d4422017-08-03 08:27:51 -07002490 video_stream_encoder_->TriggerCpuOveruse();
sprangb1ca0732017-02-01 08:38:12 -08002491 video_source_.IncomingCapturedFrame(
Åsa Persson8c1bf952018-09-13 10:42:19 +02002492 CreateFrame(2 * kFrameIntervalMs, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002493 WaitForEncodedFrame((kFrameWidth * 3) / 4, (kFrameHeight * 3) / 4);
sprangb1ca0732017-02-01 08:38:12 -08002494
asaperssonfab67072017-04-04 05:51:49 -07002495 // Trigger CPU normal use, return to original resolution.
mflodmancc3d4422017-08-03 08:27:51 -07002496 video_stream_encoder_->TriggerCpuNormalUsage();
sprangb1ca0732017-02-01 08:38:12 -08002497 video_source_.IncomingCapturedFrame(
Åsa Persson8c1bf952018-09-13 10:42:19 +02002498 CreateFrame(3 * kFrameIntervalMs, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002499 WaitForEncodedFrame(kFrameWidth, kFrameHeight);
sprangb1ca0732017-02-01 08:38:12 -08002500
mflodmancc3d4422017-08-03 08:27:51 -07002501 video_stream_encoder_->Stop();
sprangb1ca0732017-02-01 08:38:12 -08002502}
sprangfe627f32017-03-29 08:24:59 -07002503
mflodmancc3d4422017-08-03 08:27:51 -07002504TEST_F(VideoStreamEncoderTest,
2505 AdaptsFramerateOnOveruse_MaintainResolutionMode) {
sprangc5d62e22017-04-02 23:53:04 -07002506 const int kFrameWidth = 1280;
2507 const int kFrameHeight = 720;
sprangc5d62e22017-04-02 23:53:04 -07002508
mflodmancc3d4422017-08-03 08:27:51 -07002509 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
2510 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002511 &video_source_, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
sprangc5d62e22017-04-02 23:53:04 -07002512 video_source_.set_adaptation_enabled(true);
2513
sprang4847ae62017-06-27 07:06:52 -07002514 int64_t timestamp_ms = fake_clock_.TimeNanos() / rtc::kNumNanosecsPerMillisec;
sprangc5d62e22017-04-02 23:53:04 -07002515
2516 video_source_.IncomingCapturedFrame(
2517 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002518 WaitForEncodedFrame(timestamp_ms);
sprangc5d62e22017-04-02 23:53:04 -07002519
2520 // Try to trigger overuse. No fps estimate available => no effect.
mflodmancc3d4422017-08-03 08:27:51 -07002521 video_stream_encoder_->TriggerCpuOveruse();
sprangc5d62e22017-04-02 23:53:04 -07002522
2523 // Insert frames for one second to get a stable estimate.
sprang4847ae62017-06-27 07:06:52 -07002524 for (int i = 0; i < max_framerate_; ++i) {
sprangc5d62e22017-04-02 23:53:04 -07002525 timestamp_ms += kFrameIntervalMs;
sprangc5d62e22017-04-02 23:53:04 -07002526 video_source_.IncomingCapturedFrame(
2527 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002528 WaitForEncodedFrame(timestamp_ms);
sprangc5d62e22017-04-02 23:53:04 -07002529 }
2530
2531 // Trigger CPU overuse, reduce framerate by 2/3.
mflodmancc3d4422017-08-03 08:27:51 -07002532 video_stream_encoder_->TriggerCpuOveruse();
sprangc5d62e22017-04-02 23:53:04 -07002533 int num_frames_dropped = 0;
sprang4847ae62017-06-27 07:06:52 -07002534 for (int i = 0; i < max_framerate_; ++i) {
sprangc5d62e22017-04-02 23:53:04 -07002535 timestamp_ms += kFrameIntervalMs;
sprangc5d62e22017-04-02 23:53:04 -07002536 video_source_.IncomingCapturedFrame(
2537 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002538 if (!WaitForFrame(kFrameTimeoutMs)) {
sprangc5d62e22017-04-02 23:53:04 -07002539 ++num_frames_dropped;
2540 } else {
Åsa Perssonc74d8da2017-12-04 14:13:56 +01002541 sink_.CheckLastFrameSizeMatches(kFrameWidth, kFrameHeight);
sprangc5d62e22017-04-02 23:53:04 -07002542 }
2543 }
2544
sprang4847ae62017-06-27 07:06:52 -07002545 // Add some slack to account for frames dropped by the frame dropper.
2546 const int kErrorMargin = 1;
2547 EXPECT_NEAR(num_frames_dropped, max_framerate_ - (max_framerate_ * 2 / 3),
sprangc5d62e22017-04-02 23:53:04 -07002548 kErrorMargin);
2549
2550 // Trigger CPU overuse, reduce framerate by 2/3 again.
mflodmancc3d4422017-08-03 08:27:51 -07002551 video_stream_encoder_->TriggerCpuOveruse();
sprangc5d62e22017-04-02 23:53:04 -07002552 num_frames_dropped = 0;
Åsa Persson8c1bf952018-09-13 10:42:19 +02002553 for (int i = 0; i <= max_framerate_; ++i) {
sprangc5d62e22017-04-02 23:53:04 -07002554 timestamp_ms += kFrameIntervalMs;
sprangc5d62e22017-04-02 23:53:04 -07002555 video_source_.IncomingCapturedFrame(
2556 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002557 if (!WaitForFrame(kFrameTimeoutMs)) {
sprangc5d62e22017-04-02 23:53:04 -07002558 ++num_frames_dropped;
2559 } else {
Åsa Perssonc74d8da2017-12-04 14:13:56 +01002560 sink_.CheckLastFrameSizeMatches(kFrameWidth, kFrameHeight);
sprangc5d62e22017-04-02 23:53:04 -07002561 }
2562 }
sprang4847ae62017-06-27 07:06:52 -07002563 EXPECT_NEAR(num_frames_dropped, max_framerate_ - (max_framerate_ * 4 / 9),
sprangc5d62e22017-04-02 23:53:04 -07002564 kErrorMargin);
2565
2566 // Go back up one step.
mflodmancc3d4422017-08-03 08:27:51 -07002567 video_stream_encoder_->TriggerCpuNormalUsage();
sprangc5d62e22017-04-02 23:53:04 -07002568 num_frames_dropped = 0;
sprang4847ae62017-06-27 07:06:52 -07002569 for (int i = 0; i < max_framerate_; ++i) {
sprangc5d62e22017-04-02 23:53:04 -07002570 timestamp_ms += kFrameIntervalMs;
sprangc5d62e22017-04-02 23:53:04 -07002571 video_source_.IncomingCapturedFrame(
2572 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002573 if (!WaitForFrame(kFrameTimeoutMs)) {
sprangc5d62e22017-04-02 23:53:04 -07002574 ++num_frames_dropped;
2575 } else {
Åsa Perssonc74d8da2017-12-04 14:13:56 +01002576 sink_.CheckLastFrameSizeMatches(kFrameWidth, kFrameHeight);
sprangc5d62e22017-04-02 23:53:04 -07002577 }
2578 }
sprang4847ae62017-06-27 07:06:52 -07002579 EXPECT_NEAR(num_frames_dropped, max_framerate_ - (max_framerate_ * 2 / 3),
sprangc5d62e22017-04-02 23:53:04 -07002580 kErrorMargin);
2581
2582 // Go back up to original mode.
mflodmancc3d4422017-08-03 08:27:51 -07002583 video_stream_encoder_->TriggerCpuNormalUsage();
sprangc5d62e22017-04-02 23:53:04 -07002584 num_frames_dropped = 0;
sprang4847ae62017-06-27 07:06:52 -07002585 for (int i = 0; i < max_framerate_; ++i) {
sprangc5d62e22017-04-02 23:53:04 -07002586 timestamp_ms += kFrameIntervalMs;
sprangc5d62e22017-04-02 23:53:04 -07002587 video_source_.IncomingCapturedFrame(
2588 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002589 if (!WaitForFrame(kFrameTimeoutMs)) {
sprangc5d62e22017-04-02 23:53:04 -07002590 ++num_frames_dropped;
2591 } else {
Åsa Perssonc74d8da2017-12-04 14:13:56 +01002592 sink_.CheckLastFrameSizeMatches(kFrameWidth, kFrameHeight);
sprangc5d62e22017-04-02 23:53:04 -07002593 }
2594 }
2595 EXPECT_NEAR(num_frames_dropped, 0, kErrorMargin);
2596
mflodmancc3d4422017-08-03 08:27:51 -07002597 video_stream_encoder_->Stop();
sprangc5d62e22017-04-02 23:53:04 -07002598}
2599
mflodmancc3d4422017-08-03 08:27:51 -07002600TEST_F(VideoStreamEncoderTest, DoesntAdaptDownPastMinFramerate) {
sprangc5d62e22017-04-02 23:53:04 -07002601 const int kFramerateFps = 5;
2602 const int kFrameIntervalMs = rtc::kNumMillisecsPerSec / kFramerateFps;
sprangc5d62e22017-04-02 23:53:04 -07002603 const int kFrameWidth = 1280;
2604 const int kFrameHeight = 720;
2605
sprang4847ae62017-06-27 07:06:52 -07002606 // Reconfigure encoder with two temporal layers and screensharing, which will
2607 // disable frame dropping and make testing easier.
Niels Möllerf1338562018-04-26 09:51:47 +02002608 ResetEncoder("VP8", 1, 2, 1, true);
sprang4847ae62017-06-27 07:06:52 -07002609
mflodmancc3d4422017-08-03 08:27:51 -07002610 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
2611 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002612 &video_source_, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
sprangc5d62e22017-04-02 23:53:04 -07002613 video_source_.set_adaptation_enabled(true);
2614
sprang4847ae62017-06-27 07:06:52 -07002615 int64_t timestamp_ms = fake_clock_.TimeNanos() / rtc::kNumNanosecsPerMillisec;
sprangc5d62e22017-04-02 23:53:04 -07002616
2617 // Trigger overuse as much as we can.
Jonathan Yubc771b72017-12-08 17:04:29 -08002618 rtc::VideoSinkWants last_wants;
2619 do {
2620 last_wants = video_source_.sink_wants();
2621
sprangc5d62e22017-04-02 23:53:04 -07002622 // Insert frames to get a new fps estimate...
2623 for (int j = 0; j < kFramerateFps; ++j) {
2624 video_source_.IncomingCapturedFrame(
2625 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
Jonathan Yubc771b72017-12-08 17:04:29 -08002626 if (video_source_.last_sent_width()) {
2627 sink_.WaitForEncodedFrame(timestamp_ms);
2628 }
sprangc5d62e22017-04-02 23:53:04 -07002629 timestamp_ms += kFrameIntervalMs;
Yves Gerey665174f2018-06-19 15:03:05 +02002630 fake_clock_.AdvanceTimeMicros(kFrameIntervalMs *
2631 rtc::kNumMicrosecsPerMillisec);
sprangc5d62e22017-04-02 23:53:04 -07002632 }
2633 // ...and then try to adapt again.
mflodmancc3d4422017-08-03 08:27:51 -07002634 video_stream_encoder_->TriggerCpuOveruse();
Jonathan Yubc771b72017-12-08 17:04:29 -08002635 } while (video_source_.sink_wants().max_framerate_fps <
2636 last_wants.max_framerate_fps);
sprangc5d62e22017-04-02 23:53:04 -07002637
Jonathan Yubc771b72017-12-08 17:04:29 -08002638 VerifyFpsEqResolutionMax(video_source_.sink_wants(), kMinFramerateFps);
asaperssonf7e294d2017-06-13 23:25:22 -07002639
mflodmancc3d4422017-08-03 08:27:51 -07002640 video_stream_encoder_->Stop();
sprangc5d62e22017-04-02 23:53:04 -07002641}
asaperssonf7e294d2017-06-13 23:25:22 -07002642
mflodmancc3d4422017-08-03 08:27:51 -07002643TEST_F(VideoStreamEncoderTest,
2644 AdaptsResolutionAndFramerateForLowQuality_BalancedMode) {
asaperssonf7e294d2017-06-13 23:25:22 -07002645 const int kWidth = 1280;
2646 const int kHeight = 720;
2647 const int64_t kFrameIntervalMs = 150;
2648 int64_t timestamp_ms = kFrameIntervalMs;
mflodmancc3d4422017-08-03 08:27:51 -07002649 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -07002650
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002651 // Enable BALANCED preference, no initial limitation.
asaperssonf7e294d2017-06-13 23:25:22 -07002652 AdaptingFrameForwarder source;
2653 source.set_adaptation_enabled(true);
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002654 video_stream_encoder_->SetSource(&source,
2655 webrtc::DegradationPreference::BALANCED);
asaperssonf7e294d2017-06-13 23:25:22 -07002656 timestamp_ms += kFrameIntervalMs;
2657 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002658 WaitForEncodedFrame(kWidth, kHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +02002659 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07002660 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2661 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2662 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2663
2664 // Trigger adapt down, expect scaled down resolution (960x540@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002665 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002666 timestamp_ms += kFrameIntervalMs;
2667 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002668 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002669 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
2670 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2671 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2672 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2673
2674 // Trigger adapt down, expect scaled down resolution (640x360@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002675 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002676 timestamp_ms += kFrameIntervalMs;
2677 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002678 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002679 VerifyFpsMaxResolutionLt(source.sink_wants(), source.last_wants());
2680 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2681 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2682 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2683
2684 // Trigger adapt down, expect reduced fps (640x360@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07002685 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002686 timestamp_ms += kFrameIntervalMs;
2687 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002688 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002689 VerifyFpsLtResolutionEq(source.sink_wants(), source.last_wants());
2690 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2691 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2692 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2693
2694 // Trigger adapt down, expect scaled down resolution (480x270@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07002695 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002696 timestamp_ms += kFrameIntervalMs;
2697 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002698 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002699 VerifyFpsEqResolutionLt(source.sink_wants(), source.last_wants());
2700 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2701 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2702 EXPECT_EQ(4, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2703
2704 // Restrict bitrate, trigger adapt down, expect reduced fps (480x270@10fps).
mflodmancc3d4422017-08-03 08:27:51 -07002705 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002706 timestamp_ms += kFrameIntervalMs;
2707 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002708 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002709 VerifyFpsLtResolutionEq(source.sink_wants(), source.last_wants());
2710 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2711 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2712 EXPECT_EQ(5, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2713
2714 // Trigger adapt down, expect scaled down resolution (320x180@10fps).
mflodmancc3d4422017-08-03 08:27:51 -07002715 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002716 timestamp_ms += kFrameIntervalMs;
2717 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002718 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002719 VerifyFpsEqResolutionLt(source.sink_wants(), source.last_wants());
2720 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2721 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2722 EXPECT_EQ(6, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2723
2724 // Trigger adapt down, expect reduced fps (320x180@7fps).
mflodmancc3d4422017-08-03 08:27:51 -07002725 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002726 timestamp_ms += kFrameIntervalMs;
2727 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002728 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002729 VerifyFpsLtResolutionEq(source.sink_wants(), source.last_wants());
2730 rtc::VideoSinkWants last_wants = source.sink_wants();
2731 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2732 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2733 EXPECT_EQ(7, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2734
2735 // Trigger adapt down, min resolution reached, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07002736 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002737 timestamp_ms += kFrameIntervalMs;
2738 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002739 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002740 VerifyFpsEqResolutionEq(source.sink_wants(), last_wants);
2741 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2742 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2743 EXPECT_EQ(7, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2744
2745 // Trigger adapt down, expect expect increased fps (320x180@10fps).
mflodmancc3d4422017-08-03 08:27:51 -07002746 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002747 timestamp_ms += kFrameIntervalMs;
2748 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002749 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002750 VerifyFpsGtResolutionEq(source.sink_wants(), source.last_wants());
2751 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2752 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2753 EXPECT_EQ(8, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2754
2755 // Trigger adapt up, expect upscaled resolution (480x270@10fps).
mflodmancc3d4422017-08-03 08:27:51 -07002756 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002757 timestamp_ms += kFrameIntervalMs;
2758 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002759 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002760 VerifyFpsEqResolutionGt(source.sink_wants(), source.last_wants());
2761 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2762 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2763 EXPECT_EQ(9, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2764
2765 // Increase bitrate, trigger adapt up, expect increased fps (480x270@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07002766 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002767 timestamp_ms += kFrameIntervalMs;
2768 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002769 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002770 VerifyFpsGtResolutionEq(source.sink_wants(), source.last_wants());
2771 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2772 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2773 EXPECT_EQ(10, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2774
2775 // Trigger adapt up, expect upscaled resolution (640x360@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07002776 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002777 timestamp_ms += kFrameIntervalMs;
2778 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002779 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002780 VerifyFpsEqResolutionGt(source.sink_wants(), source.last_wants());
2781 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2782 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2783 EXPECT_EQ(11, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2784
2785 // Trigger adapt up, expect increased fps (640x360@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002786 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002787 timestamp_ms += kFrameIntervalMs;
2788 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002789 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002790 VerifyFpsMaxResolutionEq(source.sink_wants(), source.last_wants());
2791 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2792 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2793 EXPECT_EQ(12, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2794
2795 // Trigger adapt up, expect upscaled resolution (960x540@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002796 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002797 timestamp_ms += kFrameIntervalMs;
2798 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002799 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002800 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
2801 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2802 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2803 EXPECT_EQ(13, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2804
2805 // Trigger adapt up, expect no restriction (1280x720fps@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002806 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002807 timestamp_ms += kFrameIntervalMs;
2808 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002809 WaitForEncodedFrame(kWidth, kHeight);
asaperssonf7e294d2017-06-13 23:25:22 -07002810 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
Åsa Persson8c1bf952018-09-13 10:42:19 +02002811 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07002812 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2813 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2814 EXPECT_EQ(14, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2815
2816 // Trigger adapt up, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07002817 video_stream_encoder_->TriggerQualityHigh();
Åsa Persson8c1bf952018-09-13 10:42:19 +02002818 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07002819 EXPECT_EQ(14, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2820
mflodmancc3d4422017-08-03 08:27:51 -07002821 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07002822}
2823
mflodmancc3d4422017-08-03 08:27:51 -07002824TEST_F(VideoStreamEncoderTest, AdaptWithTwoReasonsAndDifferentOrder_Framerate) {
asaperssonf7e294d2017-06-13 23:25:22 -07002825 const int kWidth = 1280;
2826 const int kHeight = 720;
2827 const int64_t kFrameIntervalMs = 150;
2828 int64_t timestamp_ms = kFrameIntervalMs;
mflodmancc3d4422017-08-03 08:27:51 -07002829 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -07002830
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002831 // Enable BALANCED preference, no initial limitation.
asaperssonf7e294d2017-06-13 23:25:22 -07002832 AdaptingFrameForwarder source;
2833 source.set_adaptation_enabled(true);
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002834 video_stream_encoder_->SetSource(&source,
2835 webrtc::DegradationPreference::BALANCED);
asaperssonf7e294d2017-06-13 23:25:22 -07002836 timestamp_ms += kFrameIntervalMs;
2837 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002838 WaitForEncodedFrame(kWidth, kHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +02002839 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07002840 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2841 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2842 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2843 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
2844 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2845 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2846
2847 // Trigger cpu adapt down, expect scaled down resolution (960x540@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002848 video_stream_encoder_->TriggerCpuOveruse();
asaperssonf7e294d2017-06-13 23:25:22 -07002849 timestamp_ms += kFrameIntervalMs;
2850 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002851 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002852 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
2853 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2854 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2855 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2856 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
2857 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2858 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2859
2860 // Trigger cpu adapt down, expect scaled down resolution (640x360@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002861 video_stream_encoder_->TriggerCpuOveruse();
asaperssonf7e294d2017-06-13 23:25:22 -07002862 timestamp_ms += kFrameIntervalMs;
2863 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002864 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002865 VerifyFpsMaxResolutionLt(source.sink_wants(), source.last_wants());
2866 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2867 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2868 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2869 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
2870 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2871 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2872
2873 // Trigger quality adapt down, expect reduced fps (640x360@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07002874 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002875 timestamp_ms += kFrameIntervalMs;
2876 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002877 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002878 VerifyFpsLtResolutionEq(source.sink_wants(), source.last_wants());
2879 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2880 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2881 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2882 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
2883 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2884 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2885
2886 // Trigger cpu adapt up, expect increased fps (640x360@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002887 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssonf7e294d2017-06-13 23:25:22 -07002888 timestamp_ms += kFrameIntervalMs;
2889 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002890 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002891 VerifyFpsMaxResolutionEq(source.sink_wants(), source.last_wants());
2892 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2893 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2894 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2895 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
2896 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2897 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2898
2899 // Trigger quality adapt up, expect upscaled resolution (960x540@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002900 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002901 timestamp_ms += kFrameIntervalMs;
2902 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002903 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002904 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
2905 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2906 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2907 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2908 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
2909 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2910 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2911
2912 // Trigger cpu adapt up, expect no restriction (1280x720fps@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002913 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssonf7e294d2017-06-13 23:25:22 -07002914 timestamp_ms += kFrameIntervalMs;
2915 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002916 WaitForEncodedFrame(kWidth, kHeight);
asaperssonf7e294d2017-06-13 23:25:22 -07002917 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
Åsa Persson8c1bf952018-09-13 10:42:19 +02002918 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07002919 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2920 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2921 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2922 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
2923 EXPECT_EQ(4, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2924 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2925
2926 // Trigger adapt up, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07002927 video_stream_encoder_->TriggerQualityHigh();
Åsa Persson8c1bf952018-09-13 10:42:19 +02002928 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07002929 EXPECT_EQ(4, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2930 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2931
mflodmancc3d4422017-08-03 08:27:51 -07002932 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07002933}
2934
mflodmancc3d4422017-08-03 08:27:51 -07002935TEST_F(VideoStreamEncoderTest,
2936 AdaptWithTwoReasonsAndDifferentOrder_Resolution) {
asaperssonf7e294d2017-06-13 23:25:22 -07002937 const int kWidth = 640;
2938 const int kHeight = 360;
2939 const int kFpsLimit = 15;
2940 const int64_t kFrameIntervalMs = 150;
2941 int64_t timestamp_ms = kFrameIntervalMs;
mflodmancc3d4422017-08-03 08:27:51 -07002942 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -07002943
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002944 // Enable BALANCED preference, no initial limitation.
asaperssonf7e294d2017-06-13 23:25:22 -07002945 AdaptingFrameForwarder source;
2946 source.set_adaptation_enabled(true);
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002947 video_stream_encoder_->SetSource(&source,
2948 webrtc::DegradationPreference::BALANCED);
asaperssonf7e294d2017-06-13 23:25:22 -07002949 timestamp_ms += kFrameIntervalMs;
2950 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002951 WaitForEncodedFrame(kWidth, kHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +02002952 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07002953 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2954 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2955 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2956 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
2957 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2958 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2959
2960 // Trigger cpu adapt down, expect scaled down framerate (640x360@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07002961 video_stream_encoder_->TriggerCpuOveruse();
asaperssonf7e294d2017-06-13 23:25:22 -07002962 timestamp_ms += kFrameIntervalMs;
2963 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002964 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002965 VerifyFpsEqResolutionMax(source.sink_wants(), kFpsLimit);
2966 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2967 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2968 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2969 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_framerate);
2970 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2971 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2972
2973 // Trigger quality adapt down, expect scaled down resolution (480x270@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07002974 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002975 timestamp_ms += kFrameIntervalMs;
2976 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002977 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002978 VerifyFpsEqResolutionLt(source.sink_wants(), source.last_wants());
2979 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2980 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2981 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2982 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_framerate);
2983 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2984 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2985
2986 // Trigger cpu adapt up, expect upscaled resolution (640x360@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07002987 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssonf7e294d2017-06-13 23:25:22 -07002988 timestamp_ms += kFrameIntervalMs;
2989 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002990 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002991 VerifyFpsEqResolutionGt(source.sink_wants(), source.last_wants());
2992 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2993 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2994 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2995 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
2996 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2997 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2998
2999 // Trigger quality adapt up, expect increased fps (640x360@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07003000 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07003001 timestamp_ms += kFrameIntervalMs;
3002 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003003 WaitForEncodedFrame(timestamp_ms);
Åsa Persson8c1bf952018-09-13 10:42:19 +02003004 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07003005 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
3006 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
3007 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
3008 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
3009 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
3010 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3011
3012 // Trigger adapt up, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07003013 video_stream_encoder_->TriggerQualityHigh();
Åsa Persson8c1bf952018-09-13 10:42:19 +02003014 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07003015 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
3016 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3017
mflodmancc3d4422017-08-03 08:27:51 -07003018 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07003019}
3020
mflodmancc3d4422017-08-03 08:27:51 -07003021TEST_F(VideoStreamEncoderTest, AcceptsFullHdAdaptedDownSimulcastFrames) {
ilnik6b826ef2017-06-16 06:53:48 -07003022 // Simulates simulcast behavior and makes highest stream resolutions divisible
3023 // by 4.
3024 class CroppingVideoStreamFactory
3025 : public VideoEncoderConfig::VideoStreamFactoryInterface {
3026 public:
3027 explicit CroppingVideoStreamFactory(size_t num_temporal_layers,
3028 int framerate)
3029 : num_temporal_layers_(num_temporal_layers), framerate_(framerate) {
3030 EXPECT_GT(num_temporal_layers, 0u);
3031 EXPECT_GT(framerate, 0);
3032 }
3033
3034 private:
3035 std::vector<VideoStream> CreateEncoderStreams(
3036 int width,
3037 int height,
3038 const VideoEncoderConfig& encoder_config) override {
Yves Gerey665174f2018-06-19 15:03:05 +02003039 std::vector<VideoStream> streams = test::CreateVideoStreams(
3040 width - width % 4, height - height % 4, encoder_config);
ilnik6b826ef2017-06-16 06:53:48 -07003041 for (VideoStream& stream : streams) {
Sergey Silkina796a7e2018-03-01 15:11:29 +01003042 stream.num_temporal_layers = num_temporal_layers_;
ilnik6b826ef2017-06-16 06:53:48 -07003043 stream.max_framerate = framerate_;
3044 }
3045 return streams;
3046 }
3047
3048 const size_t num_temporal_layers_;
3049 const int framerate_;
3050 };
3051
3052 const int kFrameWidth = 1920;
3053 const int kFrameHeight = 1080;
3054 // 3/4 of 1920.
3055 const int kAdaptedFrameWidth = 1440;
3056 // 3/4 of 1080 rounded down to multiple of 4.
3057 const int kAdaptedFrameHeight = 808;
3058 const int kFramerate = 24;
3059
mflodmancc3d4422017-08-03 08:27:51 -07003060 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
ilnik6b826ef2017-06-16 06:53:48 -07003061 // Trigger reconfigure encoder (without resetting the entire instance).
3062 VideoEncoderConfig video_encoder_config;
Niels Möller259a4972018-04-05 15:36:51 +02003063 video_encoder_config.codec_type = kVideoCodecVP8;
ilnik6b826ef2017-06-16 06:53:48 -07003064 video_encoder_config.max_bitrate_bps = kTargetBitrateBps;
3065 video_encoder_config.number_of_streams = 1;
3066 video_encoder_config.video_stream_factory =
3067 new rtc::RefCountedObject<CroppingVideoStreamFactory>(1, kFramerate);
mflodmancc3d4422017-08-03 08:27:51 -07003068 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
Niels Möllerf1338562018-04-26 09:51:47 +02003069 kMaxPayloadLength);
mflodmancc3d4422017-08-03 08:27:51 -07003070 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
ilnik6b826ef2017-06-16 06:53:48 -07003071
3072 video_source_.set_adaptation_enabled(true);
3073
3074 video_source_.IncomingCapturedFrame(
3075 CreateFrame(1, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07003076 WaitForEncodedFrame(kFrameWidth, kFrameHeight);
ilnik6b826ef2017-06-16 06:53:48 -07003077
3078 // Trigger CPU overuse, downscale by 3/4.
mflodmancc3d4422017-08-03 08:27:51 -07003079 video_stream_encoder_->TriggerCpuOveruse();
ilnik6b826ef2017-06-16 06:53:48 -07003080 video_source_.IncomingCapturedFrame(
3081 CreateFrame(2, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07003082 WaitForEncodedFrame(kAdaptedFrameWidth, kAdaptedFrameHeight);
ilnik6b826ef2017-06-16 06:53:48 -07003083
mflodmancc3d4422017-08-03 08:27:51 -07003084 video_stream_encoder_->Stop();
ilnik6b826ef2017-06-16 06:53:48 -07003085}
3086
mflodmancc3d4422017-08-03 08:27:51 -07003087TEST_F(VideoStreamEncoderTest, PeriodicallyUpdatesChannelParameters) {
sprang4847ae62017-06-27 07:06:52 -07003088 const int kFrameWidth = 1280;
3089 const int kFrameHeight = 720;
3090 const int kLowFps = 2;
3091 const int kHighFps = 30;
3092
mflodmancc3d4422017-08-03 08:27:51 -07003093 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
sprang4847ae62017-06-27 07:06:52 -07003094
3095 int64_t timestamp_ms = fake_clock_.TimeNanos() / rtc::kNumNanosecsPerMillisec;
3096 max_framerate_ = kLowFps;
3097
3098 // Insert 2 seconds of 2fps video.
3099 for (int i = 0; i < kLowFps * 2; ++i) {
3100 video_source_.IncomingCapturedFrame(
3101 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
3102 WaitForEncodedFrame(timestamp_ms);
3103 timestamp_ms += 1000 / kLowFps;
3104 }
3105
3106 // Make sure encoder is updated with new target.
mflodmancc3d4422017-08-03 08:27:51 -07003107 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
sprang4847ae62017-06-27 07:06:52 -07003108 video_source_.IncomingCapturedFrame(
3109 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
3110 WaitForEncodedFrame(timestamp_ms);
3111 timestamp_ms += 1000 / kLowFps;
3112
3113 EXPECT_EQ(kLowFps, fake_encoder_.GetConfiguredInputFramerate());
3114
3115 // Insert 30fps frames for just a little more than the forced update period.
3116 const int kVcmTimerIntervalFrames =
3117 (vcm::VCMProcessTimer::kDefaultProcessIntervalMs * kHighFps) / 1000;
3118 const int kFrameIntervalMs = 1000 / kHighFps;
3119 max_framerate_ = kHighFps;
3120 for (int i = 0; i < kVcmTimerIntervalFrames + 2; ++i) {
3121 video_source_.IncomingCapturedFrame(
3122 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
3123 // Wait for encoded frame, but skip ahead if it doesn't arrive as it might
3124 // be dropped if the encoder hans't been updated with the new higher target
3125 // framerate yet, causing it to overshoot the target bitrate and then
3126 // suffering the wrath of the media optimizer.
3127 TimedWaitForEncodedFrame(timestamp_ms, 2 * kFrameIntervalMs);
3128 timestamp_ms += kFrameIntervalMs;
3129 }
3130
3131 // Don expect correct measurement just yet, but it should be higher than
3132 // before.
3133 EXPECT_GT(fake_encoder_.GetConfiguredInputFramerate(), kLowFps);
3134
mflodmancc3d4422017-08-03 08:27:51 -07003135 video_stream_encoder_->Stop();
sprang4847ae62017-06-27 07:06:52 -07003136}
3137
mflodmancc3d4422017-08-03 08:27:51 -07003138TEST_F(VideoStreamEncoderTest, DoesNotUpdateBitrateAllocationWhenSuspended) {
sprang4847ae62017-06-27 07:06:52 -07003139 const int kFrameWidth = 1280;
3140 const int kFrameHeight = 720;
3141 const int kTargetBitrateBps = 1000000;
3142
3143 MockBitrateObserver bitrate_observer;
Niels Möller0327c2d2018-05-21 14:09:31 +02003144 video_stream_encoder_->SetBitrateAllocationObserver(&bitrate_observer);
sprang4847ae62017-06-27 07:06:52 -07003145
3146 EXPECT_CALL(bitrate_observer, OnBitrateAllocationUpdated(_)).Times(1);
3147 // Initial bitrate update.
mflodmancc3d4422017-08-03 08:27:51 -07003148 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
3149 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
sprang4847ae62017-06-27 07:06:52 -07003150
3151 // Insert a first video frame, causes another bitrate update.
3152 int64_t timestamp_ms = fake_clock_.TimeNanos() / rtc::kNumNanosecsPerMillisec;
3153 EXPECT_CALL(bitrate_observer, OnBitrateAllocationUpdated(_)).Times(1);
3154 video_source_.IncomingCapturedFrame(
3155 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
3156 WaitForEncodedFrame(timestamp_ms);
3157
3158 // Next, simulate video suspension due to pacer queue overrun.
mflodmancc3d4422017-08-03 08:27:51 -07003159 video_stream_encoder_->OnBitrateUpdated(0, 0, 1);
sprang4847ae62017-06-27 07:06:52 -07003160
3161 // Skip ahead until a new periodic parameter update should have occured.
3162 timestamp_ms += vcm::VCMProcessTimer::kDefaultProcessIntervalMs;
3163 fake_clock_.AdvanceTimeMicros(
3164 vcm::VCMProcessTimer::kDefaultProcessIntervalMs *
3165 rtc::kNumMicrosecsPerMillisec);
3166
3167 // Bitrate observer should not be called.
3168 EXPECT_CALL(bitrate_observer, OnBitrateAllocationUpdated(_)).Times(0);
3169 video_source_.IncomingCapturedFrame(
3170 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
3171 ExpectDroppedFrame();
3172
mflodmancc3d4422017-08-03 08:27:51 -07003173 video_stream_encoder_->Stop();
sprang4847ae62017-06-27 07:06:52 -07003174}
ilnik6b826ef2017-06-16 06:53:48 -07003175
Niels Möller4db138e2018-04-19 09:04:13 +02003176TEST_F(VideoStreamEncoderTest,
3177 DefaultCpuAdaptationThresholdsForSoftwareEncoder) {
3178 const int kFrameWidth = 1280;
3179 const int kFrameHeight = 720;
3180 const CpuOveruseOptions default_options;
3181 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
3182 video_source_.IncomingCapturedFrame(
3183 CreateFrame(1, kFrameWidth, kFrameHeight));
3184 WaitForEncodedFrame(1);
3185 EXPECT_EQ(video_stream_encoder_->overuse_detector_proxy_->GetOptions()
3186 .low_encode_usage_threshold_percent,
3187 default_options.low_encode_usage_threshold_percent);
3188 EXPECT_EQ(video_stream_encoder_->overuse_detector_proxy_->GetOptions()
3189 .high_encode_usage_threshold_percent,
3190 default_options.high_encode_usage_threshold_percent);
3191 video_stream_encoder_->Stop();
3192}
3193
3194TEST_F(VideoStreamEncoderTest,
3195 HigherCpuAdaptationThresholdsForHardwareEncoder) {
3196 const int kFrameWidth = 1280;
3197 const int kFrameHeight = 720;
3198 CpuOveruseOptions hardware_options;
3199 hardware_options.low_encode_usage_threshold_percent = 150;
3200 hardware_options.high_encode_usage_threshold_percent = 200;
Mirta Dvorniciccdc5eb02018-12-05 13:22:09 +01003201 fake_encoder_.SetIsHardwareAccelerated(true);
Niels Möller4db138e2018-04-19 09:04:13 +02003202
3203 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
3204 video_source_.IncomingCapturedFrame(
3205 CreateFrame(1, kFrameWidth, kFrameHeight));
3206 WaitForEncodedFrame(1);
3207 EXPECT_EQ(video_stream_encoder_->overuse_detector_proxy_->GetOptions()
3208 .low_encode_usage_threshold_percent,
3209 hardware_options.low_encode_usage_threshold_percent);
3210 EXPECT_EQ(video_stream_encoder_->overuse_detector_proxy_->GetOptions()
3211 .high_encode_usage_threshold_percent,
3212 hardware_options.high_encode_usage_threshold_percent);
3213 video_stream_encoder_->Stop();
3214}
3215
perkj26091b12016-09-01 01:17:40 -07003216} // namespace webrtc