blob: 4b392239bb6307d3465848c928725afb0c14fab9 [file] [log] [blame]
perkj26091b12016-09-01 01:17:40 -07001/*
2 * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved.
3 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
sprangfe627f32017-03-29 08:24:59 -070011#include <algorithm>
perkj803d97f2016-11-01 11:45:46 -070012#include <limits>
Per512ecb32016-09-23 15:52:06 +020013#include <utility>
14
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020015#include "api/video/i420_buffer.h"
16#include "media/base/videoadapter.h"
17#include "modules/video_coding/codecs/vp8/temporal_layers.h"
Sergey Silkin86684962018-03-28 19:32:37 +020018#include "modules/video_coding/codecs/vp9/include/vp9_globals.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020019#include "modules/video_coding/utility/default_video_bitrate_allocator.h"
20#include "rtc_base/fakeclock.h"
21#include "rtc_base/logging.h"
22#include "system_wrappers/include/metrics_default.h"
23#include "system_wrappers/include/sleep.h"
Niels Möller4db138e2018-04-19 09:04:13 +020024#include "test/encoder_proxy_factory.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020025#include "test/encoder_settings.h"
26#include "test/fake_encoder.h"
27#include "test/frame_generator.h"
28#include "test/gmock.h"
29#include "test/gtest.h"
30#include "video/send_statistics_proxy.h"
31#include "video/video_stream_encoder.h"
perkj26091b12016-09-01 01:17:40 -070032
kthelgason33ce8892016-12-09 03:53:59 -080033namespace {
kthelgason33ce8892016-12-09 03:53:59 -080034const int kMinPixelsPerFrame = 320 * 180;
sprangc5d62e22017-04-02 23:53:04 -070035const int kMinFramerateFps = 2;
Jonathan Yubc771b72017-12-08 17:04:29 -080036const int kMinBalancedFramerateFps = 7;
sprangc5d62e22017-04-02 23:53:04 -070037const int64_t kFrameTimeoutMs = 100;
emircanbbcc3562017-08-18 00:28:40 -070038const unsigned char kNumSlDummy = 0;
sprangc5d62e22017-04-02 23:53:04 -070039} // namespace
kthelgason33ce8892016-12-09 03:53:59 -080040
perkj26091b12016-09-01 01:17:40 -070041namespace webrtc {
42
kthelgason876222f2016-11-29 01:44:11 -080043using DegredationPreference = VideoSendStream::DegradationPreference;
sprangb1ca0732017-02-01 08:38:12 -080044using ScaleReason = AdaptationObserverInterface::AdaptReason;
sprang57c2fff2017-01-16 06:24:02 -080045using ::testing::_;
46using ::testing::Return;
kthelgason876222f2016-11-29 01:44:11 -080047
perkj803d97f2016-11-01 11:45:46 -070048namespace {
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;
asapersson5f7226f2016-11-25 04:37:00 -080054
perkj803d97f2016-11-01 11:45:46 -070055class TestBuffer : public webrtc::I420Buffer {
56 public:
57 TestBuffer(rtc::Event* event, int width, int height)
58 : I420Buffer(width, height), event_(event) {}
59
60 private:
61 friend class rtc::RefCountedObject<TestBuffer>;
62 ~TestBuffer() override {
63 if (event_)
64 event_->Set();
65 }
66 rtc::Event* const event_;
67};
68
Niels Möller7dc26b72017-12-06 10:27:48 +010069class CpuOveruseDetectorProxy : public OveruseFrameDetector {
70 public:
Niels Möllerd1f7eb62018-03-28 16:40:58 +020071 explicit CpuOveruseDetectorProxy(CpuOveruseMetricsObserver* metrics_observer)
72 : OveruseFrameDetector(metrics_observer),
Niels Möller7dc26b72017-12-06 10:27:48 +010073 last_target_framerate_fps_(-1) {}
74 virtual ~CpuOveruseDetectorProxy() {}
75
76 void OnTargetFramerateUpdated(int framerate_fps) override {
77 rtc::CritScope cs(&lock_);
78 last_target_framerate_fps_ = framerate_fps;
79 OveruseFrameDetector::OnTargetFramerateUpdated(framerate_fps);
80 }
81
82 int GetLastTargetFramerate() {
83 rtc::CritScope cs(&lock_);
84 return last_target_framerate_fps_;
85 }
86
Niels Möller4db138e2018-04-19 09:04:13 +020087 CpuOveruseOptions GetOptions() { return options_; }
88
Niels Möller7dc26b72017-12-06 10:27:48 +010089 private:
90 rtc::CriticalSection lock_;
91 int last_target_framerate_fps_ RTC_GUARDED_BY(lock_);
92};
93
mflodmancc3d4422017-08-03 08:27:51 -070094class VideoStreamEncoderUnderTest : public VideoStreamEncoder {
perkj803d97f2016-11-01 11:45:46 -070095 public:
Niels Möller7dc26b72017-12-06 10:27:48 +010096 VideoStreamEncoderUnderTest(SendStatisticsProxy* stats_proxy,
97 const VideoSendStream::Config::EncoderSettings& settings)
mflodmancc3d4422017-08-03 08:27:51 -070098 : VideoStreamEncoder(
99 1 /* number_of_cores */,
100 stats_proxy,
101 settings,
102 nullptr /* pre_encode_callback */,
mflodmancc3d4422017-08-03 08:27:51 -0700103 std::unique_ptr<OveruseFrameDetector>(
Niels Möller7dc26b72017-12-06 10:27:48 +0100104 overuse_detector_proxy_ = new CpuOveruseDetectorProxy(
mflodmancc3d4422017-08-03 08:27:51 -0700105 stats_proxy))) {}
perkj803d97f2016-11-01 11:45:46 -0700106
sprangb1ca0732017-02-01 08:38:12 -0800107 void PostTaskAndWait(bool down, AdaptReason reason) {
perkj803d97f2016-11-01 11:45:46 -0700108 rtc::Event event(false, false);
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() {
119 rtc::Event event(false, false);
120 encoder_queue()->PostTask([&event] {
121 event.Set();
122 });
123 ASSERT_TRUE(event.Wait(5000));
124 }
125
sprangb1ca0732017-02-01 08:38:12 -0800126 void TriggerCpuOveruse() { PostTaskAndWait(true, AdaptReason::kCpu); }
kthelgason876222f2016-11-29 01:44:11 -0800127
sprangb1ca0732017-02-01 08:38:12 -0800128 void TriggerCpuNormalUsage() { PostTaskAndWait(false, AdaptReason::kCpu); }
kthelgason876222f2016-11-29 01:44:11 -0800129
sprangb1ca0732017-02-01 08:38:12 -0800130 void TriggerQualityLow() { PostTaskAndWait(true, AdaptReason::kQuality); }
kthelgason876222f2016-11-29 01:44:11 -0800131
sprangb1ca0732017-02-01 08:38:12 -0800132 void TriggerQualityHigh() { PostTaskAndWait(false, AdaptReason::kQuality); }
sprangfda496a2017-06-15 04:21:07 -0700133
Niels Möller7dc26b72017-12-06 10:27:48 +0100134 CpuOveruseDetectorProxy* overuse_detector_proxy_;
perkj803d97f2016-11-01 11:45:46 -0700135};
136
asapersson5f7226f2016-11-25 04:37:00 -0800137class VideoStreamFactory
138 : public VideoEncoderConfig::VideoStreamFactoryInterface {
139 public:
sprangfda496a2017-06-15 04:21:07 -0700140 explicit VideoStreamFactory(size_t num_temporal_layers, int framerate)
141 : num_temporal_layers_(num_temporal_layers), framerate_(framerate) {
asapersson5f7226f2016-11-25 04:37:00 -0800142 EXPECT_GT(num_temporal_layers, 0u);
sprangfda496a2017-06-15 04:21:07 -0700143 EXPECT_GT(framerate, 0);
asapersson5f7226f2016-11-25 04:37:00 -0800144 }
145
146 private:
147 std::vector<VideoStream> CreateEncoderStreams(
148 int width,
149 int height,
150 const VideoEncoderConfig& encoder_config) override {
151 std::vector<VideoStream> streams =
152 test::CreateVideoStreams(width, height, encoder_config);
153 for (VideoStream& stream : streams) {
Sergey Silkina796a7e2018-03-01 15:11:29 +0100154 stream.num_temporal_layers = num_temporal_layers_;
sprangfda496a2017-06-15 04:21:07 -0700155 stream.max_framerate = framerate_;
asapersson5f7226f2016-11-25 04:37:00 -0800156 }
157 return streams;
158 }
sprangfda496a2017-06-15 04:21:07 -0700159
asapersson5f7226f2016-11-25 04:37:00 -0800160 const size_t num_temporal_layers_;
sprangfda496a2017-06-15 04:21:07 -0700161 const int framerate_;
asapersson5f7226f2016-11-25 04:37:00 -0800162};
163
ilnik6b826ef2017-06-16 06:53:48 -0700164
sprangb1ca0732017-02-01 08:38:12 -0800165class AdaptingFrameForwarder : public test::FrameForwarder {
166 public:
167 AdaptingFrameForwarder() : adaptation_enabled_(false) {}
asaperssonfab67072017-04-04 05:51:49 -0700168 ~AdaptingFrameForwarder() override {}
sprangb1ca0732017-02-01 08:38:12 -0800169
170 void set_adaptation_enabled(bool enabled) {
171 rtc::CritScope cs(&crit_);
172 adaptation_enabled_ = enabled;
173 }
174
asaperssonfab67072017-04-04 05:51:49 -0700175 bool adaption_enabled() const {
sprangb1ca0732017-02-01 08:38:12 -0800176 rtc::CritScope cs(&crit_);
177 return adaptation_enabled_;
178 }
179
asapersson09f05612017-05-15 23:40:18 -0700180 rtc::VideoSinkWants last_wants() const {
181 rtc::CritScope cs(&crit_);
182 return last_wants_;
183 }
184
Jonathan Yubc771b72017-12-08 17:04:29 -0800185 rtc::Optional<int> last_sent_width() const { return last_width_; }
186 rtc::Optional<int> last_sent_height() const { return last_height_; }
187
sprangb1ca0732017-02-01 08:38:12 -0800188 void IncomingCapturedFrame(const VideoFrame& video_frame) override {
189 int cropped_width = 0;
190 int cropped_height = 0;
191 int out_width = 0;
192 int out_height = 0;
sprangc5d62e22017-04-02 23:53:04 -0700193 if (adaption_enabled()) {
194 if (adapter_.AdaptFrameResolution(
195 video_frame.width(), video_frame.height(),
196 video_frame.timestamp_us() * 1000, &cropped_width,
197 &cropped_height, &out_width, &out_height)) {
198 VideoFrame adapted_frame(new rtc::RefCountedObject<TestBuffer>(
199 nullptr, out_width, out_height),
200 99, 99, kVideoRotation_0);
201 adapted_frame.set_ntp_time_ms(video_frame.ntp_time_ms());
202 test::FrameForwarder::IncomingCapturedFrame(adapted_frame);
Jonathan Yubc771b72017-12-08 17:04:29 -0800203 last_width_.emplace(adapted_frame.width());
204 last_height_.emplace(adapted_frame.height());
205 } else {
206 last_width_ = rtc::nullopt;
207 last_height_ = rtc::nullopt;
sprangc5d62e22017-04-02 23:53:04 -0700208 }
sprangb1ca0732017-02-01 08:38:12 -0800209 } else {
210 test::FrameForwarder::IncomingCapturedFrame(video_frame);
Jonathan Yubc771b72017-12-08 17:04:29 -0800211 last_width_.emplace(video_frame.width());
212 last_height_.emplace(video_frame.height());
sprangb1ca0732017-02-01 08:38:12 -0800213 }
214 }
215
216 void AddOrUpdateSink(rtc::VideoSinkInterface<VideoFrame>* sink,
217 const rtc::VideoSinkWants& wants) override {
218 rtc::CritScope cs(&crit_);
asapersson09f05612017-05-15 23:40:18 -0700219 last_wants_ = sink_wants();
sprangc5d62e22017-04-02 23:53:04 -0700220 adapter_.OnResolutionFramerateRequest(wants.target_pixel_count,
221 wants.max_pixel_count,
222 wants.max_framerate_fps);
sprangb1ca0732017-02-01 08:38:12 -0800223 test::FrameForwarder::AddOrUpdateSink(sink, wants);
224 }
sprangb1ca0732017-02-01 08:38:12 -0800225 cricket::VideoAdapter adapter_;
danilchapa37de392017-09-09 04:17:22 -0700226 bool adaptation_enabled_ RTC_GUARDED_BY(crit_);
227 rtc::VideoSinkWants last_wants_ RTC_GUARDED_BY(crit_);
Jonathan Yubc771b72017-12-08 17:04:29 -0800228 rtc::Optional<int> last_width_;
229 rtc::Optional<int> last_height_;
sprangb1ca0732017-02-01 08:38:12 -0800230};
sprangc5d62e22017-04-02 23:53:04 -0700231
232class MockableSendStatisticsProxy : public SendStatisticsProxy {
233 public:
234 MockableSendStatisticsProxy(Clock* clock,
235 const VideoSendStream::Config& config,
236 VideoEncoderConfig::ContentType content_type)
237 : SendStatisticsProxy(clock, config, content_type) {}
238
239 VideoSendStream::Stats GetStats() override {
240 rtc::CritScope cs(&lock_);
241 if (mock_stats_)
242 return *mock_stats_;
243 return SendStatisticsProxy::GetStats();
244 }
245
246 void SetMockStats(const VideoSendStream::Stats& stats) {
247 rtc::CritScope cs(&lock_);
248 mock_stats_.emplace(stats);
249 }
250
251 void ResetMockStats() {
252 rtc::CritScope cs(&lock_);
253 mock_stats_.reset();
254 }
255
256 private:
257 rtc::CriticalSection lock_;
danilchapa37de392017-09-09 04:17:22 -0700258 rtc::Optional<VideoSendStream::Stats> mock_stats_ RTC_GUARDED_BY(lock_);
sprangc5d62e22017-04-02 23:53:04 -0700259};
260
sprang4847ae62017-06-27 07:06:52 -0700261class MockBitrateObserver : public VideoBitrateAllocationObserver {
262 public:
263 MOCK_METHOD1(OnBitrateAllocationUpdated, void(const BitrateAllocation&));
264};
265
perkj803d97f2016-11-01 11:45:46 -0700266} // namespace
267
mflodmancc3d4422017-08-03 08:27:51 -0700268class VideoStreamEncoderTest : public ::testing::Test {
perkj26091b12016-09-01 01:17:40 -0700269 public:
270 static const int kDefaultTimeoutMs = 30 * 1000;
271
mflodmancc3d4422017-08-03 08:27:51 -0700272 VideoStreamEncoderTest()
perkj26091b12016-09-01 01:17:40 -0700273 : video_send_config_(VideoSendStream::Config(nullptr)),
perkjfa10b552016-10-02 23:45:26 -0700274 codec_width_(320),
275 codec_height_(240),
sprang4847ae62017-06-27 07:06:52 -0700276 max_framerate_(30),
perkj26091b12016-09-01 01:17:40 -0700277 fake_encoder_(),
Niels Möller4db138e2018-04-19 09:04:13 +0200278 encoder_factory_(&fake_encoder_),
sprangc5d62e22017-04-02 23:53:04 -0700279 stats_proxy_(new MockableSendStatisticsProxy(
perkj803d97f2016-11-01 11:45:46 -0700280 Clock::GetRealTimeClock(),
281 video_send_config_,
282 webrtc::VideoEncoderConfig::ContentType::kRealtimeVideo)),
perkj26091b12016-09-01 01:17:40 -0700283 sink_(&fake_encoder_) {}
284
285 void SetUp() override {
perkj803d97f2016-11-01 11:45:46 -0700286 metrics::Reset();
perkj26091b12016-09-01 01:17:40 -0700287 video_send_config_ = VideoSendStream::Config(nullptr);
Niels Möller4db138e2018-04-19 09:04:13 +0200288 video_send_config_.encoder_settings.encoder_factory = &encoder_factory_;
Niels Möller259a4972018-04-05 15:36:51 +0200289 video_send_config_.rtp.payload_name = "FAKE";
290 video_send_config_.rtp.payload_type = 125;
perkj26091b12016-09-01 01:17:40 -0700291
Per512ecb32016-09-23 15:52:06 +0200292 VideoEncoderConfig video_encoder_config;
Niels Möller259a4972018-04-05 15:36:51 +0200293 test::FillEncoderConfiguration(kVideoCodecVP8, 1, &video_encoder_config);
sprang4847ae62017-06-27 07:06:52 -0700294 video_encoder_config.video_stream_factory =
295 new rtc::RefCountedObject<VideoStreamFactory>(1, max_framerate_);
Erik Språng08127a92016-11-16 16:41:30 +0100296 video_encoder_config_ = video_encoder_config.Copy();
sprang4847ae62017-06-27 07:06:52 -0700297
298 // Framerate limit is specified by the VideoStreamFactory.
299 std::vector<VideoStream> streams =
300 video_encoder_config.video_stream_factory->CreateEncoderStreams(
301 codec_width_, codec_height_, video_encoder_config);
302 max_framerate_ = streams[0].max_framerate;
303 fake_clock_.SetTimeMicros(1234);
304
asapersson5f7226f2016-11-25 04:37:00 -0800305 ConfigureEncoder(std::move(video_encoder_config), true /* nack_enabled */);
306 }
307
308 void ConfigureEncoder(VideoEncoderConfig video_encoder_config,
309 bool nack_enabled) {
mflodmancc3d4422017-08-03 08:27:51 -0700310 if (video_stream_encoder_)
311 video_stream_encoder_->Stop();
312 video_stream_encoder_.reset(new VideoStreamEncoderUnderTest(
perkj803d97f2016-11-01 11:45:46 -0700313 stats_proxy_.get(), video_send_config_.encoder_settings));
mflodmancc3d4422017-08-03 08:27:51 -0700314 video_stream_encoder_->SetSink(&sink_, false /* rotation_applied */);
315 video_stream_encoder_->SetSource(
sprangc5d62e22017-04-02 23:53:04 -0700316 &video_source_,
317 VideoSendStream::DegradationPreference::kMaintainFramerate);
mflodmancc3d4422017-08-03 08:27:51 -0700318 video_stream_encoder_->SetStartBitrate(kTargetBitrateBps);
319 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
320 kMaxPayloadLength, nack_enabled);
321 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
asapersson5f7226f2016-11-25 04:37:00 -0800322 }
323
324 void ResetEncoder(const std::string& payload_name,
325 size_t num_streams,
326 size_t num_temporal_layers,
emircanbbcc3562017-08-18 00:28:40 -0700327 unsigned char num_spatial_layers,
sprang4847ae62017-06-27 07:06:52 -0700328 bool nack_enabled,
329 bool screenshare) {
Niels Möller259a4972018-04-05 15:36:51 +0200330 video_send_config_.rtp.payload_name = payload_name;
asapersson5f7226f2016-11-25 04:37:00 -0800331
332 VideoEncoderConfig video_encoder_config;
Niels Möller259a4972018-04-05 15:36:51 +0200333 video_encoder_config.codec_type = PayloadStringToCodecType(payload_name);
asapersson5f7226f2016-11-25 04:37:00 -0800334 video_encoder_config.number_of_streams = num_streams;
kthelgason2bc68642017-02-07 07:02:22 -0800335 video_encoder_config.max_bitrate_bps = kTargetBitrateBps;
asapersson5f7226f2016-11-25 04:37:00 -0800336 video_encoder_config.video_stream_factory =
sprangfda496a2017-06-15 04:21:07 -0700337 new rtc::RefCountedObject<VideoStreamFactory>(num_temporal_layers,
338 kDefaultFramerate);
sprang4847ae62017-06-27 07:06:52 -0700339 video_encoder_config.content_type =
340 screenshare ? VideoEncoderConfig::ContentType::kScreen
341 : VideoEncoderConfig::ContentType::kRealtimeVideo;
emircanbbcc3562017-08-18 00:28:40 -0700342 if (payload_name == "VP9") {
343 VideoCodecVP9 vp9_settings = VideoEncoder::GetDefaultVp9Settings();
344 vp9_settings.numberOfSpatialLayers = num_spatial_layers;
345 video_encoder_config.encoder_specific_settings =
346 new rtc::RefCountedObject<
347 VideoEncoderConfig::Vp9EncoderSpecificSettings>(vp9_settings);
348 }
asapersson5f7226f2016-11-25 04:37:00 -0800349 ConfigureEncoder(std::move(video_encoder_config), nack_enabled);
perkj26091b12016-09-01 01:17:40 -0700350 }
351
sprang57c2fff2017-01-16 06:24:02 -0800352 VideoFrame CreateFrame(int64_t ntp_time_ms,
353 rtc::Event* destruction_event) const {
Per512ecb32016-09-23 15:52:06 +0200354 VideoFrame frame(new rtc::RefCountedObject<TestBuffer>(
355 destruction_event, codec_width_, codec_height_),
356 99, 99, kVideoRotation_0);
sprang57c2fff2017-01-16 06:24:02 -0800357 frame.set_ntp_time_ms(ntp_time_ms);
perkj26091b12016-09-01 01:17:40 -0700358 return frame;
359 }
360
sprang57c2fff2017-01-16 06:24:02 -0800361 VideoFrame CreateFrame(int64_t ntp_time_ms, int width, int height) const {
perkj803d97f2016-11-01 11:45:46 -0700362 VideoFrame frame(
363 new rtc::RefCountedObject<TestBuffer>(nullptr, width, height), 99, 99,
364 kVideoRotation_0);
sprang57c2fff2017-01-16 06:24:02 -0800365 frame.set_ntp_time_ms(ntp_time_ms);
sprangc5d62e22017-04-02 23:53:04 -0700366 frame.set_timestamp_us(ntp_time_ms * 1000);
perkj803d97f2016-11-01 11:45:46 -0700367 return frame;
368 }
369
asapersson02465b82017-04-10 01:12:52 -0700370 void VerifyNoLimitation(const rtc::VideoSinkWants& wants) {
asapersson02465b82017-04-10 01:12:52 -0700371 EXPECT_EQ(std::numeric_limits<int>::max(), wants.max_framerate_fps);
asapersson09f05612017-05-15 23:40:18 -0700372 EXPECT_EQ(std::numeric_limits<int>::max(), wants.max_pixel_count);
373 EXPECT_FALSE(wants.target_pixel_count);
asapersson02465b82017-04-10 01:12:52 -0700374 }
375
asapersson09f05612017-05-15 23:40:18 -0700376 void VerifyFpsEqResolutionEq(const rtc::VideoSinkWants& wants1,
377 const rtc::VideoSinkWants& wants2) {
378 EXPECT_EQ(wants1.max_framerate_fps, wants2.max_framerate_fps);
379 EXPECT_EQ(wants1.max_pixel_count, wants2.max_pixel_count);
380 }
381
382 void VerifyFpsMaxResolutionLt(const rtc::VideoSinkWants& wants1,
383 const rtc::VideoSinkWants& wants2) {
384 EXPECT_EQ(std::numeric_limits<int>::max(), wants1.max_framerate_fps);
385 EXPECT_LT(wants1.max_pixel_count, wants2.max_pixel_count);
386 EXPECT_GT(wants1.max_pixel_count, 0);
387 }
388
389 void VerifyFpsMaxResolutionGt(const rtc::VideoSinkWants& wants1,
390 const rtc::VideoSinkWants& wants2) {
391 EXPECT_EQ(std::numeric_limits<int>::max(), wants1.max_framerate_fps);
392 EXPECT_GT(wants1.max_pixel_count, wants2.max_pixel_count);
393 }
394
asaperssonf7e294d2017-06-13 23:25:22 -0700395 void VerifyFpsMaxResolutionEq(const rtc::VideoSinkWants& wants1,
396 const rtc::VideoSinkWants& wants2) {
397 EXPECT_EQ(std::numeric_limits<int>::max(), wants1.max_framerate_fps);
398 EXPECT_EQ(wants1.max_pixel_count, wants2.max_pixel_count);
399 }
400
401 void VerifyFpsLtResolutionEq(const rtc::VideoSinkWants& wants1,
402 const rtc::VideoSinkWants& wants2) {
403 EXPECT_LT(wants1.max_framerate_fps, wants2.max_framerate_fps);
404 EXPECT_EQ(wants1.max_pixel_count, wants2.max_pixel_count);
405 }
406
407 void VerifyFpsGtResolutionEq(const rtc::VideoSinkWants& wants1,
408 const rtc::VideoSinkWants& wants2) {
409 EXPECT_GT(wants1.max_framerate_fps, wants2.max_framerate_fps);
410 EXPECT_EQ(wants1.max_pixel_count, wants2.max_pixel_count);
411 }
412
413 void VerifyFpsEqResolutionLt(const rtc::VideoSinkWants& wants1,
414 const rtc::VideoSinkWants& wants2) {
415 EXPECT_EQ(wants1.max_framerate_fps, wants2.max_framerate_fps);
416 EXPECT_LT(wants1.max_pixel_count, wants2.max_pixel_count);
417 EXPECT_GT(wants1.max_pixel_count, 0);
418 }
419
420 void VerifyFpsEqResolutionGt(const rtc::VideoSinkWants& wants1,
421 const rtc::VideoSinkWants& wants2) {
422 EXPECT_EQ(wants1.max_framerate_fps, wants2.max_framerate_fps);
423 EXPECT_GT(wants1.max_pixel_count, wants2.max_pixel_count);
424 }
425
asapersson09f05612017-05-15 23:40:18 -0700426 void VerifyFpsMaxResolutionLt(const rtc::VideoSinkWants& wants,
427 int pixel_count) {
428 EXPECT_EQ(std::numeric_limits<int>::max(), wants.max_framerate_fps);
asapersson02465b82017-04-10 01:12:52 -0700429 EXPECT_LT(wants.max_pixel_count, pixel_count);
430 EXPECT_GT(wants.max_pixel_count, 0);
asapersson09f05612017-05-15 23:40:18 -0700431 }
432
433 void VerifyFpsLtResolutionMax(const rtc::VideoSinkWants& wants, int fps) {
434 EXPECT_LT(wants.max_framerate_fps, fps);
435 EXPECT_EQ(std::numeric_limits<int>::max(), wants.max_pixel_count);
436 EXPECT_FALSE(wants.target_pixel_count);
asapersson02465b82017-04-10 01:12:52 -0700437 }
438
asaperssonf7e294d2017-06-13 23:25:22 -0700439 void VerifyFpsEqResolutionMax(const rtc::VideoSinkWants& wants,
440 int expected_fps) {
441 EXPECT_EQ(expected_fps, wants.max_framerate_fps);
442 EXPECT_EQ(std::numeric_limits<int>::max(), wants.max_pixel_count);
443 EXPECT_FALSE(wants.target_pixel_count);
444 }
445
Jonathan Yubc771b72017-12-08 17:04:29 -0800446 void VerifyBalancedModeFpsRange(const rtc::VideoSinkWants& wants,
447 int last_frame_pixels) {
448 // Balanced mode should always scale FPS to the desired range before
449 // attempting to scale resolution.
450 int fps_limit = wants.max_framerate_fps;
451 if (last_frame_pixels <= 320 * 240) {
452 EXPECT_TRUE(7 <= fps_limit && fps_limit <= 10);
453 } else if (last_frame_pixels <= 480 * 270) {
454 EXPECT_TRUE(10 <= fps_limit && fps_limit <= 15);
455 } else if (last_frame_pixels <= 640 * 480) {
456 EXPECT_LE(15, fps_limit);
457 } else {
458 EXPECT_EQ(std::numeric_limits<int>::max(), fps_limit);
459 }
460 }
461
sprang4847ae62017-06-27 07:06:52 -0700462 void WaitForEncodedFrame(int64_t expected_ntp_time) {
463 sink_.WaitForEncodedFrame(expected_ntp_time);
464 fake_clock_.AdvanceTimeMicros(rtc::kNumMicrosecsPerSec / max_framerate_);
465 }
466
467 bool TimedWaitForEncodedFrame(int64_t expected_ntp_time, int64_t timeout_ms) {
468 bool ok = sink_.TimedWaitForEncodedFrame(expected_ntp_time, timeout_ms);
469 fake_clock_.AdvanceTimeMicros(rtc::kNumMicrosecsPerSec / max_framerate_);
470 return ok;
471 }
472
473 void WaitForEncodedFrame(uint32_t expected_width, uint32_t expected_height) {
474 sink_.WaitForEncodedFrame(expected_width, expected_height);
475 fake_clock_.AdvanceTimeMicros(rtc::kNumMicrosecsPerSec / max_framerate_);
476 }
477
478 void ExpectDroppedFrame() {
479 sink_.ExpectDroppedFrame();
480 fake_clock_.AdvanceTimeMicros(rtc::kNumMicrosecsPerSec / max_framerate_);
481 }
482
483 bool WaitForFrame(int64_t timeout_ms) {
484 bool ok = sink_.WaitForFrame(timeout_ms);
485 fake_clock_.AdvanceTimeMicros(rtc::kNumMicrosecsPerSec / max_framerate_);
486 return ok;
487 }
488
perkj26091b12016-09-01 01:17:40 -0700489 class TestEncoder : public test::FakeEncoder {
490 public:
491 TestEncoder()
492 : FakeEncoder(Clock::GetRealTimeClock()),
493 continue_encode_event_(false, false) {}
494
asaperssonfab67072017-04-04 05:51:49 -0700495 VideoCodec codec_config() const {
brandtre78d2662017-01-16 05:57:16 -0800496 rtc::CritScope lock(&crit_sect_);
perkjfa10b552016-10-02 23:45:26 -0700497 return config_;
498 }
499
500 void BlockNextEncode() {
brandtre78d2662017-01-16 05:57:16 -0800501 rtc::CritScope lock(&local_crit_sect_);
perkjfa10b552016-10-02 23:45:26 -0700502 block_next_encode_ = true;
503 }
504
kthelgason876222f2016-11-29 01:44:11 -0800505 VideoEncoder::ScalingSettings GetScalingSettings() const override {
kthelgason2fc52542017-03-03 00:24:41 -0800506 rtc::CritScope lock(&local_crit_sect_);
kthelgasonad9010c2017-02-14 00:46:51 -0800507 if (quality_scaling_)
Niels Möller225c7872018-02-22 15:03:53 +0100508 return VideoEncoder::ScalingSettings(1, 2, kMinPixelsPerFrame);
509 return VideoEncoder::ScalingSettings::kOff;
kthelgason876222f2016-11-29 01:44:11 -0800510 }
511
perkjfa10b552016-10-02 23:45:26 -0700512 void ContinueEncode() { continue_encode_event_.Set(); }
513
514 void CheckLastTimeStampsMatch(int64_t ntp_time_ms,
515 uint32_t timestamp) const {
brandtre78d2662017-01-16 05:57:16 -0800516 rtc::CritScope lock(&local_crit_sect_);
perkjfa10b552016-10-02 23:45:26 -0700517 EXPECT_EQ(timestamp_, timestamp);
518 EXPECT_EQ(ntp_time_ms_, ntp_time_ms);
519 }
520
kthelgason2fc52542017-03-03 00:24:41 -0800521 void SetQualityScaling(bool b) {
522 rtc::CritScope lock(&local_crit_sect_);
523 quality_scaling_ = b;
524 }
kthelgasonad9010c2017-02-14 00:46:51 -0800525
sprangfe627f32017-03-29 08:24:59 -0700526 void ForceInitEncodeFailure(bool force_failure) {
527 rtc::CritScope lock(&local_crit_sect_);
528 force_init_encode_failed_ = force_failure;
529 }
530
perkjfa10b552016-10-02 23:45:26 -0700531 private:
perkj26091b12016-09-01 01:17:40 -0700532 int32_t Encode(const VideoFrame& input_image,
533 const CodecSpecificInfo* codec_specific_info,
534 const std::vector<FrameType>* frame_types) override {
535 bool block_encode;
536 {
brandtre78d2662017-01-16 05:57:16 -0800537 rtc::CritScope lock(&local_crit_sect_);
perkj26091b12016-09-01 01:17:40 -0700538 EXPECT_GT(input_image.timestamp(), timestamp_);
539 EXPECT_GT(input_image.ntp_time_ms(), ntp_time_ms_);
540 EXPECT_EQ(input_image.timestamp(), input_image.ntp_time_ms() * 90);
541
542 timestamp_ = input_image.timestamp();
543 ntp_time_ms_ = input_image.ntp_time_ms();
perkj803d97f2016-11-01 11:45:46 -0700544 last_input_width_ = input_image.width();
545 last_input_height_ = input_image.height();
perkj26091b12016-09-01 01:17:40 -0700546 block_encode = block_next_encode_;
547 block_next_encode_ = false;
548 }
549 int32_t result =
550 FakeEncoder::Encode(input_image, codec_specific_info, frame_types);
551 if (block_encode)
perkja49cbd32016-09-16 07:53:41 -0700552 EXPECT_TRUE(continue_encode_event_.Wait(kDefaultTimeoutMs));
perkj26091b12016-09-01 01:17:40 -0700553 return result;
554 }
555
sprangfe627f32017-03-29 08:24:59 -0700556 int32_t InitEncode(const VideoCodec* config,
557 int32_t number_of_cores,
558 size_t max_payload_size) override {
559 int res =
560 FakeEncoder::InitEncode(config, number_of_cores, max_payload_size);
561 rtc::CritScope lock(&local_crit_sect_);
Erik Språng82fad3d2018-03-21 09:57:23 +0100562 if (config->codecType == kVideoCodecVP8) {
sprangfe627f32017-03-29 08:24:59 -0700563 // Simulate setting up temporal layers, in order to validate the life
564 // cycle of these objects.
565 int num_streams = std::max<int>(1, config->numberOfSimulcastStreams);
sprangfe627f32017-03-29 08:24:59 -0700566 for (int i = 0; i < num_streams; ++i) {
567 allocated_temporal_layers_.emplace_back(
Niels Möller150dcb02018-03-27 14:16:55 +0200568 TemporalLayers::CreateTemporalLayers(*config, i));
sprangfe627f32017-03-29 08:24:59 -0700569 }
570 }
571 if (force_init_encode_failed_)
572 return -1;
573 return res;
574 }
575
brandtre78d2662017-01-16 05:57:16 -0800576 rtc::CriticalSection local_crit_sect_;
danilchapa37de392017-09-09 04:17:22 -0700577 bool block_next_encode_ RTC_GUARDED_BY(local_crit_sect_) = false;
perkj26091b12016-09-01 01:17:40 -0700578 rtc::Event continue_encode_event_;
danilchapa37de392017-09-09 04:17:22 -0700579 uint32_t timestamp_ RTC_GUARDED_BY(local_crit_sect_) = 0;
580 int64_t ntp_time_ms_ RTC_GUARDED_BY(local_crit_sect_) = 0;
581 int last_input_width_ RTC_GUARDED_BY(local_crit_sect_) = 0;
582 int last_input_height_ RTC_GUARDED_BY(local_crit_sect_) = 0;
583 bool quality_scaling_ RTC_GUARDED_BY(local_crit_sect_) = true;
sprangfe627f32017-03-29 08:24:59 -0700584 std::vector<std::unique_ptr<TemporalLayers>> allocated_temporal_layers_
danilchapa37de392017-09-09 04:17:22 -0700585 RTC_GUARDED_BY(local_crit_sect_);
586 bool force_init_encode_failed_ RTC_GUARDED_BY(local_crit_sect_) = false;
perkj26091b12016-09-01 01:17:40 -0700587 };
588
mflodmancc3d4422017-08-03 08:27:51 -0700589 class TestSink : public VideoStreamEncoder::EncoderSink {
perkj26091b12016-09-01 01:17:40 -0700590 public:
591 explicit TestSink(TestEncoder* test_encoder)
592 : test_encoder_(test_encoder), encoded_frame_event_(false, false) {}
593
perkj26091b12016-09-01 01:17:40 -0700594 void WaitForEncodedFrame(int64_t expected_ntp_time) {
sprang4847ae62017-06-27 07:06:52 -0700595 EXPECT_TRUE(
596 TimedWaitForEncodedFrame(expected_ntp_time, kDefaultTimeoutMs));
597 }
598
599 bool TimedWaitForEncodedFrame(int64_t expected_ntp_time,
600 int64_t timeout_ms) {
perkj26091b12016-09-01 01:17:40 -0700601 uint32_t timestamp = 0;
sprang4847ae62017-06-27 07:06:52 -0700602 if (!encoded_frame_event_.Wait(timeout_ms))
603 return false;
perkj26091b12016-09-01 01:17:40 -0700604 {
605 rtc::CritScope lock(&crit_);
sprangb1ca0732017-02-01 08:38:12 -0800606 timestamp = last_timestamp_;
perkj26091b12016-09-01 01:17:40 -0700607 }
608 test_encoder_->CheckLastTimeStampsMatch(expected_ntp_time, timestamp);
sprang4847ae62017-06-27 07:06:52 -0700609 return true;
perkj26091b12016-09-01 01:17:40 -0700610 }
611
sprangb1ca0732017-02-01 08:38:12 -0800612 void WaitForEncodedFrame(uint32_t expected_width,
613 uint32_t expected_height) {
sprangc5d62e22017-04-02 23:53:04 -0700614 EXPECT_TRUE(encoded_frame_event_.Wait(kDefaultTimeoutMs));
Åsa Perssonc74d8da2017-12-04 14:13:56 +0100615 CheckLastFrameSizeMatches(expected_width, expected_height);
sprangc5d62e22017-04-02 23:53:04 -0700616 }
617
Åsa Perssonc74d8da2017-12-04 14:13:56 +0100618 void CheckLastFrameSizeMatches(uint32_t expected_width,
sprangc5d62e22017-04-02 23:53:04 -0700619 uint32_t expected_height) {
sprangb1ca0732017-02-01 08:38:12 -0800620 uint32_t width = 0;
621 uint32_t height = 0;
sprangb1ca0732017-02-01 08:38:12 -0800622 {
623 rtc::CritScope lock(&crit_);
624 width = last_width_;
625 height = last_height_;
626 }
627 EXPECT_EQ(expected_height, height);
628 EXPECT_EQ(expected_width, width);
629 }
630
kthelgason2fc52542017-03-03 00:24:41 -0800631 void ExpectDroppedFrame() { EXPECT_FALSE(encoded_frame_event_.Wait(100)); }
kthelgason2bc68642017-02-07 07:02:22 -0800632
sprangc5d62e22017-04-02 23:53:04 -0700633 bool WaitForFrame(int64_t timeout_ms) {
634 return encoded_frame_event_.Wait(timeout_ms);
635 }
636
perkj26091b12016-09-01 01:17:40 -0700637 void SetExpectNoFrames() {
638 rtc::CritScope lock(&crit_);
639 expect_frames_ = false;
640 }
641
asaperssonfab67072017-04-04 05:51:49 -0700642 int number_of_reconfigurations() const {
Per512ecb32016-09-23 15:52:06 +0200643 rtc::CritScope lock(&crit_);
644 return number_of_reconfigurations_;
645 }
646
asaperssonfab67072017-04-04 05:51:49 -0700647 int last_min_transmit_bitrate() const {
Per512ecb32016-09-23 15:52:06 +0200648 rtc::CritScope lock(&crit_);
649 return min_transmit_bitrate_bps_;
650 }
651
perkj26091b12016-09-01 01:17:40 -0700652 private:
sergeyu2cb155a2016-11-04 11:39:29 -0700653 Result OnEncodedImage(
654 const EncodedImage& encoded_image,
655 const CodecSpecificInfo* codec_specific_info,
656 const RTPFragmentationHeader* fragmentation) override {
Per512ecb32016-09-23 15:52:06 +0200657 rtc::CritScope lock(&crit_);
658 EXPECT_TRUE(expect_frames_);
sprangb1ca0732017-02-01 08:38:12 -0800659 last_timestamp_ = encoded_image._timeStamp;
660 last_width_ = encoded_image._encodedWidth;
661 last_height_ = encoded_image._encodedHeight;
Per512ecb32016-09-23 15:52:06 +0200662 encoded_frame_event_.Set();
sprangb1ca0732017-02-01 08:38:12 -0800663 return Result(Result::OK, last_timestamp_);
Per512ecb32016-09-23 15:52:06 +0200664 }
665
666 void OnEncoderConfigurationChanged(std::vector<VideoStream> streams,
667 int min_transmit_bitrate_bps) override {
668 rtc::CriticalSection crit_;
669 ++number_of_reconfigurations_;
670 min_transmit_bitrate_bps_ = min_transmit_bitrate_bps;
671 }
672
perkj26091b12016-09-01 01:17:40 -0700673 rtc::CriticalSection crit_;
674 TestEncoder* test_encoder_;
675 rtc::Event encoded_frame_event_;
sprangb1ca0732017-02-01 08:38:12 -0800676 uint32_t last_timestamp_ = 0;
677 uint32_t last_height_ = 0;
678 uint32_t last_width_ = 0;
perkj26091b12016-09-01 01:17:40 -0700679 bool expect_frames_ = true;
Per512ecb32016-09-23 15:52:06 +0200680 int number_of_reconfigurations_ = 0;
681 int min_transmit_bitrate_bps_ = 0;
perkj26091b12016-09-01 01:17:40 -0700682 };
683
684 VideoSendStream::Config video_send_config_;
Erik Språng08127a92016-11-16 16:41:30 +0100685 VideoEncoderConfig video_encoder_config_;
Per512ecb32016-09-23 15:52:06 +0200686 int codec_width_;
687 int codec_height_;
sprang4847ae62017-06-27 07:06:52 -0700688 int max_framerate_;
perkj26091b12016-09-01 01:17:40 -0700689 TestEncoder fake_encoder_;
Niels Möller4db138e2018-04-19 09:04:13 +0200690 test::EncoderProxyFactory encoder_factory_;
sprangc5d62e22017-04-02 23:53:04 -0700691 std::unique_ptr<MockableSendStatisticsProxy> stats_proxy_;
perkj26091b12016-09-01 01:17:40 -0700692 TestSink sink_;
sprangb1ca0732017-02-01 08:38:12 -0800693 AdaptingFrameForwarder video_source_;
mflodmancc3d4422017-08-03 08:27:51 -0700694 std::unique_ptr<VideoStreamEncoderUnderTest> video_stream_encoder_;
sprang4847ae62017-06-27 07:06:52 -0700695 rtc::ScopedFakeClock fake_clock_;
perkj26091b12016-09-01 01:17:40 -0700696};
697
mflodmancc3d4422017-08-03 08:27:51 -0700698TEST_F(VideoStreamEncoderTest, EncodeOneFrame) {
699 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkj26091b12016-09-01 01:17:40 -0700700 rtc::Event frame_destroyed_event(false, false);
perkja49cbd32016-09-16 07:53:41 -0700701 video_source_.IncomingCapturedFrame(CreateFrame(1, &frame_destroyed_event));
sprang4847ae62017-06-27 07:06:52 -0700702 WaitForEncodedFrame(1);
perkja49cbd32016-09-16 07:53:41 -0700703 EXPECT_TRUE(frame_destroyed_event.Wait(kDefaultTimeoutMs));
mflodmancc3d4422017-08-03 08:27:51 -0700704 video_stream_encoder_->Stop();
perkj26091b12016-09-01 01:17:40 -0700705}
706
mflodmancc3d4422017-08-03 08:27:51 -0700707TEST_F(VideoStreamEncoderTest, DropsFramesBeforeFirstOnBitrateUpdated) {
perkj26091b12016-09-01 01:17:40 -0700708 // Dropped since no target bitrate has been set.
709 rtc::Event frame_destroyed_event(false, false);
Sebastian Janssona3177052018-04-10 13:05:49 +0200710 // The encoder will cache up to one frame for a short duration. Adding two
711 // frames means that the first frame will be dropped and the second frame will
712 // be sent when the encoder is enabled.
perkja49cbd32016-09-16 07:53:41 -0700713 video_source_.IncomingCapturedFrame(CreateFrame(1, &frame_destroyed_event));
Sebastian Janssona3177052018-04-10 13:05:49 +0200714 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
perkja49cbd32016-09-16 07:53:41 -0700715 EXPECT_TRUE(frame_destroyed_event.Wait(kDefaultTimeoutMs));
perkj26091b12016-09-01 01:17:40 -0700716
mflodmancc3d4422017-08-03 08:27:51 -0700717 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkj26091b12016-09-01 01:17:40 -0700718
Sebastian Janssona3177052018-04-10 13:05:49 +0200719 // The pending frame should be received.
sprang4847ae62017-06-27 07:06:52 -0700720 WaitForEncodedFrame(2);
Sebastian Janssona3177052018-04-10 13:05:49 +0200721 video_source_.IncomingCapturedFrame(CreateFrame(3, nullptr));
722
723 WaitForEncodedFrame(3);
mflodmancc3d4422017-08-03 08:27:51 -0700724 video_stream_encoder_->Stop();
perkj26091b12016-09-01 01:17:40 -0700725}
726
mflodmancc3d4422017-08-03 08:27:51 -0700727TEST_F(VideoStreamEncoderTest, DropsFramesWhenRateSetToZero) {
728 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkja49cbd32016-09-16 07:53:41 -0700729 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700730 WaitForEncodedFrame(1);
perkj26091b12016-09-01 01:17:40 -0700731
mflodmancc3d4422017-08-03 08:27:51 -0700732 video_stream_encoder_->OnBitrateUpdated(0, 0, 0);
Sebastian Janssona3177052018-04-10 13:05:49 +0200733 // The encoder will cache up to one frame for a short duration. Adding two
734 // frames means that the first frame will be dropped and the second frame will
735 // be sent when the encoder is resumed.
perkja49cbd32016-09-16 07:53:41 -0700736 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
Sebastian Janssona3177052018-04-10 13:05:49 +0200737 video_source_.IncomingCapturedFrame(CreateFrame(3, nullptr));
perkj26091b12016-09-01 01:17:40 -0700738
mflodmancc3d4422017-08-03 08:27:51 -0700739 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
sprang4847ae62017-06-27 07:06:52 -0700740 WaitForEncodedFrame(3);
Sebastian Janssona3177052018-04-10 13:05:49 +0200741 video_source_.IncomingCapturedFrame(CreateFrame(4, nullptr));
742 WaitForEncodedFrame(4);
mflodmancc3d4422017-08-03 08:27:51 -0700743 video_stream_encoder_->Stop();
perkj26091b12016-09-01 01:17:40 -0700744}
745
mflodmancc3d4422017-08-03 08:27:51 -0700746TEST_F(VideoStreamEncoderTest, DropsFramesWithSameOrOldNtpTimestamp) {
747 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkja49cbd32016-09-16 07:53:41 -0700748 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700749 WaitForEncodedFrame(1);
perkj26091b12016-09-01 01:17:40 -0700750
751 // This frame will be dropped since it has the same ntp timestamp.
perkja49cbd32016-09-16 07:53:41 -0700752 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
perkj26091b12016-09-01 01:17:40 -0700753
perkja49cbd32016-09-16 07:53:41 -0700754 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700755 WaitForEncodedFrame(2);
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, DropsFrameAfterStop) {
760 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkj26091b12016-09-01 01:17:40 -0700761
perkja49cbd32016-09-16 07:53:41 -0700762 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700763 WaitForEncodedFrame(1);
perkj26091b12016-09-01 01:17:40 -0700764
mflodmancc3d4422017-08-03 08:27:51 -0700765 video_stream_encoder_->Stop();
perkj26091b12016-09-01 01:17:40 -0700766 sink_.SetExpectNoFrames();
767 rtc::Event frame_destroyed_event(false, false);
perkja49cbd32016-09-16 07:53:41 -0700768 video_source_.IncomingCapturedFrame(CreateFrame(2, &frame_destroyed_event));
769 EXPECT_TRUE(frame_destroyed_event.Wait(kDefaultTimeoutMs));
perkj26091b12016-09-01 01:17:40 -0700770}
771
mflodmancc3d4422017-08-03 08:27:51 -0700772TEST_F(VideoStreamEncoderTest, DropsPendingFramesOnSlowEncode) {
773 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkj26091b12016-09-01 01:17:40 -0700774
775 fake_encoder_.BlockNextEncode();
perkja49cbd32016-09-16 07:53:41 -0700776 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700777 WaitForEncodedFrame(1);
perkj26091b12016-09-01 01:17:40 -0700778 // Here, the encoder thread will be blocked in the TestEncoder waiting for a
779 // call to ContinueEncode.
perkja49cbd32016-09-16 07:53:41 -0700780 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
781 video_source_.IncomingCapturedFrame(CreateFrame(3, nullptr));
perkj26091b12016-09-01 01:17:40 -0700782 fake_encoder_.ContinueEncode();
sprang4847ae62017-06-27 07:06:52 -0700783 WaitForEncodedFrame(3);
perkj26091b12016-09-01 01:17:40 -0700784
mflodmancc3d4422017-08-03 08:27:51 -0700785 video_stream_encoder_->Stop();
perkj26091b12016-09-01 01:17:40 -0700786}
787
mflodmancc3d4422017-08-03 08:27:51 -0700788TEST_F(VideoStreamEncoderTest,
789 ConfigureEncoderTriggersOnEncoderConfigurationChanged) {
790 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
Per21d45d22016-10-30 21:37:57 +0100791 EXPECT_EQ(0, sink_.number_of_reconfigurations());
Per512ecb32016-09-23 15:52:06 +0200792
793 // Capture a frame and wait for it to synchronize with the encoder thread.
Perf8c5f2b2016-09-23 16:24:55 +0200794 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700795 WaitForEncodedFrame(1);
Per21d45d22016-10-30 21:37:57 +0100796 // The encoder will have been configured once when the first frame is
797 // received.
798 EXPECT_EQ(1, sink_.number_of_reconfigurations());
Per512ecb32016-09-23 15:52:06 +0200799
800 VideoEncoderConfig video_encoder_config;
Niels Möller259a4972018-04-05 15:36:51 +0200801 test::FillEncoderConfiguration(kVideoCodecVP8, 1, &video_encoder_config);
Per512ecb32016-09-23 15:52:06 +0200802 video_encoder_config.min_transmit_bitrate_bps = 9999;
mflodmancc3d4422017-08-03 08:27:51 -0700803 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
804 kMaxPayloadLength,
805 true /* nack_enabled */);
Per512ecb32016-09-23 15:52:06 +0200806
807 // Capture a frame and wait for it to synchronize with the encoder thread.
Perf8c5f2b2016-09-23 16:24:55 +0200808 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700809 WaitForEncodedFrame(2);
Per21d45d22016-10-30 21:37:57 +0100810 EXPECT_EQ(2, sink_.number_of_reconfigurations());
perkj3b703ed2016-09-29 23:25:40 -0700811 EXPECT_EQ(9999, sink_.last_min_transmit_bitrate());
perkj26105b42016-09-29 22:39:10 -0700812
mflodmancc3d4422017-08-03 08:27:51 -0700813 video_stream_encoder_->Stop();
perkj26105b42016-09-29 22:39:10 -0700814}
815
mflodmancc3d4422017-08-03 08:27:51 -0700816TEST_F(VideoStreamEncoderTest, FrameResolutionChangeReconfigureEncoder) {
817 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkjfa10b552016-10-02 23:45:26 -0700818
819 // Capture a frame and wait for it to synchronize with the encoder thread.
820 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700821 WaitForEncodedFrame(1);
Per21d45d22016-10-30 21:37:57 +0100822 // The encoder will have been configured once.
823 EXPECT_EQ(1, sink_.number_of_reconfigurations());
perkjfa10b552016-10-02 23:45:26 -0700824 EXPECT_EQ(codec_width_, fake_encoder_.codec_config().width);
825 EXPECT_EQ(codec_height_, fake_encoder_.codec_config().height);
826
827 codec_width_ *= 2;
828 codec_height_ *= 2;
829 // Capture a frame with a higher resolution and wait for it to synchronize
830 // with the encoder thread.
831 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700832 WaitForEncodedFrame(2);
perkjfa10b552016-10-02 23:45:26 -0700833 EXPECT_EQ(codec_width_, fake_encoder_.codec_config().width);
834 EXPECT_EQ(codec_height_, fake_encoder_.codec_config().height);
Per21d45d22016-10-30 21:37:57 +0100835 EXPECT_EQ(2, sink_.number_of_reconfigurations());
perkjfa10b552016-10-02 23:45:26 -0700836
mflodmancc3d4422017-08-03 08:27:51 -0700837 video_stream_encoder_->Stop();
perkjfa10b552016-10-02 23:45:26 -0700838}
839
mflodmancc3d4422017-08-03 08:27:51 -0700840TEST_F(VideoStreamEncoderTest, Vp8ResilienceIsOffFor1S1TLWithNackEnabled) {
asapersson5f7226f2016-11-25 04:37:00 -0800841 const bool kNackEnabled = true;
842 const size_t kNumStreams = 1;
843 const size_t kNumTl = 1;
emircanbbcc3562017-08-18 00:28:40 -0700844 ResetEncoder("VP8", kNumStreams, kNumTl, kNumSlDummy, kNackEnabled, false);
mflodmancc3d4422017-08-03 08:27:51 -0700845 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson5f7226f2016-11-25 04:37:00 -0800846
847 // Capture a frame and wait for it to synchronize with the encoder thread.
848 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700849 WaitForEncodedFrame(1);
asapersson5f7226f2016-11-25 04:37:00 -0800850 // The encoder have been configured once when the first frame is received.
851 EXPECT_EQ(1, sink_.number_of_reconfigurations());
852 EXPECT_EQ(kVideoCodecVP8, fake_encoder_.codec_config().codecType);
853 EXPECT_EQ(kNumStreams, fake_encoder_.codec_config().numberOfSimulcastStreams);
854 EXPECT_EQ(kNumTl, fake_encoder_.codec_config().VP8()->numberOfTemporalLayers);
855 // Resilience is off for no temporal layers with nack on.
856 EXPECT_EQ(kResilienceOff, fake_encoder_.codec_config().VP8()->resilience);
mflodmancc3d4422017-08-03 08:27:51 -0700857 video_stream_encoder_->Stop();
asapersson5f7226f2016-11-25 04:37:00 -0800858}
859
mflodmancc3d4422017-08-03 08:27:51 -0700860TEST_F(VideoStreamEncoderTest, Vp8ResilienceIsOffFor2S1TlWithNackEnabled) {
asapersson5f7226f2016-11-25 04:37:00 -0800861 const bool kNackEnabled = true;
862 const size_t kNumStreams = 2;
863 const size_t kNumTl = 1;
emircanbbcc3562017-08-18 00:28:40 -0700864 ResetEncoder("VP8", kNumStreams, kNumTl, kNumSlDummy, kNackEnabled, false);
mflodmancc3d4422017-08-03 08:27:51 -0700865 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson5f7226f2016-11-25 04:37:00 -0800866
867 // Capture a frame and wait for it to synchronize with the encoder thread.
868 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700869 WaitForEncodedFrame(1);
asapersson5f7226f2016-11-25 04:37:00 -0800870 // The encoder have been configured once when the first frame is received.
871 EXPECT_EQ(1, sink_.number_of_reconfigurations());
872 EXPECT_EQ(kVideoCodecVP8, fake_encoder_.codec_config().codecType);
873 EXPECT_EQ(kNumStreams, fake_encoder_.codec_config().numberOfSimulcastStreams);
874 EXPECT_EQ(kNumTl, fake_encoder_.codec_config().VP8()->numberOfTemporalLayers);
875 // Resilience is off for no temporal layers and >1 streams with nack on.
876 EXPECT_EQ(kResilienceOff, fake_encoder_.codec_config().VP8()->resilience);
mflodmancc3d4422017-08-03 08:27:51 -0700877 video_stream_encoder_->Stop();
asapersson5f7226f2016-11-25 04:37:00 -0800878}
879
mflodmancc3d4422017-08-03 08:27:51 -0700880TEST_F(VideoStreamEncoderTest, Vp8ResilienceIsOnFor1S1TLWithNackDisabled) {
asapersson5f7226f2016-11-25 04:37:00 -0800881 const bool kNackEnabled = false;
882 const size_t kNumStreams = 1;
883 const size_t kNumTl = 1;
emircanbbcc3562017-08-18 00:28:40 -0700884 ResetEncoder("VP8", kNumStreams, kNumTl, kNumSlDummy, kNackEnabled, false);
mflodmancc3d4422017-08-03 08:27:51 -0700885 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson5f7226f2016-11-25 04:37:00 -0800886
887 // Capture a frame and wait for it to synchronize with the encoder thread.
888 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700889 WaitForEncodedFrame(1);
asapersson5f7226f2016-11-25 04:37:00 -0800890 // The encoder have been configured once when the first frame is received.
891 EXPECT_EQ(1, sink_.number_of_reconfigurations());
892 EXPECT_EQ(kVideoCodecVP8, fake_encoder_.codec_config().codecType);
893 EXPECT_EQ(kNumStreams, fake_encoder_.codec_config().numberOfSimulcastStreams);
894 EXPECT_EQ(kNumTl, fake_encoder_.codec_config().VP8()->numberOfTemporalLayers);
895 // Resilience is on for no temporal layers with nack off.
896 EXPECT_EQ(kResilientStream, fake_encoder_.codec_config().VP8()->resilience);
mflodmancc3d4422017-08-03 08:27:51 -0700897 video_stream_encoder_->Stop();
asapersson5f7226f2016-11-25 04:37:00 -0800898}
899
mflodmancc3d4422017-08-03 08:27:51 -0700900TEST_F(VideoStreamEncoderTest, Vp8ResilienceIsOnFor1S2TlWithNackEnabled) {
asapersson5f7226f2016-11-25 04:37:00 -0800901 const bool kNackEnabled = true;
902 const size_t kNumStreams = 1;
903 const size_t kNumTl = 2;
emircanbbcc3562017-08-18 00:28:40 -0700904 ResetEncoder("VP8", kNumStreams, kNumTl, kNumSlDummy, kNackEnabled, false);
mflodmancc3d4422017-08-03 08:27:51 -0700905 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson5f7226f2016-11-25 04:37:00 -0800906
907 // Capture a frame and wait for it to synchronize with the encoder thread.
908 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700909 WaitForEncodedFrame(1);
asapersson5f7226f2016-11-25 04:37:00 -0800910 // The encoder have been configured once when the first frame is received.
911 EXPECT_EQ(1, sink_.number_of_reconfigurations());
912 EXPECT_EQ(kVideoCodecVP8, fake_encoder_.codec_config().codecType);
913 EXPECT_EQ(kNumStreams, fake_encoder_.codec_config().numberOfSimulcastStreams);
914 EXPECT_EQ(kNumTl, fake_encoder_.codec_config().VP8()->numberOfTemporalLayers);
915 // Resilience is on for temporal layers.
916 EXPECT_EQ(kResilientStream, fake_encoder_.codec_config().VP8()->resilience);
mflodmancc3d4422017-08-03 08:27:51 -0700917 video_stream_encoder_->Stop();
asapersson5f7226f2016-11-25 04:37:00 -0800918}
919
emircanbbcc3562017-08-18 00:28:40 -0700920TEST_F(VideoStreamEncoderTest, Vp9ResilienceIsOffFor1SL1TLWithNackEnabled) {
921 const bool kNackEnabled = true;
922 const size_t kNumStreams = 1;
923 const size_t kNumTl = 1;
924 const unsigned char kNumSl = 1;
925 ResetEncoder("VP9", kNumStreams, kNumTl, kNumSl, kNackEnabled, false);
926 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
927
928 // Capture a frame and wait for it to synchronize with the encoder thread.
929 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
930 sink_.WaitForEncodedFrame(1);
931 // The encoder have been configured once when the first frame is received.
932 EXPECT_EQ(1, sink_.number_of_reconfigurations());
933 EXPECT_EQ(kVideoCodecVP9, fake_encoder_.codec_config().codecType);
934 EXPECT_EQ(kNumStreams, fake_encoder_.codec_config().numberOfSimulcastStreams);
935 EXPECT_EQ(kNumTl, fake_encoder_.codec_config().VP9()->numberOfTemporalLayers);
936 EXPECT_EQ(kNumSl, fake_encoder_.codec_config().VP9()->numberOfSpatialLayers);
937 // Resilience is off for no spatial and temporal layers with nack on.
938 EXPECT_FALSE(fake_encoder_.codec_config().VP9()->resilienceOn);
939 video_stream_encoder_->Stop();
940}
941
942TEST_F(VideoStreamEncoderTest, Vp9ResilienceIsOnFor1SL1TLWithNackDisabled) {
943 const bool kNackEnabled = false;
944 const size_t kNumStreams = 1;
945 const size_t kNumTl = 1;
946 const unsigned char kNumSl = 1;
947 ResetEncoder("VP9", kNumStreams, kNumTl, kNumSl, kNackEnabled, false);
948 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
949
950 // Capture a frame and wait for it to synchronize with the encoder thread.
951 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
952 sink_.WaitForEncodedFrame(1);
953 // The encoder have been configured once when the first frame is received.
954 EXPECT_EQ(1, sink_.number_of_reconfigurations());
955 EXPECT_EQ(kVideoCodecVP9, fake_encoder_.codec_config().codecType);
956 EXPECT_EQ(kNumStreams, fake_encoder_.codec_config().numberOfSimulcastStreams);
957 EXPECT_EQ(kNumTl, fake_encoder_.codec_config().VP9()->numberOfTemporalLayers);
958 EXPECT_EQ(kNumSl, fake_encoder_.codec_config().VP9()->numberOfSpatialLayers);
959 // Resilience is on if nack is off.
960 EXPECT_TRUE(fake_encoder_.codec_config().VP9()->resilienceOn);
961 video_stream_encoder_->Stop();
962}
963
964TEST_F(VideoStreamEncoderTest, Vp9ResilienceIsOnFor2SL1TLWithNackEnabled) {
965 const bool kNackEnabled = true;
966 const size_t kNumStreams = 1;
967 const size_t kNumTl = 1;
968 const unsigned char kNumSl = 2;
Sergey Silkin86684962018-03-28 19:32:37 +0200969 const int kFrameWidth = kMinVp9SpatialLayerWidth << (kNumSl - 1);
970 const int kFrameHeight = kMinVp9SpatialLayerHeight << (kNumSl - 1);
emircanbbcc3562017-08-18 00:28:40 -0700971 ResetEncoder("VP9", kNumStreams, kNumTl, kNumSl, kNackEnabled, false);
972 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
973
974 // Capture a frame and wait for it to synchronize with the encoder thread.
Sergey Silkin86684962018-03-28 19:32:37 +0200975 video_source_.IncomingCapturedFrame(
976 CreateFrame(1, kFrameWidth, kFrameHeight));
emircanbbcc3562017-08-18 00:28:40 -0700977 sink_.WaitForEncodedFrame(1);
978 // The encoder have been configured once when the first frame is received.
979 EXPECT_EQ(1, sink_.number_of_reconfigurations());
980 EXPECT_EQ(kVideoCodecVP9, fake_encoder_.codec_config().codecType);
981 EXPECT_EQ(kNumStreams, fake_encoder_.codec_config().numberOfSimulcastStreams);
982 EXPECT_EQ(kNumTl, fake_encoder_.codec_config().VP9()->numberOfTemporalLayers);
983 EXPECT_EQ(kNumSl, fake_encoder_.codec_config().VP9()->numberOfSpatialLayers);
984 // Resilience is on for spatial layers.
985 EXPECT_TRUE(fake_encoder_.codec_config().VP9()->resilienceOn);
986 video_stream_encoder_->Stop();
987}
988
989TEST_F(VideoStreamEncoderTest, Vp9ResilienceIsOnFor1SL2TLWithNackEnabled) {
990 const bool kNackEnabled = true;
991 const size_t kNumStreams = 1;
992 const size_t kNumTl = 2;
993 const unsigned char kNumSl = 1;
994 ResetEncoder("VP9", kNumStreams, kNumTl, kNumSl, kNackEnabled, false);
995 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
996
997 // Capture a frame and wait for it to synchronize with the encoder thread.
998 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
999 sink_.WaitForEncodedFrame(1);
1000 // The encoder have been configured once when the first frame is received.
1001 EXPECT_EQ(1, sink_.number_of_reconfigurations());
1002 EXPECT_EQ(kVideoCodecVP9, fake_encoder_.codec_config().codecType);
1003 EXPECT_EQ(kNumStreams, fake_encoder_.codec_config().numberOfSimulcastStreams);
1004 EXPECT_EQ(kNumTl, fake_encoder_.codec_config().VP9()->numberOfTemporalLayers);
1005 EXPECT_EQ(kNumSl, fake_encoder_.codec_config().VP9()->numberOfSpatialLayers);
1006 // Resilience is on for temporal layers.
1007 EXPECT_TRUE(fake_encoder_.codec_config().VP9()->resilienceOn);
1008 video_stream_encoder_->Stop();
1009}
1010
mflodmancc3d4422017-08-03 08:27:51 -07001011TEST_F(VideoStreamEncoderTest, SwitchSourceDeregisterEncoderAsSink) {
perkj803d97f2016-11-01 11:45:46 -07001012 EXPECT_TRUE(video_source_.has_sinks());
1013 test::FrameForwarder new_video_source;
mflodmancc3d4422017-08-03 08:27:51 -07001014 video_stream_encoder_->SetSource(
sprangc5d62e22017-04-02 23:53:04 -07001015 &new_video_source,
1016 VideoSendStream::DegradationPreference::kMaintainFramerate);
perkj803d97f2016-11-01 11:45:46 -07001017 EXPECT_FALSE(video_source_.has_sinks());
1018 EXPECT_TRUE(new_video_source.has_sinks());
1019
mflodmancc3d4422017-08-03 08:27:51 -07001020 video_stream_encoder_->Stop();
perkj803d97f2016-11-01 11:45:46 -07001021}
1022
mflodmancc3d4422017-08-03 08:27:51 -07001023TEST_F(VideoStreamEncoderTest, SinkWantsRotationApplied) {
perkj803d97f2016-11-01 11:45:46 -07001024 EXPECT_FALSE(video_source_.sink_wants().rotation_applied);
mflodmancc3d4422017-08-03 08:27:51 -07001025 video_stream_encoder_->SetSink(&sink_, true /*rotation_applied*/);
perkj803d97f2016-11-01 11:45:46 -07001026 EXPECT_TRUE(video_source_.sink_wants().rotation_applied);
mflodmancc3d4422017-08-03 08:27:51 -07001027 video_stream_encoder_->Stop();
perkj803d97f2016-11-01 11:45:46 -07001028}
1029
Jonathan Yubc771b72017-12-08 17:04:29 -08001030TEST_F(VideoStreamEncoderTest, TestCpuDowngrades_BalancedMode) {
1031 const int kFramerateFps = 30;
asaperssonf7e294d2017-06-13 23:25:22 -07001032 const int kWidth = 1280;
1033 const int kHeight = 720;
Jonathan Yubc771b72017-12-08 17:04:29 -08001034
1035 // We rely on the automatic resolution adaptation, but we handle framerate
1036 // adaptation manually by mocking the stats proxy.
1037 video_source_.set_adaptation_enabled(true);
asaperssonf7e294d2017-06-13 23:25:22 -07001038
1039 // Enable kBalanced preference, no initial limitation.
Jonathan Yubc771b72017-12-08 17:04:29 -08001040 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
mflodmancc3d4422017-08-03 08:27:51 -07001041 video_stream_encoder_->SetSource(
Jonathan Yubc771b72017-12-08 17:04:29 -08001042 &video_source_,
mflodmancc3d4422017-08-03 08:27:51 -07001043 VideoSendStream::DegradationPreference::kBalanced);
Jonathan Yubc771b72017-12-08 17:04:29 -08001044 VerifyNoLimitation(video_source_.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07001045 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
Jonathan Yubc771b72017-12-08 17:04:29 -08001046 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
asaperssonf7e294d2017-06-13 23:25:22 -07001047 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1048
Jonathan Yubc771b72017-12-08 17:04:29 -08001049 // Adapt down as far as possible.
1050 rtc::VideoSinkWants last_wants;
1051 int64_t t = 1;
1052 int loop_count = 0;
1053 do {
1054 ++loop_count;
1055 last_wants = video_source_.sink_wants();
1056
1057 // Simulate the framerate we've been asked to adapt to.
1058 const int fps = std::min(kFramerateFps, last_wants.max_framerate_fps);
1059 const int frame_interval_ms = rtc::kNumMillisecsPerSec / fps;
1060 VideoSendStream::Stats mock_stats = stats_proxy_->GetStats();
1061 mock_stats.input_frame_rate = fps;
1062 stats_proxy_->SetMockStats(mock_stats);
1063
1064 video_source_.IncomingCapturedFrame(CreateFrame(t, kWidth, kHeight));
1065 sink_.WaitForEncodedFrame(t);
1066 t += frame_interval_ms;
1067
mflodmancc3d4422017-08-03 08:27:51 -07001068 video_stream_encoder_->TriggerCpuOveruse();
Jonathan Yubc771b72017-12-08 17:04:29 -08001069 VerifyBalancedModeFpsRange(
1070 video_source_.sink_wants(),
1071 *video_source_.last_sent_width() * *video_source_.last_sent_height());
1072 } while (video_source_.sink_wants().max_pixel_count <
1073 last_wants.max_pixel_count ||
1074 video_source_.sink_wants().max_framerate_fps <
1075 last_wants.max_framerate_fps);
asaperssonf7e294d2017-06-13 23:25:22 -07001076
Jonathan Yubc771b72017-12-08 17:04:29 -08001077 // Verify that we've adapted all the way down.
1078 stats_proxy_->ResetMockStats();
asaperssonf7e294d2017-06-13 23:25:22 -07001079 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
Jonathan Yubc771b72017-12-08 17:04:29 -08001080 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_framerate);
1081 EXPECT_EQ(loop_count - 1,
asaperssonf7e294d2017-06-13 23:25:22 -07001082 stats_proxy_->GetStats().number_of_cpu_adapt_changes);
Jonathan Yubc771b72017-12-08 17:04:29 -08001083 EXPECT_EQ(kMinPixelsPerFrame, *video_source_.last_sent_width() *
1084 *video_source_.last_sent_height());
1085 EXPECT_EQ(kMinBalancedFramerateFps,
1086 video_source_.sink_wants().max_framerate_fps);
asaperssonf7e294d2017-06-13 23:25:22 -07001087
Jonathan Yubc771b72017-12-08 17:04:29 -08001088 // Adapt back up the same number of times we adapted down.
1089 for (int i = 0; i < loop_count - 1; ++i) {
1090 last_wants = video_source_.sink_wants();
1091
1092 // Simulate the framerate we've been asked to adapt to.
1093 const int fps = std::min(kFramerateFps, last_wants.max_framerate_fps);
1094 const int frame_interval_ms = rtc::kNumMillisecsPerSec / fps;
1095 VideoSendStream::Stats mock_stats = stats_proxy_->GetStats();
1096 mock_stats.input_frame_rate = fps;
1097 stats_proxy_->SetMockStats(mock_stats);
1098
1099 video_source_.IncomingCapturedFrame(CreateFrame(t, kWidth, kHeight));
1100 sink_.WaitForEncodedFrame(t);
1101 t += frame_interval_ms;
1102
mflodmancc3d4422017-08-03 08:27:51 -07001103 video_stream_encoder_->TriggerCpuNormalUsage();
Jonathan Yubc771b72017-12-08 17:04:29 -08001104 VerifyBalancedModeFpsRange(
1105 video_source_.sink_wants(),
1106 *video_source_.last_sent_width() * *video_source_.last_sent_height());
1107 EXPECT_TRUE(video_source_.sink_wants().max_pixel_count >
1108 last_wants.max_pixel_count ||
1109 video_source_.sink_wants().max_framerate_fps >
1110 last_wants.max_framerate_fps);
asaperssonf7e294d2017-06-13 23:25:22 -07001111 }
1112
Jonathan Yubc771b72017-12-08 17:04:29 -08001113 VerifyNoLimitation(video_source_.sink_wants());
1114 stats_proxy_->ResetMockStats();
asaperssonf7e294d2017-06-13 23:25:22 -07001115 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
Jonathan Yubc771b72017-12-08 17:04:29 -08001116 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
1117 EXPECT_EQ((loop_count - 1) * 2,
1118 stats_proxy_->GetStats().number_of_cpu_adapt_changes);
asaperssonf7e294d2017-06-13 23:25:22 -07001119
mflodmancc3d4422017-08-03 08:27:51 -07001120 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07001121}
mflodmancc3d4422017-08-03 08:27:51 -07001122TEST_F(VideoStreamEncoderTest, SinkWantsStoredByDegradationPreference) {
1123 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson02465b82017-04-10 01:12:52 -07001124 VerifyNoLimitation(video_source_.sink_wants());
perkj803d97f2016-11-01 11:45:46 -07001125
sprangc5d62e22017-04-02 23:53:04 -07001126 const int kFrameWidth = 1280;
1127 const int kFrameHeight = 720;
1128 const int kFrameIntervalMs = 1000 / 30;
1129
1130 int frame_timestamp = 1;
perkj803d97f2016-11-01 11:45:46 -07001131
kthelgason5e13d412016-12-01 03:59:51 -08001132 video_source_.IncomingCapturedFrame(
sprangc5d62e22017-04-02 23:53:04 -07001133 CreateFrame(frame_timestamp, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07001134 WaitForEncodedFrame(frame_timestamp);
sprangc5d62e22017-04-02 23:53:04 -07001135 frame_timestamp += kFrameIntervalMs;
1136
perkj803d97f2016-11-01 11:45:46 -07001137 // Trigger CPU overuse.
mflodmancc3d4422017-08-03 08:27:51 -07001138 video_stream_encoder_->TriggerCpuOveruse();
perkj803d97f2016-11-01 11:45:46 -07001139 video_source_.IncomingCapturedFrame(
sprangc5d62e22017-04-02 23:53:04 -07001140 CreateFrame(frame_timestamp, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07001141 WaitForEncodedFrame(frame_timestamp);
sprangc5d62e22017-04-02 23:53:04 -07001142 frame_timestamp += kFrameIntervalMs;
sprang3ea3c772017-03-30 07:23:48 -07001143
asapersson0944a802017-04-07 00:57:58 -07001144 // Default degradation preference is maintain-framerate, so will lower max
sprangc5d62e22017-04-02 23:53:04 -07001145 // wanted resolution.
1146 EXPECT_FALSE(video_source_.sink_wants().target_pixel_count);
1147 EXPECT_LT(video_source_.sink_wants().max_pixel_count,
1148 kFrameWidth * kFrameHeight);
1149 EXPECT_EQ(std::numeric_limits<int>::max(),
1150 video_source_.sink_wants().max_framerate_fps);
1151
1152 // Set new source, switch to maintain-resolution.
perkj803d97f2016-11-01 11:45:46 -07001153 test::FrameForwarder new_video_source;
mflodmancc3d4422017-08-03 08:27:51 -07001154 video_stream_encoder_->SetSource(
perkj803d97f2016-11-01 11:45:46 -07001155 &new_video_source,
1156 VideoSendStream::DegradationPreference::kMaintainResolution);
1157
sprangc5d62e22017-04-02 23:53:04 -07001158 // Initially no degradation registered.
asapersson02465b82017-04-10 01:12:52 -07001159 VerifyNoLimitation(new_video_source.sink_wants());
perkj803d97f2016-11-01 11:45:46 -07001160
sprangc5d62e22017-04-02 23:53:04 -07001161 // Force an input frame rate to be available, or the adaptation call won't
1162 // know what framerate to adapt form.
asapersson02465b82017-04-10 01:12:52 -07001163 const int kInputFps = 30;
sprangc5d62e22017-04-02 23:53:04 -07001164 VideoSendStream::Stats stats = stats_proxy_->GetStats();
asapersson02465b82017-04-10 01:12:52 -07001165 stats.input_frame_rate = kInputFps;
sprangc5d62e22017-04-02 23:53:04 -07001166 stats_proxy_->SetMockStats(stats);
1167
mflodmancc3d4422017-08-03 08:27:51 -07001168 video_stream_encoder_->TriggerCpuOveruse();
perkj803d97f2016-11-01 11:45:46 -07001169 new_video_source.IncomingCapturedFrame(
sprangc5d62e22017-04-02 23:53:04 -07001170 CreateFrame(frame_timestamp, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07001171 WaitForEncodedFrame(frame_timestamp);
sprangc5d62e22017-04-02 23:53:04 -07001172 frame_timestamp += kFrameIntervalMs;
1173
1174 // Some framerate constraint should be set.
sprang84a37592017-02-10 07:04:27 -08001175 EXPECT_FALSE(new_video_source.sink_wants().target_pixel_count);
sprangc5d62e22017-04-02 23:53:04 -07001176 EXPECT_EQ(std::numeric_limits<int>::max(),
1177 new_video_source.sink_wants().max_pixel_count);
asapersson02465b82017-04-10 01:12:52 -07001178 EXPECT_LT(new_video_source.sink_wants().max_framerate_fps, kInputFps);
sprangc5d62e22017-04-02 23:53:04 -07001179
asapersson02465b82017-04-10 01:12:52 -07001180 // Turn off degradation completely.
mflodmancc3d4422017-08-03 08:27:51 -07001181 video_stream_encoder_->SetSource(
sprangc5d62e22017-04-02 23:53:04 -07001182 &new_video_source,
1183 VideoSendStream::DegradationPreference::kDegradationDisabled);
asapersson02465b82017-04-10 01:12:52 -07001184 VerifyNoLimitation(new_video_source.sink_wants());
sprangc5d62e22017-04-02 23:53:04 -07001185
mflodmancc3d4422017-08-03 08:27:51 -07001186 video_stream_encoder_->TriggerCpuOveruse();
sprangc5d62e22017-04-02 23:53:04 -07001187 new_video_source.IncomingCapturedFrame(
1188 CreateFrame(frame_timestamp, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07001189 WaitForEncodedFrame(frame_timestamp);
sprangc5d62e22017-04-02 23:53:04 -07001190 frame_timestamp += kFrameIntervalMs;
1191
1192 // Still no degradation.
asapersson02465b82017-04-10 01:12:52 -07001193 VerifyNoLimitation(new_video_source.sink_wants());
perkj803d97f2016-11-01 11:45:46 -07001194
1195 // Calling SetSource with resolution scaling enabled apply the old SinkWants.
mflodmancc3d4422017-08-03 08:27:51 -07001196 video_stream_encoder_->SetSource(
sprangc5d62e22017-04-02 23:53:04 -07001197 &new_video_source,
1198 VideoSendStream::DegradationPreference::kMaintainFramerate);
1199 EXPECT_LT(new_video_source.sink_wants().max_pixel_count,
1200 kFrameWidth * kFrameHeight);
sprang84a37592017-02-10 07:04:27 -08001201 EXPECT_FALSE(new_video_source.sink_wants().target_pixel_count);
sprangc5d62e22017-04-02 23:53:04 -07001202 EXPECT_EQ(std::numeric_limits<int>::max(),
1203 new_video_source.sink_wants().max_framerate_fps);
1204
1205 // Calling SetSource with framerate scaling enabled apply the old SinkWants.
mflodmancc3d4422017-08-03 08:27:51 -07001206 video_stream_encoder_->SetSource(
sprangc5d62e22017-04-02 23:53:04 -07001207 &new_video_source,
1208 VideoSendStream::DegradationPreference::kMaintainResolution);
1209 EXPECT_FALSE(new_video_source.sink_wants().target_pixel_count);
1210 EXPECT_EQ(std::numeric_limits<int>::max(),
1211 new_video_source.sink_wants().max_pixel_count);
asapersson02465b82017-04-10 01:12:52 -07001212 EXPECT_LT(new_video_source.sink_wants().max_framerate_fps, kInputFps);
perkj803d97f2016-11-01 11:45:46 -07001213
mflodmancc3d4422017-08-03 08:27:51 -07001214 video_stream_encoder_->Stop();
perkj803d97f2016-11-01 11:45:46 -07001215}
1216
mflodmancc3d4422017-08-03 08:27:51 -07001217TEST_F(VideoStreamEncoderTest, StatsTracksQualityAdaptationStats) {
1218 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkj803d97f2016-11-01 11:45:46 -07001219
asaperssonfab67072017-04-04 05:51:49 -07001220 const int kWidth = 1280;
1221 const int kHeight = 720;
asaperssonfab67072017-04-04 05:51:49 -07001222 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001223 WaitForEncodedFrame(1);
asaperssonfab67072017-04-04 05:51:49 -07001224 VideoSendStream::Stats stats = stats_proxy_->GetStats();
1225 EXPECT_FALSE(stats.bw_limited_resolution);
1226 EXPECT_EQ(0, stats.number_of_quality_adapt_changes);
1227
1228 // Trigger adapt down.
mflodmancc3d4422017-08-03 08:27:51 -07001229 video_stream_encoder_->TriggerQualityLow();
asaperssonfab67072017-04-04 05:51:49 -07001230 video_source_.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001231 WaitForEncodedFrame(2);
asaperssonfab67072017-04-04 05:51:49 -07001232
1233 stats = stats_proxy_->GetStats();
1234 EXPECT_TRUE(stats.bw_limited_resolution);
1235 EXPECT_EQ(1, stats.number_of_quality_adapt_changes);
1236
1237 // Trigger adapt up.
mflodmancc3d4422017-08-03 08:27:51 -07001238 video_stream_encoder_->TriggerQualityHigh();
asaperssonfab67072017-04-04 05:51:49 -07001239 video_source_.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001240 WaitForEncodedFrame(3);
asaperssonfab67072017-04-04 05:51:49 -07001241
1242 stats = stats_proxy_->GetStats();
1243 EXPECT_FALSE(stats.bw_limited_resolution);
1244 EXPECT_EQ(2, stats.number_of_quality_adapt_changes);
1245 EXPECT_EQ(0, stats.number_of_cpu_adapt_changes);
1246
mflodmancc3d4422017-08-03 08:27:51 -07001247 video_stream_encoder_->Stop();
asaperssonfab67072017-04-04 05:51:49 -07001248}
1249
mflodmancc3d4422017-08-03 08:27:51 -07001250TEST_F(VideoStreamEncoderTest, StatsTracksCpuAdaptationStats) {
1251 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonfab67072017-04-04 05:51:49 -07001252
1253 const int kWidth = 1280;
1254 const int kHeight = 720;
asaperssonfab67072017-04-04 05:51:49 -07001255 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001256 WaitForEncodedFrame(1);
perkj803d97f2016-11-01 11:45:46 -07001257 VideoSendStream::Stats stats = stats_proxy_->GetStats();
1258 EXPECT_FALSE(stats.cpu_limited_resolution);
1259 EXPECT_EQ(0, stats.number_of_cpu_adapt_changes);
1260
1261 // Trigger CPU overuse.
mflodmancc3d4422017-08-03 08:27:51 -07001262 video_stream_encoder_->TriggerCpuOveruse();
asaperssonfab67072017-04-04 05:51:49 -07001263 video_source_.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001264 WaitForEncodedFrame(2);
perkj803d97f2016-11-01 11:45:46 -07001265
1266 stats = stats_proxy_->GetStats();
1267 EXPECT_TRUE(stats.cpu_limited_resolution);
1268 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1269
1270 // Trigger CPU normal use.
mflodmancc3d4422017-08-03 08:27:51 -07001271 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssonfab67072017-04-04 05:51:49 -07001272 video_source_.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001273 WaitForEncodedFrame(3);
perkj803d97f2016-11-01 11:45:46 -07001274
1275 stats = stats_proxy_->GetStats();
1276 EXPECT_FALSE(stats.cpu_limited_resolution);
1277 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
asaperssonfab67072017-04-04 05:51:49 -07001278 EXPECT_EQ(0, stats.number_of_quality_adapt_changes);
perkj803d97f2016-11-01 11:45:46 -07001279
mflodmancc3d4422017-08-03 08:27:51 -07001280 video_stream_encoder_->Stop();
perkj803d97f2016-11-01 11:45:46 -07001281}
1282
mflodmancc3d4422017-08-03 08:27:51 -07001283TEST_F(VideoStreamEncoderTest, SwitchingSourceKeepsCpuAdaptation) {
1284 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
kthelgason876222f2016-11-29 01:44:11 -08001285
asaperssonfab67072017-04-04 05:51:49 -07001286 const int kWidth = 1280;
1287 const int kHeight = 720;
1288 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001289 WaitForEncodedFrame(1);
kthelgason876222f2016-11-29 01:44:11 -08001290 VideoSendStream::Stats stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001291 EXPECT_FALSE(stats.bw_limited_resolution);
kthelgason876222f2016-11-29 01:44:11 -08001292 EXPECT_FALSE(stats.cpu_limited_resolution);
1293 EXPECT_EQ(0, stats.number_of_cpu_adapt_changes);
1294
asaperssonfab67072017-04-04 05:51:49 -07001295 // Trigger CPU overuse.
mflodmancc3d4422017-08-03 08:27:51 -07001296 video_stream_encoder_->TriggerCpuOveruse();
asaperssonfab67072017-04-04 05:51:49 -07001297 video_source_.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001298 WaitForEncodedFrame(2);
kthelgason876222f2016-11-29 01:44:11 -08001299 stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001300 EXPECT_FALSE(stats.bw_limited_resolution);
kthelgason876222f2016-11-29 01:44:11 -08001301 EXPECT_TRUE(stats.cpu_limited_resolution);
1302 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1303
1304 // Set new source with adaptation still enabled.
1305 test::FrameForwarder new_video_source;
mflodmancc3d4422017-08-03 08:27:51 -07001306 video_stream_encoder_->SetSource(
sprangc5d62e22017-04-02 23:53:04 -07001307 &new_video_source,
1308 VideoSendStream::DegradationPreference::kMaintainFramerate);
kthelgason876222f2016-11-29 01:44:11 -08001309
asaperssonfab67072017-04-04 05:51:49 -07001310 new_video_source.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001311 WaitForEncodedFrame(3);
kthelgason876222f2016-11-29 01:44:11 -08001312 stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001313 EXPECT_FALSE(stats.bw_limited_resolution);
kthelgason876222f2016-11-29 01:44:11 -08001314 EXPECT_TRUE(stats.cpu_limited_resolution);
1315 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1316
1317 // Set adaptation disabled.
mflodmancc3d4422017-08-03 08:27:51 -07001318 video_stream_encoder_->SetSource(
kthelgason876222f2016-11-29 01:44:11 -08001319 &new_video_source,
sprangc5d62e22017-04-02 23:53:04 -07001320 VideoSendStream::DegradationPreference::kDegradationDisabled);
kthelgason876222f2016-11-29 01:44:11 -08001321
asaperssonfab67072017-04-04 05:51:49 -07001322 new_video_source.IncomingCapturedFrame(CreateFrame(4, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001323 WaitForEncodedFrame(4);
kthelgason876222f2016-11-29 01:44:11 -08001324 stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001325 EXPECT_FALSE(stats.bw_limited_resolution);
kthelgason876222f2016-11-29 01:44:11 -08001326 EXPECT_FALSE(stats.cpu_limited_resolution);
1327 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1328
1329 // Set adaptation back to enabled.
mflodmancc3d4422017-08-03 08:27:51 -07001330 video_stream_encoder_->SetSource(
sprangc5d62e22017-04-02 23:53:04 -07001331 &new_video_source,
1332 VideoSendStream::DegradationPreference::kMaintainFramerate);
kthelgason876222f2016-11-29 01:44:11 -08001333
asaperssonfab67072017-04-04 05:51:49 -07001334 new_video_source.IncomingCapturedFrame(CreateFrame(5, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001335 WaitForEncodedFrame(5);
kthelgason876222f2016-11-29 01:44:11 -08001336 stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001337 EXPECT_FALSE(stats.bw_limited_resolution);
kthelgason876222f2016-11-29 01:44:11 -08001338 EXPECT_TRUE(stats.cpu_limited_resolution);
1339 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1340
asaperssonfab67072017-04-04 05:51:49 -07001341 // Trigger CPU normal use.
mflodmancc3d4422017-08-03 08:27:51 -07001342 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssonfab67072017-04-04 05:51:49 -07001343 new_video_source.IncomingCapturedFrame(CreateFrame(6, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001344 WaitForEncodedFrame(6);
kthelgason876222f2016-11-29 01:44:11 -08001345 stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001346 EXPECT_FALSE(stats.bw_limited_resolution);
kthelgason876222f2016-11-29 01:44:11 -08001347 EXPECT_FALSE(stats.cpu_limited_resolution);
1348 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
asapersson02465b82017-04-10 01:12:52 -07001349 EXPECT_EQ(0, stats.number_of_quality_adapt_changes);
kthelgason876222f2016-11-29 01:44:11 -08001350
mflodmancc3d4422017-08-03 08:27:51 -07001351 video_stream_encoder_->Stop();
kthelgason876222f2016-11-29 01:44:11 -08001352}
1353
mflodmancc3d4422017-08-03 08:27:51 -07001354TEST_F(VideoStreamEncoderTest, SwitchingSourceKeepsQualityAdaptation) {
1355 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
kthelgason876222f2016-11-29 01:44:11 -08001356
asaperssonfab67072017-04-04 05:51:49 -07001357 const int kWidth = 1280;
1358 const int kHeight = 720;
1359 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001360 WaitForEncodedFrame(1);
kthelgason876222f2016-11-29 01:44:11 -08001361 VideoSendStream::Stats stats = stats_proxy_->GetStats();
kthelgason876222f2016-11-29 01:44:11 -08001362 EXPECT_FALSE(stats.bw_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001363 EXPECT_FALSE(stats.bw_limited_framerate);
asaperssonfab67072017-04-04 05:51:49 -07001364 EXPECT_EQ(0, stats.number_of_quality_adapt_changes);
kthelgason876222f2016-11-29 01:44:11 -08001365
1366 // Set new source with adaptation still enabled.
1367 test::FrameForwarder new_video_source;
mflodmancc3d4422017-08-03 08:27:51 -07001368 video_stream_encoder_->SetSource(
1369 &new_video_source,
1370 VideoSendStream::DegradationPreference::kBalanced);
kthelgason876222f2016-11-29 01:44:11 -08001371
asaperssonfab67072017-04-04 05:51:49 -07001372 new_video_source.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001373 WaitForEncodedFrame(2);
kthelgason876222f2016-11-29 01:44:11 -08001374 stats = stats_proxy_->GetStats();
kthelgason876222f2016-11-29 01:44:11 -08001375 EXPECT_FALSE(stats.bw_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001376 EXPECT_FALSE(stats.bw_limited_framerate);
asaperssonfab67072017-04-04 05:51:49 -07001377 EXPECT_EQ(0, stats.number_of_quality_adapt_changes);
kthelgason876222f2016-11-29 01:44:11 -08001378
asaperssonfab67072017-04-04 05:51:49 -07001379 // Trigger adapt down.
mflodmancc3d4422017-08-03 08:27:51 -07001380 video_stream_encoder_->TriggerQualityLow();
asaperssonfab67072017-04-04 05:51:49 -07001381 new_video_source.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001382 WaitForEncodedFrame(3);
kthelgason876222f2016-11-29 01:44:11 -08001383 stats = stats_proxy_->GetStats();
kthelgason876222f2016-11-29 01:44:11 -08001384 EXPECT_TRUE(stats.bw_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001385 EXPECT_FALSE(stats.bw_limited_framerate);
asaperssonfab67072017-04-04 05:51:49 -07001386 EXPECT_EQ(1, stats.number_of_quality_adapt_changes);
kthelgason876222f2016-11-29 01:44:11 -08001387
asaperssonfab67072017-04-04 05:51:49 -07001388 // Set new source with adaptation still enabled.
mflodmancc3d4422017-08-03 08:27:51 -07001389 video_stream_encoder_->SetSource(
1390 &new_video_source,
1391 VideoSendStream::DegradationPreference::kBalanced);
kthelgason876222f2016-11-29 01:44:11 -08001392
asaperssonfab67072017-04-04 05:51:49 -07001393 new_video_source.IncomingCapturedFrame(CreateFrame(4, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001394 WaitForEncodedFrame(4);
kthelgason876222f2016-11-29 01:44:11 -08001395 stats = stats_proxy_->GetStats();
kthelgason876222f2016-11-29 01:44:11 -08001396 EXPECT_TRUE(stats.bw_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001397 EXPECT_FALSE(stats.bw_limited_framerate);
asaperssonfab67072017-04-04 05:51:49 -07001398 EXPECT_EQ(1, stats.number_of_quality_adapt_changes);
kthelgason876222f2016-11-29 01:44:11 -08001399
asapersson02465b82017-04-10 01:12:52 -07001400 // Disable resolution scaling.
mflodmancc3d4422017-08-03 08:27:51 -07001401 video_stream_encoder_->SetSource(
kthelgason876222f2016-11-29 01:44:11 -08001402 &new_video_source,
1403 VideoSendStream::DegradationPreference::kMaintainResolution);
1404
asaperssonfab67072017-04-04 05:51:49 -07001405 new_video_source.IncomingCapturedFrame(CreateFrame(5, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001406 WaitForEncodedFrame(5);
kthelgason876222f2016-11-29 01:44:11 -08001407 stats = stats_proxy_->GetStats();
kthelgason876222f2016-11-29 01:44:11 -08001408 EXPECT_FALSE(stats.bw_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001409 EXPECT_FALSE(stats.bw_limited_framerate);
asaperssonfab67072017-04-04 05:51:49 -07001410 EXPECT_EQ(1, stats.number_of_quality_adapt_changes);
1411 EXPECT_EQ(0, stats.number_of_cpu_adapt_changes);
kthelgason876222f2016-11-29 01:44:11 -08001412
mflodmancc3d4422017-08-03 08:27:51 -07001413 video_stream_encoder_->Stop();
kthelgason876222f2016-11-29 01:44:11 -08001414}
1415
mflodmancc3d4422017-08-03 08:27:51 -07001416TEST_F(VideoStreamEncoderTest,
1417 QualityAdaptationStatsAreResetWhenScalerIsDisabled) {
1418 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson36e9eb42017-03-31 05:29:12 -07001419
1420 const int kWidth = 1280;
1421 const int kHeight = 720;
1422 video_source_.set_adaptation_enabled(true);
1423 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001424 WaitForEncodedFrame(1);
asapersson36e9eb42017-03-31 05:29:12 -07001425 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1426 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1427 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1428
1429 // Trigger adapt down.
mflodmancc3d4422017-08-03 08:27:51 -07001430 video_stream_encoder_->TriggerQualityLow();
asapersson36e9eb42017-03-31 05:29:12 -07001431 video_source_.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001432 WaitForEncodedFrame(2);
asapersson36e9eb42017-03-31 05:29:12 -07001433 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1434 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1435 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1436
1437 // Trigger overuse.
mflodmancc3d4422017-08-03 08:27:51 -07001438 video_stream_encoder_->TriggerCpuOveruse();
asapersson36e9eb42017-03-31 05:29:12 -07001439 video_source_.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001440 WaitForEncodedFrame(3);
asapersson36e9eb42017-03-31 05:29:12 -07001441 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1442 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1443 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1444
Niels Möller4db138e2018-04-19 09:04:13 +02001445 // Leave source unchanged, but disable quality scaler.
asapersson36e9eb42017-03-31 05:29:12 -07001446 fake_encoder_.SetQualityScaling(false);
Niels Möller4db138e2018-04-19 09:04:13 +02001447
1448 VideoEncoderConfig video_encoder_config;
1449 test::FillEncoderConfiguration(kVideoCodecVP8, 1, &video_encoder_config);
1450 // Make format different, to force recreation of encoder.
1451 video_encoder_config.video_format.parameters["foo"] = "foo";
1452 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
1453 kMaxPayloadLength,
1454 true /* nack_enabled */);
asapersson36e9eb42017-03-31 05:29:12 -07001455
1456 video_source_.IncomingCapturedFrame(CreateFrame(4, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001457 WaitForEncodedFrame(4);
asapersson36e9eb42017-03-31 05:29:12 -07001458 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1459 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1460 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1461
mflodmancc3d4422017-08-03 08:27:51 -07001462 video_stream_encoder_->Stop();
asapersson36e9eb42017-03-31 05:29:12 -07001463}
1464
mflodmancc3d4422017-08-03 08:27:51 -07001465TEST_F(VideoStreamEncoderTest,
1466 StatsTracksCpuAdaptationStatsWhenSwitchingSource) {
1467 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkj803d97f2016-11-01 11:45:46 -07001468
asapersson0944a802017-04-07 00:57:58 -07001469 const int kWidth = 1280;
1470 const int kHeight = 720;
sprang84a37592017-02-10 07:04:27 -08001471 int sequence = 1;
perkj803d97f2016-11-01 11:45:46 -07001472
asaperssonfab67072017-04-04 05:51:49 -07001473 video_source_.IncomingCapturedFrame(CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001474 WaitForEncodedFrame(sequence++);
perkj803d97f2016-11-01 11:45:46 -07001475 VideoSendStream::Stats stats = stats_proxy_->GetStats();
sprang84a37592017-02-10 07:04:27 -08001476 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001477 EXPECT_FALSE(stats.cpu_limited_framerate);
sprang84a37592017-02-10 07:04:27 -08001478 EXPECT_EQ(0, stats.number_of_cpu_adapt_changes);
1479
asapersson02465b82017-04-10 01:12:52 -07001480 // Trigger CPU overuse, should now adapt down.
mflodmancc3d4422017-08-03 08:27:51 -07001481 video_stream_encoder_->TriggerCpuOveruse();
asaperssonfab67072017-04-04 05:51:49 -07001482 video_source_.IncomingCapturedFrame(CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001483 WaitForEncodedFrame(sequence++);
sprang84a37592017-02-10 07:04:27 -08001484 stats = stats_proxy_->GetStats();
perkj803d97f2016-11-01 11:45:46 -07001485 EXPECT_TRUE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001486 EXPECT_FALSE(stats.cpu_limited_framerate);
perkj803d97f2016-11-01 11:45:46 -07001487 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1488
1489 // Set new source with adaptation still enabled.
1490 test::FrameForwarder new_video_source;
mflodmancc3d4422017-08-03 08:27:51 -07001491 video_stream_encoder_->SetSource(
sprangc5d62e22017-04-02 23:53:04 -07001492 &new_video_source,
1493 VideoSendStream::DegradationPreference::kMaintainFramerate);
perkj803d97f2016-11-01 11:45:46 -07001494
1495 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001496 CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001497 WaitForEncodedFrame(sequence++);
perkj803d97f2016-11-01 11:45:46 -07001498 stats = stats_proxy_->GetStats();
1499 EXPECT_TRUE(stats.cpu_limited_resolution);
asapersson09f05612017-05-15 23:40:18 -07001500 EXPECT_FALSE(stats.cpu_limited_framerate);
perkj803d97f2016-11-01 11:45:46 -07001501 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1502
sprangc5d62e22017-04-02 23:53:04 -07001503 // Set cpu adaptation by frame dropping.
mflodmancc3d4422017-08-03 08:27:51 -07001504 video_stream_encoder_->SetSource(
perkj803d97f2016-11-01 11:45:46 -07001505 &new_video_source,
1506 VideoSendStream::DegradationPreference::kMaintainResolution);
1507 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001508 CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001509 WaitForEncodedFrame(sequence++);
perkj803d97f2016-11-01 11:45:46 -07001510 stats = stats_proxy_->GetStats();
sprangc5d62e22017-04-02 23:53:04 -07001511 // Not adapted at first.
perkj803d97f2016-11-01 11:45:46 -07001512 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson09f05612017-05-15 23:40:18 -07001513 EXPECT_FALSE(stats.cpu_limited_framerate);
perkj803d97f2016-11-01 11:45:46 -07001514 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1515
sprangc5d62e22017-04-02 23:53:04 -07001516 // Force an input frame rate to be available, or the adaptation call won't
asapersson09f05612017-05-15 23:40:18 -07001517 // know what framerate to adapt from.
sprangc5d62e22017-04-02 23:53:04 -07001518 VideoSendStream::Stats mock_stats = stats_proxy_->GetStats();
1519 mock_stats.input_frame_rate = 30;
1520 stats_proxy_->SetMockStats(mock_stats);
mflodmancc3d4422017-08-03 08:27:51 -07001521 video_stream_encoder_->TriggerCpuOveruse();
sprangc5d62e22017-04-02 23:53:04 -07001522 stats_proxy_->ResetMockStats();
1523
1524 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001525 CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001526 WaitForEncodedFrame(sequence++);
sprangc5d62e22017-04-02 23:53:04 -07001527
1528 // Framerate now adapted.
1529 stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001530 EXPECT_FALSE(stats.cpu_limited_resolution);
1531 EXPECT_TRUE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001532 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
1533
1534 // Disable CPU adaptation.
mflodmancc3d4422017-08-03 08:27:51 -07001535 video_stream_encoder_->SetSource(
sprangc5d62e22017-04-02 23:53:04 -07001536 &new_video_source,
1537 VideoSendStream::DegradationPreference::kDegradationDisabled);
1538 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001539 CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001540 WaitForEncodedFrame(sequence++);
sprangc5d62e22017-04-02 23:53:04 -07001541
1542 stats = stats_proxy_->GetStats();
1543 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001544 EXPECT_FALSE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001545 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
1546
1547 // Try to trigger overuse. Should not succeed.
1548 stats_proxy_->SetMockStats(mock_stats);
mflodmancc3d4422017-08-03 08:27:51 -07001549 video_stream_encoder_->TriggerCpuOveruse();
sprangc5d62e22017-04-02 23:53:04 -07001550 stats_proxy_->ResetMockStats();
1551
1552 stats = stats_proxy_->GetStats();
1553 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001554 EXPECT_FALSE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001555 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
1556
1557 // Switch back the source with resolution adaptation enabled.
mflodmancc3d4422017-08-03 08:27:51 -07001558 video_stream_encoder_->SetSource(
sprangc5d62e22017-04-02 23:53:04 -07001559 &video_source_,
1560 VideoSendStream::DegradationPreference::kMaintainFramerate);
asaperssonfab67072017-04-04 05:51:49 -07001561 video_source_.IncomingCapturedFrame(CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001562 WaitForEncodedFrame(sequence++);
perkj803d97f2016-11-01 11:45:46 -07001563 stats = stats_proxy_->GetStats();
1564 EXPECT_TRUE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001565 EXPECT_FALSE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001566 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
perkj803d97f2016-11-01 11:45:46 -07001567
1568 // Trigger CPU normal usage.
mflodmancc3d4422017-08-03 08:27:51 -07001569 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssonfab67072017-04-04 05:51:49 -07001570 video_source_.IncomingCapturedFrame(CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001571 WaitForEncodedFrame(sequence++);
perkj803d97f2016-11-01 11:45:46 -07001572 stats = stats_proxy_->GetStats();
1573 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001574 EXPECT_FALSE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001575 EXPECT_EQ(3, stats.number_of_cpu_adapt_changes);
1576
1577 // Back to the source with adaptation off, set it back to maintain-resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001578 video_stream_encoder_->SetSource(
sprangc5d62e22017-04-02 23:53:04 -07001579 &new_video_source,
1580 VideoSendStream::DegradationPreference::kMaintainResolution);
1581 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001582 CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001583 WaitForEncodedFrame(sequence++);
sprangc5d62e22017-04-02 23:53:04 -07001584 stats = stats_proxy_->GetStats();
asapersson13874762017-06-07 00:01:02 -07001585 // Disabled, since we previously switched the source to disabled.
sprangc5d62e22017-04-02 23:53:04 -07001586 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001587 EXPECT_TRUE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001588 EXPECT_EQ(3, stats.number_of_cpu_adapt_changes);
1589
1590 // Trigger CPU normal usage.
mflodmancc3d4422017-08-03 08:27:51 -07001591 video_stream_encoder_->TriggerCpuNormalUsage();
sprangc5d62e22017-04-02 23:53:04 -07001592 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001593 CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001594 WaitForEncodedFrame(sequence++);
sprangc5d62e22017-04-02 23:53:04 -07001595 stats = stats_proxy_->GetStats();
1596 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001597 EXPECT_FALSE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001598 EXPECT_EQ(4, stats.number_of_cpu_adapt_changes);
asapersson02465b82017-04-10 01:12:52 -07001599 EXPECT_EQ(0, stats.number_of_quality_adapt_changes);
perkj803d97f2016-11-01 11:45:46 -07001600
mflodmancc3d4422017-08-03 08:27:51 -07001601 video_stream_encoder_->Stop();
perkj803d97f2016-11-01 11:45:46 -07001602}
1603
mflodmancc3d4422017-08-03 08:27:51 -07001604TEST_F(VideoStreamEncoderTest, StatsTracksPreferredBitrate) {
1605 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
Erik Språng08127a92016-11-16 16:41:30 +01001606
asaperssonfab67072017-04-04 05:51:49 -07001607 const int kWidth = 1280;
1608 const int kHeight = 720;
1609 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001610 WaitForEncodedFrame(1);
Erik Språng08127a92016-11-16 16:41:30 +01001611
1612 VideoSendStream::Stats stats = stats_proxy_->GetStats();
1613 EXPECT_EQ(video_encoder_config_.max_bitrate_bps,
1614 stats.preferred_media_bitrate_bps);
1615
mflodmancc3d4422017-08-03 08:27:51 -07001616 video_stream_encoder_->Stop();
Erik Språng08127a92016-11-16 16:41:30 +01001617}
1618
mflodmancc3d4422017-08-03 08:27:51 -07001619TEST_F(VideoStreamEncoderTest,
1620 ScalingUpAndDownDoesNothingWithMaintainResolution) {
asaperssonfab67072017-04-04 05:51:49 -07001621 const int kWidth = 1280;
1622 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001623 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
kthelgason876222f2016-11-29 01:44:11 -08001624
asaperssonfab67072017-04-04 05:51:49 -07001625 // Expect no scaling to begin with.
asapersson02465b82017-04-10 01:12:52 -07001626 VerifyNoLimitation(video_source_.sink_wants());
kthelgason876222f2016-11-29 01:44:11 -08001627
asaperssonfab67072017-04-04 05:51:49 -07001628 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001629 WaitForEncodedFrame(1);
kthelgason876222f2016-11-29 01:44:11 -08001630
asaperssonfab67072017-04-04 05:51:49 -07001631 // Trigger scale down.
mflodmancc3d4422017-08-03 08:27:51 -07001632 video_stream_encoder_->TriggerQualityLow();
kthelgason5e13d412016-12-01 03:59:51 -08001633
asaperssonfab67072017-04-04 05:51:49 -07001634 video_source_.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001635 WaitForEncodedFrame(2);
kthelgason5e13d412016-12-01 03:59:51 -08001636
kthelgason876222f2016-11-29 01:44:11 -08001637 // Expect a scale down.
1638 EXPECT_TRUE(video_source_.sink_wants().max_pixel_count);
asaperssonfab67072017-04-04 05:51:49 -07001639 EXPECT_LT(video_source_.sink_wants().max_pixel_count, kWidth * kHeight);
kthelgason876222f2016-11-29 01:44:11 -08001640
asapersson02465b82017-04-10 01:12:52 -07001641 // Set resolution scaling disabled.
kthelgason876222f2016-11-29 01:44:11 -08001642 test::FrameForwarder new_video_source;
mflodmancc3d4422017-08-03 08:27:51 -07001643 video_stream_encoder_->SetSource(
kthelgason876222f2016-11-29 01:44:11 -08001644 &new_video_source,
1645 VideoSendStream::DegradationPreference::kMaintainResolution);
1646
asaperssonfab67072017-04-04 05:51:49 -07001647 // Trigger scale down.
mflodmancc3d4422017-08-03 08:27:51 -07001648 video_stream_encoder_->TriggerQualityLow();
asaperssonfab67072017-04-04 05:51:49 -07001649 new_video_source.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001650 WaitForEncodedFrame(3);
kthelgason876222f2016-11-29 01:44:11 -08001651
asaperssonfab67072017-04-04 05:51:49 -07001652 // Expect no scaling.
sprangc5d62e22017-04-02 23:53:04 -07001653 EXPECT_EQ(std::numeric_limits<int>::max(),
1654 new_video_source.sink_wants().max_pixel_count);
kthelgason876222f2016-11-29 01:44:11 -08001655
asaperssonfab67072017-04-04 05:51:49 -07001656 // Trigger scale up.
mflodmancc3d4422017-08-03 08:27:51 -07001657 video_stream_encoder_->TriggerQualityHigh();
asaperssonfab67072017-04-04 05:51:49 -07001658 new_video_source.IncomingCapturedFrame(CreateFrame(4, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001659 WaitForEncodedFrame(4);
kthelgason876222f2016-11-29 01:44:11 -08001660
asapersson02465b82017-04-10 01:12:52 -07001661 // Expect nothing to change, still no scaling.
sprangc5d62e22017-04-02 23:53:04 -07001662 EXPECT_EQ(std::numeric_limits<int>::max(),
1663 new_video_source.sink_wants().max_pixel_count);
kthelgason876222f2016-11-29 01:44:11 -08001664
mflodmancc3d4422017-08-03 08:27:51 -07001665 video_stream_encoder_->Stop();
kthelgason876222f2016-11-29 01:44:11 -08001666}
1667
mflodmancc3d4422017-08-03 08:27:51 -07001668TEST_F(VideoStreamEncoderTest,
1669 SkipsSameAdaptDownRequest_MaintainFramerateMode) {
asapersson02465b82017-04-10 01:12:52 -07001670 const int kWidth = 1280;
1671 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001672 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson02465b82017-04-10 01:12:52 -07001673
1674 // Enable kMaintainFramerate preference, no initial limitation.
1675 test::FrameForwarder source;
mflodmancc3d4422017-08-03 08:27:51 -07001676 video_stream_encoder_->SetSource(
asapersson02465b82017-04-10 01:12:52 -07001677 &source, VideoSendStream::DegradationPreference::kMaintainFramerate);
1678
1679 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001680 WaitForEncodedFrame(1);
asapersson02465b82017-04-10 01:12:52 -07001681 VerifyNoLimitation(source.sink_wants());
1682 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1683 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1684
1685 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001686 video_stream_encoder_->TriggerCpuOveruse();
asapersson09f05612017-05-15 23:40:18 -07001687 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
asapersson02465b82017-04-10 01:12:52 -07001688 const int kLastMaxPixelCount = source.sink_wants().max_pixel_count;
1689 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1690 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1691
1692 // Trigger adapt down for same input resolution, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07001693 video_stream_encoder_->TriggerCpuOveruse();
asapersson02465b82017-04-10 01:12:52 -07001694 EXPECT_EQ(kLastMaxPixelCount, source.sink_wants().max_pixel_count);
1695 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1696 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1697
mflodmancc3d4422017-08-03 08:27:51 -07001698 video_stream_encoder_->Stop();
asapersson02465b82017-04-10 01:12:52 -07001699}
1700
mflodmancc3d4422017-08-03 08:27:51 -07001701TEST_F(VideoStreamEncoderTest, SkipsSameOrLargerAdaptDownRequest_BalancedMode) {
asaperssonf7e294d2017-06-13 23:25:22 -07001702 const int kWidth = 1280;
1703 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001704 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -07001705
1706 // Enable kBalanced preference, no initial limitation.
1707 test::FrameForwarder source;
mflodmancc3d4422017-08-03 08:27:51 -07001708 video_stream_encoder_->SetSource(
1709 &source,
1710 VideoSendStream::DegradationPreference::kBalanced);
asaperssonf7e294d2017-06-13 23:25:22 -07001711 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
1712 sink_.WaitForEncodedFrame(1);
1713 VerifyNoLimitation(source.sink_wants());
1714
1715 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001716 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07001717 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
1718 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1719 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1720 const int kLastMaxPixelCount = source.sink_wants().max_pixel_count;
1721
1722 // Trigger adapt down for same input resolution, expect no change.
1723 source.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
1724 sink_.WaitForEncodedFrame(2);
mflodmancc3d4422017-08-03 08:27:51 -07001725 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07001726 EXPECT_EQ(kLastMaxPixelCount, source.sink_wants().max_pixel_count);
1727 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1728 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1729
1730 // Trigger adapt down for larger input resolution, expect no change.
1731 source.IncomingCapturedFrame(CreateFrame(3, kWidth + 1, kHeight + 1));
1732 sink_.WaitForEncodedFrame(3);
mflodmancc3d4422017-08-03 08:27:51 -07001733 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07001734 EXPECT_EQ(kLastMaxPixelCount, source.sink_wants().max_pixel_count);
1735 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1736 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1737
mflodmancc3d4422017-08-03 08:27:51 -07001738 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07001739}
1740
mflodmancc3d4422017-08-03 08:27:51 -07001741TEST_F(VideoStreamEncoderTest,
1742 NoChangeForInitialNormalUsage_MaintainFramerateMode) {
asapersson02465b82017-04-10 01:12:52 -07001743 const int kWidth = 1280;
1744 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001745 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson02465b82017-04-10 01:12:52 -07001746
1747 // Enable kMaintainFramerate preference, no initial limitation.
1748 test::FrameForwarder source;
mflodmancc3d4422017-08-03 08:27:51 -07001749 video_stream_encoder_->SetSource(
asapersson02465b82017-04-10 01:12:52 -07001750 &source, VideoSendStream::DegradationPreference::kMaintainFramerate);
1751
1752 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001753 WaitForEncodedFrame(kWidth, kHeight);
asapersson02465b82017-04-10 01:12:52 -07001754 VerifyNoLimitation(source.sink_wants());
1755 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1756 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1757
1758 // Trigger adapt up, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07001759 video_stream_encoder_->TriggerCpuNormalUsage();
asapersson02465b82017-04-10 01:12:52 -07001760 VerifyNoLimitation(source.sink_wants());
1761 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1762 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1763
mflodmancc3d4422017-08-03 08:27:51 -07001764 video_stream_encoder_->Stop();
asapersson02465b82017-04-10 01:12:52 -07001765}
1766
mflodmancc3d4422017-08-03 08:27:51 -07001767TEST_F(VideoStreamEncoderTest,
1768 NoChangeForInitialNormalUsage_MaintainResolutionMode) {
asapersson02465b82017-04-10 01:12:52 -07001769 const int kWidth = 1280;
1770 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001771 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson02465b82017-04-10 01:12:52 -07001772
1773 // Enable kMaintainResolution preference, no initial limitation.
1774 test::FrameForwarder source;
mflodmancc3d4422017-08-03 08:27:51 -07001775 video_stream_encoder_->SetSource(
asapersson02465b82017-04-10 01:12:52 -07001776 &source, VideoSendStream::DegradationPreference::kMaintainResolution);
1777
1778 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001779 WaitForEncodedFrame(kWidth, kHeight);
asapersson02465b82017-04-10 01:12:52 -07001780 VerifyNoLimitation(source.sink_wants());
asapersson09f05612017-05-15 23:40:18 -07001781 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
asapersson02465b82017-04-10 01:12:52 -07001782 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1783
1784 // Trigger adapt up, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07001785 video_stream_encoder_->TriggerCpuNormalUsage();
asapersson02465b82017-04-10 01:12:52 -07001786 VerifyNoLimitation(source.sink_wants());
asapersson09f05612017-05-15 23:40:18 -07001787 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
asapersson02465b82017-04-10 01:12:52 -07001788 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1789
mflodmancc3d4422017-08-03 08:27:51 -07001790 video_stream_encoder_->Stop();
asapersson02465b82017-04-10 01:12:52 -07001791}
1792
mflodmancc3d4422017-08-03 08:27:51 -07001793TEST_F(VideoStreamEncoderTest, NoChangeForInitialNormalUsage_BalancedMode) {
asaperssonf7e294d2017-06-13 23:25:22 -07001794 const int kWidth = 1280;
1795 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001796 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -07001797
1798 // Enable kBalanced preference, no initial limitation.
1799 test::FrameForwarder source;
mflodmancc3d4422017-08-03 08:27:51 -07001800 video_stream_encoder_->SetSource(
1801 &source,
1802 VideoSendStream::DegradationPreference::kBalanced);
asaperssonf7e294d2017-06-13 23:25:22 -07001803
1804 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
1805 sink_.WaitForEncodedFrame(kWidth, kHeight);
1806 VerifyNoLimitation(source.sink_wants());
1807 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1808 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
1809 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1810
1811 // Trigger adapt up, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07001812 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07001813 VerifyNoLimitation(source.sink_wants());
1814 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1815 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
1816 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1817
mflodmancc3d4422017-08-03 08:27:51 -07001818 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07001819}
1820
mflodmancc3d4422017-08-03 08:27:51 -07001821TEST_F(VideoStreamEncoderTest, NoChangeForInitialNormalUsage_DisabledMode) {
asapersson09f05612017-05-15 23:40:18 -07001822 const int kWidth = 1280;
1823 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001824 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson09f05612017-05-15 23:40:18 -07001825
1826 // Enable kDegradationDisabled preference, no initial limitation.
1827 test::FrameForwarder source;
mflodmancc3d4422017-08-03 08:27:51 -07001828 video_stream_encoder_->SetSource(
asapersson09f05612017-05-15 23:40:18 -07001829 &source, VideoSendStream::DegradationPreference::kDegradationDisabled);
1830
1831 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
1832 sink_.WaitForEncodedFrame(kWidth, kHeight);
1833 VerifyNoLimitation(source.sink_wants());
1834 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1835 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
1836 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1837
1838 // Trigger adapt up, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07001839 video_stream_encoder_->TriggerQualityHigh();
asapersson09f05612017-05-15 23:40:18 -07001840 VerifyNoLimitation(source.sink_wants());
1841 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1842 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
1843 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1844
mflodmancc3d4422017-08-03 08:27:51 -07001845 video_stream_encoder_->Stop();
asapersson09f05612017-05-15 23:40:18 -07001846}
1847
mflodmancc3d4422017-08-03 08:27:51 -07001848TEST_F(VideoStreamEncoderTest,
1849 AdaptsResolutionForLowQuality_MaintainFramerateMode) {
asapersson02465b82017-04-10 01:12:52 -07001850 const int kWidth = 1280;
1851 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001852 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson02465b82017-04-10 01:12:52 -07001853
1854 // Enable kMaintainFramerate preference, no initial limitation.
1855 AdaptingFrameForwarder source;
1856 source.set_adaptation_enabled(true);
mflodmancc3d4422017-08-03 08:27:51 -07001857 video_stream_encoder_->SetSource(
asapersson02465b82017-04-10 01:12:52 -07001858 &source, VideoSendStream::DegradationPreference::kMaintainFramerate);
1859
1860 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001861 WaitForEncodedFrame(1);
asapersson02465b82017-04-10 01:12:52 -07001862 VerifyNoLimitation(source.sink_wants());
1863 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1864 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1865
1866 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001867 video_stream_encoder_->TriggerQualityLow();
asapersson02465b82017-04-10 01:12:52 -07001868 source.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001869 WaitForEncodedFrame(2);
asapersson09f05612017-05-15 23:40:18 -07001870 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
asapersson02465b82017-04-10 01:12:52 -07001871 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1872 EXPECT_EQ(1, 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();
asapersson02465b82017-04-10 01:12:52 -07001876 VerifyNoLimitation(source.sink_wants());
1877 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1878 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1879 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1880
mflodmancc3d4422017-08-03 08:27:51 -07001881 video_stream_encoder_->Stop();
asapersson02465b82017-04-10 01:12:52 -07001882}
1883
mflodmancc3d4422017-08-03 08:27:51 -07001884TEST_F(VideoStreamEncoderTest,
1885 AdaptsFramerateForLowQuality_MaintainResolutionMode) {
asapersson09f05612017-05-15 23:40:18 -07001886 const int kWidth = 1280;
1887 const int kHeight = 720;
1888 const int kInputFps = 30;
mflodmancc3d4422017-08-03 08:27:51 -07001889 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson09f05612017-05-15 23:40:18 -07001890
1891 VideoSendStream::Stats stats = stats_proxy_->GetStats();
1892 stats.input_frame_rate = kInputFps;
1893 stats_proxy_->SetMockStats(stats);
1894
1895 // Expect no scaling to begin with (preference: kMaintainFramerate).
1896 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
1897 sink_.WaitForEncodedFrame(1);
1898 VerifyNoLimitation(video_source_.sink_wants());
1899
1900 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001901 video_stream_encoder_->TriggerQualityLow();
asapersson09f05612017-05-15 23:40:18 -07001902 video_source_.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
1903 sink_.WaitForEncodedFrame(2);
1904 VerifyFpsMaxResolutionLt(video_source_.sink_wants(), kWidth * kHeight);
1905
1906 // Enable kMaintainResolution preference.
1907 test::FrameForwarder new_video_source;
mflodmancc3d4422017-08-03 08:27:51 -07001908 video_stream_encoder_->SetSource(
asapersson09f05612017-05-15 23:40:18 -07001909 &new_video_source,
1910 VideoSendStream::DegradationPreference::kMaintainResolution);
1911 VerifyNoLimitation(new_video_source.sink_wants());
1912
1913 // Trigger adapt down, expect reduced framerate.
mflodmancc3d4422017-08-03 08:27:51 -07001914 video_stream_encoder_->TriggerQualityLow();
asapersson09f05612017-05-15 23:40:18 -07001915 new_video_source.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
1916 sink_.WaitForEncodedFrame(3);
1917 VerifyFpsLtResolutionMax(new_video_source.sink_wants(), kInputFps);
1918
1919 // Trigger adapt up, expect no restriction.
mflodmancc3d4422017-08-03 08:27:51 -07001920 video_stream_encoder_->TriggerQualityHigh();
asapersson09f05612017-05-15 23:40:18 -07001921 VerifyNoLimitation(new_video_source.sink_wants());
1922
mflodmancc3d4422017-08-03 08:27:51 -07001923 video_stream_encoder_->Stop();
asapersson09f05612017-05-15 23:40:18 -07001924}
1925
mflodmancc3d4422017-08-03 08:27:51 -07001926TEST_F(VideoStreamEncoderTest, DoesNotScaleBelowSetResolutionLimit) {
asaperssond0de2952017-04-21 01:47:31 -07001927 const int kWidth = 1280;
1928 const int kHeight = 720;
1929 const size_t kNumFrames = 10;
1930
mflodmancc3d4422017-08-03 08:27:51 -07001931 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
kthelgason5e13d412016-12-01 03:59:51 -08001932
asaperssond0de2952017-04-21 01:47:31 -07001933 // Enable adapter, expected input resolutions when downscaling:
asapersson142fcc92017-08-17 08:58:54 -07001934 // 1280x720 -> 960x540 -> 640x360 -> 480x270 -> 320x180 (kMinPixelsPerFrame)
asaperssond0de2952017-04-21 01:47:31 -07001935 video_source_.set_adaptation_enabled(true);
1936
1937 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1938 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1939
1940 int downscales = 0;
1941 for (size_t i = 1; i <= kNumFrames; i++) {
1942 video_source_.IncomingCapturedFrame(CreateFrame(i, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001943 WaitForEncodedFrame(i);
asaperssond0de2952017-04-21 01:47:31 -07001944
asaperssonfab67072017-04-04 05:51:49 -07001945 // Trigger scale down.
asaperssond0de2952017-04-21 01:47:31 -07001946 rtc::VideoSinkWants last_wants = video_source_.sink_wants();
mflodmancc3d4422017-08-03 08:27:51 -07001947 video_stream_encoder_->TriggerQualityLow();
sprangc5d62e22017-04-02 23:53:04 -07001948 EXPECT_GE(video_source_.sink_wants().max_pixel_count, kMinPixelsPerFrame);
asaperssond0de2952017-04-21 01:47:31 -07001949
1950 if (video_source_.sink_wants().max_pixel_count < last_wants.max_pixel_count)
1951 ++downscales;
1952
1953 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1954 EXPECT_EQ(downscales,
1955 stats_proxy_->GetStats().number_of_quality_adapt_changes);
1956 EXPECT_GT(downscales, 0);
kthelgason5e13d412016-12-01 03:59:51 -08001957 }
mflodmancc3d4422017-08-03 08:27:51 -07001958 video_stream_encoder_->Stop();
asaperssond0de2952017-04-21 01:47:31 -07001959}
1960
mflodmancc3d4422017-08-03 08:27:51 -07001961TEST_F(VideoStreamEncoderTest,
asaperssond0de2952017-04-21 01:47:31 -07001962 AdaptsResolutionUpAndDownTwiceOnOveruse_MaintainFramerateMode) {
1963 const int kWidth = 1280;
1964 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001965 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssond0de2952017-04-21 01:47:31 -07001966
1967 // Enable kMaintainFramerate preference, no initial limitation.
1968 AdaptingFrameForwarder source;
1969 source.set_adaptation_enabled(true);
mflodmancc3d4422017-08-03 08:27:51 -07001970 video_stream_encoder_->SetSource(
asaperssond0de2952017-04-21 01:47:31 -07001971 &source, VideoSendStream::DegradationPreference::kMaintainFramerate);
1972
1973 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001974 WaitForEncodedFrame(kWidth, kHeight);
asaperssond0de2952017-04-21 01:47:31 -07001975 VerifyNoLimitation(source.sink_wants());
1976 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1977 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1978
1979 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001980 video_stream_encoder_->TriggerCpuOveruse();
asaperssond0de2952017-04-21 01:47:31 -07001981 source.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001982 WaitForEncodedFrame(2);
asapersson09f05612017-05-15 23:40:18 -07001983 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
asaperssond0de2952017-04-21 01:47:31 -07001984 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1985 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1986
1987 // Trigger adapt up, expect no restriction.
mflodmancc3d4422017-08-03 08:27:51 -07001988 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssond0de2952017-04-21 01:47:31 -07001989 source.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001990 WaitForEncodedFrame(kWidth, kHeight);
asaperssond0de2952017-04-21 01:47:31 -07001991 VerifyNoLimitation(source.sink_wants());
1992 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1993 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1994
1995 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001996 video_stream_encoder_->TriggerCpuOveruse();
asaperssond0de2952017-04-21 01:47:31 -07001997 source.IncomingCapturedFrame(CreateFrame(4, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001998 WaitForEncodedFrame(4);
asapersson09f05612017-05-15 23:40:18 -07001999 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
asaperssond0de2952017-04-21 01:47:31 -07002000 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2001 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2002
2003 // Trigger adapt up, expect no restriction.
mflodmancc3d4422017-08-03 08:27:51 -07002004 video_stream_encoder_->TriggerCpuNormalUsage();
asapersson09f05612017-05-15 23:40:18 -07002005 source.IncomingCapturedFrame(CreateFrame(5, kWidth, kHeight));
2006 sink_.WaitForEncodedFrame(kWidth, kHeight);
asaperssond0de2952017-04-21 01:47:31 -07002007 VerifyNoLimitation(source.sink_wants());
2008 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2009 EXPECT_EQ(4, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2010
mflodmancc3d4422017-08-03 08:27:51 -07002011 video_stream_encoder_->Stop();
asaperssond0de2952017-04-21 01:47:31 -07002012}
2013
mflodmancc3d4422017-08-03 08:27:51 -07002014TEST_F(VideoStreamEncoderTest,
asaperssonf7e294d2017-06-13 23:25:22 -07002015 AdaptsResolutionUpAndDownTwiceForLowQuality_BalancedMode_NoFpsLimit) {
2016 const int kWidth = 1280;
2017 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07002018 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -07002019
2020 // Enable kBalanced preference, no initial limitation.
2021 AdaptingFrameForwarder source;
2022 source.set_adaptation_enabled(true);
mflodmancc3d4422017-08-03 08:27:51 -07002023 video_stream_encoder_->SetSource(
2024 &source,
2025 VideoSendStream::DegradationPreference::kBalanced);
asaperssonf7e294d2017-06-13 23:25:22 -07002026
2027 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
2028 sink_.WaitForEncodedFrame(kWidth, kHeight);
2029 VerifyNoLimitation(source.sink_wants());
2030 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2031 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2032
2033 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07002034 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002035 source.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
2036 sink_.WaitForEncodedFrame(2);
2037 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
2038 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2039 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2040
2041 // Trigger adapt up, expect no restriction.
mflodmancc3d4422017-08-03 08:27:51 -07002042 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002043 source.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
2044 sink_.WaitForEncodedFrame(kWidth, kHeight);
2045 VerifyNoLimitation(source.sink_wants());
2046 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2047 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2048
2049 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07002050 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002051 source.IncomingCapturedFrame(CreateFrame(4, kWidth, kHeight));
2052 sink_.WaitForEncodedFrame(4);
2053 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
2054 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2055 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2056
2057 // Trigger adapt up, expect no restriction.
mflodmancc3d4422017-08-03 08:27:51 -07002058 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002059 source.IncomingCapturedFrame(CreateFrame(5, kWidth, kHeight));
2060 sink_.WaitForEncodedFrame(kWidth, kHeight);
2061 VerifyNoLimitation(source.sink_wants());
2062 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2063 EXPECT_EQ(4, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2064
mflodmancc3d4422017-08-03 08:27:51 -07002065 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07002066}
2067
mflodmancc3d4422017-08-03 08:27:51 -07002068TEST_F(VideoStreamEncoderTest,
asaperssond0de2952017-04-21 01:47:31 -07002069 AdaptsResolutionOnOveruseAndLowQuality_MaintainFramerateMode) {
2070 const int kWidth = 1280;
2071 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07002072 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssond0de2952017-04-21 01:47:31 -07002073
2074 // Enable kMaintainFramerate preference, no initial limitation.
2075 AdaptingFrameForwarder source;
2076 source.set_adaptation_enabled(true);
mflodmancc3d4422017-08-03 08:27:51 -07002077 video_stream_encoder_->SetSource(
asaperssond0de2952017-04-21 01:47:31 -07002078 &source, VideoSendStream::DegradationPreference::kMaintainFramerate);
2079
2080 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002081 WaitForEncodedFrame(kWidth, kHeight);
asaperssond0de2952017-04-21 01:47:31 -07002082 VerifyNoLimitation(source.sink_wants());
2083 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2084 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2085 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2086 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2087
2088 // Trigger cpu adapt down, expect scaled down resolution (960x540).
mflodmancc3d4422017-08-03 08:27:51 -07002089 video_stream_encoder_->TriggerCpuOveruse();
asaperssond0de2952017-04-21 01:47:31 -07002090 source.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002091 WaitForEncodedFrame(2);
asapersson09f05612017-05-15 23:40:18 -07002092 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
asaperssond0de2952017-04-21 01:47:31 -07002093 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2094 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2095 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2096 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2097
2098 // Trigger cpu adapt down, expect scaled down resolution (640x360).
mflodmancc3d4422017-08-03 08:27:51 -07002099 video_stream_encoder_->TriggerCpuOveruse();
asaperssond0de2952017-04-21 01:47:31 -07002100 source.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002101 WaitForEncodedFrame(3);
asapersson09f05612017-05-15 23:40:18 -07002102 VerifyFpsMaxResolutionLt(source.sink_wants(), source.last_wants());
asaperssond0de2952017-04-21 01:47:31 -07002103 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2104 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2105 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2106 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2107
Jonathan Yubc771b72017-12-08 17:04:29 -08002108 // Trigger cpu adapt down, expect scaled down resolution (480x270).
mflodmancc3d4422017-08-03 08:27:51 -07002109 video_stream_encoder_->TriggerCpuOveruse();
asaperssond0de2952017-04-21 01:47:31 -07002110 source.IncomingCapturedFrame(CreateFrame(4, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002111 WaitForEncodedFrame(4);
Jonathan Yubc771b72017-12-08 17:04:29 -08002112 VerifyFpsMaxResolutionLt(source.sink_wants(), source.last_wants());
asaperssond0de2952017-04-21 01:47:31 -07002113 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2114 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
Jonathan Yubc771b72017-12-08 17:04:29 -08002115 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
asaperssond0de2952017-04-21 01:47:31 -07002116 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2117
Jonathan Yubc771b72017-12-08 17:04:29 -08002118 // Trigger quality adapt down, expect scaled down resolution (320x180).
mflodmancc3d4422017-08-03 08:27:51 -07002119 video_stream_encoder_->TriggerQualityLow();
asaperssond0de2952017-04-21 01:47:31 -07002120 source.IncomingCapturedFrame(CreateFrame(5, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002121 WaitForEncodedFrame(5);
asapersson09f05612017-05-15 23:40:18 -07002122 VerifyFpsMaxResolutionLt(source.sink_wants(), source.last_wants());
Jonathan Yubc771b72017-12-08 17:04:29 -08002123 rtc::VideoSinkWants last_wants = source.sink_wants();
asaperssond0de2952017-04-21 01:47:31 -07002124 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2125 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2126 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2127 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2128
Jonathan Yubc771b72017-12-08 17:04:29 -08002129 // Trigger quality adapt down, expect no change (min resolution reached).
2130 video_stream_encoder_->TriggerQualityLow();
2131 source.IncomingCapturedFrame(CreateFrame(6, kWidth, kHeight));
2132 WaitForEncodedFrame(6);
2133 VerifyFpsMaxResolutionEq(source.sink_wants(), last_wants);
2134 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2135 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2136 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2137 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2138
2139 // Trigger cpu adapt up, expect upscaled resolution (480x270).
mflodmancc3d4422017-08-03 08:27:51 -07002140 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssond0de2952017-04-21 01:47:31 -07002141 source.IncomingCapturedFrame(CreateFrame(7, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002142 WaitForEncodedFrame(7);
asapersson09f05612017-05-15 23:40:18 -07002143 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
Jonathan Yubc771b72017-12-08 17:04:29 -08002144 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2145 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2146 EXPECT_EQ(4, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2147 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2148
2149 // Trigger cpu adapt up, expect upscaled resolution (640x360).
2150 video_stream_encoder_->TriggerCpuNormalUsage();
2151 source.IncomingCapturedFrame(CreateFrame(8, kWidth, kHeight));
2152 WaitForEncodedFrame(8);
2153 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
2154 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2155 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2156 EXPECT_EQ(5, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2157 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2158
2159 // Trigger cpu adapt up, expect upscaled resolution (960x540).
2160 video_stream_encoder_->TriggerCpuNormalUsage();
2161 source.IncomingCapturedFrame(CreateFrame(9, kWidth, kHeight));
2162 WaitForEncodedFrame(9);
2163 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
asaperssond0de2952017-04-21 01:47:31 -07002164 last_wants = source.sink_wants();
2165 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2166 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
Jonathan Yubc771b72017-12-08 17:04:29 -08002167 EXPECT_EQ(6, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
asaperssond0de2952017-04-21 01:47:31 -07002168 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2169
2170 // Trigger cpu adapt up, no cpu downgrades, expect no change (960x540).
mflodmancc3d4422017-08-03 08:27:51 -07002171 video_stream_encoder_->TriggerCpuNormalUsage();
Jonathan Yubc771b72017-12-08 17:04:29 -08002172 source.IncomingCapturedFrame(CreateFrame(10, kWidth, kHeight));
2173 WaitForEncodedFrame(10);
asapersson09f05612017-05-15 23:40:18 -07002174 VerifyFpsEqResolutionEq(source.sink_wants(), last_wants);
asaperssond0de2952017-04-21 01:47:31 -07002175 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2176 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
Jonathan Yubc771b72017-12-08 17:04:29 -08002177 EXPECT_EQ(6, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
asaperssond0de2952017-04-21 01:47:31 -07002178 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2179
2180 // Trigger quality adapt up, expect no restriction (1280x720).
mflodmancc3d4422017-08-03 08:27:51 -07002181 video_stream_encoder_->TriggerQualityHigh();
Jonathan Yubc771b72017-12-08 17:04:29 -08002182 source.IncomingCapturedFrame(CreateFrame(11, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002183 WaitForEncodedFrame(kWidth, kHeight);
asapersson09f05612017-05-15 23:40:18 -07002184 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
asaperssond0de2952017-04-21 01:47:31 -07002185 VerifyNoLimitation(source.sink_wants());
2186 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2187 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
Jonathan Yubc771b72017-12-08 17:04:29 -08002188 EXPECT_EQ(6, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
asaperssond0de2952017-04-21 01:47:31 -07002189 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
kthelgason5e13d412016-12-01 03:59:51 -08002190
mflodmancc3d4422017-08-03 08:27:51 -07002191 video_stream_encoder_->Stop();
kthelgason5e13d412016-12-01 03:59:51 -08002192}
2193
mflodmancc3d4422017-08-03 08:27:51 -07002194TEST_F(VideoStreamEncoderTest, CpuLimitedHistogramIsReported) {
asaperssonfab67072017-04-04 05:51:49 -07002195 const int kWidth = 640;
2196 const int kHeight = 360;
perkj803d97f2016-11-01 11:45:46 -07002197
mflodmancc3d4422017-08-03 08:27:51 -07002198 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
sprang4847ae62017-06-27 07:06:52 -07002199
perkj803d97f2016-11-01 11:45:46 -07002200 for (int i = 1; i <= SendStatisticsProxy::kMinRequiredMetricsSamples; ++i) {
asaperssonfab67072017-04-04 05:51:49 -07002201 video_source_.IncomingCapturedFrame(CreateFrame(i, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002202 WaitForEncodedFrame(i);
perkj803d97f2016-11-01 11:45:46 -07002203 }
2204
mflodmancc3d4422017-08-03 08:27:51 -07002205 video_stream_encoder_->TriggerCpuOveruse();
perkj803d97f2016-11-01 11:45:46 -07002206 for (int i = 1; i <= SendStatisticsProxy::kMinRequiredMetricsSamples; ++i) {
asaperssonfab67072017-04-04 05:51:49 -07002207 video_source_.IncomingCapturedFrame(CreateFrame(
2208 SendStatisticsProxy::kMinRequiredMetricsSamples + i, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002209 WaitForEncodedFrame(SendStatisticsProxy::kMinRequiredMetricsSamples + i);
perkj803d97f2016-11-01 11:45:46 -07002210 }
2211
mflodmancc3d4422017-08-03 08:27:51 -07002212 video_stream_encoder_->Stop();
2213 video_stream_encoder_.reset();
perkj803d97f2016-11-01 11:45:46 -07002214 stats_proxy_.reset();
sprangf8ee65e2017-02-28 08:49:33 -08002215
perkj803d97f2016-11-01 11:45:46 -07002216 EXPECT_EQ(1,
2217 metrics::NumSamples("WebRTC.Video.CpuLimitedResolutionInPercent"));
2218 EXPECT_EQ(
2219 1, metrics::NumEvents("WebRTC.Video.CpuLimitedResolutionInPercent", 50));
2220}
2221
mflodmancc3d4422017-08-03 08:27:51 -07002222TEST_F(VideoStreamEncoderTest,
2223 CpuLimitedHistogramIsNotReportedForDisabledDegradation) {
2224 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonf4e44af2017-04-19 02:01:06 -07002225 const int kWidth = 640;
2226 const int kHeight = 360;
2227
mflodmancc3d4422017-08-03 08:27:51 -07002228 video_stream_encoder_->SetSource(
asaperssonf4e44af2017-04-19 02:01:06 -07002229 &video_source_,
2230 VideoSendStream::DegradationPreference::kDegradationDisabled);
2231
2232 for (int i = 1; i <= SendStatisticsProxy::kMinRequiredMetricsSamples; ++i) {
2233 video_source_.IncomingCapturedFrame(CreateFrame(i, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002234 WaitForEncodedFrame(i);
asaperssonf4e44af2017-04-19 02:01:06 -07002235 }
2236
mflodmancc3d4422017-08-03 08:27:51 -07002237 video_stream_encoder_->Stop();
2238 video_stream_encoder_.reset();
asaperssonf4e44af2017-04-19 02:01:06 -07002239 stats_proxy_.reset();
2240
2241 EXPECT_EQ(0,
2242 metrics::NumSamples("WebRTC.Video.CpuLimitedResolutionInPercent"));
2243}
2244
mflodmancc3d4422017-08-03 08:27:51 -07002245TEST_F(VideoStreamEncoderTest, CallsBitrateObserver) {
sprang4847ae62017-06-27 07:06:52 -07002246 MockBitrateObserver bitrate_observer;
mflodmancc3d4422017-08-03 08:27:51 -07002247 video_stream_encoder_->SetBitrateObserver(&bitrate_observer);
sprang57c2fff2017-01-16 06:24:02 -08002248
2249 const int kDefaultFps = 30;
2250 const BitrateAllocation expected_bitrate =
2251 DefaultVideoBitrateAllocator(fake_encoder_.codec_config())
kthelgason2bc68642017-02-07 07:02:22 -08002252 .GetAllocation(kLowTargetBitrateBps, kDefaultFps);
sprang57c2fff2017-01-16 06:24:02 -08002253
2254 // First called on bitrate updated, then again on first frame.
2255 EXPECT_CALL(bitrate_observer, OnBitrateAllocationUpdated(expected_bitrate))
2256 .Times(2);
mflodmancc3d4422017-08-03 08:27:51 -07002257 video_stream_encoder_->OnBitrateUpdated(kLowTargetBitrateBps, 0, 0);
sprang57c2fff2017-01-16 06:24:02 -08002258
2259 const int64_t kStartTimeMs = 1;
2260 video_source_.IncomingCapturedFrame(
2261 CreateFrame(kStartTimeMs, codec_width_, codec_height_));
sprang4847ae62017-06-27 07:06:52 -07002262 WaitForEncodedFrame(kStartTimeMs);
sprang57c2fff2017-01-16 06:24:02 -08002263
2264 // Not called on second frame.
2265 EXPECT_CALL(bitrate_observer, OnBitrateAllocationUpdated(expected_bitrate))
2266 .Times(0);
2267 video_source_.IncomingCapturedFrame(
2268 CreateFrame(kStartTimeMs + 1, codec_width_, codec_height_));
sprang4847ae62017-06-27 07:06:52 -07002269 WaitForEncodedFrame(kStartTimeMs + 1);
sprang57c2fff2017-01-16 06:24:02 -08002270
2271 // Called after a process interval.
2272 const int64_t kProcessIntervalMs =
2273 vcm::VCMProcessTimer::kDefaultProcessIntervalMs;
sprang4847ae62017-06-27 07:06:52 -07002274 fake_clock_.AdvanceTimeMicros(rtc::kNumMicrosecsPerMillisec *
2275 (kProcessIntervalMs + (1000 / kDefaultFps)));
sprang57c2fff2017-01-16 06:24:02 -08002276 EXPECT_CALL(bitrate_observer, OnBitrateAllocationUpdated(expected_bitrate))
2277 .Times(1);
2278 video_source_.IncomingCapturedFrame(CreateFrame(
2279 kStartTimeMs + kProcessIntervalMs, codec_width_, codec_height_));
sprang4847ae62017-06-27 07:06:52 -07002280 WaitForEncodedFrame(kStartTimeMs + kProcessIntervalMs);
sprang57c2fff2017-01-16 06:24:02 -08002281
mflodmancc3d4422017-08-03 08:27:51 -07002282 video_stream_encoder_->Stop();
sprang57c2fff2017-01-16 06:24:02 -08002283}
2284
Niels Möller7dc26b72017-12-06 10:27:48 +01002285TEST_F(VideoStreamEncoderTest, OveruseDetectorUpdatedOnReconfigureAndAdaption) {
2286 const int kFrameWidth = 1280;
2287 const int kFrameHeight = 720;
2288 const int kFramerate = 24;
2289
2290 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
2291 test::FrameForwarder source;
2292 video_stream_encoder_->SetSource(
2293 &source, VideoSendStream::DegradationPreference::kMaintainResolution);
2294
2295 // Insert a single frame, triggering initial configuration.
2296 source.IncomingCapturedFrame(CreateFrame(1, kFrameWidth, kFrameHeight));
2297 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2298
2299 EXPECT_EQ(
2300 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2301 kDefaultFramerate);
2302
2303 // Trigger reconfigure encoder (without resetting the entire instance).
2304 VideoEncoderConfig video_encoder_config;
Niels Möller259a4972018-04-05 15:36:51 +02002305 video_encoder_config.codec_type = kVideoCodecVP8;
Niels Möller7dc26b72017-12-06 10:27:48 +01002306 video_encoder_config.max_bitrate_bps = kTargetBitrateBps;
2307 video_encoder_config.number_of_streams = 1;
2308 video_encoder_config.video_stream_factory =
2309 new rtc::RefCountedObject<VideoStreamFactory>(1, kFramerate);
2310 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
2311 kMaxPayloadLength, false);
2312 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2313
2314 // Detector should be updated with fps limit from codec config.
2315 EXPECT_EQ(
2316 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2317 kFramerate);
2318
2319 // Trigger overuse, max framerate should be reduced.
2320 VideoSendStream::Stats stats = stats_proxy_->GetStats();
2321 stats.input_frame_rate = kFramerate;
2322 stats_proxy_->SetMockStats(stats);
2323 video_stream_encoder_->TriggerCpuOveruse();
2324 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2325 int adapted_framerate =
2326 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate();
2327 EXPECT_LT(adapted_framerate, kFramerate);
2328
2329 // Trigger underuse, max framerate should go back to codec configured fps.
2330 // Set extra low fps, to make sure it's actually reset, not just incremented.
2331 stats = stats_proxy_->GetStats();
2332 stats.input_frame_rate = adapted_framerate / 2;
2333 stats_proxy_->SetMockStats(stats);
2334 video_stream_encoder_->TriggerCpuNormalUsage();
2335 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2336 EXPECT_EQ(
2337 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2338 kFramerate);
2339
2340 video_stream_encoder_->Stop();
2341}
2342
2343TEST_F(VideoStreamEncoderTest,
2344 OveruseDetectorUpdatedRespectsFramerateAfterUnderuse) {
2345 const int kFrameWidth = 1280;
2346 const int kFrameHeight = 720;
2347 const int kLowFramerate = 15;
2348 const int kHighFramerate = 25;
2349
2350 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
2351 test::FrameForwarder source;
2352 video_stream_encoder_->SetSource(
2353 &source, VideoSendStream::DegradationPreference::kMaintainResolution);
2354
2355 // Trigger initial configuration.
2356 VideoEncoderConfig video_encoder_config;
Niels Möller259a4972018-04-05 15:36:51 +02002357 video_encoder_config.codec_type = kVideoCodecVP8;
Niels Möller7dc26b72017-12-06 10:27:48 +01002358 video_encoder_config.max_bitrate_bps = kTargetBitrateBps;
2359 video_encoder_config.number_of_streams = 1;
2360 video_encoder_config.video_stream_factory =
2361 new rtc::RefCountedObject<VideoStreamFactory>(1, kLowFramerate);
2362 source.IncomingCapturedFrame(CreateFrame(1, kFrameWidth, kFrameHeight));
2363 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
2364 kMaxPayloadLength, false);
2365 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2366
2367 EXPECT_EQ(
2368 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2369 kLowFramerate);
2370
2371 // Trigger overuse, max framerate should be reduced.
2372 VideoSendStream::Stats stats = stats_proxy_->GetStats();
2373 stats.input_frame_rate = kLowFramerate;
2374 stats_proxy_->SetMockStats(stats);
2375 video_stream_encoder_->TriggerCpuOveruse();
2376 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2377 int adapted_framerate =
2378 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate();
2379 EXPECT_LT(adapted_framerate, kLowFramerate);
2380
2381 // Reconfigure the encoder with a new (higher max framerate), max fps should
2382 // still respect the adaptation.
2383 video_encoder_config.video_stream_factory =
2384 new rtc::RefCountedObject<VideoStreamFactory>(1, kHighFramerate);
2385 source.IncomingCapturedFrame(CreateFrame(1, kFrameWidth, kFrameHeight));
2386 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
2387 kMaxPayloadLength, false);
2388 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2389
2390 EXPECT_EQ(
2391 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2392 adapted_framerate);
2393
2394 // Trigger underuse, max framerate should go back to codec configured fps.
2395 stats = stats_proxy_->GetStats();
2396 stats.input_frame_rate = adapted_framerate;
2397 stats_proxy_->SetMockStats(stats);
2398 video_stream_encoder_->TriggerCpuNormalUsage();
2399 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2400 EXPECT_EQ(
2401 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2402 kHighFramerate);
2403
2404 video_stream_encoder_->Stop();
2405}
2406
mflodmancc3d4422017-08-03 08:27:51 -07002407TEST_F(VideoStreamEncoderTest,
2408 OveruseDetectorUpdatedOnDegradationPreferenceChange) {
sprangfda496a2017-06-15 04:21:07 -07002409 const int kFrameWidth = 1280;
2410 const int kFrameHeight = 720;
2411 const int kFramerate = 24;
2412
mflodmancc3d4422017-08-03 08:27:51 -07002413 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
sprangfda496a2017-06-15 04:21:07 -07002414 test::FrameForwarder source;
mflodmancc3d4422017-08-03 08:27:51 -07002415 video_stream_encoder_->SetSource(
sprangfda496a2017-06-15 04:21:07 -07002416 &source, VideoSendStream::DegradationPreference::kMaintainResolution);
2417
2418 // Trigger initial configuration.
2419 VideoEncoderConfig video_encoder_config;
Niels Möller259a4972018-04-05 15:36:51 +02002420 video_encoder_config.codec_type = kVideoCodecVP8;
sprangfda496a2017-06-15 04:21:07 -07002421 video_encoder_config.max_bitrate_bps = kTargetBitrateBps;
2422 video_encoder_config.number_of_streams = 1;
2423 video_encoder_config.video_stream_factory =
2424 new rtc::RefCountedObject<VideoStreamFactory>(1, kFramerate);
2425 source.IncomingCapturedFrame(CreateFrame(1, kFrameWidth, kFrameHeight));
mflodmancc3d4422017-08-03 08:27:51 -07002426 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
2427 kMaxPayloadLength, false);
2428 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
sprangfda496a2017-06-15 04:21:07 -07002429
Niels Möller7dc26b72017-12-06 10:27:48 +01002430 EXPECT_EQ(
2431 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2432 kFramerate);
sprangfda496a2017-06-15 04:21:07 -07002433
2434 // Trigger overuse, max framerate should be reduced.
2435 VideoSendStream::Stats stats = stats_proxy_->GetStats();
2436 stats.input_frame_rate = kFramerate;
2437 stats_proxy_->SetMockStats(stats);
mflodmancc3d4422017-08-03 08:27:51 -07002438 video_stream_encoder_->TriggerCpuOveruse();
2439 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
Niels Möller7dc26b72017-12-06 10:27:48 +01002440 int adapted_framerate =
2441 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate();
sprangfda496a2017-06-15 04:21:07 -07002442 EXPECT_LT(adapted_framerate, kFramerate);
2443
2444 // Change degradation preference to not enable framerate scaling. Target
2445 // framerate should be changed to codec defined limit.
mflodmancc3d4422017-08-03 08:27:51 -07002446 video_stream_encoder_->SetSource(
sprangfda496a2017-06-15 04:21:07 -07002447 &source, VideoSendStream::DegradationPreference::kMaintainFramerate);
mflodmancc3d4422017-08-03 08:27:51 -07002448 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
Niels Möller7dc26b72017-12-06 10:27:48 +01002449 EXPECT_EQ(
2450 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2451 kFramerate);
sprangfda496a2017-06-15 04:21:07 -07002452
mflodmancc3d4422017-08-03 08:27:51 -07002453 video_stream_encoder_->Stop();
sprangfda496a2017-06-15 04:21:07 -07002454}
2455
mflodmancc3d4422017-08-03 08:27:51 -07002456TEST_F(VideoStreamEncoderTest, DropsFramesAndScalesWhenBitrateIsTooLow) {
asaperssonfab67072017-04-04 05:51:49 -07002457 const int kTooLowBitrateForFrameSizeBps = 10000;
mflodmancc3d4422017-08-03 08:27:51 -07002458 video_stream_encoder_->OnBitrateUpdated(kTooLowBitrateForFrameSizeBps, 0, 0);
asaperssonfab67072017-04-04 05:51:49 -07002459 const int kWidth = 640;
2460 const int kHeight = 360;
kthelgason2bc68642017-02-07 07:02:22 -08002461
asaperssonfab67072017-04-04 05:51:49 -07002462 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
kthelgason2bc68642017-02-07 07:02:22 -08002463
2464 // Expect to drop this frame, the wait should time out.
sprang4847ae62017-06-27 07:06:52 -07002465 ExpectDroppedFrame();
kthelgason2bc68642017-02-07 07:02:22 -08002466
2467 // Expect the sink_wants to specify a scaled frame.
asapersson0944a802017-04-07 00:57:58 -07002468 EXPECT_LT(video_source_.sink_wants().max_pixel_count, kWidth * kHeight);
kthelgason2bc68642017-02-07 07:02:22 -08002469
sprangc5d62e22017-04-02 23:53:04 -07002470 int last_pixel_count = video_source_.sink_wants().max_pixel_count;
kthelgason2bc68642017-02-07 07:02:22 -08002471
asaperssonfab67072017-04-04 05:51:49 -07002472 // Next frame is scaled.
kthelgason2bc68642017-02-07 07:02:22 -08002473 video_source_.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07002474 CreateFrame(2, kWidth * 3 / 4, kHeight * 3 / 4));
kthelgason2bc68642017-02-07 07:02:22 -08002475
2476 // Expect to drop this frame, the wait should time out.
sprang4847ae62017-06-27 07:06:52 -07002477 ExpectDroppedFrame();
kthelgason2bc68642017-02-07 07:02:22 -08002478
sprangc5d62e22017-04-02 23:53:04 -07002479 EXPECT_LT(video_source_.sink_wants().max_pixel_count, last_pixel_count);
kthelgason2bc68642017-02-07 07:02:22 -08002480
mflodmancc3d4422017-08-03 08:27:51 -07002481 video_stream_encoder_->Stop();
kthelgason2bc68642017-02-07 07:02:22 -08002482}
2483
mflodmancc3d4422017-08-03 08:27:51 -07002484TEST_F(VideoStreamEncoderTest,
2485 NumberOfDroppedFramesLimitedWhenBitrateIsTooLow) {
asaperssonfab67072017-04-04 05:51:49 -07002486 const int kTooLowBitrateForFrameSizeBps = 10000;
mflodmancc3d4422017-08-03 08:27:51 -07002487 video_stream_encoder_->OnBitrateUpdated(kTooLowBitrateForFrameSizeBps, 0, 0);
asaperssonfab67072017-04-04 05:51:49 -07002488 const int kWidth = 640;
2489 const int kHeight = 360;
kthelgason2bc68642017-02-07 07:02:22 -08002490
2491 // We expect the n initial frames to get dropped.
2492 int i;
2493 for (i = 1; i <= kMaxInitialFramedrop; ++i) {
asaperssonfab67072017-04-04 05:51:49 -07002494 video_source_.IncomingCapturedFrame(CreateFrame(i, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002495 ExpectDroppedFrame();
kthelgason2bc68642017-02-07 07:02:22 -08002496 }
2497 // The n+1th frame should not be dropped, even though it's size is too large.
asaperssonfab67072017-04-04 05:51:49 -07002498 video_source_.IncomingCapturedFrame(CreateFrame(i, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002499 WaitForEncodedFrame(i);
kthelgason2bc68642017-02-07 07:02:22 -08002500
2501 // Expect the sink_wants to specify a scaled frame.
asaperssonfab67072017-04-04 05:51:49 -07002502 EXPECT_LT(video_source_.sink_wants().max_pixel_count, kWidth * kHeight);
kthelgason2bc68642017-02-07 07:02:22 -08002503
mflodmancc3d4422017-08-03 08:27:51 -07002504 video_stream_encoder_->Stop();
kthelgason2bc68642017-02-07 07:02:22 -08002505}
2506
mflodmancc3d4422017-08-03 08:27:51 -07002507TEST_F(VideoStreamEncoderTest,
2508 InitialFrameDropOffWithMaintainResolutionPreference) {
asaperssonfab67072017-04-04 05:51:49 -07002509 const int kWidth = 640;
2510 const int kHeight = 360;
mflodmancc3d4422017-08-03 08:27:51 -07002511 video_stream_encoder_->OnBitrateUpdated(kLowTargetBitrateBps, 0, 0);
kthelgason2bc68642017-02-07 07:02:22 -08002512
2513 // Set degradation preference.
mflodmancc3d4422017-08-03 08:27:51 -07002514 video_stream_encoder_->SetSource(
kthelgason2bc68642017-02-07 07:02:22 -08002515 &video_source_,
2516 VideoSendStream::DegradationPreference::kMaintainResolution);
2517
asaperssonfab67072017-04-04 05:51:49 -07002518 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
kthelgason2bc68642017-02-07 07:02:22 -08002519 // Frame should not be dropped, even if it's too large.
sprang4847ae62017-06-27 07:06:52 -07002520 WaitForEncodedFrame(1);
kthelgason2bc68642017-02-07 07:02:22 -08002521
mflodmancc3d4422017-08-03 08:27:51 -07002522 video_stream_encoder_->Stop();
kthelgason2bc68642017-02-07 07:02:22 -08002523}
2524
mflodmancc3d4422017-08-03 08:27:51 -07002525TEST_F(VideoStreamEncoderTest, InitialFrameDropOffWhenEncoderDisabledScaling) {
asaperssonfab67072017-04-04 05:51:49 -07002526 const int kWidth = 640;
2527 const int kHeight = 360;
kthelgasonad9010c2017-02-14 00:46:51 -08002528 fake_encoder_.SetQualityScaling(false);
Niels Möller4db138e2018-04-19 09:04:13 +02002529
2530 VideoEncoderConfig video_encoder_config;
2531 test::FillEncoderConfiguration(kVideoCodecVP8, 1, &video_encoder_config);
2532 // Make format different, to force recreation of encoder.
2533 video_encoder_config.video_format.parameters["foo"] = "foo";
2534 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
2535 kMaxPayloadLength,
2536 true /* nack_enabled */);
mflodmancc3d4422017-08-03 08:27:51 -07002537 video_stream_encoder_->OnBitrateUpdated(kLowTargetBitrateBps, 0, 0);
asapersson09f05612017-05-15 23:40:18 -07002538
kthelgasonb83797b2017-02-14 11:57:25 -08002539 // Force quality scaler reconfiguration by resetting the source.
mflodmancc3d4422017-08-03 08:27:51 -07002540 video_stream_encoder_->SetSource(
2541 &video_source_,
2542 VideoSendStream::DegradationPreference::kBalanced);
kthelgasonad9010c2017-02-14 00:46:51 -08002543
asaperssonfab67072017-04-04 05:51:49 -07002544 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
kthelgasonad9010c2017-02-14 00:46:51 -08002545 // Frame should not be dropped, even if it's too large.
sprang4847ae62017-06-27 07:06:52 -07002546 WaitForEncodedFrame(1);
kthelgasonad9010c2017-02-14 00:46:51 -08002547
mflodmancc3d4422017-08-03 08:27:51 -07002548 video_stream_encoder_->Stop();
kthelgasonad9010c2017-02-14 00:46:51 -08002549 fake_encoder_.SetQualityScaling(true);
2550}
2551
mflodmancc3d4422017-08-03 08:27:51 -07002552TEST_F(VideoStreamEncoderTest,
asaperssond0de2952017-04-21 01:47:31 -07002553 ResolutionNotAdaptedForTooSmallFrame_MaintainFramerateMode) {
2554 const int kTooSmallWidth = 10;
2555 const int kTooSmallHeight = 10;
mflodmancc3d4422017-08-03 08:27:51 -07002556 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssond0de2952017-04-21 01:47:31 -07002557
2558 // Enable kMaintainFramerate preference, no initial limitation.
2559 test::FrameForwarder source;
mflodmancc3d4422017-08-03 08:27:51 -07002560 video_stream_encoder_->SetSource(
asaperssond0de2952017-04-21 01:47:31 -07002561 &source, VideoSendStream::DegradationPreference::kMaintainFramerate);
2562 VerifyNoLimitation(source.sink_wants());
2563 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2564
2565 // Trigger adapt down, too small frame, expect no change.
2566 source.IncomingCapturedFrame(CreateFrame(1, kTooSmallWidth, kTooSmallHeight));
sprang4847ae62017-06-27 07:06:52 -07002567 WaitForEncodedFrame(1);
mflodmancc3d4422017-08-03 08:27:51 -07002568 video_stream_encoder_->TriggerCpuOveruse();
asaperssond0de2952017-04-21 01:47:31 -07002569 VerifyNoLimitation(source.sink_wants());
2570 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2571 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2572
mflodmancc3d4422017-08-03 08:27:51 -07002573 video_stream_encoder_->Stop();
asaperssond0de2952017-04-21 01:47:31 -07002574}
2575
mflodmancc3d4422017-08-03 08:27:51 -07002576TEST_F(VideoStreamEncoderTest,
2577 ResolutionNotAdaptedForTooSmallFrame_BalancedMode) {
asaperssonf7e294d2017-06-13 23:25:22 -07002578 const int kTooSmallWidth = 10;
2579 const int kTooSmallHeight = 10;
2580 const int kFpsLimit = 7;
mflodmancc3d4422017-08-03 08:27:51 -07002581 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -07002582
2583 // Enable kBalanced preference, no initial limitation.
2584 test::FrameForwarder source;
mflodmancc3d4422017-08-03 08:27:51 -07002585 video_stream_encoder_->SetSource(
2586 &source,
2587 VideoSendStream::DegradationPreference::kBalanced);
asaperssonf7e294d2017-06-13 23:25:22 -07002588 VerifyNoLimitation(source.sink_wants());
2589 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2590 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2591
2592 // Trigger adapt down, expect limited framerate.
2593 source.IncomingCapturedFrame(CreateFrame(1, kTooSmallWidth, kTooSmallHeight));
sprang4847ae62017-06-27 07:06:52 -07002594 WaitForEncodedFrame(1);
mflodmancc3d4422017-08-03 08:27:51 -07002595 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002596 VerifyFpsEqResolutionMax(source.sink_wants(), kFpsLimit);
2597 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2598 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2599 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2600
2601 // Trigger adapt down, too small frame, expect no change.
2602 source.IncomingCapturedFrame(CreateFrame(2, kTooSmallWidth, kTooSmallHeight));
sprang4847ae62017-06-27 07:06:52 -07002603 WaitForEncodedFrame(2);
mflodmancc3d4422017-08-03 08:27:51 -07002604 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002605 VerifyFpsEqResolutionMax(source.sink_wants(), kFpsLimit);
2606 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2607 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2608 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2609
mflodmancc3d4422017-08-03 08:27:51 -07002610 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07002611}
2612
mflodmancc3d4422017-08-03 08:27:51 -07002613TEST_F(VideoStreamEncoderTest, FailingInitEncodeDoesntCauseCrash) {
asapersson02465b82017-04-10 01:12:52 -07002614 fake_encoder_.ForceInitEncodeFailure(true);
mflodmancc3d4422017-08-03 08:27:51 -07002615 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
emircanbbcc3562017-08-18 00:28:40 -07002616 ResetEncoder("VP8", 2, 1, 1, true, false);
asapersson02465b82017-04-10 01:12:52 -07002617 const int kFrameWidth = 1280;
2618 const int kFrameHeight = 720;
2619 video_source_.IncomingCapturedFrame(
2620 CreateFrame(1, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002621 ExpectDroppedFrame();
mflodmancc3d4422017-08-03 08:27:51 -07002622 video_stream_encoder_->Stop();
asapersson02465b82017-04-10 01:12:52 -07002623}
2624
sprangb1ca0732017-02-01 08:38:12 -08002625// TODO(sprang): Extend this with fps throttling and any "balanced" extensions.
mflodmancc3d4422017-08-03 08:27:51 -07002626TEST_F(VideoStreamEncoderTest,
2627 AdaptsResolutionOnOveruse_MaintainFramerateMode) {
2628 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
sprangb1ca0732017-02-01 08:38:12 -08002629
2630 const int kFrameWidth = 1280;
2631 const int kFrameHeight = 720;
2632 // Enabled default VideoAdapter downscaling. First step is 3/4, not 3/5 as
mflodmancc3d4422017-08-03 08:27:51 -07002633 // requested by
2634 // VideoStreamEncoder::VideoSourceProxy::RequestResolutionLowerThan().
sprangb1ca0732017-02-01 08:38:12 -08002635 video_source_.set_adaptation_enabled(true);
2636
2637 video_source_.IncomingCapturedFrame(
2638 CreateFrame(1, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002639 WaitForEncodedFrame(kFrameWidth, kFrameHeight);
sprangb1ca0732017-02-01 08:38:12 -08002640
2641 // Trigger CPU overuse, downscale by 3/4.
mflodmancc3d4422017-08-03 08:27:51 -07002642 video_stream_encoder_->TriggerCpuOveruse();
sprangb1ca0732017-02-01 08:38:12 -08002643 video_source_.IncomingCapturedFrame(
2644 CreateFrame(2, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002645 WaitForEncodedFrame((kFrameWidth * 3) / 4, (kFrameHeight * 3) / 4);
sprangb1ca0732017-02-01 08:38:12 -08002646
asaperssonfab67072017-04-04 05:51:49 -07002647 // Trigger CPU normal use, return to original resolution.
mflodmancc3d4422017-08-03 08:27:51 -07002648 video_stream_encoder_->TriggerCpuNormalUsage();
sprangb1ca0732017-02-01 08:38:12 -08002649 video_source_.IncomingCapturedFrame(
2650 CreateFrame(3, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002651 WaitForEncodedFrame(kFrameWidth, kFrameHeight);
sprangb1ca0732017-02-01 08:38:12 -08002652
mflodmancc3d4422017-08-03 08:27:51 -07002653 video_stream_encoder_->Stop();
sprangb1ca0732017-02-01 08:38:12 -08002654}
sprangfe627f32017-03-29 08:24:59 -07002655
mflodmancc3d4422017-08-03 08:27:51 -07002656TEST_F(VideoStreamEncoderTest,
2657 AdaptsFramerateOnOveruse_MaintainResolutionMode) {
sprangc5d62e22017-04-02 23:53:04 -07002658 const int kFrameWidth = 1280;
2659 const int kFrameHeight = 720;
sprang4847ae62017-06-27 07:06:52 -07002660 int kFrameIntervalMs = rtc::kNumMillisecsPerSec / max_framerate_;
sprangc5d62e22017-04-02 23:53:04 -07002661
mflodmancc3d4422017-08-03 08:27:51 -07002662 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
2663 video_stream_encoder_->SetSource(
sprangc5d62e22017-04-02 23:53:04 -07002664 &video_source_,
2665 VideoSendStream::DegradationPreference::kMaintainResolution);
2666 video_source_.set_adaptation_enabled(true);
2667
sprang4847ae62017-06-27 07:06:52 -07002668 int64_t timestamp_ms = fake_clock_.TimeNanos() / rtc::kNumNanosecsPerMillisec;
sprangc5d62e22017-04-02 23:53:04 -07002669
2670 video_source_.IncomingCapturedFrame(
2671 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002672 WaitForEncodedFrame(timestamp_ms);
sprangc5d62e22017-04-02 23:53:04 -07002673
2674 // Try to trigger overuse. No fps estimate available => no effect.
mflodmancc3d4422017-08-03 08:27:51 -07002675 video_stream_encoder_->TriggerCpuOveruse();
sprangc5d62e22017-04-02 23:53:04 -07002676
2677 // Insert frames for one second to get a stable estimate.
sprang4847ae62017-06-27 07:06:52 -07002678 for (int i = 0; i < max_framerate_; ++i) {
sprangc5d62e22017-04-02 23:53:04 -07002679 timestamp_ms += kFrameIntervalMs;
sprangc5d62e22017-04-02 23:53:04 -07002680 video_source_.IncomingCapturedFrame(
2681 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002682 WaitForEncodedFrame(timestamp_ms);
sprangc5d62e22017-04-02 23:53:04 -07002683 }
2684
2685 // Trigger CPU overuse, reduce framerate by 2/3.
mflodmancc3d4422017-08-03 08:27:51 -07002686 video_stream_encoder_->TriggerCpuOveruse();
sprangc5d62e22017-04-02 23:53:04 -07002687 int num_frames_dropped = 0;
sprang4847ae62017-06-27 07:06:52 -07002688 for (int i = 0; i < max_framerate_; ++i) {
sprangc5d62e22017-04-02 23:53:04 -07002689 timestamp_ms += kFrameIntervalMs;
sprangc5d62e22017-04-02 23:53:04 -07002690 video_source_.IncomingCapturedFrame(
2691 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002692 if (!WaitForFrame(kFrameTimeoutMs)) {
sprangc5d62e22017-04-02 23:53:04 -07002693 ++num_frames_dropped;
2694 } else {
Åsa Perssonc74d8da2017-12-04 14:13:56 +01002695 sink_.CheckLastFrameSizeMatches(kFrameWidth, kFrameHeight);
sprangc5d62e22017-04-02 23:53:04 -07002696 }
2697 }
2698
sprang4847ae62017-06-27 07:06:52 -07002699 // Add some slack to account for frames dropped by the frame dropper.
2700 const int kErrorMargin = 1;
2701 EXPECT_NEAR(num_frames_dropped, max_framerate_ - (max_framerate_ * 2 / 3),
sprangc5d62e22017-04-02 23:53:04 -07002702 kErrorMargin);
2703
2704 // Trigger CPU overuse, reduce framerate by 2/3 again.
mflodmancc3d4422017-08-03 08:27:51 -07002705 video_stream_encoder_->TriggerCpuOveruse();
sprangc5d62e22017-04-02 23:53:04 -07002706 num_frames_dropped = 0;
sprang4847ae62017-06-27 07:06:52 -07002707 for (int i = 0; i < max_framerate_; ++i) {
sprangc5d62e22017-04-02 23:53:04 -07002708 timestamp_ms += kFrameIntervalMs;
sprangc5d62e22017-04-02 23:53:04 -07002709 video_source_.IncomingCapturedFrame(
2710 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002711 if (!WaitForFrame(kFrameTimeoutMs)) {
sprangc5d62e22017-04-02 23:53:04 -07002712 ++num_frames_dropped;
2713 } else {
Åsa Perssonc74d8da2017-12-04 14:13:56 +01002714 sink_.CheckLastFrameSizeMatches(kFrameWidth, kFrameHeight);
sprangc5d62e22017-04-02 23:53:04 -07002715 }
2716 }
sprang4847ae62017-06-27 07:06:52 -07002717 EXPECT_NEAR(num_frames_dropped, max_framerate_ - (max_framerate_ * 4 / 9),
sprangc5d62e22017-04-02 23:53:04 -07002718 kErrorMargin);
2719
2720 // Go back up one step.
mflodmancc3d4422017-08-03 08:27:51 -07002721 video_stream_encoder_->TriggerCpuNormalUsage();
sprangc5d62e22017-04-02 23:53:04 -07002722 num_frames_dropped = 0;
sprang4847ae62017-06-27 07:06:52 -07002723 for (int i = 0; i < max_framerate_; ++i) {
sprangc5d62e22017-04-02 23:53:04 -07002724 timestamp_ms += kFrameIntervalMs;
sprangc5d62e22017-04-02 23:53:04 -07002725 video_source_.IncomingCapturedFrame(
2726 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002727 if (!WaitForFrame(kFrameTimeoutMs)) {
sprangc5d62e22017-04-02 23:53:04 -07002728 ++num_frames_dropped;
2729 } else {
Åsa Perssonc74d8da2017-12-04 14:13:56 +01002730 sink_.CheckLastFrameSizeMatches(kFrameWidth, kFrameHeight);
sprangc5d62e22017-04-02 23:53:04 -07002731 }
2732 }
sprang4847ae62017-06-27 07:06:52 -07002733 EXPECT_NEAR(num_frames_dropped, max_framerate_ - (max_framerate_ * 2 / 3),
sprangc5d62e22017-04-02 23:53:04 -07002734 kErrorMargin);
2735
2736 // Go back up to original mode.
mflodmancc3d4422017-08-03 08:27:51 -07002737 video_stream_encoder_->TriggerCpuNormalUsage();
sprangc5d62e22017-04-02 23:53:04 -07002738 num_frames_dropped = 0;
sprang4847ae62017-06-27 07:06:52 -07002739 for (int i = 0; i < max_framerate_; ++i) {
sprangc5d62e22017-04-02 23:53:04 -07002740 timestamp_ms += kFrameIntervalMs;
sprangc5d62e22017-04-02 23:53:04 -07002741 video_source_.IncomingCapturedFrame(
2742 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002743 if (!WaitForFrame(kFrameTimeoutMs)) {
sprangc5d62e22017-04-02 23:53:04 -07002744 ++num_frames_dropped;
2745 } else {
Åsa Perssonc74d8da2017-12-04 14:13:56 +01002746 sink_.CheckLastFrameSizeMatches(kFrameWidth, kFrameHeight);
sprangc5d62e22017-04-02 23:53:04 -07002747 }
2748 }
2749 EXPECT_NEAR(num_frames_dropped, 0, kErrorMargin);
2750
mflodmancc3d4422017-08-03 08:27:51 -07002751 video_stream_encoder_->Stop();
sprangc5d62e22017-04-02 23:53:04 -07002752}
2753
mflodmancc3d4422017-08-03 08:27:51 -07002754TEST_F(VideoStreamEncoderTest, DoesntAdaptDownPastMinFramerate) {
sprangc5d62e22017-04-02 23:53:04 -07002755 const int kFramerateFps = 5;
2756 const int kFrameIntervalMs = rtc::kNumMillisecsPerSec / kFramerateFps;
sprangc5d62e22017-04-02 23:53:04 -07002757 const int kFrameWidth = 1280;
2758 const int kFrameHeight = 720;
2759
sprang4847ae62017-06-27 07:06:52 -07002760 // Reconfigure encoder with two temporal layers and screensharing, which will
2761 // disable frame dropping and make testing easier.
emircanbbcc3562017-08-18 00:28:40 -07002762 ResetEncoder("VP8", 1, 2, 1, true, true);
sprang4847ae62017-06-27 07:06:52 -07002763
mflodmancc3d4422017-08-03 08:27:51 -07002764 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
2765 video_stream_encoder_->SetSource(
sprangc5d62e22017-04-02 23:53:04 -07002766 &video_source_,
2767 VideoSendStream::DegradationPreference::kMaintainResolution);
2768 video_source_.set_adaptation_enabled(true);
2769
sprang4847ae62017-06-27 07:06:52 -07002770 int64_t timestamp_ms = fake_clock_.TimeNanos() / rtc::kNumNanosecsPerMillisec;
sprangc5d62e22017-04-02 23:53:04 -07002771
2772 // Trigger overuse as much as we can.
Jonathan Yubc771b72017-12-08 17:04:29 -08002773 rtc::VideoSinkWants last_wants;
2774 do {
2775 last_wants = video_source_.sink_wants();
2776
sprangc5d62e22017-04-02 23:53:04 -07002777 // Insert frames to get a new fps estimate...
2778 for (int j = 0; j < kFramerateFps; ++j) {
2779 video_source_.IncomingCapturedFrame(
2780 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
Jonathan Yubc771b72017-12-08 17:04:29 -08002781 if (video_source_.last_sent_width()) {
2782 sink_.WaitForEncodedFrame(timestamp_ms);
2783 }
sprangc5d62e22017-04-02 23:53:04 -07002784 timestamp_ms += kFrameIntervalMs;
Jonathan Yubc771b72017-12-08 17:04:29 -08002785 fake_clock_.AdvanceTimeMicros(
2786 kFrameIntervalMs * rtc::kNumMicrosecsPerMillisec);
sprangc5d62e22017-04-02 23:53:04 -07002787 }
2788 // ...and then try to adapt again.
mflodmancc3d4422017-08-03 08:27:51 -07002789 video_stream_encoder_->TriggerCpuOveruse();
Jonathan Yubc771b72017-12-08 17:04:29 -08002790 } while (video_source_.sink_wants().max_framerate_fps <
2791 last_wants.max_framerate_fps);
sprangc5d62e22017-04-02 23:53:04 -07002792
Jonathan Yubc771b72017-12-08 17:04:29 -08002793 VerifyFpsEqResolutionMax(video_source_.sink_wants(), kMinFramerateFps);
asaperssonf7e294d2017-06-13 23:25:22 -07002794
mflodmancc3d4422017-08-03 08:27:51 -07002795 video_stream_encoder_->Stop();
sprangc5d62e22017-04-02 23:53:04 -07002796}
asaperssonf7e294d2017-06-13 23:25:22 -07002797
mflodmancc3d4422017-08-03 08:27:51 -07002798TEST_F(VideoStreamEncoderTest,
2799 AdaptsResolutionAndFramerateForLowQuality_BalancedMode) {
asaperssonf7e294d2017-06-13 23:25:22 -07002800 const int kWidth = 1280;
2801 const int kHeight = 720;
2802 const int64_t kFrameIntervalMs = 150;
2803 int64_t timestamp_ms = kFrameIntervalMs;
mflodmancc3d4422017-08-03 08:27:51 -07002804 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -07002805
2806 // Enable kBalanced preference, no initial limitation.
2807 AdaptingFrameForwarder source;
2808 source.set_adaptation_enabled(true);
mflodmancc3d4422017-08-03 08:27:51 -07002809 video_stream_encoder_->SetSource(
2810 &source,
2811 VideoSendStream::DegradationPreference::kBalanced);
asaperssonf7e294d2017-06-13 23:25:22 -07002812 timestamp_ms += kFrameIntervalMs;
2813 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002814 WaitForEncodedFrame(kWidth, kHeight);
asaperssonf7e294d2017-06-13 23:25:22 -07002815 VerifyNoLimitation(source.sink_wants());
2816 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2817 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2818 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2819
2820 // Trigger adapt down, expect scaled down resolution (960x540@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002821 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002822 timestamp_ms += kFrameIntervalMs;
2823 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002824 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002825 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
2826 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2827 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2828 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2829
2830 // Trigger adapt down, expect scaled down resolution (640x360@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002831 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002832 timestamp_ms += kFrameIntervalMs;
2833 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002834 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002835 VerifyFpsMaxResolutionLt(source.sink_wants(), source.last_wants());
2836 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2837 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2838 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2839
2840 // Trigger adapt down, expect reduced fps (640x360@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07002841 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002842 timestamp_ms += kFrameIntervalMs;
2843 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002844 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002845 VerifyFpsLtResolutionEq(source.sink_wants(), source.last_wants());
2846 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2847 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2848 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2849
2850 // Trigger adapt down, expect scaled down resolution (480x270@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07002851 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002852 timestamp_ms += kFrameIntervalMs;
2853 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002854 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002855 VerifyFpsEqResolutionLt(source.sink_wants(), source.last_wants());
2856 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2857 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2858 EXPECT_EQ(4, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2859
2860 // Restrict bitrate, trigger adapt down, expect reduced fps (480x270@10fps).
mflodmancc3d4422017-08-03 08:27:51 -07002861 video_stream_encoder_->TriggerQualityLow();
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 VerifyFpsLtResolutionEq(source.sink_wants(), source.last_wants());
2866 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2867 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2868 EXPECT_EQ(5, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2869
2870 // Trigger adapt down, expect scaled down resolution (320x180@10fps).
mflodmancc3d4422017-08-03 08:27:51 -07002871 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002872 timestamp_ms += kFrameIntervalMs;
2873 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002874 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002875 VerifyFpsEqResolutionLt(source.sink_wants(), source.last_wants());
2876 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2877 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2878 EXPECT_EQ(6, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2879
2880 // Trigger adapt down, expect reduced fps (320x180@7fps).
mflodmancc3d4422017-08-03 08:27:51 -07002881 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002882 timestamp_ms += kFrameIntervalMs;
2883 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002884 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002885 VerifyFpsLtResolutionEq(source.sink_wants(), source.last_wants());
2886 rtc::VideoSinkWants last_wants = source.sink_wants();
2887 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2888 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2889 EXPECT_EQ(7, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2890
2891 // Trigger adapt down, min resolution reached, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07002892 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002893 timestamp_ms += kFrameIntervalMs;
2894 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002895 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002896 VerifyFpsEqResolutionEq(source.sink_wants(), last_wants);
2897 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2898 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2899 EXPECT_EQ(7, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2900
2901 // Trigger adapt down, expect expect increased fps (320x180@10fps).
mflodmancc3d4422017-08-03 08:27:51 -07002902 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002903 timestamp_ms += kFrameIntervalMs;
2904 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002905 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002906 VerifyFpsGtResolutionEq(source.sink_wants(), source.last_wants());
2907 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2908 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2909 EXPECT_EQ(8, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2910
2911 // Trigger adapt up, expect upscaled resolution (480x270@10fps).
mflodmancc3d4422017-08-03 08:27:51 -07002912 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002913 timestamp_ms += kFrameIntervalMs;
2914 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002915 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002916 VerifyFpsEqResolutionGt(source.sink_wants(), source.last_wants());
2917 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2918 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2919 EXPECT_EQ(9, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2920
2921 // Increase bitrate, trigger adapt up, expect increased fps (480x270@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07002922 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002923 timestamp_ms += kFrameIntervalMs;
2924 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002925 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002926 VerifyFpsGtResolutionEq(source.sink_wants(), source.last_wants());
2927 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2928 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2929 EXPECT_EQ(10, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2930
2931 // Trigger adapt up, expect upscaled resolution (640x360@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07002932 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002933 timestamp_ms += kFrameIntervalMs;
2934 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002935 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002936 VerifyFpsEqResolutionGt(source.sink_wants(), source.last_wants());
2937 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2938 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2939 EXPECT_EQ(11, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2940
2941 // Trigger adapt up, expect increased fps (640x360@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002942 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002943 timestamp_ms += kFrameIntervalMs;
2944 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002945 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002946 VerifyFpsMaxResolutionEq(source.sink_wants(), source.last_wants());
2947 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2948 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2949 EXPECT_EQ(12, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2950
2951 // Trigger adapt up, expect upscaled resolution (960x540@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002952 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002953 timestamp_ms += kFrameIntervalMs;
2954 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002955 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002956 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
2957 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2958 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2959 EXPECT_EQ(13, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2960
2961 // Trigger adapt up, expect no restriction (1280x720fps@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002962 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002963 timestamp_ms += kFrameIntervalMs;
2964 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002965 WaitForEncodedFrame(kWidth, kHeight);
asaperssonf7e294d2017-06-13 23:25:22 -07002966 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
2967 VerifyNoLimitation(source.sink_wants());
2968 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2969 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2970 EXPECT_EQ(14, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2971
2972 // Trigger adapt up, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07002973 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002974 VerifyNoLimitation(source.sink_wants());
2975 EXPECT_EQ(14, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2976
mflodmancc3d4422017-08-03 08:27:51 -07002977 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07002978}
2979
mflodmancc3d4422017-08-03 08:27:51 -07002980TEST_F(VideoStreamEncoderTest, AdaptWithTwoReasonsAndDifferentOrder_Framerate) {
asaperssonf7e294d2017-06-13 23:25:22 -07002981 const int kWidth = 1280;
2982 const int kHeight = 720;
2983 const int64_t kFrameIntervalMs = 150;
2984 int64_t timestamp_ms = kFrameIntervalMs;
mflodmancc3d4422017-08-03 08:27:51 -07002985 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -07002986
2987 // Enable kBalanced preference, no initial limitation.
2988 AdaptingFrameForwarder source;
2989 source.set_adaptation_enabled(true);
mflodmancc3d4422017-08-03 08:27:51 -07002990 video_stream_encoder_->SetSource(
2991 &source,
2992 VideoSendStream::DegradationPreference::kBalanced);
asaperssonf7e294d2017-06-13 23:25:22 -07002993 timestamp_ms += kFrameIntervalMs;
2994 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002995 WaitForEncodedFrame(kWidth, kHeight);
asaperssonf7e294d2017-06-13 23:25:22 -07002996 VerifyNoLimitation(source.sink_wants());
2997 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2998 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2999 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
3000 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
3001 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
3002 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3003
3004 // Trigger cpu adapt down, expect scaled down resolution (960x540@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07003005 video_stream_encoder_->TriggerCpuOveruse();
asaperssonf7e294d2017-06-13 23:25:22 -07003006 timestamp_ms += kFrameIntervalMs;
3007 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003008 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07003009 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
3010 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
3011 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
3012 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
3013 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
3014 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
3015 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3016
3017 // Trigger cpu adapt down, expect scaled down resolution (640x360@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07003018 video_stream_encoder_->TriggerCpuOveruse();
asaperssonf7e294d2017-06-13 23:25:22 -07003019 timestamp_ms += kFrameIntervalMs;
3020 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003021 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07003022 VerifyFpsMaxResolutionLt(source.sink_wants(), source.last_wants());
3023 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
3024 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
3025 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
3026 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
3027 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
3028 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3029
3030 // Trigger quality adapt down, expect reduced fps (640x360@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07003031 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07003032 timestamp_ms += kFrameIntervalMs;
3033 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003034 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07003035 VerifyFpsLtResolutionEq(source.sink_wants(), source.last_wants());
3036 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
3037 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
3038 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
3039 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
3040 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
3041 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3042
3043 // Trigger cpu adapt up, expect increased fps (640x360@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07003044 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssonf7e294d2017-06-13 23:25:22 -07003045 timestamp_ms += kFrameIntervalMs;
3046 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003047 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07003048 VerifyFpsMaxResolutionEq(source.sink_wants(), source.last_wants());
3049 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
3050 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
3051 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
3052 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
3053 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
3054 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3055
3056 // Trigger quality adapt up, expect upscaled resolution (960x540@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07003057 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07003058 timestamp_ms += kFrameIntervalMs;
3059 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003060 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07003061 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
3062 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
3063 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
3064 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
3065 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
3066 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
3067 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3068
3069 // Trigger cpu adapt up, expect no restriction (1280x720fps@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07003070 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssonf7e294d2017-06-13 23:25:22 -07003071 timestamp_ms += kFrameIntervalMs;
3072 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003073 WaitForEncodedFrame(kWidth, kHeight);
asaperssonf7e294d2017-06-13 23:25:22 -07003074 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
3075 VerifyNoLimitation(source.sink_wants());
3076 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
3077 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
3078 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
3079 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
3080 EXPECT_EQ(4, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
3081 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3082
3083 // Trigger adapt up, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07003084 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07003085 VerifyNoLimitation(source.sink_wants());
3086 EXPECT_EQ(4, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
3087 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3088
mflodmancc3d4422017-08-03 08:27:51 -07003089 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07003090}
3091
mflodmancc3d4422017-08-03 08:27:51 -07003092TEST_F(VideoStreamEncoderTest,
3093 AdaptWithTwoReasonsAndDifferentOrder_Resolution) {
asaperssonf7e294d2017-06-13 23:25:22 -07003094 const int kWidth = 640;
3095 const int kHeight = 360;
3096 const int kFpsLimit = 15;
3097 const int64_t kFrameIntervalMs = 150;
3098 int64_t timestamp_ms = kFrameIntervalMs;
mflodmancc3d4422017-08-03 08:27:51 -07003099 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -07003100
3101 // Enable kBalanced preference, no initial limitation.
3102 AdaptingFrameForwarder source;
3103 source.set_adaptation_enabled(true);
mflodmancc3d4422017-08-03 08:27:51 -07003104 video_stream_encoder_->SetSource(
3105 &source,
3106 VideoSendStream::DegradationPreference::kBalanced);
asaperssonf7e294d2017-06-13 23:25:22 -07003107 timestamp_ms += kFrameIntervalMs;
3108 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003109 WaitForEncodedFrame(kWidth, kHeight);
asaperssonf7e294d2017-06-13 23:25:22 -07003110 VerifyNoLimitation(source.sink_wants());
3111 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
3112 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
3113 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
3114 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
3115 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
3116 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3117
3118 // Trigger cpu adapt down, expect scaled down framerate (640x360@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07003119 video_stream_encoder_->TriggerCpuOveruse();
asaperssonf7e294d2017-06-13 23:25:22 -07003120 timestamp_ms += kFrameIntervalMs;
3121 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003122 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07003123 VerifyFpsEqResolutionMax(source.sink_wants(), kFpsLimit);
3124 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
3125 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
3126 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
3127 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_framerate);
3128 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
3129 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3130
3131 // Trigger quality adapt down, expect scaled down resolution (480x270@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07003132 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07003133 timestamp_ms += kFrameIntervalMs;
3134 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003135 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07003136 VerifyFpsEqResolutionLt(source.sink_wants(), source.last_wants());
3137 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
3138 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
3139 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
3140 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_framerate);
3141 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
3142 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3143
3144 // Trigger cpu adapt up, expect upscaled resolution (640x360@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07003145 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssonf7e294d2017-06-13 23:25:22 -07003146 timestamp_ms += kFrameIntervalMs;
3147 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003148 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07003149 VerifyFpsEqResolutionGt(source.sink_wants(), source.last_wants());
3150 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
3151 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
3152 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
3153 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
3154 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
3155 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3156
3157 // Trigger quality adapt up, expect increased fps (640x360@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07003158 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07003159 timestamp_ms += kFrameIntervalMs;
3160 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003161 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07003162 VerifyNoLimitation(source.sink_wants());
3163 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
3164 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
3165 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
3166 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
3167 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
3168 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3169
3170 // Trigger adapt up, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07003171 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07003172 VerifyNoLimitation(source.sink_wants());
3173 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
3174 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3175
mflodmancc3d4422017-08-03 08:27:51 -07003176 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07003177}
3178
mflodmancc3d4422017-08-03 08:27:51 -07003179TEST_F(VideoStreamEncoderTest, AcceptsFullHdAdaptedDownSimulcastFrames) {
ilnik6b826ef2017-06-16 06:53:48 -07003180 // Simulates simulcast behavior and makes highest stream resolutions divisible
3181 // by 4.
3182 class CroppingVideoStreamFactory
3183 : public VideoEncoderConfig::VideoStreamFactoryInterface {
3184 public:
3185 explicit CroppingVideoStreamFactory(size_t num_temporal_layers,
3186 int framerate)
3187 : num_temporal_layers_(num_temporal_layers), framerate_(framerate) {
3188 EXPECT_GT(num_temporal_layers, 0u);
3189 EXPECT_GT(framerate, 0);
3190 }
3191
3192 private:
3193 std::vector<VideoStream> CreateEncoderStreams(
3194 int width,
3195 int height,
3196 const VideoEncoderConfig& encoder_config) override {
3197 std::vector<VideoStream> streams =
3198 test::CreateVideoStreams(width - width % 4, height - height % 4,
3199 encoder_config);
3200 for (VideoStream& stream : streams) {
Sergey Silkina796a7e2018-03-01 15:11:29 +01003201 stream.num_temporal_layers = num_temporal_layers_;
ilnik6b826ef2017-06-16 06:53:48 -07003202 stream.max_framerate = framerate_;
3203 }
3204 return streams;
3205 }
3206
3207 const size_t num_temporal_layers_;
3208 const int framerate_;
3209 };
3210
3211 const int kFrameWidth = 1920;
3212 const int kFrameHeight = 1080;
3213 // 3/4 of 1920.
3214 const int kAdaptedFrameWidth = 1440;
3215 // 3/4 of 1080 rounded down to multiple of 4.
3216 const int kAdaptedFrameHeight = 808;
3217 const int kFramerate = 24;
3218
mflodmancc3d4422017-08-03 08:27:51 -07003219 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
ilnik6b826ef2017-06-16 06:53:48 -07003220 // Trigger reconfigure encoder (without resetting the entire instance).
3221 VideoEncoderConfig video_encoder_config;
Niels Möller259a4972018-04-05 15:36:51 +02003222 video_encoder_config.codec_type = kVideoCodecVP8;
ilnik6b826ef2017-06-16 06:53:48 -07003223 video_encoder_config.max_bitrate_bps = kTargetBitrateBps;
3224 video_encoder_config.number_of_streams = 1;
3225 video_encoder_config.video_stream_factory =
3226 new rtc::RefCountedObject<CroppingVideoStreamFactory>(1, kFramerate);
mflodmancc3d4422017-08-03 08:27:51 -07003227 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
3228 kMaxPayloadLength, false);
3229 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
ilnik6b826ef2017-06-16 06:53:48 -07003230
3231 video_source_.set_adaptation_enabled(true);
3232
3233 video_source_.IncomingCapturedFrame(
3234 CreateFrame(1, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07003235 WaitForEncodedFrame(kFrameWidth, kFrameHeight);
ilnik6b826ef2017-06-16 06:53:48 -07003236
3237 // Trigger CPU overuse, downscale by 3/4.
mflodmancc3d4422017-08-03 08:27:51 -07003238 video_stream_encoder_->TriggerCpuOveruse();
ilnik6b826ef2017-06-16 06:53:48 -07003239 video_source_.IncomingCapturedFrame(
3240 CreateFrame(2, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07003241 WaitForEncodedFrame(kAdaptedFrameWidth, kAdaptedFrameHeight);
ilnik6b826ef2017-06-16 06:53:48 -07003242
mflodmancc3d4422017-08-03 08:27:51 -07003243 video_stream_encoder_->Stop();
ilnik6b826ef2017-06-16 06:53:48 -07003244}
3245
mflodmancc3d4422017-08-03 08:27:51 -07003246TEST_F(VideoStreamEncoderTest, PeriodicallyUpdatesChannelParameters) {
sprang4847ae62017-06-27 07:06:52 -07003247 const int kFrameWidth = 1280;
3248 const int kFrameHeight = 720;
3249 const int kLowFps = 2;
3250 const int kHighFps = 30;
3251
mflodmancc3d4422017-08-03 08:27:51 -07003252 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
sprang4847ae62017-06-27 07:06:52 -07003253
3254 int64_t timestamp_ms = fake_clock_.TimeNanos() / rtc::kNumNanosecsPerMillisec;
3255 max_framerate_ = kLowFps;
3256
3257 // Insert 2 seconds of 2fps video.
3258 for (int i = 0; i < kLowFps * 2; ++i) {
3259 video_source_.IncomingCapturedFrame(
3260 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
3261 WaitForEncodedFrame(timestamp_ms);
3262 timestamp_ms += 1000 / kLowFps;
3263 }
3264
3265 // Make sure encoder is updated with new target.
mflodmancc3d4422017-08-03 08:27:51 -07003266 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
sprang4847ae62017-06-27 07:06:52 -07003267 video_source_.IncomingCapturedFrame(
3268 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
3269 WaitForEncodedFrame(timestamp_ms);
3270 timestamp_ms += 1000 / kLowFps;
3271
3272 EXPECT_EQ(kLowFps, fake_encoder_.GetConfiguredInputFramerate());
3273
3274 // Insert 30fps frames for just a little more than the forced update period.
3275 const int kVcmTimerIntervalFrames =
3276 (vcm::VCMProcessTimer::kDefaultProcessIntervalMs * kHighFps) / 1000;
3277 const int kFrameIntervalMs = 1000 / kHighFps;
3278 max_framerate_ = kHighFps;
3279 for (int i = 0; i < kVcmTimerIntervalFrames + 2; ++i) {
3280 video_source_.IncomingCapturedFrame(
3281 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
3282 // Wait for encoded frame, but skip ahead if it doesn't arrive as it might
3283 // be dropped if the encoder hans't been updated with the new higher target
3284 // framerate yet, causing it to overshoot the target bitrate and then
3285 // suffering the wrath of the media optimizer.
3286 TimedWaitForEncodedFrame(timestamp_ms, 2 * kFrameIntervalMs);
3287 timestamp_ms += kFrameIntervalMs;
3288 }
3289
3290 // Don expect correct measurement just yet, but it should be higher than
3291 // before.
3292 EXPECT_GT(fake_encoder_.GetConfiguredInputFramerate(), kLowFps);
3293
mflodmancc3d4422017-08-03 08:27:51 -07003294 video_stream_encoder_->Stop();
sprang4847ae62017-06-27 07:06:52 -07003295}
3296
mflodmancc3d4422017-08-03 08:27:51 -07003297TEST_F(VideoStreamEncoderTest, DoesNotUpdateBitrateAllocationWhenSuspended) {
sprang4847ae62017-06-27 07:06:52 -07003298 const int kFrameWidth = 1280;
3299 const int kFrameHeight = 720;
3300 const int kTargetBitrateBps = 1000000;
3301
3302 MockBitrateObserver bitrate_observer;
mflodmancc3d4422017-08-03 08:27:51 -07003303 video_stream_encoder_->SetBitrateObserver(&bitrate_observer);
sprang4847ae62017-06-27 07:06:52 -07003304
3305 EXPECT_CALL(bitrate_observer, OnBitrateAllocationUpdated(_)).Times(1);
3306 // Initial bitrate update.
mflodmancc3d4422017-08-03 08:27:51 -07003307 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
3308 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
sprang4847ae62017-06-27 07:06:52 -07003309
3310 // Insert a first video frame, causes another bitrate update.
3311 int64_t timestamp_ms = fake_clock_.TimeNanos() / rtc::kNumNanosecsPerMillisec;
3312 EXPECT_CALL(bitrate_observer, OnBitrateAllocationUpdated(_)).Times(1);
3313 video_source_.IncomingCapturedFrame(
3314 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
3315 WaitForEncodedFrame(timestamp_ms);
3316
3317 // Next, simulate video suspension due to pacer queue overrun.
mflodmancc3d4422017-08-03 08:27:51 -07003318 video_stream_encoder_->OnBitrateUpdated(0, 0, 1);
sprang4847ae62017-06-27 07:06:52 -07003319
3320 // Skip ahead until a new periodic parameter update should have occured.
3321 timestamp_ms += vcm::VCMProcessTimer::kDefaultProcessIntervalMs;
3322 fake_clock_.AdvanceTimeMicros(
3323 vcm::VCMProcessTimer::kDefaultProcessIntervalMs *
3324 rtc::kNumMicrosecsPerMillisec);
3325
3326 // Bitrate observer should not be called.
3327 EXPECT_CALL(bitrate_observer, OnBitrateAllocationUpdated(_)).Times(0);
3328 video_source_.IncomingCapturedFrame(
3329 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
3330 ExpectDroppedFrame();
3331
mflodmancc3d4422017-08-03 08:27:51 -07003332 video_stream_encoder_->Stop();
sprang4847ae62017-06-27 07:06:52 -07003333}
ilnik6b826ef2017-06-16 06:53:48 -07003334
Niels Möller4db138e2018-04-19 09:04:13 +02003335TEST_F(VideoStreamEncoderTest,
3336 DefaultCpuAdaptationThresholdsForSoftwareEncoder) {
3337 const int kFrameWidth = 1280;
3338 const int kFrameHeight = 720;
3339 const CpuOveruseOptions default_options;
3340 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
3341 video_source_.IncomingCapturedFrame(
3342 CreateFrame(1, kFrameWidth, kFrameHeight));
3343 WaitForEncodedFrame(1);
3344 EXPECT_EQ(video_stream_encoder_->overuse_detector_proxy_->GetOptions()
3345 .low_encode_usage_threshold_percent,
3346 default_options.low_encode_usage_threshold_percent);
3347 EXPECT_EQ(video_stream_encoder_->overuse_detector_proxy_->GetOptions()
3348 .high_encode_usage_threshold_percent,
3349 default_options.high_encode_usage_threshold_percent);
3350 video_stream_encoder_->Stop();
3351}
3352
3353TEST_F(VideoStreamEncoderTest,
3354 HigherCpuAdaptationThresholdsForHardwareEncoder) {
3355 const int kFrameWidth = 1280;
3356 const int kFrameHeight = 720;
3357 CpuOveruseOptions hardware_options;
3358 hardware_options.low_encode_usage_threshold_percent = 150;
3359 hardware_options.high_encode_usage_threshold_percent = 200;
3360 encoder_factory_.SetIsHardwareAccelerated(true);
3361
3362 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
3363 video_source_.IncomingCapturedFrame(
3364 CreateFrame(1, kFrameWidth, kFrameHeight));
3365 WaitForEncodedFrame(1);
3366 EXPECT_EQ(video_stream_encoder_->overuse_detector_proxy_->GetOptions()
3367 .low_encode_usage_threshold_percent,
3368 hardware_options.low_encode_usage_threshold_percent);
3369 EXPECT_EQ(video_stream_encoder_->overuse_detector_proxy_->GetOptions()
3370 .high_encode_usage_threshold_percent,
3371 hardware_options.high_encode_usage_threshold_percent);
3372 video_stream_encoder_->Stop();
3373}
3374
perkj26091b12016-09-01 01:17:40 -07003375} // namespace webrtc