blob: 8a6d4e1c20c9f1bac8d5ec3a639f56547027c94e [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"
24#include "test/encoder_settings.h"
25#include "test/fake_encoder.h"
26#include "test/frame_generator.h"
27#include "test/gmock.h"
28#include "test/gtest.h"
29#include "video/send_statistics_proxy.h"
30#include "video/video_stream_encoder.h"
perkj26091b12016-09-01 01:17:40 -070031
kthelgason33ce8892016-12-09 03:53:59 -080032namespace {
kthelgason33ce8892016-12-09 03:53:59 -080033const int kMinPixelsPerFrame = 320 * 180;
sprangc5d62e22017-04-02 23:53:04 -070034const int kMinFramerateFps = 2;
Jonathan Yubc771b72017-12-08 17:04:29 -080035const int kMinBalancedFramerateFps = 7;
sprangc5d62e22017-04-02 23:53:04 -070036const int64_t kFrameTimeoutMs = 100;
emircanbbcc3562017-08-18 00:28:40 -070037const unsigned char kNumSlDummy = 0;
sprangc5d62e22017-04-02 23:53:04 -070038} // namespace
kthelgason33ce8892016-12-09 03:53:59 -080039
perkj26091b12016-09-01 01:17:40 -070040namespace webrtc {
41
kthelgason876222f2016-11-29 01:44:11 -080042using DegredationPreference = VideoSendStream::DegradationPreference;
sprangb1ca0732017-02-01 08:38:12 -080043using ScaleReason = AdaptationObserverInterface::AdaptReason;
sprang57c2fff2017-01-16 06:24:02 -080044using ::testing::_;
45using ::testing::Return;
kthelgason876222f2016-11-29 01:44:11 -080046
perkj803d97f2016-11-01 11:45:46 -070047namespace {
asapersson5f7226f2016-11-25 04:37:00 -080048const size_t kMaxPayloadLength = 1440;
kthelgason2bc68642017-02-07 07:02:22 -080049const int kTargetBitrateBps = 1000000;
50const int kLowTargetBitrateBps = kTargetBitrateBps / 10;
51const int kMaxInitialFramedrop = 4;
sprangfda496a2017-06-15 04:21:07 -070052const int kDefaultFramerate = 30;
asapersson5f7226f2016-11-25 04:37:00 -080053
perkj803d97f2016-11-01 11:45:46 -070054class TestBuffer : public webrtc::I420Buffer {
55 public:
56 TestBuffer(rtc::Event* event, int width, int height)
57 : I420Buffer(width, height), event_(event) {}
58
59 private:
60 friend class rtc::RefCountedObject<TestBuffer>;
61 ~TestBuffer() override {
62 if (event_)
63 event_->Set();
64 }
65 rtc::Event* const event_;
66};
67
Niels Möller7dc26b72017-12-06 10:27:48 +010068class CpuOveruseDetectorProxy : public OveruseFrameDetector {
69 public:
Niels Möllerd1f7eb62018-03-28 16:40:58 +020070 explicit CpuOveruseDetectorProxy(CpuOveruseMetricsObserver* metrics_observer)
71 : OveruseFrameDetector(metrics_observer),
Niels Möller7dc26b72017-12-06 10:27:48 +010072 last_target_framerate_fps_(-1) {}
73 virtual ~CpuOveruseDetectorProxy() {}
74
75 void OnTargetFramerateUpdated(int framerate_fps) override {
76 rtc::CritScope cs(&lock_);
77 last_target_framerate_fps_ = framerate_fps;
78 OveruseFrameDetector::OnTargetFramerateUpdated(framerate_fps);
79 }
80
81 int GetLastTargetFramerate() {
82 rtc::CritScope cs(&lock_);
83 return last_target_framerate_fps_;
84 }
85
86 private:
87 rtc::CriticalSection lock_;
88 int last_target_framerate_fps_ RTC_GUARDED_BY(lock_);
89};
90
mflodmancc3d4422017-08-03 08:27:51 -070091class VideoStreamEncoderUnderTest : public VideoStreamEncoder {
perkj803d97f2016-11-01 11:45:46 -070092 public:
Niels Möller7dc26b72017-12-06 10:27:48 +010093 VideoStreamEncoderUnderTest(SendStatisticsProxy* stats_proxy,
94 const VideoSendStream::Config::EncoderSettings& settings)
mflodmancc3d4422017-08-03 08:27:51 -070095 : VideoStreamEncoder(
96 1 /* number_of_cores */,
97 stats_proxy,
98 settings,
99 nullptr /* pre_encode_callback */,
mflodmancc3d4422017-08-03 08:27:51 -0700100 std::unique_ptr<OveruseFrameDetector>(
Niels Möller7dc26b72017-12-06 10:27:48 +0100101 overuse_detector_proxy_ = new CpuOveruseDetectorProxy(
mflodmancc3d4422017-08-03 08:27:51 -0700102 stats_proxy))) {}
perkj803d97f2016-11-01 11:45:46 -0700103
sprangb1ca0732017-02-01 08:38:12 -0800104 void PostTaskAndWait(bool down, AdaptReason reason) {
perkj803d97f2016-11-01 11:45:46 -0700105 rtc::Event event(false, false);
kthelgason876222f2016-11-29 01:44:11 -0800106 encoder_queue()->PostTask([this, &event, reason, down] {
sprangb1ca0732017-02-01 08:38:12 -0800107 down ? AdaptDown(reason) : AdaptUp(reason);
perkj803d97f2016-11-01 11:45:46 -0700108 event.Set();
109 });
perkj070ba852017-02-16 15:46:27 -0800110 ASSERT_TRUE(event.Wait(5000));
perkj803d97f2016-11-01 11:45:46 -0700111 }
112
kthelgason2fc52542017-03-03 00:24:41 -0800113 // This is used as a synchronisation mechanism, to make sure that the
114 // encoder queue is not blocked before we start sending it frames.
115 void WaitUntilTaskQueueIsIdle() {
116 rtc::Event event(false, false);
117 encoder_queue()->PostTask([&event] {
118 event.Set();
119 });
120 ASSERT_TRUE(event.Wait(5000));
121 }
122
sprangb1ca0732017-02-01 08:38:12 -0800123 void TriggerCpuOveruse() { PostTaskAndWait(true, AdaptReason::kCpu); }
kthelgason876222f2016-11-29 01:44:11 -0800124
sprangb1ca0732017-02-01 08:38:12 -0800125 void TriggerCpuNormalUsage() { PostTaskAndWait(false, AdaptReason::kCpu); }
kthelgason876222f2016-11-29 01:44:11 -0800126
sprangb1ca0732017-02-01 08:38:12 -0800127 void TriggerQualityLow() { PostTaskAndWait(true, AdaptReason::kQuality); }
kthelgason876222f2016-11-29 01:44:11 -0800128
sprangb1ca0732017-02-01 08:38:12 -0800129 void TriggerQualityHigh() { PostTaskAndWait(false, AdaptReason::kQuality); }
sprangfda496a2017-06-15 04:21:07 -0700130
Niels Möller7dc26b72017-12-06 10:27:48 +0100131 CpuOveruseDetectorProxy* overuse_detector_proxy_;
perkj803d97f2016-11-01 11:45:46 -0700132};
133
asapersson5f7226f2016-11-25 04:37:00 -0800134class VideoStreamFactory
135 : public VideoEncoderConfig::VideoStreamFactoryInterface {
136 public:
sprangfda496a2017-06-15 04:21:07 -0700137 explicit VideoStreamFactory(size_t num_temporal_layers, int framerate)
138 : num_temporal_layers_(num_temporal_layers), framerate_(framerate) {
asapersson5f7226f2016-11-25 04:37:00 -0800139 EXPECT_GT(num_temporal_layers, 0u);
sprangfda496a2017-06-15 04:21:07 -0700140 EXPECT_GT(framerate, 0);
asapersson5f7226f2016-11-25 04:37:00 -0800141 }
142
143 private:
144 std::vector<VideoStream> CreateEncoderStreams(
145 int width,
146 int height,
147 const VideoEncoderConfig& encoder_config) override {
148 std::vector<VideoStream> streams =
149 test::CreateVideoStreams(width, height, encoder_config);
150 for (VideoStream& stream : streams) {
Sergey Silkina796a7e2018-03-01 15:11:29 +0100151 stream.num_temporal_layers = num_temporal_layers_;
sprangfda496a2017-06-15 04:21:07 -0700152 stream.max_framerate = framerate_;
asapersson5f7226f2016-11-25 04:37:00 -0800153 }
154 return streams;
155 }
sprangfda496a2017-06-15 04:21:07 -0700156
asapersson5f7226f2016-11-25 04:37:00 -0800157 const size_t num_temporal_layers_;
sprangfda496a2017-06-15 04:21:07 -0700158 const int framerate_;
asapersson5f7226f2016-11-25 04:37:00 -0800159};
160
ilnik6b826ef2017-06-16 06:53:48 -0700161
sprangb1ca0732017-02-01 08:38:12 -0800162class AdaptingFrameForwarder : public test::FrameForwarder {
163 public:
164 AdaptingFrameForwarder() : adaptation_enabled_(false) {}
asaperssonfab67072017-04-04 05:51:49 -0700165 ~AdaptingFrameForwarder() override {}
sprangb1ca0732017-02-01 08:38:12 -0800166
167 void set_adaptation_enabled(bool enabled) {
168 rtc::CritScope cs(&crit_);
169 adaptation_enabled_ = enabled;
170 }
171
asaperssonfab67072017-04-04 05:51:49 -0700172 bool adaption_enabled() const {
sprangb1ca0732017-02-01 08:38:12 -0800173 rtc::CritScope cs(&crit_);
174 return adaptation_enabled_;
175 }
176
asapersson09f05612017-05-15 23:40:18 -0700177 rtc::VideoSinkWants last_wants() const {
178 rtc::CritScope cs(&crit_);
179 return last_wants_;
180 }
181
Jonathan Yubc771b72017-12-08 17:04:29 -0800182 rtc::Optional<int> last_sent_width() const { return last_width_; }
183 rtc::Optional<int> last_sent_height() const { return last_height_; }
184
sprangb1ca0732017-02-01 08:38:12 -0800185 void IncomingCapturedFrame(const VideoFrame& video_frame) override {
186 int cropped_width = 0;
187 int cropped_height = 0;
188 int out_width = 0;
189 int out_height = 0;
sprangc5d62e22017-04-02 23:53:04 -0700190 if (adaption_enabled()) {
191 if (adapter_.AdaptFrameResolution(
192 video_frame.width(), video_frame.height(),
193 video_frame.timestamp_us() * 1000, &cropped_width,
194 &cropped_height, &out_width, &out_height)) {
195 VideoFrame adapted_frame(new rtc::RefCountedObject<TestBuffer>(
196 nullptr, out_width, out_height),
197 99, 99, kVideoRotation_0);
198 adapted_frame.set_ntp_time_ms(video_frame.ntp_time_ms());
199 test::FrameForwarder::IncomingCapturedFrame(adapted_frame);
Jonathan Yubc771b72017-12-08 17:04:29 -0800200 last_width_.emplace(adapted_frame.width());
201 last_height_.emplace(adapted_frame.height());
202 } else {
203 last_width_ = rtc::nullopt;
204 last_height_ = rtc::nullopt;
sprangc5d62e22017-04-02 23:53:04 -0700205 }
sprangb1ca0732017-02-01 08:38:12 -0800206 } else {
207 test::FrameForwarder::IncomingCapturedFrame(video_frame);
Jonathan Yubc771b72017-12-08 17:04:29 -0800208 last_width_.emplace(video_frame.width());
209 last_height_.emplace(video_frame.height());
sprangb1ca0732017-02-01 08:38:12 -0800210 }
211 }
212
213 void AddOrUpdateSink(rtc::VideoSinkInterface<VideoFrame>* sink,
214 const rtc::VideoSinkWants& wants) override {
215 rtc::CritScope cs(&crit_);
asapersson09f05612017-05-15 23:40:18 -0700216 last_wants_ = sink_wants();
sprangc5d62e22017-04-02 23:53:04 -0700217 adapter_.OnResolutionFramerateRequest(wants.target_pixel_count,
218 wants.max_pixel_count,
219 wants.max_framerate_fps);
sprangb1ca0732017-02-01 08:38:12 -0800220 test::FrameForwarder::AddOrUpdateSink(sink, wants);
221 }
sprangb1ca0732017-02-01 08:38:12 -0800222 cricket::VideoAdapter adapter_;
danilchapa37de392017-09-09 04:17:22 -0700223 bool adaptation_enabled_ RTC_GUARDED_BY(crit_);
224 rtc::VideoSinkWants last_wants_ RTC_GUARDED_BY(crit_);
Jonathan Yubc771b72017-12-08 17:04:29 -0800225 rtc::Optional<int> last_width_;
226 rtc::Optional<int> last_height_;
sprangb1ca0732017-02-01 08:38:12 -0800227};
sprangc5d62e22017-04-02 23:53:04 -0700228
229class MockableSendStatisticsProxy : public SendStatisticsProxy {
230 public:
231 MockableSendStatisticsProxy(Clock* clock,
232 const VideoSendStream::Config& config,
233 VideoEncoderConfig::ContentType content_type)
234 : SendStatisticsProxy(clock, config, content_type) {}
235
236 VideoSendStream::Stats GetStats() override {
237 rtc::CritScope cs(&lock_);
238 if (mock_stats_)
239 return *mock_stats_;
240 return SendStatisticsProxy::GetStats();
241 }
242
243 void SetMockStats(const VideoSendStream::Stats& stats) {
244 rtc::CritScope cs(&lock_);
245 mock_stats_.emplace(stats);
246 }
247
248 void ResetMockStats() {
249 rtc::CritScope cs(&lock_);
250 mock_stats_.reset();
251 }
252
253 private:
254 rtc::CriticalSection lock_;
danilchapa37de392017-09-09 04:17:22 -0700255 rtc::Optional<VideoSendStream::Stats> mock_stats_ RTC_GUARDED_BY(lock_);
sprangc5d62e22017-04-02 23:53:04 -0700256};
257
sprang4847ae62017-06-27 07:06:52 -0700258class MockBitrateObserver : public VideoBitrateAllocationObserver {
259 public:
260 MOCK_METHOD1(OnBitrateAllocationUpdated, void(const BitrateAllocation&));
261};
262
perkj803d97f2016-11-01 11:45:46 -0700263} // namespace
264
mflodmancc3d4422017-08-03 08:27:51 -0700265class VideoStreamEncoderTest : public ::testing::Test {
perkj26091b12016-09-01 01:17:40 -0700266 public:
267 static const int kDefaultTimeoutMs = 30 * 1000;
268
mflodmancc3d4422017-08-03 08:27:51 -0700269 VideoStreamEncoderTest()
perkj26091b12016-09-01 01:17:40 -0700270 : video_send_config_(VideoSendStream::Config(nullptr)),
perkjfa10b552016-10-02 23:45:26 -0700271 codec_width_(320),
272 codec_height_(240),
sprang4847ae62017-06-27 07:06:52 -0700273 max_framerate_(30),
perkj26091b12016-09-01 01:17:40 -0700274 fake_encoder_(),
sprangc5d62e22017-04-02 23:53:04 -0700275 stats_proxy_(new MockableSendStatisticsProxy(
perkj803d97f2016-11-01 11:45:46 -0700276 Clock::GetRealTimeClock(),
277 video_send_config_,
278 webrtc::VideoEncoderConfig::ContentType::kRealtimeVideo)),
perkj26091b12016-09-01 01:17:40 -0700279 sink_(&fake_encoder_) {}
280
281 void SetUp() override {
perkj803d97f2016-11-01 11:45:46 -0700282 metrics::Reset();
perkj26091b12016-09-01 01:17:40 -0700283 video_send_config_ = VideoSendStream::Config(nullptr);
284 video_send_config_.encoder_settings.encoder = &fake_encoder_;
Niels Möller259a4972018-04-05 15:36:51 +0200285 video_send_config_.rtp.payload_name = "FAKE";
286 video_send_config_.rtp.payload_type = 125;
perkj26091b12016-09-01 01:17:40 -0700287
Per512ecb32016-09-23 15:52:06 +0200288 VideoEncoderConfig video_encoder_config;
Niels Möller259a4972018-04-05 15:36:51 +0200289 test::FillEncoderConfiguration(kVideoCodecVP8, 1, &video_encoder_config);
sprang4847ae62017-06-27 07:06:52 -0700290 video_encoder_config.video_stream_factory =
291 new rtc::RefCountedObject<VideoStreamFactory>(1, max_framerate_);
Erik Språng08127a92016-11-16 16:41:30 +0100292 video_encoder_config_ = video_encoder_config.Copy();
sprang4847ae62017-06-27 07:06:52 -0700293
294 // Framerate limit is specified by the VideoStreamFactory.
295 std::vector<VideoStream> streams =
296 video_encoder_config.video_stream_factory->CreateEncoderStreams(
297 codec_width_, codec_height_, video_encoder_config);
298 max_framerate_ = streams[0].max_framerate;
299 fake_clock_.SetTimeMicros(1234);
300
asapersson5f7226f2016-11-25 04:37:00 -0800301 ConfigureEncoder(std::move(video_encoder_config), true /* nack_enabled */);
302 }
303
304 void ConfigureEncoder(VideoEncoderConfig video_encoder_config,
305 bool nack_enabled) {
mflodmancc3d4422017-08-03 08:27:51 -0700306 if (video_stream_encoder_)
307 video_stream_encoder_->Stop();
308 video_stream_encoder_.reset(new VideoStreamEncoderUnderTest(
perkj803d97f2016-11-01 11:45:46 -0700309 stats_proxy_.get(), video_send_config_.encoder_settings));
mflodmancc3d4422017-08-03 08:27:51 -0700310 video_stream_encoder_->SetSink(&sink_, false /* rotation_applied */);
311 video_stream_encoder_->SetSource(
sprangc5d62e22017-04-02 23:53:04 -0700312 &video_source_,
313 VideoSendStream::DegradationPreference::kMaintainFramerate);
mflodmancc3d4422017-08-03 08:27:51 -0700314 video_stream_encoder_->SetStartBitrate(kTargetBitrateBps);
315 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
316 kMaxPayloadLength, nack_enabled);
317 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
asapersson5f7226f2016-11-25 04:37:00 -0800318 }
319
320 void ResetEncoder(const std::string& payload_name,
321 size_t num_streams,
322 size_t num_temporal_layers,
emircanbbcc3562017-08-18 00:28:40 -0700323 unsigned char num_spatial_layers,
sprang4847ae62017-06-27 07:06:52 -0700324 bool nack_enabled,
325 bool screenshare) {
Niels Möller259a4972018-04-05 15:36:51 +0200326 video_send_config_.rtp.payload_name = payload_name;
asapersson5f7226f2016-11-25 04:37:00 -0800327
328 VideoEncoderConfig video_encoder_config;
Niels Möller259a4972018-04-05 15:36:51 +0200329 video_encoder_config.codec_type = PayloadStringToCodecType(payload_name);
asapersson5f7226f2016-11-25 04:37:00 -0800330 video_encoder_config.number_of_streams = num_streams;
kthelgason2bc68642017-02-07 07:02:22 -0800331 video_encoder_config.max_bitrate_bps = kTargetBitrateBps;
asapersson5f7226f2016-11-25 04:37:00 -0800332 video_encoder_config.video_stream_factory =
sprangfda496a2017-06-15 04:21:07 -0700333 new rtc::RefCountedObject<VideoStreamFactory>(num_temporal_layers,
334 kDefaultFramerate);
sprang4847ae62017-06-27 07:06:52 -0700335 video_encoder_config.content_type =
336 screenshare ? VideoEncoderConfig::ContentType::kScreen
337 : VideoEncoderConfig::ContentType::kRealtimeVideo;
emircanbbcc3562017-08-18 00:28:40 -0700338 if (payload_name == "VP9") {
339 VideoCodecVP9 vp9_settings = VideoEncoder::GetDefaultVp9Settings();
340 vp9_settings.numberOfSpatialLayers = num_spatial_layers;
341 video_encoder_config.encoder_specific_settings =
342 new rtc::RefCountedObject<
343 VideoEncoderConfig::Vp9EncoderSpecificSettings>(vp9_settings);
344 }
asapersson5f7226f2016-11-25 04:37:00 -0800345 ConfigureEncoder(std::move(video_encoder_config), nack_enabled);
perkj26091b12016-09-01 01:17:40 -0700346 }
347
sprang57c2fff2017-01-16 06:24:02 -0800348 VideoFrame CreateFrame(int64_t ntp_time_ms,
349 rtc::Event* destruction_event) const {
Per512ecb32016-09-23 15:52:06 +0200350 VideoFrame frame(new rtc::RefCountedObject<TestBuffer>(
351 destruction_event, codec_width_, codec_height_),
352 99, 99, kVideoRotation_0);
sprang57c2fff2017-01-16 06:24:02 -0800353 frame.set_ntp_time_ms(ntp_time_ms);
perkj26091b12016-09-01 01:17:40 -0700354 return frame;
355 }
356
sprang57c2fff2017-01-16 06:24:02 -0800357 VideoFrame CreateFrame(int64_t ntp_time_ms, int width, int height) const {
perkj803d97f2016-11-01 11:45:46 -0700358 VideoFrame frame(
359 new rtc::RefCountedObject<TestBuffer>(nullptr, width, height), 99, 99,
360 kVideoRotation_0);
sprang57c2fff2017-01-16 06:24:02 -0800361 frame.set_ntp_time_ms(ntp_time_ms);
sprangc5d62e22017-04-02 23:53:04 -0700362 frame.set_timestamp_us(ntp_time_ms * 1000);
perkj803d97f2016-11-01 11:45:46 -0700363 return frame;
364 }
365
asapersson02465b82017-04-10 01:12:52 -0700366 void VerifyNoLimitation(const rtc::VideoSinkWants& wants) {
asapersson02465b82017-04-10 01:12:52 -0700367 EXPECT_EQ(std::numeric_limits<int>::max(), wants.max_framerate_fps);
asapersson09f05612017-05-15 23:40:18 -0700368 EXPECT_EQ(std::numeric_limits<int>::max(), wants.max_pixel_count);
369 EXPECT_FALSE(wants.target_pixel_count);
asapersson02465b82017-04-10 01:12:52 -0700370 }
371
asapersson09f05612017-05-15 23:40:18 -0700372 void VerifyFpsEqResolutionEq(const rtc::VideoSinkWants& wants1,
373 const rtc::VideoSinkWants& wants2) {
374 EXPECT_EQ(wants1.max_framerate_fps, wants2.max_framerate_fps);
375 EXPECT_EQ(wants1.max_pixel_count, wants2.max_pixel_count);
376 }
377
378 void VerifyFpsMaxResolutionLt(const rtc::VideoSinkWants& wants1,
379 const rtc::VideoSinkWants& wants2) {
380 EXPECT_EQ(std::numeric_limits<int>::max(), wants1.max_framerate_fps);
381 EXPECT_LT(wants1.max_pixel_count, wants2.max_pixel_count);
382 EXPECT_GT(wants1.max_pixel_count, 0);
383 }
384
385 void VerifyFpsMaxResolutionGt(const rtc::VideoSinkWants& wants1,
386 const rtc::VideoSinkWants& wants2) {
387 EXPECT_EQ(std::numeric_limits<int>::max(), wants1.max_framerate_fps);
388 EXPECT_GT(wants1.max_pixel_count, wants2.max_pixel_count);
389 }
390
asaperssonf7e294d2017-06-13 23:25:22 -0700391 void VerifyFpsMaxResolutionEq(const rtc::VideoSinkWants& wants1,
392 const rtc::VideoSinkWants& wants2) {
393 EXPECT_EQ(std::numeric_limits<int>::max(), wants1.max_framerate_fps);
394 EXPECT_EQ(wants1.max_pixel_count, wants2.max_pixel_count);
395 }
396
397 void VerifyFpsLtResolutionEq(const rtc::VideoSinkWants& wants1,
398 const rtc::VideoSinkWants& wants2) {
399 EXPECT_LT(wants1.max_framerate_fps, wants2.max_framerate_fps);
400 EXPECT_EQ(wants1.max_pixel_count, wants2.max_pixel_count);
401 }
402
403 void VerifyFpsGtResolutionEq(const rtc::VideoSinkWants& wants1,
404 const rtc::VideoSinkWants& wants2) {
405 EXPECT_GT(wants1.max_framerate_fps, wants2.max_framerate_fps);
406 EXPECT_EQ(wants1.max_pixel_count, wants2.max_pixel_count);
407 }
408
409 void VerifyFpsEqResolutionLt(const rtc::VideoSinkWants& wants1,
410 const rtc::VideoSinkWants& wants2) {
411 EXPECT_EQ(wants1.max_framerate_fps, wants2.max_framerate_fps);
412 EXPECT_LT(wants1.max_pixel_count, wants2.max_pixel_count);
413 EXPECT_GT(wants1.max_pixel_count, 0);
414 }
415
416 void VerifyFpsEqResolutionGt(const rtc::VideoSinkWants& wants1,
417 const rtc::VideoSinkWants& wants2) {
418 EXPECT_EQ(wants1.max_framerate_fps, wants2.max_framerate_fps);
419 EXPECT_GT(wants1.max_pixel_count, wants2.max_pixel_count);
420 }
421
asapersson09f05612017-05-15 23:40:18 -0700422 void VerifyFpsMaxResolutionLt(const rtc::VideoSinkWants& wants,
423 int pixel_count) {
424 EXPECT_EQ(std::numeric_limits<int>::max(), wants.max_framerate_fps);
asapersson02465b82017-04-10 01:12:52 -0700425 EXPECT_LT(wants.max_pixel_count, pixel_count);
426 EXPECT_GT(wants.max_pixel_count, 0);
asapersson09f05612017-05-15 23:40:18 -0700427 }
428
429 void VerifyFpsLtResolutionMax(const rtc::VideoSinkWants& wants, int fps) {
430 EXPECT_LT(wants.max_framerate_fps, fps);
431 EXPECT_EQ(std::numeric_limits<int>::max(), wants.max_pixel_count);
432 EXPECT_FALSE(wants.target_pixel_count);
asapersson02465b82017-04-10 01:12:52 -0700433 }
434
asaperssonf7e294d2017-06-13 23:25:22 -0700435 void VerifyFpsEqResolutionMax(const rtc::VideoSinkWants& wants,
436 int expected_fps) {
437 EXPECT_EQ(expected_fps, wants.max_framerate_fps);
438 EXPECT_EQ(std::numeric_limits<int>::max(), wants.max_pixel_count);
439 EXPECT_FALSE(wants.target_pixel_count);
440 }
441
Jonathan Yubc771b72017-12-08 17:04:29 -0800442 void VerifyBalancedModeFpsRange(const rtc::VideoSinkWants& wants,
443 int last_frame_pixels) {
444 // Balanced mode should always scale FPS to the desired range before
445 // attempting to scale resolution.
446 int fps_limit = wants.max_framerate_fps;
447 if (last_frame_pixels <= 320 * 240) {
448 EXPECT_TRUE(7 <= fps_limit && fps_limit <= 10);
449 } else if (last_frame_pixels <= 480 * 270) {
450 EXPECT_TRUE(10 <= fps_limit && fps_limit <= 15);
451 } else if (last_frame_pixels <= 640 * 480) {
452 EXPECT_LE(15, fps_limit);
453 } else {
454 EXPECT_EQ(std::numeric_limits<int>::max(), fps_limit);
455 }
456 }
457
sprang4847ae62017-06-27 07:06:52 -0700458 void WaitForEncodedFrame(int64_t expected_ntp_time) {
459 sink_.WaitForEncodedFrame(expected_ntp_time);
460 fake_clock_.AdvanceTimeMicros(rtc::kNumMicrosecsPerSec / max_framerate_);
461 }
462
463 bool TimedWaitForEncodedFrame(int64_t expected_ntp_time, int64_t timeout_ms) {
464 bool ok = sink_.TimedWaitForEncodedFrame(expected_ntp_time, timeout_ms);
465 fake_clock_.AdvanceTimeMicros(rtc::kNumMicrosecsPerSec / max_framerate_);
466 return ok;
467 }
468
469 void WaitForEncodedFrame(uint32_t expected_width, uint32_t expected_height) {
470 sink_.WaitForEncodedFrame(expected_width, expected_height);
471 fake_clock_.AdvanceTimeMicros(rtc::kNumMicrosecsPerSec / max_framerate_);
472 }
473
474 void ExpectDroppedFrame() {
475 sink_.ExpectDroppedFrame();
476 fake_clock_.AdvanceTimeMicros(rtc::kNumMicrosecsPerSec / max_framerate_);
477 }
478
479 bool WaitForFrame(int64_t timeout_ms) {
480 bool ok = sink_.WaitForFrame(timeout_ms);
481 fake_clock_.AdvanceTimeMicros(rtc::kNumMicrosecsPerSec / max_framerate_);
482 return ok;
483 }
484
perkj26091b12016-09-01 01:17:40 -0700485 class TestEncoder : public test::FakeEncoder {
486 public:
487 TestEncoder()
488 : FakeEncoder(Clock::GetRealTimeClock()),
489 continue_encode_event_(false, false) {}
490
asaperssonfab67072017-04-04 05:51:49 -0700491 VideoCodec codec_config() const {
brandtre78d2662017-01-16 05:57:16 -0800492 rtc::CritScope lock(&crit_sect_);
perkjfa10b552016-10-02 23:45:26 -0700493 return config_;
494 }
495
496 void BlockNextEncode() {
brandtre78d2662017-01-16 05:57:16 -0800497 rtc::CritScope lock(&local_crit_sect_);
perkjfa10b552016-10-02 23:45:26 -0700498 block_next_encode_ = true;
499 }
500
kthelgason876222f2016-11-29 01:44:11 -0800501 VideoEncoder::ScalingSettings GetScalingSettings() const override {
kthelgason2fc52542017-03-03 00:24:41 -0800502 rtc::CritScope lock(&local_crit_sect_);
kthelgasonad9010c2017-02-14 00:46:51 -0800503 if (quality_scaling_)
Niels Möller225c7872018-02-22 15:03:53 +0100504 return VideoEncoder::ScalingSettings(1, 2, kMinPixelsPerFrame);
505 return VideoEncoder::ScalingSettings::kOff;
kthelgason876222f2016-11-29 01:44:11 -0800506 }
507
perkjfa10b552016-10-02 23:45:26 -0700508 void ContinueEncode() { continue_encode_event_.Set(); }
509
510 void CheckLastTimeStampsMatch(int64_t ntp_time_ms,
511 uint32_t timestamp) const {
brandtre78d2662017-01-16 05:57:16 -0800512 rtc::CritScope lock(&local_crit_sect_);
perkjfa10b552016-10-02 23:45:26 -0700513 EXPECT_EQ(timestamp_, timestamp);
514 EXPECT_EQ(ntp_time_ms_, ntp_time_ms);
515 }
516
kthelgason2fc52542017-03-03 00:24:41 -0800517 void SetQualityScaling(bool b) {
518 rtc::CritScope lock(&local_crit_sect_);
519 quality_scaling_ = b;
520 }
kthelgasonad9010c2017-02-14 00:46:51 -0800521
sprangfe627f32017-03-29 08:24:59 -0700522 void ForceInitEncodeFailure(bool force_failure) {
523 rtc::CritScope lock(&local_crit_sect_);
524 force_init_encode_failed_ = force_failure;
525 }
526
perkjfa10b552016-10-02 23:45:26 -0700527 private:
perkj26091b12016-09-01 01:17:40 -0700528 int32_t Encode(const VideoFrame& input_image,
529 const CodecSpecificInfo* codec_specific_info,
530 const std::vector<FrameType>* frame_types) override {
531 bool block_encode;
532 {
brandtre78d2662017-01-16 05:57:16 -0800533 rtc::CritScope lock(&local_crit_sect_);
perkj26091b12016-09-01 01:17:40 -0700534 EXPECT_GT(input_image.timestamp(), timestamp_);
535 EXPECT_GT(input_image.ntp_time_ms(), ntp_time_ms_);
536 EXPECT_EQ(input_image.timestamp(), input_image.ntp_time_ms() * 90);
537
538 timestamp_ = input_image.timestamp();
539 ntp_time_ms_ = input_image.ntp_time_ms();
perkj803d97f2016-11-01 11:45:46 -0700540 last_input_width_ = input_image.width();
541 last_input_height_ = input_image.height();
perkj26091b12016-09-01 01:17:40 -0700542 block_encode = block_next_encode_;
543 block_next_encode_ = false;
544 }
545 int32_t result =
546 FakeEncoder::Encode(input_image, codec_specific_info, frame_types);
547 if (block_encode)
perkja49cbd32016-09-16 07:53:41 -0700548 EXPECT_TRUE(continue_encode_event_.Wait(kDefaultTimeoutMs));
perkj26091b12016-09-01 01:17:40 -0700549 return result;
550 }
551
sprangfe627f32017-03-29 08:24:59 -0700552 int32_t InitEncode(const VideoCodec* config,
553 int32_t number_of_cores,
554 size_t max_payload_size) override {
555 int res =
556 FakeEncoder::InitEncode(config, number_of_cores, max_payload_size);
557 rtc::CritScope lock(&local_crit_sect_);
Erik Språng82fad3d2018-03-21 09:57:23 +0100558 if (config->codecType == kVideoCodecVP8) {
sprangfe627f32017-03-29 08:24:59 -0700559 // Simulate setting up temporal layers, in order to validate the life
560 // cycle of these objects.
561 int num_streams = std::max<int>(1, config->numberOfSimulcastStreams);
sprangfe627f32017-03-29 08:24:59 -0700562 for (int i = 0; i < num_streams; ++i) {
563 allocated_temporal_layers_.emplace_back(
Niels Möller150dcb02018-03-27 14:16:55 +0200564 TemporalLayers::CreateTemporalLayers(*config, i));
sprangfe627f32017-03-29 08:24:59 -0700565 }
566 }
567 if (force_init_encode_failed_)
568 return -1;
569 return res;
570 }
571
brandtre78d2662017-01-16 05:57:16 -0800572 rtc::CriticalSection local_crit_sect_;
danilchapa37de392017-09-09 04:17:22 -0700573 bool block_next_encode_ RTC_GUARDED_BY(local_crit_sect_) = false;
perkj26091b12016-09-01 01:17:40 -0700574 rtc::Event continue_encode_event_;
danilchapa37de392017-09-09 04:17:22 -0700575 uint32_t timestamp_ RTC_GUARDED_BY(local_crit_sect_) = 0;
576 int64_t ntp_time_ms_ RTC_GUARDED_BY(local_crit_sect_) = 0;
577 int last_input_width_ RTC_GUARDED_BY(local_crit_sect_) = 0;
578 int last_input_height_ RTC_GUARDED_BY(local_crit_sect_) = 0;
579 bool quality_scaling_ RTC_GUARDED_BY(local_crit_sect_) = true;
sprangfe627f32017-03-29 08:24:59 -0700580 std::vector<std::unique_ptr<TemporalLayers>> allocated_temporal_layers_
danilchapa37de392017-09-09 04:17:22 -0700581 RTC_GUARDED_BY(local_crit_sect_);
582 bool force_init_encode_failed_ RTC_GUARDED_BY(local_crit_sect_) = false;
perkj26091b12016-09-01 01:17:40 -0700583 };
584
mflodmancc3d4422017-08-03 08:27:51 -0700585 class TestSink : public VideoStreamEncoder::EncoderSink {
perkj26091b12016-09-01 01:17:40 -0700586 public:
587 explicit TestSink(TestEncoder* test_encoder)
588 : test_encoder_(test_encoder), encoded_frame_event_(false, false) {}
589
perkj26091b12016-09-01 01:17:40 -0700590 void WaitForEncodedFrame(int64_t expected_ntp_time) {
sprang4847ae62017-06-27 07:06:52 -0700591 EXPECT_TRUE(
592 TimedWaitForEncodedFrame(expected_ntp_time, kDefaultTimeoutMs));
593 }
594
595 bool TimedWaitForEncodedFrame(int64_t expected_ntp_time,
596 int64_t timeout_ms) {
perkj26091b12016-09-01 01:17:40 -0700597 uint32_t timestamp = 0;
sprang4847ae62017-06-27 07:06:52 -0700598 if (!encoded_frame_event_.Wait(timeout_ms))
599 return false;
perkj26091b12016-09-01 01:17:40 -0700600 {
601 rtc::CritScope lock(&crit_);
sprangb1ca0732017-02-01 08:38:12 -0800602 timestamp = last_timestamp_;
perkj26091b12016-09-01 01:17:40 -0700603 }
604 test_encoder_->CheckLastTimeStampsMatch(expected_ntp_time, timestamp);
sprang4847ae62017-06-27 07:06:52 -0700605 return true;
perkj26091b12016-09-01 01:17:40 -0700606 }
607
sprangb1ca0732017-02-01 08:38:12 -0800608 void WaitForEncodedFrame(uint32_t expected_width,
609 uint32_t expected_height) {
sprangc5d62e22017-04-02 23:53:04 -0700610 EXPECT_TRUE(encoded_frame_event_.Wait(kDefaultTimeoutMs));
Åsa Perssonc74d8da2017-12-04 14:13:56 +0100611 CheckLastFrameSizeMatches(expected_width, expected_height);
sprangc5d62e22017-04-02 23:53:04 -0700612 }
613
Åsa Perssonc74d8da2017-12-04 14:13:56 +0100614 void CheckLastFrameSizeMatches(uint32_t expected_width,
sprangc5d62e22017-04-02 23:53:04 -0700615 uint32_t expected_height) {
sprangb1ca0732017-02-01 08:38:12 -0800616 uint32_t width = 0;
617 uint32_t height = 0;
sprangb1ca0732017-02-01 08:38:12 -0800618 {
619 rtc::CritScope lock(&crit_);
620 width = last_width_;
621 height = last_height_;
622 }
623 EXPECT_EQ(expected_height, height);
624 EXPECT_EQ(expected_width, width);
625 }
626
kthelgason2fc52542017-03-03 00:24:41 -0800627 void ExpectDroppedFrame() { EXPECT_FALSE(encoded_frame_event_.Wait(100)); }
kthelgason2bc68642017-02-07 07:02:22 -0800628
sprangc5d62e22017-04-02 23:53:04 -0700629 bool WaitForFrame(int64_t timeout_ms) {
630 return encoded_frame_event_.Wait(timeout_ms);
631 }
632
perkj26091b12016-09-01 01:17:40 -0700633 void SetExpectNoFrames() {
634 rtc::CritScope lock(&crit_);
635 expect_frames_ = false;
636 }
637
asaperssonfab67072017-04-04 05:51:49 -0700638 int number_of_reconfigurations() const {
Per512ecb32016-09-23 15:52:06 +0200639 rtc::CritScope lock(&crit_);
640 return number_of_reconfigurations_;
641 }
642
asaperssonfab67072017-04-04 05:51:49 -0700643 int last_min_transmit_bitrate() const {
Per512ecb32016-09-23 15:52:06 +0200644 rtc::CritScope lock(&crit_);
645 return min_transmit_bitrate_bps_;
646 }
647
perkj26091b12016-09-01 01:17:40 -0700648 private:
sergeyu2cb155a2016-11-04 11:39:29 -0700649 Result OnEncodedImage(
650 const EncodedImage& encoded_image,
651 const CodecSpecificInfo* codec_specific_info,
652 const RTPFragmentationHeader* fragmentation) override {
Per512ecb32016-09-23 15:52:06 +0200653 rtc::CritScope lock(&crit_);
654 EXPECT_TRUE(expect_frames_);
sprangb1ca0732017-02-01 08:38:12 -0800655 last_timestamp_ = encoded_image._timeStamp;
656 last_width_ = encoded_image._encodedWidth;
657 last_height_ = encoded_image._encodedHeight;
Per512ecb32016-09-23 15:52:06 +0200658 encoded_frame_event_.Set();
sprangb1ca0732017-02-01 08:38:12 -0800659 return Result(Result::OK, last_timestamp_);
Per512ecb32016-09-23 15:52:06 +0200660 }
661
662 void OnEncoderConfigurationChanged(std::vector<VideoStream> streams,
663 int min_transmit_bitrate_bps) override {
664 rtc::CriticalSection crit_;
665 ++number_of_reconfigurations_;
666 min_transmit_bitrate_bps_ = min_transmit_bitrate_bps;
667 }
668
perkj26091b12016-09-01 01:17:40 -0700669 rtc::CriticalSection crit_;
670 TestEncoder* test_encoder_;
671 rtc::Event encoded_frame_event_;
sprangb1ca0732017-02-01 08:38:12 -0800672 uint32_t last_timestamp_ = 0;
673 uint32_t last_height_ = 0;
674 uint32_t last_width_ = 0;
perkj26091b12016-09-01 01:17:40 -0700675 bool expect_frames_ = true;
Per512ecb32016-09-23 15:52:06 +0200676 int number_of_reconfigurations_ = 0;
677 int min_transmit_bitrate_bps_ = 0;
perkj26091b12016-09-01 01:17:40 -0700678 };
679
680 VideoSendStream::Config video_send_config_;
Erik Språng08127a92016-11-16 16:41:30 +0100681 VideoEncoderConfig video_encoder_config_;
Per512ecb32016-09-23 15:52:06 +0200682 int codec_width_;
683 int codec_height_;
sprang4847ae62017-06-27 07:06:52 -0700684 int max_framerate_;
perkj26091b12016-09-01 01:17:40 -0700685 TestEncoder fake_encoder_;
sprangc5d62e22017-04-02 23:53:04 -0700686 std::unique_ptr<MockableSendStatisticsProxy> stats_proxy_;
perkj26091b12016-09-01 01:17:40 -0700687 TestSink sink_;
sprangb1ca0732017-02-01 08:38:12 -0800688 AdaptingFrameForwarder video_source_;
mflodmancc3d4422017-08-03 08:27:51 -0700689 std::unique_ptr<VideoStreamEncoderUnderTest> video_stream_encoder_;
sprang4847ae62017-06-27 07:06:52 -0700690 rtc::ScopedFakeClock fake_clock_;
perkj26091b12016-09-01 01:17:40 -0700691};
692
mflodmancc3d4422017-08-03 08:27:51 -0700693TEST_F(VideoStreamEncoderTest, EncodeOneFrame) {
694 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkj26091b12016-09-01 01:17:40 -0700695 rtc::Event frame_destroyed_event(false, false);
perkja49cbd32016-09-16 07:53:41 -0700696 video_source_.IncomingCapturedFrame(CreateFrame(1, &frame_destroyed_event));
sprang4847ae62017-06-27 07:06:52 -0700697 WaitForEncodedFrame(1);
perkja49cbd32016-09-16 07:53:41 -0700698 EXPECT_TRUE(frame_destroyed_event.Wait(kDefaultTimeoutMs));
mflodmancc3d4422017-08-03 08:27:51 -0700699 video_stream_encoder_->Stop();
perkj26091b12016-09-01 01:17:40 -0700700}
701
mflodmancc3d4422017-08-03 08:27:51 -0700702TEST_F(VideoStreamEncoderTest, DropsFramesBeforeFirstOnBitrateUpdated) {
perkj26091b12016-09-01 01:17:40 -0700703 // Dropped since no target bitrate has been set.
704 rtc::Event frame_destroyed_event(false, false);
Sebastian Janssona3177052018-04-10 13:05:49 +0200705 // The encoder will cache up to one frame for a short duration. Adding two
706 // frames means that the first frame will be dropped and the second frame will
707 // be sent when the encoder is enabled.
perkja49cbd32016-09-16 07:53:41 -0700708 video_source_.IncomingCapturedFrame(CreateFrame(1, &frame_destroyed_event));
Sebastian Janssona3177052018-04-10 13:05:49 +0200709 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
perkja49cbd32016-09-16 07:53:41 -0700710 EXPECT_TRUE(frame_destroyed_event.Wait(kDefaultTimeoutMs));
perkj26091b12016-09-01 01:17:40 -0700711
mflodmancc3d4422017-08-03 08:27:51 -0700712 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkj26091b12016-09-01 01:17:40 -0700713
Sebastian Janssona3177052018-04-10 13:05:49 +0200714 // The pending frame should be received.
sprang4847ae62017-06-27 07:06:52 -0700715 WaitForEncodedFrame(2);
Sebastian Janssona3177052018-04-10 13:05:49 +0200716 video_source_.IncomingCapturedFrame(CreateFrame(3, nullptr));
717
718 WaitForEncodedFrame(3);
mflodmancc3d4422017-08-03 08:27:51 -0700719 video_stream_encoder_->Stop();
perkj26091b12016-09-01 01:17:40 -0700720}
721
mflodmancc3d4422017-08-03 08:27:51 -0700722TEST_F(VideoStreamEncoderTest, DropsFramesWhenRateSetToZero) {
723 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkja49cbd32016-09-16 07:53:41 -0700724 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700725 WaitForEncodedFrame(1);
perkj26091b12016-09-01 01:17:40 -0700726
mflodmancc3d4422017-08-03 08:27:51 -0700727 video_stream_encoder_->OnBitrateUpdated(0, 0, 0);
Sebastian Janssona3177052018-04-10 13:05:49 +0200728 // The encoder will cache up to one frame for a short duration. Adding two
729 // frames means that the first frame will be dropped and the second frame will
730 // be sent when the encoder is resumed.
perkja49cbd32016-09-16 07:53:41 -0700731 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
Sebastian Janssona3177052018-04-10 13:05:49 +0200732 video_source_.IncomingCapturedFrame(CreateFrame(3, nullptr));
perkj26091b12016-09-01 01:17:40 -0700733
mflodmancc3d4422017-08-03 08:27:51 -0700734 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
sprang4847ae62017-06-27 07:06:52 -0700735 WaitForEncodedFrame(3);
Sebastian Janssona3177052018-04-10 13:05:49 +0200736 video_source_.IncomingCapturedFrame(CreateFrame(4, nullptr));
737 WaitForEncodedFrame(4);
mflodmancc3d4422017-08-03 08:27:51 -0700738 video_stream_encoder_->Stop();
perkj26091b12016-09-01 01:17:40 -0700739}
740
mflodmancc3d4422017-08-03 08:27:51 -0700741TEST_F(VideoStreamEncoderTest, DropsFramesWithSameOrOldNtpTimestamp) {
742 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkja49cbd32016-09-16 07:53:41 -0700743 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700744 WaitForEncodedFrame(1);
perkj26091b12016-09-01 01:17:40 -0700745
746 // This frame will be dropped since it has the same ntp timestamp.
perkja49cbd32016-09-16 07:53:41 -0700747 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
perkj26091b12016-09-01 01:17:40 -0700748
perkja49cbd32016-09-16 07:53:41 -0700749 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700750 WaitForEncodedFrame(2);
mflodmancc3d4422017-08-03 08:27:51 -0700751 video_stream_encoder_->Stop();
perkj26091b12016-09-01 01:17:40 -0700752}
753
mflodmancc3d4422017-08-03 08:27:51 -0700754TEST_F(VideoStreamEncoderTest, DropsFrameAfterStop) {
755 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkj26091b12016-09-01 01:17:40 -0700756
perkja49cbd32016-09-16 07:53:41 -0700757 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700758 WaitForEncodedFrame(1);
perkj26091b12016-09-01 01:17:40 -0700759
mflodmancc3d4422017-08-03 08:27:51 -0700760 video_stream_encoder_->Stop();
perkj26091b12016-09-01 01:17:40 -0700761 sink_.SetExpectNoFrames();
762 rtc::Event frame_destroyed_event(false, false);
perkja49cbd32016-09-16 07:53:41 -0700763 video_source_.IncomingCapturedFrame(CreateFrame(2, &frame_destroyed_event));
764 EXPECT_TRUE(frame_destroyed_event.Wait(kDefaultTimeoutMs));
perkj26091b12016-09-01 01:17:40 -0700765}
766
mflodmancc3d4422017-08-03 08:27:51 -0700767TEST_F(VideoStreamEncoderTest, DropsPendingFramesOnSlowEncode) {
768 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkj26091b12016-09-01 01:17:40 -0700769
770 fake_encoder_.BlockNextEncode();
perkja49cbd32016-09-16 07:53:41 -0700771 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700772 WaitForEncodedFrame(1);
perkj26091b12016-09-01 01:17:40 -0700773 // Here, the encoder thread will be blocked in the TestEncoder waiting for a
774 // call to ContinueEncode.
perkja49cbd32016-09-16 07:53:41 -0700775 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
776 video_source_.IncomingCapturedFrame(CreateFrame(3, nullptr));
perkj26091b12016-09-01 01:17:40 -0700777 fake_encoder_.ContinueEncode();
sprang4847ae62017-06-27 07:06:52 -0700778 WaitForEncodedFrame(3);
perkj26091b12016-09-01 01:17:40 -0700779
mflodmancc3d4422017-08-03 08:27:51 -0700780 video_stream_encoder_->Stop();
perkj26091b12016-09-01 01:17:40 -0700781}
782
mflodmancc3d4422017-08-03 08:27:51 -0700783TEST_F(VideoStreamEncoderTest,
784 ConfigureEncoderTriggersOnEncoderConfigurationChanged) {
785 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
Per21d45d22016-10-30 21:37:57 +0100786 EXPECT_EQ(0, sink_.number_of_reconfigurations());
Per512ecb32016-09-23 15:52:06 +0200787
788 // Capture a frame and wait for it to synchronize with the encoder thread.
Perf8c5f2b2016-09-23 16:24:55 +0200789 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700790 WaitForEncodedFrame(1);
Per21d45d22016-10-30 21:37:57 +0100791 // The encoder will have been configured once when the first frame is
792 // received.
793 EXPECT_EQ(1, sink_.number_of_reconfigurations());
Per512ecb32016-09-23 15:52:06 +0200794
795 VideoEncoderConfig video_encoder_config;
Niels Möller259a4972018-04-05 15:36:51 +0200796 test::FillEncoderConfiguration(kVideoCodecVP8, 1, &video_encoder_config);
Per512ecb32016-09-23 15:52:06 +0200797 video_encoder_config.min_transmit_bitrate_bps = 9999;
mflodmancc3d4422017-08-03 08:27:51 -0700798 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
799 kMaxPayloadLength,
800 true /* nack_enabled */);
Per512ecb32016-09-23 15:52:06 +0200801
802 // Capture a frame and wait for it to synchronize with the encoder thread.
Perf8c5f2b2016-09-23 16:24:55 +0200803 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700804 WaitForEncodedFrame(2);
Per21d45d22016-10-30 21:37:57 +0100805 EXPECT_EQ(2, sink_.number_of_reconfigurations());
perkj3b703ed2016-09-29 23:25:40 -0700806 EXPECT_EQ(9999, sink_.last_min_transmit_bitrate());
perkj26105b42016-09-29 22:39:10 -0700807
mflodmancc3d4422017-08-03 08:27:51 -0700808 video_stream_encoder_->Stop();
perkj26105b42016-09-29 22:39:10 -0700809}
810
mflodmancc3d4422017-08-03 08:27:51 -0700811TEST_F(VideoStreamEncoderTest, FrameResolutionChangeReconfigureEncoder) {
812 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkjfa10b552016-10-02 23:45:26 -0700813
814 // Capture a frame and wait for it to synchronize with the encoder thread.
815 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700816 WaitForEncodedFrame(1);
Per21d45d22016-10-30 21:37:57 +0100817 // The encoder will have been configured once.
818 EXPECT_EQ(1, sink_.number_of_reconfigurations());
perkjfa10b552016-10-02 23:45:26 -0700819 EXPECT_EQ(codec_width_, fake_encoder_.codec_config().width);
820 EXPECT_EQ(codec_height_, fake_encoder_.codec_config().height);
821
822 codec_width_ *= 2;
823 codec_height_ *= 2;
824 // Capture a frame with a higher resolution and wait for it to synchronize
825 // with the encoder thread.
826 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700827 WaitForEncodedFrame(2);
perkjfa10b552016-10-02 23:45:26 -0700828 EXPECT_EQ(codec_width_, fake_encoder_.codec_config().width);
829 EXPECT_EQ(codec_height_, fake_encoder_.codec_config().height);
Per21d45d22016-10-30 21:37:57 +0100830 EXPECT_EQ(2, sink_.number_of_reconfigurations());
perkjfa10b552016-10-02 23:45:26 -0700831
mflodmancc3d4422017-08-03 08:27:51 -0700832 video_stream_encoder_->Stop();
perkjfa10b552016-10-02 23:45:26 -0700833}
834
mflodmancc3d4422017-08-03 08:27:51 -0700835TEST_F(VideoStreamEncoderTest, Vp8ResilienceIsOffFor1S1TLWithNackEnabled) {
asapersson5f7226f2016-11-25 04:37:00 -0800836 const bool kNackEnabled = true;
837 const size_t kNumStreams = 1;
838 const size_t kNumTl = 1;
emircanbbcc3562017-08-18 00:28:40 -0700839 ResetEncoder("VP8", kNumStreams, kNumTl, kNumSlDummy, kNackEnabled, false);
mflodmancc3d4422017-08-03 08:27:51 -0700840 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson5f7226f2016-11-25 04:37:00 -0800841
842 // Capture a frame and wait for it to synchronize with the encoder thread.
843 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700844 WaitForEncodedFrame(1);
asapersson5f7226f2016-11-25 04:37:00 -0800845 // The encoder have been configured once when the first frame is received.
846 EXPECT_EQ(1, sink_.number_of_reconfigurations());
847 EXPECT_EQ(kVideoCodecVP8, fake_encoder_.codec_config().codecType);
848 EXPECT_EQ(kNumStreams, fake_encoder_.codec_config().numberOfSimulcastStreams);
849 EXPECT_EQ(kNumTl, fake_encoder_.codec_config().VP8()->numberOfTemporalLayers);
850 // Resilience is off for no temporal layers with nack on.
851 EXPECT_EQ(kResilienceOff, fake_encoder_.codec_config().VP8()->resilience);
mflodmancc3d4422017-08-03 08:27:51 -0700852 video_stream_encoder_->Stop();
asapersson5f7226f2016-11-25 04:37:00 -0800853}
854
mflodmancc3d4422017-08-03 08:27:51 -0700855TEST_F(VideoStreamEncoderTest, Vp8ResilienceIsOffFor2S1TlWithNackEnabled) {
asapersson5f7226f2016-11-25 04:37:00 -0800856 const bool kNackEnabled = true;
857 const size_t kNumStreams = 2;
858 const size_t kNumTl = 1;
emircanbbcc3562017-08-18 00:28:40 -0700859 ResetEncoder("VP8", kNumStreams, kNumTl, kNumSlDummy, kNackEnabled, false);
mflodmancc3d4422017-08-03 08:27:51 -0700860 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson5f7226f2016-11-25 04:37:00 -0800861
862 // Capture a frame and wait for it to synchronize with the encoder thread.
863 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700864 WaitForEncodedFrame(1);
asapersson5f7226f2016-11-25 04:37:00 -0800865 // The encoder have been configured once when the first frame is received.
866 EXPECT_EQ(1, sink_.number_of_reconfigurations());
867 EXPECT_EQ(kVideoCodecVP8, fake_encoder_.codec_config().codecType);
868 EXPECT_EQ(kNumStreams, fake_encoder_.codec_config().numberOfSimulcastStreams);
869 EXPECT_EQ(kNumTl, fake_encoder_.codec_config().VP8()->numberOfTemporalLayers);
870 // Resilience is off for no temporal layers and >1 streams with nack on.
871 EXPECT_EQ(kResilienceOff, fake_encoder_.codec_config().VP8()->resilience);
mflodmancc3d4422017-08-03 08:27:51 -0700872 video_stream_encoder_->Stop();
asapersson5f7226f2016-11-25 04:37:00 -0800873}
874
mflodmancc3d4422017-08-03 08:27:51 -0700875TEST_F(VideoStreamEncoderTest, Vp8ResilienceIsOnFor1S1TLWithNackDisabled) {
asapersson5f7226f2016-11-25 04:37:00 -0800876 const bool kNackEnabled = false;
877 const size_t kNumStreams = 1;
878 const size_t kNumTl = 1;
emircanbbcc3562017-08-18 00:28:40 -0700879 ResetEncoder("VP8", kNumStreams, kNumTl, kNumSlDummy, kNackEnabled, false);
mflodmancc3d4422017-08-03 08:27:51 -0700880 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson5f7226f2016-11-25 04:37:00 -0800881
882 // Capture a frame and wait for it to synchronize with the encoder thread.
883 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700884 WaitForEncodedFrame(1);
asapersson5f7226f2016-11-25 04:37:00 -0800885 // The encoder have been configured once when the first frame is received.
886 EXPECT_EQ(1, sink_.number_of_reconfigurations());
887 EXPECT_EQ(kVideoCodecVP8, fake_encoder_.codec_config().codecType);
888 EXPECT_EQ(kNumStreams, fake_encoder_.codec_config().numberOfSimulcastStreams);
889 EXPECT_EQ(kNumTl, fake_encoder_.codec_config().VP8()->numberOfTemporalLayers);
890 // Resilience is on for no temporal layers with nack off.
891 EXPECT_EQ(kResilientStream, fake_encoder_.codec_config().VP8()->resilience);
mflodmancc3d4422017-08-03 08:27:51 -0700892 video_stream_encoder_->Stop();
asapersson5f7226f2016-11-25 04:37:00 -0800893}
894
mflodmancc3d4422017-08-03 08:27:51 -0700895TEST_F(VideoStreamEncoderTest, Vp8ResilienceIsOnFor1S2TlWithNackEnabled) {
asapersson5f7226f2016-11-25 04:37:00 -0800896 const bool kNackEnabled = true;
897 const size_t kNumStreams = 1;
898 const size_t kNumTl = 2;
emircanbbcc3562017-08-18 00:28:40 -0700899 ResetEncoder("VP8", kNumStreams, kNumTl, kNumSlDummy, kNackEnabled, false);
mflodmancc3d4422017-08-03 08:27:51 -0700900 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson5f7226f2016-11-25 04:37:00 -0800901
902 // Capture a frame and wait for it to synchronize with the encoder thread.
903 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700904 WaitForEncodedFrame(1);
asapersson5f7226f2016-11-25 04:37:00 -0800905 // The encoder have been configured once when the first frame is received.
906 EXPECT_EQ(1, sink_.number_of_reconfigurations());
907 EXPECT_EQ(kVideoCodecVP8, fake_encoder_.codec_config().codecType);
908 EXPECT_EQ(kNumStreams, fake_encoder_.codec_config().numberOfSimulcastStreams);
909 EXPECT_EQ(kNumTl, fake_encoder_.codec_config().VP8()->numberOfTemporalLayers);
910 // Resilience is on for temporal layers.
911 EXPECT_EQ(kResilientStream, fake_encoder_.codec_config().VP8()->resilience);
mflodmancc3d4422017-08-03 08:27:51 -0700912 video_stream_encoder_->Stop();
asapersson5f7226f2016-11-25 04:37:00 -0800913}
914
emircanbbcc3562017-08-18 00:28:40 -0700915TEST_F(VideoStreamEncoderTest, Vp9ResilienceIsOffFor1SL1TLWithNackEnabled) {
916 const bool kNackEnabled = true;
917 const size_t kNumStreams = 1;
918 const size_t kNumTl = 1;
919 const unsigned char kNumSl = 1;
920 ResetEncoder("VP9", kNumStreams, kNumTl, kNumSl, kNackEnabled, false);
921 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
922
923 // Capture a frame and wait for it to synchronize with the encoder thread.
924 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
925 sink_.WaitForEncodedFrame(1);
926 // The encoder have been configured once when the first frame is received.
927 EXPECT_EQ(1, sink_.number_of_reconfigurations());
928 EXPECT_EQ(kVideoCodecVP9, fake_encoder_.codec_config().codecType);
929 EXPECT_EQ(kNumStreams, fake_encoder_.codec_config().numberOfSimulcastStreams);
930 EXPECT_EQ(kNumTl, fake_encoder_.codec_config().VP9()->numberOfTemporalLayers);
931 EXPECT_EQ(kNumSl, fake_encoder_.codec_config().VP9()->numberOfSpatialLayers);
932 // Resilience is off for no spatial and temporal layers with nack on.
933 EXPECT_FALSE(fake_encoder_.codec_config().VP9()->resilienceOn);
934 video_stream_encoder_->Stop();
935}
936
937TEST_F(VideoStreamEncoderTest, Vp9ResilienceIsOnFor1SL1TLWithNackDisabled) {
938 const bool kNackEnabled = false;
939 const size_t kNumStreams = 1;
940 const size_t kNumTl = 1;
941 const unsigned char kNumSl = 1;
942 ResetEncoder("VP9", kNumStreams, kNumTl, kNumSl, kNackEnabled, false);
943 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
944
945 // Capture a frame and wait for it to synchronize with the encoder thread.
946 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
947 sink_.WaitForEncodedFrame(1);
948 // The encoder have been configured once when the first frame is received.
949 EXPECT_EQ(1, sink_.number_of_reconfigurations());
950 EXPECT_EQ(kVideoCodecVP9, fake_encoder_.codec_config().codecType);
951 EXPECT_EQ(kNumStreams, fake_encoder_.codec_config().numberOfSimulcastStreams);
952 EXPECT_EQ(kNumTl, fake_encoder_.codec_config().VP9()->numberOfTemporalLayers);
953 EXPECT_EQ(kNumSl, fake_encoder_.codec_config().VP9()->numberOfSpatialLayers);
954 // Resilience is on if nack is off.
955 EXPECT_TRUE(fake_encoder_.codec_config().VP9()->resilienceOn);
956 video_stream_encoder_->Stop();
957}
958
959TEST_F(VideoStreamEncoderTest, Vp9ResilienceIsOnFor2SL1TLWithNackEnabled) {
960 const bool kNackEnabled = true;
961 const size_t kNumStreams = 1;
962 const size_t kNumTl = 1;
963 const unsigned char kNumSl = 2;
Sergey Silkin86684962018-03-28 19:32:37 +0200964 const int kFrameWidth = kMinVp9SpatialLayerWidth << (kNumSl - 1);
965 const int kFrameHeight = kMinVp9SpatialLayerHeight << (kNumSl - 1);
emircanbbcc3562017-08-18 00:28:40 -0700966 ResetEncoder("VP9", kNumStreams, kNumTl, kNumSl, kNackEnabled, false);
967 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
968
969 // Capture a frame and wait for it to synchronize with the encoder thread.
Sergey Silkin86684962018-03-28 19:32:37 +0200970 video_source_.IncomingCapturedFrame(
971 CreateFrame(1, kFrameWidth, kFrameHeight));
emircanbbcc3562017-08-18 00:28:40 -0700972 sink_.WaitForEncodedFrame(1);
973 // The encoder have been configured once when the first frame is received.
974 EXPECT_EQ(1, sink_.number_of_reconfigurations());
975 EXPECT_EQ(kVideoCodecVP9, fake_encoder_.codec_config().codecType);
976 EXPECT_EQ(kNumStreams, fake_encoder_.codec_config().numberOfSimulcastStreams);
977 EXPECT_EQ(kNumTl, fake_encoder_.codec_config().VP9()->numberOfTemporalLayers);
978 EXPECT_EQ(kNumSl, fake_encoder_.codec_config().VP9()->numberOfSpatialLayers);
979 // Resilience is on for spatial layers.
980 EXPECT_TRUE(fake_encoder_.codec_config().VP9()->resilienceOn);
981 video_stream_encoder_->Stop();
982}
983
984TEST_F(VideoStreamEncoderTest, Vp9ResilienceIsOnFor1SL2TLWithNackEnabled) {
985 const bool kNackEnabled = true;
986 const size_t kNumStreams = 1;
987 const size_t kNumTl = 2;
988 const unsigned char kNumSl = 1;
989 ResetEncoder("VP9", kNumStreams, kNumTl, kNumSl, kNackEnabled, false);
990 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
991
992 // Capture a frame and wait for it to synchronize with the encoder thread.
993 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
994 sink_.WaitForEncodedFrame(1);
995 // The encoder have been configured once when the first frame is received.
996 EXPECT_EQ(1, sink_.number_of_reconfigurations());
997 EXPECT_EQ(kVideoCodecVP9, fake_encoder_.codec_config().codecType);
998 EXPECT_EQ(kNumStreams, fake_encoder_.codec_config().numberOfSimulcastStreams);
999 EXPECT_EQ(kNumTl, fake_encoder_.codec_config().VP9()->numberOfTemporalLayers);
1000 EXPECT_EQ(kNumSl, fake_encoder_.codec_config().VP9()->numberOfSpatialLayers);
1001 // Resilience is on for temporal layers.
1002 EXPECT_TRUE(fake_encoder_.codec_config().VP9()->resilienceOn);
1003 video_stream_encoder_->Stop();
1004}
1005
mflodmancc3d4422017-08-03 08:27:51 -07001006TEST_F(VideoStreamEncoderTest, SwitchSourceDeregisterEncoderAsSink) {
perkj803d97f2016-11-01 11:45:46 -07001007 EXPECT_TRUE(video_source_.has_sinks());
1008 test::FrameForwarder new_video_source;
mflodmancc3d4422017-08-03 08:27:51 -07001009 video_stream_encoder_->SetSource(
sprangc5d62e22017-04-02 23:53:04 -07001010 &new_video_source,
1011 VideoSendStream::DegradationPreference::kMaintainFramerate);
perkj803d97f2016-11-01 11:45:46 -07001012 EXPECT_FALSE(video_source_.has_sinks());
1013 EXPECT_TRUE(new_video_source.has_sinks());
1014
mflodmancc3d4422017-08-03 08:27:51 -07001015 video_stream_encoder_->Stop();
perkj803d97f2016-11-01 11:45:46 -07001016}
1017
mflodmancc3d4422017-08-03 08:27:51 -07001018TEST_F(VideoStreamEncoderTest, SinkWantsRotationApplied) {
perkj803d97f2016-11-01 11:45:46 -07001019 EXPECT_FALSE(video_source_.sink_wants().rotation_applied);
mflodmancc3d4422017-08-03 08:27:51 -07001020 video_stream_encoder_->SetSink(&sink_, true /*rotation_applied*/);
perkj803d97f2016-11-01 11:45:46 -07001021 EXPECT_TRUE(video_source_.sink_wants().rotation_applied);
mflodmancc3d4422017-08-03 08:27:51 -07001022 video_stream_encoder_->Stop();
perkj803d97f2016-11-01 11:45:46 -07001023}
1024
Jonathan Yubc771b72017-12-08 17:04:29 -08001025TEST_F(VideoStreamEncoderTest, TestCpuDowngrades_BalancedMode) {
1026 const int kFramerateFps = 30;
asaperssonf7e294d2017-06-13 23:25:22 -07001027 const int kWidth = 1280;
1028 const int kHeight = 720;
Jonathan Yubc771b72017-12-08 17:04:29 -08001029
1030 // We rely on the automatic resolution adaptation, but we handle framerate
1031 // adaptation manually by mocking the stats proxy.
1032 video_source_.set_adaptation_enabled(true);
asaperssonf7e294d2017-06-13 23:25:22 -07001033
1034 // Enable kBalanced preference, no initial limitation.
Jonathan Yubc771b72017-12-08 17:04:29 -08001035 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
mflodmancc3d4422017-08-03 08:27:51 -07001036 video_stream_encoder_->SetSource(
Jonathan Yubc771b72017-12-08 17:04:29 -08001037 &video_source_,
mflodmancc3d4422017-08-03 08:27:51 -07001038 VideoSendStream::DegradationPreference::kBalanced);
Jonathan Yubc771b72017-12-08 17:04:29 -08001039 VerifyNoLimitation(video_source_.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07001040 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
Jonathan Yubc771b72017-12-08 17:04:29 -08001041 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
asaperssonf7e294d2017-06-13 23:25:22 -07001042 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1043
Jonathan Yubc771b72017-12-08 17:04:29 -08001044 // Adapt down as far as possible.
1045 rtc::VideoSinkWants last_wants;
1046 int64_t t = 1;
1047 int loop_count = 0;
1048 do {
1049 ++loop_count;
1050 last_wants = video_source_.sink_wants();
1051
1052 // Simulate the framerate we've been asked to adapt to.
1053 const int fps = std::min(kFramerateFps, last_wants.max_framerate_fps);
1054 const int frame_interval_ms = rtc::kNumMillisecsPerSec / fps;
1055 VideoSendStream::Stats mock_stats = stats_proxy_->GetStats();
1056 mock_stats.input_frame_rate = fps;
1057 stats_proxy_->SetMockStats(mock_stats);
1058
1059 video_source_.IncomingCapturedFrame(CreateFrame(t, kWidth, kHeight));
1060 sink_.WaitForEncodedFrame(t);
1061 t += frame_interval_ms;
1062
mflodmancc3d4422017-08-03 08:27:51 -07001063 video_stream_encoder_->TriggerCpuOveruse();
Jonathan Yubc771b72017-12-08 17:04:29 -08001064 VerifyBalancedModeFpsRange(
1065 video_source_.sink_wants(),
1066 *video_source_.last_sent_width() * *video_source_.last_sent_height());
1067 } while (video_source_.sink_wants().max_pixel_count <
1068 last_wants.max_pixel_count ||
1069 video_source_.sink_wants().max_framerate_fps <
1070 last_wants.max_framerate_fps);
asaperssonf7e294d2017-06-13 23:25:22 -07001071
Jonathan Yubc771b72017-12-08 17:04:29 -08001072 // Verify that we've adapted all the way down.
1073 stats_proxy_->ResetMockStats();
asaperssonf7e294d2017-06-13 23:25:22 -07001074 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
Jonathan Yubc771b72017-12-08 17:04:29 -08001075 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_framerate);
1076 EXPECT_EQ(loop_count - 1,
asaperssonf7e294d2017-06-13 23:25:22 -07001077 stats_proxy_->GetStats().number_of_cpu_adapt_changes);
Jonathan Yubc771b72017-12-08 17:04:29 -08001078 EXPECT_EQ(kMinPixelsPerFrame, *video_source_.last_sent_width() *
1079 *video_source_.last_sent_height());
1080 EXPECT_EQ(kMinBalancedFramerateFps,
1081 video_source_.sink_wants().max_framerate_fps);
asaperssonf7e294d2017-06-13 23:25:22 -07001082
Jonathan Yubc771b72017-12-08 17:04:29 -08001083 // Adapt back up the same number of times we adapted down.
1084 for (int i = 0; i < loop_count - 1; ++i) {
1085 last_wants = video_source_.sink_wants();
1086
1087 // Simulate the framerate we've been asked to adapt to.
1088 const int fps = std::min(kFramerateFps, last_wants.max_framerate_fps);
1089 const int frame_interval_ms = rtc::kNumMillisecsPerSec / fps;
1090 VideoSendStream::Stats mock_stats = stats_proxy_->GetStats();
1091 mock_stats.input_frame_rate = fps;
1092 stats_proxy_->SetMockStats(mock_stats);
1093
1094 video_source_.IncomingCapturedFrame(CreateFrame(t, kWidth, kHeight));
1095 sink_.WaitForEncodedFrame(t);
1096 t += frame_interval_ms;
1097
mflodmancc3d4422017-08-03 08:27:51 -07001098 video_stream_encoder_->TriggerCpuNormalUsage();
Jonathan Yubc771b72017-12-08 17:04:29 -08001099 VerifyBalancedModeFpsRange(
1100 video_source_.sink_wants(),
1101 *video_source_.last_sent_width() * *video_source_.last_sent_height());
1102 EXPECT_TRUE(video_source_.sink_wants().max_pixel_count >
1103 last_wants.max_pixel_count ||
1104 video_source_.sink_wants().max_framerate_fps >
1105 last_wants.max_framerate_fps);
asaperssonf7e294d2017-06-13 23:25:22 -07001106 }
1107
Jonathan Yubc771b72017-12-08 17:04:29 -08001108 VerifyNoLimitation(video_source_.sink_wants());
1109 stats_proxy_->ResetMockStats();
asaperssonf7e294d2017-06-13 23:25:22 -07001110 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
Jonathan Yubc771b72017-12-08 17:04:29 -08001111 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
1112 EXPECT_EQ((loop_count - 1) * 2,
1113 stats_proxy_->GetStats().number_of_cpu_adapt_changes);
asaperssonf7e294d2017-06-13 23:25:22 -07001114
mflodmancc3d4422017-08-03 08:27:51 -07001115 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07001116}
mflodmancc3d4422017-08-03 08:27:51 -07001117TEST_F(VideoStreamEncoderTest, SinkWantsStoredByDegradationPreference) {
1118 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson02465b82017-04-10 01:12:52 -07001119 VerifyNoLimitation(video_source_.sink_wants());
perkj803d97f2016-11-01 11:45:46 -07001120
sprangc5d62e22017-04-02 23:53:04 -07001121 const int kFrameWidth = 1280;
1122 const int kFrameHeight = 720;
1123 const int kFrameIntervalMs = 1000 / 30;
1124
1125 int frame_timestamp = 1;
perkj803d97f2016-11-01 11:45:46 -07001126
kthelgason5e13d412016-12-01 03:59:51 -08001127 video_source_.IncomingCapturedFrame(
sprangc5d62e22017-04-02 23:53:04 -07001128 CreateFrame(frame_timestamp, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07001129 WaitForEncodedFrame(frame_timestamp);
sprangc5d62e22017-04-02 23:53:04 -07001130 frame_timestamp += kFrameIntervalMs;
1131
perkj803d97f2016-11-01 11:45:46 -07001132 // Trigger CPU overuse.
mflodmancc3d4422017-08-03 08:27:51 -07001133 video_stream_encoder_->TriggerCpuOveruse();
perkj803d97f2016-11-01 11:45:46 -07001134 video_source_.IncomingCapturedFrame(
sprangc5d62e22017-04-02 23:53:04 -07001135 CreateFrame(frame_timestamp, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07001136 WaitForEncodedFrame(frame_timestamp);
sprangc5d62e22017-04-02 23:53:04 -07001137 frame_timestamp += kFrameIntervalMs;
sprang3ea3c772017-03-30 07:23:48 -07001138
asapersson0944a802017-04-07 00:57:58 -07001139 // Default degradation preference is maintain-framerate, so will lower max
sprangc5d62e22017-04-02 23:53:04 -07001140 // wanted resolution.
1141 EXPECT_FALSE(video_source_.sink_wants().target_pixel_count);
1142 EXPECT_LT(video_source_.sink_wants().max_pixel_count,
1143 kFrameWidth * kFrameHeight);
1144 EXPECT_EQ(std::numeric_limits<int>::max(),
1145 video_source_.sink_wants().max_framerate_fps);
1146
1147 // Set new source, switch to maintain-resolution.
perkj803d97f2016-11-01 11:45:46 -07001148 test::FrameForwarder new_video_source;
mflodmancc3d4422017-08-03 08:27:51 -07001149 video_stream_encoder_->SetSource(
perkj803d97f2016-11-01 11:45:46 -07001150 &new_video_source,
1151 VideoSendStream::DegradationPreference::kMaintainResolution);
1152
sprangc5d62e22017-04-02 23:53:04 -07001153 // Initially no degradation registered.
asapersson02465b82017-04-10 01:12:52 -07001154 VerifyNoLimitation(new_video_source.sink_wants());
perkj803d97f2016-11-01 11:45:46 -07001155
sprangc5d62e22017-04-02 23:53:04 -07001156 // Force an input frame rate to be available, or the adaptation call won't
1157 // know what framerate to adapt form.
asapersson02465b82017-04-10 01:12:52 -07001158 const int kInputFps = 30;
sprangc5d62e22017-04-02 23:53:04 -07001159 VideoSendStream::Stats stats = stats_proxy_->GetStats();
asapersson02465b82017-04-10 01:12:52 -07001160 stats.input_frame_rate = kInputFps;
sprangc5d62e22017-04-02 23:53:04 -07001161 stats_proxy_->SetMockStats(stats);
1162
mflodmancc3d4422017-08-03 08:27:51 -07001163 video_stream_encoder_->TriggerCpuOveruse();
perkj803d97f2016-11-01 11:45:46 -07001164 new_video_source.IncomingCapturedFrame(
sprangc5d62e22017-04-02 23:53:04 -07001165 CreateFrame(frame_timestamp, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07001166 WaitForEncodedFrame(frame_timestamp);
sprangc5d62e22017-04-02 23:53:04 -07001167 frame_timestamp += kFrameIntervalMs;
1168
1169 // Some framerate constraint should be set.
sprang84a37592017-02-10 07:04:27 -08001170 EXPECT_FALSE(new_video_source.sink_wants().target_pixel_count);
sprangc5d62e22017-04-02 23:53:04 -07001171 EXPECT_EQ(std::numeric_limits<int>::max(),
1172 new_video_source.sink_wants().max_pixel_count);
asapersson02465b82017-04-10 01:12:52 -07001173 EXPECT_LT(new_video_source.sink_wants().max_framerate_fps, kInputFps);
sprangc5d62e22017-04-02 23:53:04 -07001174
asapersson02465b82017-04-10 01:12:52 -07001175 // Turn off degradation completely.
mflodmancc3d4422017-08-03 08:27:51 -07001176 video_stream_encoder_->SetSource(
sprangc5d62e22017-04-02 23:53:04 -07001177 &new_video_source,
1178 VideoSendStream::DegradationPreference::kDegradationDisabled);
asapersson02465b82017-04-10 01:12:52 -07001179 VerifyNoLimitation(new_video_source.sink_wants());
sprangc5d62e22017-04-02 23:53:04 -07001180
mflodmancc3d4422017-08-03 08:27:51 -07001181 video_stream_encoder_->TriggerCpuOveruse();
sprangc5d62e22017-04-02 23:53:04 -07001182 new_video_source.IncomingCapturedFrame(
1183 CreateFrame(frame_timestamp, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07001184 WaitForEncodedFrame(frame_timestamp);
sprangc5d62e22017-04-02 23:53:04 -07001185 frame_timestamp += kFrameIntervalMs;
1186
1187 // Still no degradation.
asapersson02465b82017-04-10 01:12:52 -07001188 VerifyNoLimitation(new_video_source.sink_wants());
perkj803d97f2016-11-01 11:45:46 -07001189
1190 // Calling SetSource with resolution scaling enabled apply the old SinkWants.
mflodmancc3d4422017-08-03 08:27:51 -07001191 video_stream_encoder_->SetSource(
sprangc5d62e22017-04-02 23:53:04 -07001192 &new_video_source,
1193 VideoSendStream::DegradationPreference::kMaintainFramerate);
1194 EXPECT_LT(new_video_source.sink_wants().max_pixel_count,
1195 kFrameWidth * kFrameHeight);
sprang84a37592017-02-10 07:04:27 -08001196 EXPECT_FALSE(new_video_source.sink_wants().target_pixel_count);
sprangc5d62e22017-04-02 23:53:04 -07001197 EXPECT_EQ(std::numeric_limits<int>::max(),
1198 new_video_source.sink_wants().max_framerate_fps);
1199
1200 // Calling SetSource with framerate scaling enabled apply the old SinkWants.
mflodmancc3d4422017-08-03 08:27:51 -07001201 video_stream_encoder_->SetSource(
sprangc5d62e22017-04-02 23:53:04 -07001202 &new_video_source,
1203 VideoSendStream::DegradationPreference::kMaintainResolution);
1204 EXPECT_FALSE(new_video_source.sink_wants().target_pixel_count);
1205 EXPECT_EQ(std::numeric_limits<int>::max(),
1206 new_video_source.sink_wants().max_pixel_count);
asapersson02465b82017-04-10 01:12:52 -07001207 EXPECT_LT(new_video_source.sink_wants().max_framerate_fps, kInputFps);
perkj803d97f2016-11-01 11:45:46 -07001208
mflodmancc3d4422017-08-03 08:27:51 -07001209 video_stream_encoder_->Stop();
perkj803d97f2016-11-01 11:45:46 -07001210}
1211
mflodmancc3d4422017-08-03 08:27:51 -07001212TEST_F(VideoStreamEncoderTest, StatsTracksQualityAdaptationStats) {
1213 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkj803d97f2016-11-01 11:45:46 -07001214
asaperssonfab67072017-04-04 05:51:49 -07001215 const int kWidth = 1280;
1216 const int kHeight = 720;
asaperssonfab67072017-04-04 05:51:49 -07001217 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001218 WaitForEncodedFrame(1);
asaperssonfab67072017-04-04 05:51:49 -07001219 VideoSendStream::Stats stats = stats_proxy_->GetStats();
1220 EXPECT_FALSE(stats.bw_limited_resolution);
1221 EXPECT_EQ(0, stats.number_of_quality_adapt_changes);
1222
1223 // Trigger adapt down.
mflodmancc3d4422017-08-03 08:27:51 -07001224 video_stream_encoder_->TriggerQualityLow();
asaperssonfab67072017-04-04 05:51:49 -07001225 video_source_.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001226 WaitForEncodedFrame(2);
asaperssonfab67072017-04-04 05:51:49 -07001227
1228 stats = stats_proxy_->GetStats();
1229 EXPECT_TRUE(stats.bw_limited_resolution);
1230 EXPECT_EQ(1, stats.number_of_quality_adapt_changes);
1231
1232 // Trigger adapt up.
mflodmancc3d4422017-08-03 08:27:51 -07001233 video_stream_encoder_->TriggerQualityHigh();
asaperssonfab67072017-04-04 05:51:49 -07001234 video_source_.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001235 WaitForEncodedFrame(3);
asaperssonfab67072017-04-04 05:51:49 -07001236
1237 stats = stats_proxy_->GetStats();
1238 EXPECT_FALSE(stats.bw_limited_resolution);
1239 EXPECT_EQ(2, stats.number_of_quality_adapt_changes);
1240 EXPECT_EQ(0, stats.number_of_cpu_adapt_changes);
1241
mflodmancc3d4422017-08-03 08:27:51 -07001242 video_stream_encoder_->Stop();
asaperssonfab67072017-04-04 05:51:49 -07001243}
1244
mflodmancc3d4422017-08-03 08:27:51 -07001245TEST_F(VideoStreamEncoderTest, StatsTracksCpuAdaptationStats) {
1246 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonfab67072017-04-04 05:51:49 -07001247
1248 const int kWidth = 1280;
1249 const int kHeight = 720;
asaperssonfab67072017-04-04 05:51:49 -07001250 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001251 WaitForEncodedFrame(1);
perkj803d97f2016-11-01 11:45:46 -07001252 VideoSendStream::Stats stats = stats_proxy_->GetStats();
1253 EXPECT_FALSE(stats.cpu_limited_resolution);
1254 EXPECT_EQ(0, stats.number_of_cpu_adapt_changes);
1255
1256 // Trigger CPU overuse.
mflodmancc3d4422017-08-03 08:27:51 -07001257 video_stream_encoder_->TriggerCpuOveruse();
asaperssonfab67072017-04-04 05:51:49 -07001258 video_source_.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001259 WaitForEncodedFrame(2);
perkj803d97f2016-11-01 11:45:46 -07001260
1261 stats = stats_proxy_->GetStats();
1262 EXPECT_TRUE(stats.cpu_limited_resolution);
1263 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1264
1265 // Trigger CPU normal use.
mflodmancc3d4422017-08-03 08:27:51 -07001266 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssonfab67072017-04-04 05:51:49 -07001267 video_source_.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001268 WaitForEncodedFrame(3);
perkj803d97f2016-11-01 11:45:46 -07001269
1270 stats = stats_proxy_->GetStats();
1271 EXPECT_FALSE(stats.cpu_limited_resolution);
1272 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
asaperssonfab67072017-04-04 05:51:49 -07001273 EXPECT_EQ(0, stats.number_of_quality_adapt_changes);
perkj803d97f2016-11-01 11:45:46 -07001274
mflodmancc3d4422017-08-03 08:27:51 -07001275 video_stream_encoder_->Stop();
perkj803d97f2016-11-01 11:45:46 -07001276}
1277
mflodmancc3d4422017-08-03 08:27:51 -07001278TEST_F(VideoStreamEncoderTest, SwitchingSourceKeepsCpuAdaptation) {
1279 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
kthelgason876222f2016-11-29 01:44:11 -08001280
asaperssonfab67072017-04-04 05:51:49 -07001281 const int kWidth = 1280;
1282 const int kHeight = 720;
1283 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001284 WaitForEncodedFrame(1);
kthelgason876222f2016-11-29 01:44:11 -08001285 VideoSendStream::Stats stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001286 EXPECT_FALSE(stats.bw_limited_resolution);
kthelgason876222f2016-11-29 01:44:11 -08001287 EXPECT_FALSE(stats.cpu_limited_resolution);
1288 EXPECT_EQ(0, stats.number_of_cpu_adapt_changes);
1289
asaperssonfab67072017-04-04 05:51:49 -07001290 // Trigger CPU overuse.
mflodmancc3d4422017-08-03 08:27:51 -07001291 video_stream_encoder_->TriggerCpuOveruse();
asaperssonfab67072017-04-04 05:51:49 -07001292 video_source_.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001293 WaitForEncodedFrame(2);
kthelgason876222f2016-11-29 01:44:11 -08001294 stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001295 EXPECT_FALSE(stats.bw_limited_resolution);
kthelgason876222f2016-11-29 01:44:11 -08001296 EXPECT_TRUE(stats.cpu_limited_resolution);
1297 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1298
1299 // Set new source with adaptation still enabled.
1300 test::FrameForwarder new_video_source;
mflodmancc3d4422017-08-03 08:27:51 -07001301 video_stream_encoder_->SetSource(
sprangc5d62e22017-04-02 23:53:04 -07001302 &new_video_source,
1303 VideoSendStream::DegradationPreference::kMaintainFramerate);
kthelgason876222f2016-11-29 01:44:11 -08001304
asaperssonfab67072017-04-04 05:51:49 -07001305 new_video_source.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001306 WaitForEncodedFrame(3);
kthelgason876222f2016-11-29 01:44:11 -08001307 stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001308 EXPECT_FALSE(stats.bw_limited_resolution);
kthelgason876222f2016-11-29 01:44:11 -08001309 EXPECT_TRUE(stats.cpu_limited_resolution);
1310 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1311
1312 // Set adaptation disabled.
mflodmancc3d4422017-08-03 08:27:51 -07001313 video_stream_encoder_->SetSource(
kthelgason876222f2016-11-29 01:44:11 -08001314 &new_video_source,
sprangc5d62e22017-04-02 23:53:04 -07001315 VideoSendStream::DegradationPreference::kDegradationDisabled);
kthelgason876222f2016-11-29 01:44:11 -08001316
asaperssonfab67072017-04-04 05:51:49 -07001317 new_video_source.IncomingCapturedFrame(CreateFrame(4, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001318 WaitForEncodedFrame(4);
kthelgason876222f2016-11-29 01:44:11 -08001319 stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001320 EXPECT_FALSE(stats.bw_limited_resolution);
kthelgason876222f2016-11-29 01:44:11 -08001321 EXPECT_FALSE(stats.cpu_limited_resolution);
1322 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1323
1324 // Set adaptation back to enabled.
mflodmancc3d4422017-08-03 08:27:51 -07001325 video_stream_encoder_->SetSource(
sprangc5d62e22017-04-02 23:53:04 -07001326 &new_video_source,
1327 VideoSendStream::DegradationPreference::kMaintainFramerate);
kthelgason876222f2016-11-29 01:44:11 -08001328
asaperssonfab67072017-04-04 05:51:49 -07001329 new_video_source.IncomingCapturedFrame(CreateFrame(5, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001330 WaitForEncodedFrame(5);
kthelgason876222f2016-11-29 01:44:11 -08001331 stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001332 EXPECT_FALSE(stats.bw_limited_resolution);
kthelgason876222f2016-11-29 01:44:11 -08001333 EXPECT_TRUE(stats.cpu_limited_resolution);
1334 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1335
asaperssonfab67072017-04-04 05:51:49 -07001336 // Trigger CPU normal use.
mflodmancc3d4422017-08-03 08:27:51 -07001337 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssonfab67072017-04-04 05:51:49 -07001338 new_video_source.IncomingCapturedFrame(CreateFrame(6, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001339 WaitForEncodedFrame(6);
kthelgason876222f2016-11-29 01:44:11 -08001340 stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001341 EXPECT_FALSE(stats.bw_limited_resolution);
kthelgason876222f2016-11-29 01:44:11 -08001342 EXPECT_FALSE(stats.cpu_limited_resolution);
1343 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
asapersson02465b82017-04-10 01:12:52 -07001344 EXPECT_EQ(0, stats.number_of_quality_adapt_changes);
kthelgason876222f2016-11-29 01:44:11 -08001345
mflodmancc3d4422017-08-03 08:27:51 -07001346 video_stream_encoder_->Stop();
kthelgason876222f2016-11-29 01:44:11 -08001347}
1348
mflodmancc3d4422017-08-03 08:27:51 -07001349TEST_F(VideoStreamEncoderTest, SwitchingSourceKeepsQualityAdaptation) {
1350 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
kthelgason876222f2016-11-29 01:44:11 -08001351
asaperssonfab67072017-04-04 05:51:49 -07001352 const int kWidth = 1280;
1353 const int kHeight = 720;
1354 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001355 WaitForEncodedFrame(1);
kthelgason876222f2016-11-29 01:44:11 -08001356 VideoSendStream::Stats stats = stats_proxy_->GetStats();
kthelgason876222f2016-11-29 01:44:11 -08001357 EXPECT_FALSE(stats.bw_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001358 EXPECT_FALSE(stats.bw_limited_framerate);
asaperssonfab67072017-04-04 05:51:49 -07001359 EXPECT_EQ(0, stats.number_of_quality_adapt_changes);
kthelgason876222f2016-11-29 01:44:11 -08001360
1361 // Set new source with adaptation still enabled.
1362 test::FrameForwarder new_video_source;
mflodmancc3d4422017-08-03 08:27:51 -07001363 video_stream_encoder_->SetSource(
1364 &new_video_source,
1365 VideoSendStream::DegradationPreference::kBalanced);
kthelgason876222f2016-11-29 01:44:11 -08001366
asaperssonfab67072017-04-04 05:51:49 -07001367 new_video_source.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001368 WaitForEncodedFrame(2);
kthelgason876222f2016-11-29 01:44:11 -08001369 stats = stats_proxy_->GetStats();
kthelgason876222f2016-11-29 01:44:11 -08001370 EXPECT_FALSE(stats.bw_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001371 EXPECT_FALSE(stats.bw_limited_framerate);
asaperssonfab67072017-04-04 05:51:49 -07001372 EXPECT_EQ(0, stats.number_of_quality_adapt_changes);
kthelgason876222f2016-11-29 01:44:11 -08001373
asaperssonfab67072017-04-04 05:51:49 -07001374 // Trigger adapt down.
mflodmancc3d4422017-08-03 08:27:51 -07001375 video_stream_encoder_->TriggerQualityLow();
asaperssonfab67072017-04-04 05:51:49 -07001376 new_video_source.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001377 WaitForEncodedFrame(3);
kthelgason876222f2016-11-29 01:44:11 -08001378 stats = stats_proxy_->GetStats();
kthelgason876222f2016-11-29 01:44:11 -08001379 EXPECT_TRUE(stats.bw_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001380 EXPECT_FALSE(stats.bw_limited_framerate);
asaperssonfab67072017-04-04 05:51:49 -07001381 EXPECT_EQ(1, stats.number_of_quality_adapt_changes);
kthelgason876222f2016-11-29 01:44:11 -08001382
asaperssonfab67072017-04-04 05:51:49 -07001383 // Set new source with adaptation still enabled.
mflodmancc3d4422017-08-03 08:27:51 -07001384 video_stream_encoder_->SetSource(
1385 &new_video_source,
1386 VideoSendStream::DegradationPreference::kBalanced);
kthelgason876222f2016-11-29 01:44:11 -08001387
asaperssonfab67072017-04-04 05:51:49 -07001388 new_video_source.IncomingCapturedFrame(CreateFrame(4, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001389 WaitForEncodedFrame(4);
kthelgason876222f2016-11-29 01:44:11 -08001390 stats = stats_proxy_->GetStats();
kthelgason876222f2016-11-29 01:44:11 -08001391 EXPECT_TRUE(stats.bw_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001392 EXPECT_FALSE(stats.bw_limited_framerate);
asaperssonfab67072017-04-04 05:51:49 -07001393 EXPECT_EQ(1, stats.number_of_quality_adapt_changes);
kthelgason876222f2016-11-29 01:44:11 -08001394
asapersson02465b82017-04-10 01:12:52 -07001395 // Disable resolution scaling.
mflodmancc3d4422017-08-03 08:27:51 -07001396 video_stream_encoder_->SetSource(
kthelgason876222f2016-11-29 01:44:11 -08001397 &new_video_source,
1398 VideoSendStream::DegradationPreference::kMaintainResolution);
1399
asaperssonfab67072017-04-04 05:51:49 -07001400 new_video_source.IncomingCapturedFrame(CreateFrame(5, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001401 WaitForEncodedFrame(5);
kthelgason876222f2016-11-29 01:44:11 -08001402 stats = stats_proxy_->GetStats();
kthelgason876222f2016-11-29 01:44:11 -08001403 EXPECT_FALSE(stats.bw_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001404 EXPECT_FALSE(stats.bw_limited_framerate);
asaperssonfab67072017-04-04 05:51:49 -07001405 EXPECT_EQ(1, stats.number_of_quality_adapt_changes);
1406 EXPECT_EQ(0, stats.number_of_cpu_adapt_changes);
kthelgason876222f2016-11-29 01:44:11 -08001407
mflodmancc3d4422017-08-03 08:27:51 -07001408 video_stream_encoder_->Stop();
kthelgason876222f2016-11-29 01:44:11 -08001409}
1410
mflodmancc3d4422017-08-03 08:27:51 -07001411TEST_F(VideoStreamEncoderTest,
1412 QualityAdaptationStatsAreResetWhenScalerIsDisabled) {
1413 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson36e9eb42017-03-31 05:29:12 -07001414
1415 const int kWidth = 1280;
1416 const int kHeight = 720;
1417 video_source_.set_adaptation_enabled(true);
1418 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001419 WaitForEncodedFrame(1);
asapersson36e9eb42017-03-31 05:29:12 -07001420 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1421 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1422 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1423
1424 // Trigger adapt down.
mflodmancc3d4422017-08-03 08:27:51 -07001425 video_stream_encoder_->TriggerQualityLow();
asapersson36e9eb42017-03-31 05:29:12 -07001426 video_source_.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001427 WaitForEncodedFrame(2);
asapersson36e9eb42017-03-31 05:29:12 -07001428 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1429 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1430 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1431
1432 // Trigger overuse.
mflodmancc3d4422017-08-03 08:27:51 -07001433 video_stream_encoder_->TriggerCpuOveruse();
asapersson36e9eb42017-03-31 05:29:12 -07001434 video_source_.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001435 WaitForEncodedFrame(3);
asapersson36e9eb42017-03-31 05:29:12 -07001436 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1437 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1438 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1439
1440 // Set source with adaptation still enabled but quality scaler is off.
1441 fake_encoder_.SetQualityScaling(false);
mflodmancc3d4422017-08-03 08:27:51 -07001442 video_stream_encoder_->SetSource(
sprangc5d62e22017-04-02 23:53:04 -07001443 &video_source_,
1444 VideoSendStream::DegradationPreference::kMaintainFramerate);
asapersson36e9eb42017-03-31 05:29:12 -07001445
1446 video_source_.IncomingCapturedFrame(CreateFrame(4, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001447 WaitForEncodedFrame(4);
asapersson36e9eb42017-03-31 05:29:12 -07001448 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1449 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1450 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1451
mflodmancc3d4422017-08-03 08:27:51 -07001452 video_stream_encoder_->Stop();
asapersson36e9eb42017-03-31 05:29:12 -07001453}
1454
mflodmancc3d4422017-08-03 08:27:51 -07001455TEST_F(VideoStreamEncoderTest,
1456 StatsTracksCpuAdaptationStatsWhenSwitchingSource) {
1457 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkj803d97f2016-11-01 11:45:46 -07001458
asapersson0944a802017-04-07 00:57:58 -07001459 const int kWidth = 1280;
1460 const int kHeight = 720;
sprang84a37592017-02-10 07:04:27 -08001461 int sequence = 1;
perkj803d97f2016-11-01 11:45:46 -07001462
asaperssonfab67072017-04-04 05:51:49 -07001463 video_source_.IncomingCapturedFrame(CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001464 WaitForEncodedFrame(sequence++);
perkj803d97f2016-11-01 11:45:46 -07001465 VideoSendStream::Stats stats = stats_proxy_->GetStats();
sprang84a37592017-02-10 07:04:27 -08001466 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001467 EXPECT_FALSE(stats.cpu_limited_framerate);
sprang84a37592017-02-10 07:04:27 -08001468 EXPECT_EQ(0, stats.number_of_cpu_adapt_changes);
1469
asapersson02465b82017-04-10 01:12:52 -07001470 // Trigger CPU overuse, should now adapt down.
mflodmancc3d4422017-08-03 08:27:51 -07001471 video_stream_encoder_->TriggerCpuOveruse();
asaperssonfab67072017-04-04 05:51:49 -07001472 video_source_.IncomingCapturedFrame(CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001473 WaitForEncodedFrame(sequence++);
sprang84a37592017-02-10 07:04:27 -08001474 stats = stats_proxy_->GetStats();
perkj803d97f2016-11-01 11:45:46 -07001475 EXPECT_TRUE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001476 EXPECT_FALSE(stats.cpu_limited_framerate);
perkj803d97f2016-11-01 11:45:46 -07001477 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1478
1479 // Set new source with adaptation still enabled.
1480 test::FrameForwarder new_video_source;
mflodmancc3d4422017-08-03 08:27:51 -07001481 video_stream_encoder_->SetSource(
sprangc5d62e22017-04-02 23:53:04 -07001482 &new_video_source,
1483 VideoSendStream::DegradationPreference::kMaintainFramerate);
perkj803d97f2016-11-01 11:45:46 -07001484
1485 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001486 CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001487 WaitForEncodedFrame(sequence++);
perkj803d97f2016-11-01 11:45:46 -07001488 stats = stats_proxy_->GetStats();
1489 EXPECT_TRUE(stats.cpu_limited_resolution);
asapersson09f05612017-05-15 23:40:18 -07001490 EXPECT_FALSE(stats.cpu_limited_framerate);
perkj803d97f2016-11-01 11:45:46 -07001491 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1492
sprangc5d62e22017-04-02 23:53:04 -07001493 // Set cpu adaptation by frame dropping.
mflodmancc3d4422017-08-03 08:27:51 -07001494 video_stream_encoder_->SetSource(
perkj803d97f2016-11-01 11:45:46 -07001495 &new_video_source,
1496 VideoSendStream::DegradationPreference::kMaintainResolution);
1497 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001498 CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001499 WaitForEncodedFrame(sequence++);
perkj803d97f2016-11-01 11:45:46 -07001500 stats = stats_proxy_->GetStats();
sprangc5d62e22017-04-02 23:53:04 -07001501 // Not adapted at first.
perkj803d97f2016-11-01 11:45:46 -07001502 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson09f05612017-05-15 23:40:18 -07001503 EXPECT_FALSE(stats.cpu_limited_framerate);
perkj803d97f2016-11-01 11:45:46 -07001504 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1505
sprangc5d62e22017-04-02 23:53:04 -07001506 // Force an input frame rate to be available, or the adaptation call won't
asapersson09f05612017-05-15 23:40:18 -07001507 // know what framerate to adapt from.
sprangc5d62e22017-04-02 23:53:04 -07001508 VideoSendStream::Stats mock_stats = stats_proxy_->GetStats();
1509 mock_stats.input_frame_rate = 30;
1510 stats_proxy_->SetMockStats(mock_stats);
mflodmancc3d4422017-08-03 08:27:51 -07001511 video_stream_encoder_->TriggerCpuOveruse();
sprangc5d62e22017-04-02 23:53:04 -07001512 stats_proxy_->ResetMockStats();
1513
1514 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001515 CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001516 WaitForEncodedFrame(sequence++);
sprangc5d62e22017-04-02 23:53:04 -07001517
1518 // Framerate now adapted.
1519 stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001520 EXPECT_FALSE(stats.cpu_limited_resolution);
1521 EXPECT_TRUE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001522 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
1523
1524 // Disable CPU adaptation.
mflodmancc3d4422017-08-03 08:27:51 -07001525 video_stream_encoder_->SetSource(
sprangc5d62e22017-04-02 23:53:04 -07001526 &new_video_source,
1527 VideoSendStream::DegradationPreference::kDegradationDisabled);
1528 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001529 CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001530 WaitForEncodedFrame(sequence++);
sprangc5d62e22017-04-02 23:53:04 -07001531
1532 stats = stats_proxy_->GetStats();
1533 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001534 EXPECT_FALSE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001535 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
1536
1537 // Try to trigger overuse. Should not succeed.
1538 stats_proxy_->SetMockStats(mock_stats);
mflodmancc3d4422017-08-03 08:27:51 -07001539 video_stream_encoder_->TriggerCpuOveruse();
sprangc5d62e22017-04-02 23:53:04 -07001540 stats_proxy_->ResetMockStats();
1541
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 // Switch back the source with resolution adaptation enabled.
mflodmancc3d4422017-08-03 08:27:51 -07001548 video_stream_encoder_->SetSource(
sprangc5d62e22017-04-02 23:53:04 -07001549 &video_source_,
1550 VideoSendStream::DegradationPreference::kMaintainFramerate);
asaperssonfab67072017-04-04 05:51:49 -07001551 video_source_.IncomingCapturedFrame(CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001552 WaitForEncodedFrame(sequence++);
perkj803d97f2016-11-01 11:45:46 -07001553 stats = stats_proxy_->GetStats();
1554 EXPECT_TRUE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001555 EXPECT_FALSE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001556 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
perkj803d97f2016-11-01 11:45:46 -07001557
1558 // Trigger CPU normal usage.
mflodmancc3d4422017-08-03 08:27:51 -07001559 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssonfab67072017-04-04 05:51:49 -07001560 video_source_.IncomingCapturedFrame(CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001561 WaitForEncodedFrame(sequence++);
perkj803d97f2016-11-01 11:45:46 -07001562 stats = stats_proxy_->GetStats();
1563 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001564 EXPECT_FALSE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001565 EXPECT_EQ(3, stats.number_of_cpu_adapt_changes);
1566
1567 // Back to the source with adaptation off, set it back to maintain-resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001568 video_stream_encoder_->SetSource(
sprangc5d62e22017-04-02 23:53:04 -07001569 &new_video_source,
1570 VideoSendStream::DegradationPreference::kMaintainResolution);
1571 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001572 CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001573 WaitForEncodedFrame(sequence++);
sprangc5d62e22017-04-02 23:53:04 -07001574 stats = stats_proxy_->GetStats();
asapersson13874762017-06-07 00:01:02 -07001575 // Disabled, since we previously switched the source to disabled.
sprangc5d62e22017-04-02 23:53:04 -07001576 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001577 EXPECT_TRUE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001578 EXPECT_EQ(3, stats.number_of_cpu_adapt_changes);
1579
1580 // Trigger CPU normal usage.
mflodmancc3d4422017-08-03 08:27:51 -07001581 video_stream_encoder_->TriggerCpuNormalUsage();
sprangc5d62e22017-04-02 23:53:04 -07001582 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001583 CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001584 WaitForEncodedFrame(sequence++);
sprangc5d62e22017-04-02 23:53:04 -07001585 stats = stats_proxy_->GetStats();
1586 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001587 EXPECT_FALSE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001588 EXPECT_EQ(4, stats.number_of_cpu_adapt_changes);
asapersson02465b82017-04-10 01:12:52 -07001589 EXPECT_EQ(0, stats.number_of_quality_adapt_changes);
perkj803d97f2016-11-01 11:45:46 -07001590
mflodmancc3d4422017-08-03 08:27:51 -07001591 video_stream_encoder_->Stop();
perkj803d97f2016-11-01 11:45:46 -07001592}
1593
mflodmancc3d4422017-08-03 08:27:51 -07001594TEST_F(VideoStreamEncoderTest, StatsTracksPreferredBitrate) {
1595 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
Erik Språng08127a92016-11-16 16:41:30 +01001596
asaperssonfab67072017-04-04 05:51:49 -07001597 const int kWidth = 1280;
1598 const int kHeight = 720;
1599 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001600 WaitForEncodedFrame(1);
Erik Språng08127a92016-11-16 16:41:30 +01001601
1602 VideoSendStream::Stats stats = stats_proxy_->GetStats();
1603 EXPECT_EQ(video_encoder_config_.max_bitrate_bps,
1604 stats.preferred_media_bitrate_bps);
1605
mflodmancc3d4422017-08-03 08:27:51 -07001606 video_stream_encoder_->Stop();
Erik Språng08127a92016-11-16 16:41:30 +01001607}
1608
mflodmancc3d4422017-08-03 08:27:51 -07001609TEST_F(VideoStreamEncoderTest,
1610 ScalingUpAndDownDoesNothingWithMaintainResolution) {
asaperssonfab67072017-04-04 05:51:49 -07001611 const int kWidth = 1280;
1612 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001613 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
kthelgason876222f2016-11-29 01:44:11 -08001614
asaperssonfab67072017-04-04 05:51:49 -07001615 // Expect no scaling to begin with.
asapersson02465b82017-04-10 01:12:52 -07001616 VerifyNoLimitation(video_source_.sink_wants());
kthelgason876222f2016-11-29 01:44:11 -08001617
asaperssonfab67072017-04-04 05:51:49 -07001618 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001619 WaitForEncodedFrame(1);
kthelgason876222f2016-11-29 01:44:11 -08001620
asaperssonfab67072017-04-04 05:51:49 -07001621 // Trigger scale down.
mflodmancc3d4422017-08-03 08:27:51 -07001622 video_stream_encoder_->TriggerQualityLow();
kthelgason5e13d412016-12-01 03:59:51 -08001623
asaperssonfab67072017-04-04 05:51:49 -07001624 video_source_.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001625 WaitForEncodedFrame(2);
kthelgason5e13d412016-12-01 03:59:51 -08001626
kthelgason876222f2016-11-29 01:44:11 -08001627 // Expect a scale down.
1628 EXPECT_TRUE(video_source_.sink_wants().max_pixel_count);
asaperssonfab67072017-04-04 05:51:49 -07001629 EXPECT_LT(video_source_.sink_wants().max_pixel_count, kWidth * kHeight);
kthelgason876222f2016-11-29 01:44:11 -08001630
asapersson02465b82017-04-10 01:12:52 -07001631 // Set resolution scaling disabled.
kthelgason876222f2016-11-29 01:44:11 -08001632 test::FrameForwarder new_video_source;
mflodmancc3d4422017-08-03 08:27:51 -07001633 video_stream_encoder_->SetSource(
kthelgason876222f2016-11-29 01:44:11 -08001634 &new_video_source,
1635 VideoSendStream::DegradationPreference::kMaintainResolution);
1636
asaperssonfab67072017-04-04 05:51:49 -07001637 // Trigger scale down.
mflodmancc3d4422017-08-03 08:27:51 -07001638 video_stream_encoder_->TriggerQualityLow();
asaperssonfab67072017-04-04 05:51:49 -07001639 new_video_source.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001640 WaitForEncodedFrame(3);
kthelgason876222f2016-11-29 01:44:11 -08001641
asaperssonfab67072017-04-04 05:51:49 -07001642 // Expect no scaling.
sprangc5d62e22017-04-02 23:53:04 -07001643 EXPECT_EQ(std::numeric_limits<int>::max(),
1644 new_video_source.sink_wants().max_pixel_count);
kthelgason876222f2016-11-29 01:44:11 -08001645
asaperssonfab67072017-04-04 05:51:49 -07001646 // Trigger scale up.
mflodmancc3d4422017-08-03 08:27:51 -07001647 video_stream_encoder_->TriggerQualityHigh();
asaperssonfab67072017-04-04 05:51:49 -07001648 new_video_source.IncomingCapturedFrame(CreateFrame(4, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001649 WaitForEncodedFrame(4);
kthelgason876222f2016-11-29 01:44:11 -08001650
asapersson02465b82017-04-10 01:12:52 -07001651 // Expect nothing to change, still no scaling.
sprangc5d62e22017-04-02 23:53:04 -07001652 EXPECT_EQ(std::numeric_limits<int>::max(),
1653 new_video_source.sink_wants().max_pixel_count);
kthelgason876222f2016-11-29 01:44:11 -08001654
mflodmancc3d4422017-08-03 08:27:51 -07001655 video_stream_encoder_->Stop();
kthelgason876222f2016-11-29 01:44:11 -08001656}
1657
mflodmancc3d4422017-08-03 08:27:51 -07001658TEST_F(VideoStreamEncoderTest,
1659 SkipsSameAdaptDownRequest_MaintainFramerateMode) {
asapersson02465b82017-04-10 01:12:52 -07001660 const int kWidth = 1280;
1661 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001662 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson02465b82017-04-10 01:12:52 -07001663
1664 // Enable kMaintainFramerate preference, no initial limitation.
1665 test::FrameForwarder source;
mflodmancc3d4422017-08-03 08:27:51 -07001666 video_stream_encoder_->SetSource(
asapersson02465b82017-04-10 01:12:52 -07001667 &source, VideoSendStream::DegradationPreference::kMaintainFramerate);
1668
1669 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001670 WaitForEncodedFrame(1);
asapersson02465b82017-04-10 01:12:52 -07001671 VerifyNoLimitation(source.sink_wants());
1672 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1673 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1674
1675 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001676 video_stream_encoder_->TriggerCpuOveruse();
asapersson09f05612017-05-15 23:40:18 -07001677 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
asapersson02465b82017-04-10 01:12:52 -07001678 const int kLastMaxPixelCount = source.sink_wants().max_pixel_count;
1679 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1680 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1681
1682 // Trigger adapt down for same input resolution, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07001683 video_stream_encoder_->TriggerCpuOveruse();
asapersson02465b82017-04-10 01:12:52 -07001684 EXPECT_EQ(kLastMaxPixelCount, source.sink_wants().max_pixel_count);
1685 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1686 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1687
mflodmancc3d4422017-08-03 08:27:51 -07001688 video_stream_encoder_->Stop();
asapersson02465b82017-04-10 01:12:52 -07001689}
1690
mflodmancc3d4422017-08-03 08:27:51 -07001691TEST_F(VideoStreamEncoderTest, SkipsSameOrLargerAdaptDownRequest_BalancedMode) {
asaperssonf7e294d2017-06-13 23:25:22 -07001692 const int kWidth = 1280;
1693 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001694 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -07001695
1696 // Enable kBalanced preference, no initial limitation.
1697 test::FrameForwarder source;
mflodmancc3d4422017-08-03 08:27:51 -07001698 video_stream_encoder_->SetSource(
1699 &source,
1700 VideoSendStream::DegradationPreference::kBalanced);
asaperssonf7e294d2017-06-13 23:25:22 -07001701 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
1702 sink_.WaitForEncodedFrame(1);
1703 VerifyNoLimitation(source.sink_wants());
1704
1705 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001706 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07001707 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
1708 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1709 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1710 const int kLastMaxPixelCount = source.sink_wants().max_pixel_count;
1711
1712 // Trigger adapt down for same input resolution, expect no change.
1713 source.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
1714 sink_.WaitForEncodedFrame(2);
mflodmancc3d4422017-08-03 08:27:51 -07001715 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07001716 EXPECT_EQ(kLastMaxPixelCount, source.sink_wants().max_pixel_count);
1717 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1718 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1719
1720 // Trigger adapt down for larger input resolution, expect no change.
1721 source.IncomingCapturedFrame(CreateFrame(3, kWidth + 1, kHeight + 1));
1722 sink_.WaitForEncodedFrame(3);
mflodmancc3d4422017-08-03 08:27:51 -07001723 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07001724 EXPECT_EQ(kLastMaxPixelCount, source.sink_wants().max_pixel_count);
1725 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1726 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1727
mflodmancc3d4422017-08-03 08:27:51 -07001728 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07001729}
1730
mflodmancc3d4422017-08-03 08:27:51 -07001731TEST_F(VideoStreamEncoderTest,
1732 NoChangeForInitialNormalUsage_MaintainFramerateMode) {
asapersson02465b82017-04-10 01:12:52 -07001733 const int kWidth = 1280;
1734 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001735 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson02465b82017-04-10 01:12:52 -07001736
1737 // Enable kMaintainFramerate preference, no initial limitation.
1738 test::FrameForwarder source;
mflodmancc3d4422017-08-03 08:27:51 -07001739 video_stream_encoder_->SetSource(
asapersson02465b82017-04-10 01:12:52 -07001740 &source, VideoSendStream::DegradationPreference::kMaintainFramerate);
1741
1742 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001743 WaitForEncodedFrame(kWidth, kHeight);
asapersson02465b82017-04-10 01:12:52 -07001744 VerifyNoLimitation(source.sink_wants());
1745 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1746 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1747
1748 // Trigger adapt up, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07001749 video_stream_encoder_->TriggerCpuNormalUsage();
asapersson02465b82017-04-10 01:12:52 -07001750 VerifyNoLimitation(source.sink_wants());
1751 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1752 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1753
mflodmancc3d4422017-08-03 08:27:51 -07001754 video_stream_encoder_->Stop();
asapersson02465b82017-04-10 01:12:52 -07001755}
1756
mflodmancc3d4422017-08-03 08:27:51 -07001757TEST_F(VideoStreamEncoderTest,
1758 NoChangeForInitialNormalUsage_MaintainResolutionMode) {
asapersson02465b82017-04-10 01:12:52 -07001759 const int kWidth = 1280;
1760 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001761 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson02465b82017-04-10 01:12:52 -07001762
1763 // Enable kMaintainResolution preference, no initial limitation.
1764 test::FrameForwarder source;
mflodmancc3d4422017-08-03 08:27:51 -07001765 video_stream_encoder_->SetSource(
asapersson02465b82017-04-10 01:12:52 -07001766 &source, VideoSendStream::DegradationPreference::kMaintainResolution);
1767
1768 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001769 WaitForEncodedFrame(kWidth, kHeight);
asapersson02465b82017-04-10 01:12:52 -07001770 VerifyNoLimitation(source.sink_wants());
asapersson09f05612017-05-15 23:40:18 -07001771 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
asapersson02465b82017-04-10 01:12:52 -07001772 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1773
1774 // Trigger adapt up, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07001775 video_stream_encoder_->TriggerCpuNormalUsage();
asapersson02465b82017-04-10 01:12:52 -07001776 VerifyNoLimitation(source.sink_wants());
asapersson09f05612017-05-15 23:40:18 -07001777 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
asapersson02465b82017-04-10 01:12:52 -07001778 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1779
mflodmancc3d4422017-08-03 08:27:51 -07001780 video_stream_encoder_->Stop();
asapersson02465b82017-04-10 01:12:52 -07001781}
1782
mflodmancc3d4422017-08-03 08:27:51 -07001783TEST_F(VideoStreamEncoderTest, NoChangeForInitialNormalUsage_BalancedMode) {
asaperssonf7e294d2017-06-13 23:25:22 -07001784 const int kWidth = 1280;
1785 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001786 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -07001787
1788 // Enable kBalanced preference, no initial limitation.
1789 test::FrameForwarder source;
mflodmancc3d4422017-08-03 08:27:51 -07001790 video_stream_encoder_->SetSource(
1791 &source,
1792 VideoSendStream::DegradationPreference::kBalanced);
asaperssonf7e294d2017-06-13 23:25:22 -07001793
1794 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
1795 sink_.WaitForEncodedFrame(kWidth, kHeight);
1796 VerifyNoLimitation(source.sink_wants());
1797 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1798 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
1799 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1800
1801 // Trigger adapt up, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07001802 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07001803 VerifyNoLimitation(source.sink_wants());
1804 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1805 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
1806 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1807
mflodmancc3d4422017-08-03 08:27:51 -07001808 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07001809}
1810
mflodmancc3d4422017-08-03 08:27:51 -07001811TEST_F(VideoStreamEncoderTest, NoChangeForInitialNormalUsage_DisabledMode) {
asapersson09f05612017-05-15 23:40:18 -07001812 const int kWidth = 1280;
1813 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001814 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson09f05612017-05-15 23:40:18 -07001815
1816 // Enable kDegradationDisabled preference, no initial limitation.
1817 test::FrameForwarder source;
mflodmancc3d4422017-08-03 08:27:51 -07001818 video_stream_encoder_->SetSource(
asapersson09f05612017-05-15 23:40:18 -07001819 &source, VideoSendStream::DegradationPreference::kDegradationDisabled);
1820
1821 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
1822 sink_.WaitForEncodedFrame(kWidth, kHeight);
1823 VerifyNoLimitation(source.sink_wants());
1824 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1825 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
1826 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1827
1828 // Trigger adapt up, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07001829 video_stream_encoder_->TriggerQualityHigh();
asapersson09f05612017-05-15 23:40:18 -07001830 VerifyNoLimitation(source.sink_wants());
1831 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1832 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
1833 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1834
mflodmancc3d4422017-08-03 08:27:51 -07001835 video_stream_encoder_->Stop();
asapersson09f05612017-05-15 23:40:18 -07001836}
1837
mflodmancc3d4422017-08-03 08:27:51 -07001838TEST_F(VideoStreamEncoderTest,
1839 AdaptsResolutionForLowQuality_MaintainFramerateMode) {
asapersson02465b82017-04-10 01:12:52 -07001840 const int kWidth = 1280;
1841 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001842 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson02465b82017-04-10 01:12:52 -07001843
1844 // Enable kMaintainFramerate preference, no initial limitation.
1845 AdaptingFrameForwarder source;
1846 source.set_adaptation_enabled(true);
mflodmancc3d4422017-08-03 08:27:51 -07001847 video_stream_encoder_->SetSource(
asapersson02465b82017-04-10 01:12:52 -07001848 &source, VideoSendStream::DegradationPreference::kMaintainFramerate);
1849
1850 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001851 WaitForEncodedFrame(1);
asapersson02465b82017-04-10 01:12:52 -07001852 VerifyNoLimitation(source.sink_wants());
1853 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1854 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1855
1856 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001857 video_stream_encoder_->TriggerQualityLow();
asapersson02465b82017-04-10 01:12:52 -07001858 source.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001859 WaitForEncodedFrame(2);
asapersson09f05612017-05-15 23:40:18 -07001860 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
asapersson02465b82017-04-10 01:12:52 -07001861 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1862 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1863
1864 // Trigger adapt up, expect no restriction.
mflodmancc3d4422017-08-03 08:27:51 -07001865 video_stream_encoder_->TriggerQualityHigh();
asapersson02465b82017-04-10 01:12:52 -07001866 VerifyNoLimitation(source.sink_wants());
1867 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1868 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1869 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1870
mflodmancc3d4422017-08-03 08:27:51 -07001871 video_stream_encoder_->Stop();
asapersson02465b82017-04-10 01:12:52 -07001872}
1873
mflodmancc3d4422017-08-03 08:27:51 -07001874TEST_F(VideoStreamEncoderTest,
1875 AdaptsFramerateForLowQuality_MaintainResolutionMode) {
asapersson09f05612017-05-15 23:40:18 -07001876 const int kWidth = 1280;
1877 const int kHeight = 720;
1878 const int kInputFps = 30;
mflodmancc3d4422017-08-03 08:27:51 -07001879 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson09f05612017-05-15 23:40:18 -07001880
1881 VideoSendStream::Stats stats = stats_proxy_->GetStats();
1882 stats.input_frame_rate = kInputFps;
1883 stats_proxy_->SetMockStats(stats);
1884
1885 // Expect no scaling to begin with (preference: kMaintainFramerate).
1886 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
1887 sink_.WaitForEncodedFrame(1);
1888 VerifyNoLimitation(video_source_.sink_wants());
1889
1890 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001891 video_stream_encoder_->TriggerQualityLow();
asapersson09f05612017-05-15 23:40:18 -07001892 video_source_.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
1893 sink_.WaitForEncodedFrame(2);
1894 VerifyFpsMaxResolutionLt(video_source_.sink_wants(), kWidth * kHeight);
1895
1896 // Enable kMaintainResolution preference.
1897 test::FrameForwarder new_video_source;
mflodmancc3d4422017-08-03 08:27:51 -07001898 video_stream_encoder_->SetSource(
asapersson09f05612017-05-15 23:40:18 -07001899 &new_video_source,
1900 VideoSendStream::DegradationPreference::kMaintainResolution);
1901 VerifyNoLimitation(new_video_source.sink_wants());
1902
1903 // Trigger adapt down, expect reduced framerate.
mflodmancc3d4422017-08-03 08:27:51 -07001904 video_stream_encoder_->TriggerQualityLow();
asapersson09f05612017-05-15 23:40:18 -07001905 new_video_source.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
1906 sink_.WaitForEncodedFrame(3);
1907 VerifyFpsLtResolutionMax(new_video_source.sink_wants(), kInputFps);
1908
1909 // Trigger adapt up, expect no restriction.
mflodmancc3d4422017-08-03 08:27:51 -07001910 video_stream_encoder_->TriggerQualityHigh();
asapersson09f05612017-05-15 23:40:18 -07001911 VerifyNoLimitation(new_video_source.sink_wants());
1912
mflodmancc3d4422017-08-03 08:27:51 -07001913 video_stream_encoder_->Stop();
asapersson09f05612017-05-15 23:40:18 -07001914}
1915
mflodmancc3d4422017-08-03 08:27:51 -07001916TEST_F(VideoStreamEncoderTest, DoesNotScaleBelowSetResolutionLimit) {
asaperssond0de2952017-04-21 01:47:31 -07001917 const int kWidth = 1280;
1918 const int kHeight = 720;
1919 const size_t kNumFrames = 10;
1920
mflodmancc3d4422017-08-03 08:27:51 -07001921 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
kthelgason5e13d412016-12-01 03:59:51 -08001922
asaperssond0de2952017-04-21 01:47:31 -07001923 // Enable adapter, expected input resolutions when downscaling:
asapersson142fcc92017-08-17 08:58:54 -07001924 // 1280x720 -> 960x540 -> 640x360 -> 480x270 -> 320x180 (kMinPixelsPerFrame)
asaperssond0de2952017-04-21 01:47:31 -07001925 video_source_.set_adaptation_enabled(true);
1926
1927 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1928 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1929
1930 int downscales = 0;
1931 for (size_t i = 1; i <= kNumFrames; i++) {
1932 video_source_.IncomingCapturedFrame(CreateFrame(i, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001933 WaitForEncodedFrame(i);
asaperssond0de2952017-04-21 01:47:31 -07001934
asaperssonfab67072017-04-04 05:51:49 -07001935 // Trigger scale down.
asaperssond0de2952017-04-21 01:47:31 -07001936 rtc::VideoSinkWants last_wants = video_source_.sink_wants();
mflodmancc3d4422017-08-03 08:27:51 -07001937 video_stream_encoder_->TriggerQualityLow();
sprangc5d62e22017-04-02 23:53:04 -07001938 EXPECT_GE(video_source_.sink_wants().max_pixel_count, kMinPixelsPerFrame);
asaperssond0de2952017-04-21 01:47:31 -07001939
1940 if (video_source_.sink_wants().max_pixel_count < last_wants.max_pixel_count)
1941 ++downscales;
1942
1943 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1944 EXPECT_EQ(downscales,
1945 stats_proxy_->GetStats().number_of_quality_adapt_changes);
1946 EXPECT_GT(downscales, 0);
kthelgason5e13d412016-12-01 03:59:51 -08001947 }
mflodmancc3d4422017-08-03 08:27:51 -07001948 video_stream_encoder_->Stop();
asaperssond0de2952017-04-21 01:47:31 -07001949}
1950
mflodmancc3d4422017-08-03 08:27:51 -07001951TEST_F(VideoStreamEncoderTest,
asaperssond0de2952017-04-21 01:47:31 -07001952 AdaptsResolutionUpAndDownTwiceOnOveruse_MaintainFramerateMode) {
1953 const int kWidth = 1280;
1954 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001955 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssond0de2952017-04-21 01:47:31 -07001956
1957 // Enable kMaintainFramerate preference, no initial limitation.
1958 AdaptingFrameForwarder source;
1959 source.set_adaptation_enabled(true);
mflodmancc3d4422017-08-03 08:27:51 -07001960 video_stream_encoder_->SetSource(
asaperssond0de2952017-04-21 01:47:31 -07001961 &source, VideoSendStream::DegradationPreference::kMaintainFramerate);
1962
1963 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001964 WaitForEncodedFrame(kWidth, kHeight);
asaperssond0de2952017-04-21 01:47:31 -07001965 VerifyNoLimitation(source.sink_wants());
1966 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1967 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1968
1969 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001970 video_stream_encoder_->TriggerCpuOveruse();
asaperssond0de2952017-04-21 01:47:31 -07001971 source.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001972 WaitForEncodedFrame(2);
asapersson09f05612017-05-15 23:40:18 -07001973 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
asaperssond0de2952017-04-21 01:47:31 -07001974 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1975 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1976
1977 // Trigger adapt up, expect no restriction.
mflodmancc3d4422017-08-03 08:27:51 -07001978 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssond0de2952017-04-21 01:47:31 -07001979 source.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001980 WaitForEncodedFrame(kWidth, kHeight);
asaperssond0de2952017-04-21 01:47:31 -07001981 VerifyNoLimitation(source.sink_wants());
1982 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1983 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1984
1985 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001986 video_stream_encoder_->TriggerCpuOveruse();
asaperssond0de2952017-04-21 01:47:31 -07001987 source.IncomingCapturedFrame(CreateFrame(4, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001988 WaitForEncodedFrame(4);
asapersson09f05612017-05-15 23:40:18 -07001989 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
asaperssond0de2952017-04-21 01:47:31 -07001990 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1991 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1992
1993 // Trigger adapt up, expect no restriction.
mflodmancc3d4422017-08-03 08:27:51 -07001994 video_stream_encoder_->TriggerCpuNormalUsage();
asapersson09f05612017-05-15 23:40:18 -07001995 source.IncomingCapturedFrame(CreateFrame(5, kWidth, kHeight));
1996 sink_.WaitForEncodedFrame(kWidth, kHeight);
asaperssond0de2952017-04-21 01:47:31 -07001997 VerifyNoLimitation(source.sink_wants());
1998 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1999 EXPECT_EQ(4, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2000
mflodmancc3d4422017-08-03 08:27:51 -07002001 video_stream_encoder_->Stop();
asaperssond0de2952017-04-21 01:47:31 -07002002}
2003
mflodmancc3d4422017-08-03 08:27:51 -07002004TEST_F(VideoStreamEncoderTest,
asaperssonf7e294d2017-06-13 23:25:22 -07002005 AdaptsResolutionUpAndDownTwiceForLowQuality_BalancedMode_NoFpsLimit) {
2006 const int kWidth = 1280;
2007 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07002008 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -07002009
2010 // Enable kBalanced preference, no initial limitation.
2011 AdaptingFrameForwarder source;
2012 source.set_adaptation_enabled(true);
mflodmancc3d4422017-08-03 08:27:51 -07002013 video_stream_encoder_->SetSource(
2014 &source,
2015 VideoSendStream::DegradationPreference::kBalanced);
asaperssonf7e294d2017-06-13 23:25:22 -07002016
2017 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
2018 sink_.WaitForEncodedFrame(kWidth, kHeight);
2019 VerifyNoLimitation(source.sink_wants());
2020 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2021 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2022
2023 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07002024 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002025 source.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
2026 sink_.WaitForEncodedFrame(2);
2027 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
2028 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2029 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2030
2031 // Trigger adapt up, expect no restriction.
mflodmancc3d4422017-08-03 08:27:51 -07002032 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002033 source.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
2034 sink_.WaitForEncodedFrame(kWidth, kHeight);
2035 VerifyNoLimitation(source.sink_wants());
2036 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2037 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2038
2039 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07002040 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002041 source.IncomingCapturedFrame(CreateFrame(4, kWidth, kHeight));
2042 sink_.WaitForEncodedFrame(4);
2043 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
2044 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2045 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2046
2047 // Trigger adapt up, expect no restriction.
mflodmancc3d4422017-08-03 08:27:51 -07002048 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002049 source.IncomingCapturedFrame(CreateFrame(5, kWidth, kHeight));
2050 sink_.WaitForEncodedFrame(kWidth, kHeight);
2051 VerifyNoLimitation(source.sink_wants());
2052 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2053 EXPECT_EQ(4, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2054
mflodmancc3d4422017-08-03 08:27:51 -07002055 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07002056}
2057
mflodmancc3d4422017-08-03 08:27:51 -07002058TEST_F(VideoStreamEncoderTest,
asaperssond0de2952017-04-21 01:47:31 -07002059 AdaptsResolutionOnOveruseAndLowQuality_MaintainFramerateMode) {
2060 const int kWidth = 1280;
2061 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07002062 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssond0de2952017-04-21 01:47:31 -07002063
2064 // Enable kMaintainFramerate preference, no initial limitation.
2065 AdaptingFrameForwarder source;
2066 source.set_adaptation_enabled(true);
mflodmancc3d4422017-08-03 08:27:51 -07002067 video_stream_encoder_->SetSource(
asaperssond0de2952017-04-21 01:47:31 -07002068 &source, VideoSendStream::DegradationPreference::kMaintainFramerate);
2069
2070 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002071 WaitForEncodedFrame(kWidth, kHeight);
asaperssond0de2952017-04-21 01:47:31 -07002072 VerifyNoLimitation(source.sink_wants());
2073 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2074 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2075 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2076 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2077
2078 // Trigger cpu adapt down, expect scaled down resolution (960x540).
mflodmancc3d4422017-08-03 08:27:51 -07002079 video_stream_encoder_->TriggerCpuOveruse();
asaperssond0de2952017-04-21 01:47:31 -07002080 source.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002081 WaitForEncodedFrame(2);
asapersson09f05612017-05-15 23:40:18 -07002082 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
asaperssond0de2952017-04-21 01:47:31 -07002083 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2084 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2085 EXPECT_EQ(1, 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 (640x360).
mflodmancc3d4422017-08-03 08:27:51 -07002089 video_stream_encoder_->TriggerCpuOveruse();
asaperssond0de2952017-04-21 01:47:31 -07002090 source.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002091 WaitForEncodedFrame(3);
asapersson09f05612017-05-15 23:40:18 -07002092 VerifyFpsMaxResolutionLt(source.sink_wants(), source.last_wants());
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(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2096 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2097
Jonathan Yubc771b72017-12-08 17:04:29 -08002098 // Trigger cpu adapt down, expect scaled down resolution (480x270).
mflodmancc3d4422017-08-03 08:27:51 -07002099 video_stream_encoder_->TriggerCpuOveruse();
asaperssond0de2952017-04-21 01:47:31 -07002100 source.IncomingCapturedFrame(CreateFrame(4, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002101 WaitForEncodedFrame(4);
Jonathan Yubc771b72017-12-08 17:04:29 -08002102 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);
Jonathan Yubc771b72017-12-08 17:04:29 -08002105 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
asaperssond0de2952017-04-21 01:47:31 -07002106 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2107
Jonathan Yubc771b72017-12-08 17:04:29 -08002108 // Trigger quality adapt down, expect scaled down resolution (320x180).
mflodmancc3d4422017-08-03 08:27:51 -07002109 video_stream_encoder_->TriggerQualityLow();
asaperssond0de2952017-04-21 01:47:31 -07002110 source.IncomingCapturedFrame(CreateFrame(5, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002111 WaitForEncodedFrame(5);
asapersson09f05612017-05-15 23:40:18 -07002112 VerifyFpsMaxResolutionLt(source.sink_wants(), source.last_wants());
Jonathan Yubc771b72017-12-08 17:04:29 -08002113 rtc::VideoSinkWants last_wants = source.sink_wants();
asaperssond0de2952017-04-21 01:47:31 -07002114 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2115 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2116 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2117 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2118
Jonathan Yubc771b72017-12-08 17:04:29 -08002119 // Trigger quality adapt down, expect no change (min resolution reached).
2120 video_stream_encoder_->TriggerQualityLow();
2121 source.IncomingCapturedFrame(CreateFrame(6, kWidth, kHeight));
2122 WaitForEncodedFrame(6);
2123 VerifyFpsMaxResolutionEq(source.sink_wants(), last_wants);
2124 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
2129 // Trigger cpu adapt up, expect upscaled resolution (480x270).
mflodmancc3d4422017-08-03 08:27:51 -07002130 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssond0de2952017-04-21 01:47:31 -07002131 source.IncomingCapturedFrame(CreateFrame(7, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002132 WaitForEncodedFrame(7);
asapersson09f05612017-05-15 23:40:18 -07002133 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
Jonathan Yubc771b72017-12-08 17:04:29 -08002134 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2135 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2136 EXPECT_EQ(4, 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 (640x360).
2140 video_stream_encoder_->TriggerCpuNormalUsage();
2141 source.IncomingCapturedFrame(CreateFrame(8, kWidth, kHeight));
2142 WaitForEncodedFrame(8);
2143 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
2144 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2145 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2146 EXPECT_EQ(5, 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 (960x540).
2150 video_stream_encoder_->TriggerCpuNormalUsage();
2151 source.IncomingCapturedFrame(CreateFrame(9, kWidth, kHeight));
2152 WaitForEncodedFrame(9);
2153 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
asaperssond0de2952017-04-21 01:47:31 -07002154 last_wants = source.sink_wants();
2155 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2156 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
Jonathan Yubc771b72017-12-08 17:04:29 -08002157 EXPECT_EQ(6, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
asaperssond0de2952017-04-21 01:47:31 -07002158 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2159
2160 // Trigger cpu adapt up, no cpu downgrades, expect no change (960x540).
mflodmancc3d4422017-08-03 08:27:51 -07002161 video_stream_encoder_->TriggerCpuNormalUsage();
Jonathan Yubc771b72017-12-08 17:04:29 -08002162 source.IncomingCapturedFrame(CreateFrame(10, kWidth, kHeight));
2163 WaitForEncodedFrame(10);
asapersson09f05612017-05-15 23:40:18 -07002164 VerifyFpsEqResolutionEq(source.sink_wants(), last_wants);
asaperssond0de2952017-04-21 01:47:31 -07002165 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 quality adapt up, expect no restriction (1280x720).
mflodmancc3d4422017-08-03 08:27:51 -07002171 video_stream_encoder_->TriggerQualityHigh();
Jonathan Yubc771b72017-12-08 17:04:29 -08002172 source.IncomingCapturedFrame(CreateFrame(11, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002173 WaitForEncodedFrame(kWidth, kHeight);
asapersson09f05612017-05-15 23:40:18 -07002174 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
asaperssond0de2952017-04-21 01:47:31 -07002175 VerifyNoLimitation(source.sink_wants());
2176 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2177 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
Jonathan Yubc771b72017-12-08 17:04:29 -08002178 EXPECT_EQ(6, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
asaperssond0de2952017-04-21 01:47:31 -07002179 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
kthelgason5e13d412016-12-01 03:59:51 -08002180
mflodmancc3d4422017-08-03 08:27:51 -07002181 video_stream_encoder_->Stop();
kthelgason5e13d412016-12-01 03:59:51 -08002182}
2183
mflodmancc3d4422017-08-03 08:27:51 -07002184TEST_F(VideoStreamEncoderTest, CpuLimitedHistogramIsReported) {
asaperssonfab67072017-04-04 05:51:49 -07002185 const int kWidth = 640;
2186 const int kHeight = 360;
perkj803d97f2016-11-01 11:45:46 -07002187
mflodmancc3d4422017-08-03 08:27:51 -07002188 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
sprang4847ae62017-06-27 07:06:52 -07002189
perkj803d97f2016-11-01 11:45:46 -07002190 for (int i = 1; i <= SendStatisticsProxy::kMinRequiredMetricsSamples; ++i) {
asaperssonfab67072017-04-04 05:51:49 -07002191 video_source_.IncomingCapturedFrame(CreateFrame(i, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002192 WaitForEncodedFrame(i);
perkj803d97f2016-11-01 11:45:46 -07002193 }
2194
mflodmancc3d4422017-08-03 08:27:51 -07002195 video_stream_encoder_->TriggerCpuOveruse();
perkj803d97f2016-11-01 11:45:46 -07002196 for (int i = 1; i <= SendStatisticsProxy::kMinRequiredMetricsSamples; ++i) {
asaperssonfab67072017-04-04 05:51:49 -07002197 video_source_.IncomingCapturedFrame(CreateFrame(
2198 SendStatisticsProxy::kMinRequiredMetricsSamples + i, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002199 WaitForEncodedFrame(SendStatisticsProxy::kMinRequiredMetricsSamples + i);
perkj803d97f2016-11-01 11:45:46 -07002200 }
2201
mflodmancc3d4422017-08-03 08:27:51 -07002202 video_stream_encoder_->Stop();
2203 video_stream_encoder_.reset();
perkj803d97f2016-11-01 11:45:46 -07002204 stats_proxy_.reset();
sprangf8ee65e2017-02-28 08:49:33 -08002205
perkj803d97f2016-11-01 11:45:46 -07002206 EXPECT_EQ(1,
2207 metrics::NumSamples("WebRTC.Video.CpuLimitedResolutionInPercent"));
2208 EXPECT_EQ(
2209 1, metrics::NumEvents("WebRTC.Video.CpuLimitedResolutionInPercent", 50));
2210}
2211
mflodmancc3d4422017-08-03 08:27:51 -07002212TEST_F(VideoStreamEncoderTest,
2213 CpuLimitedHistogramIsNotReportedForDisabledDegradation) {
2214 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonf4e44af2017-04-19 02:01:06 -07002215 const int kWidth = 640;
2216 const int kHeight = 360;
2217
mflodmancc3d4422017-08-03 08:27:51 -07002218 video_stream_encoder_->SetSource(
asaperssonf4e44af2017-04-19 02:01:06 -07002219 &video_source_,
2220 VideoSendStream::DegradationPreference::kDegradationDisabled);
2221
2222 for (int i = 1; i <= SendStatisticsProxy::kMinRequiredMetricsSamples; ++i) {
2223 video_source_.IncomingCapturedFrame(CreateFrame(i, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002224 WaitForEncodedFrame(i);
asaperssonf4e44af2017-04-19 02:01:06 -07002225 }
2226
mflodmancc3d4422017-08-03 08:27:51 -07002227 video_stream_encoder_->Stop();
2228 video_stream_encoder_.reset();
asaperssonf4e44af2017-04-19 02:01:06 -07002229 stats_proxy_.reset();
2230
2231 EXPECT_EQ(0,
2232 metrics::NumSamples("WebRTC.Video.CpuLimitedResolutionInPercent"));
2233}
2234
mflodmancc3d4422017-08-03 08:27:51 -07002235TEST_F(VideoStreamEncoderTest, CallsBitrateObserver) {
sprang4847ae62017-06-27 07:06:52 -07002236 MockBitrateObserver bitrate_observer;
mflodmancc3d4422017-08-03 08:27:51 -07002237 video_stream_encoder_->SetBitrateObserver(&bitrate_observer);
sprang57c2fff2017-01-16 06:24:02 -08002238
2239 const int kDefaultFps = 30;
2240 const BitrateAllocation expected_bitrate =
2241 DefaultVideoBitrateAllocator(fake_encoder_.codec_config())
kthelgason2bc68642017-02-07 07:02:22 -08002242 .GetAllocation(kLowTargetBitrateBps, kDefaultFps);
sprang57c2fff2017-01-16 06:24:02 -08002243
2244 // First called on bitrate updated, then again on first frame.
2245 EXPECT_CALL(bitrate_observer, OnBitrateAllocationUpdated(expected_bitrate))
2246 .Times(2);
mflodmancc3d4422017-08-03 08:27:51 -07002247 video_stream_encoder_->OnBitrateUpdated(kLowTargetBitrateBps, 0, 0);
sprang57c2fff2017-01-16 06:24:02 -08002248
2249 const int64_t kStartTimeMs = 1;
2250 video_source_.IncomingCapturedFrame(
2251 CreateFrame(kStartTimeMs, codec_width_, codec_height_));
sprang4847ae62017-06-27 07:06:52 -07002252 WaitForEncodedFrame(kStartTimeMs);
sprang57c2fff2017-01-16 06:24:02 -08002253
2254 // Not called on second frame.
2255 EXPECT_CALL(bitrate_observer, OnBitrateAllocationUpdated(expected_bitrate))
2256 .Times(0);
2257 video_source_.IncomingCapturedFrame(
2258 CreateFrame(kStartTimeMs + 1, codec_width_, codec_height_));
sprang4847ae62017-06-27 07:06:52 -07002259 WaitForEncodedFrame(kStartTimeMs + 1);
sprang57c2fff2017-01-16 06:24:02 -08002260
2261 // Called after a process interval.
2262 const int64_t kProcessIntervalMs =
2263 vcm::VCMProcessTimer::kDefaultProcessIntervalMs;
sprang4847ae62017-06-27 07:06:52 -07002264 fake_clock_.AdvanceTimeMicros(rtc::kNumMicrosecsPerMillisec *
2265 (kProcessIntervalMs + (1000 / kDefaultFps)));
sprang57c2fff2017-01-16 06:24:02 -08002266 EXPECT_CALL(bitrate_observer, OnBitrateAllocationUpdated(expected_bitrate))
2267 .Times(1);
2268 video_source_.IncomingCapturedFrame(CreateFrame(
2269 kStartTimeMs + kProcessIntervalMs, codec_width_, codec_height_));
sprang4847ae62017-06-27 07:06:52 -07002270 WaitForEncodedFrame(kStartTimeMs + kProcessIntervalMs);
sprang57c2fff2017-01-16 06:24:02 -08002271
mflodmancc3d4422017-08-03 08:27:51 -07002272 video_stream_encoder_->Stop();
sprang57c2fff2017-01-16 06:24:02 -08002273}
2274
Niels Möller7dc26b72017-12-06 10:27:48 +01002275TEST_F(VideoStreamEncoderTest, OveruseDetectorUpdatedOnReconfigureAndAdaption) {
2276 const int kFrameWidth = 1280;
2277 const int kFrameHeight = 720;
2278 const int kFramerate = 24;
2279
2280 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
2281 test::FrameForwarder source;
2282 video_stream_encoder_->SetSource(
2283 &source, VideoSendStream::DegradationPreference::kMaintainResolution);
2284
2285 // Insert a single frame, triggering initial configuration.
2286 source.IncomingCapturedFrame(CreateFrame(1, kFrameWidth, kFrameHeight));
2287 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2288
2289 EXPECT_EQ(
2290 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2291 kDefaultFramerate);
2292
2293 // Trigger reconfigure encoder (without resetting the entire instance).
2294 VideoEncoderConfig video_encoder_config;
Niels Möller259a4972018-04-05 15:36:51 +02002295 video_encoder_config.codec_type = kVideoCodecVP8;
Niels Möller7dc26b72017-12-06 10:27:48 +01002296 video_encoder_config.max_bitrate_bps = kTargetBitrateBps;
2297 video_encoder_config.number_of_streams = 1;
2298 video_encoder_config.video_stream_factory =
2299 new rtc::RefCountedObject<VideoStreamFactory>(1, kFramerate);
2300 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
2301 kMaxPayloadLength, false);
2302 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2303
2304 // Detector should be updated with fps limit from codec config.
2305 EXPECT_EQ(
2306 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2307 kFramerate);
2308
2309 // Trigger overuse, max framerate should be reduced.
2310 VideoSendStream::Stats stats = stats_proxy_->GetStats();
2311 stats.input_frame_rate = kFramerate;
2312 stats_proxy_->SetMockStats(stats);
2313 video_stream_encoder_->TriggerCpuOveruse();
2314 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2315 int adapted_framerate =
2316 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate();
2317 EXPECT_LT(adapted_framerate, kFramerate);
2318
2319 // Trigger underuse, max framerate should go back to codec configured fps.
2320 // Set extra low fps, to make sure it's actually reset, not just incremented.
2321 stats = stats_proxy_->GetStats();
2322 stats.input_frame_rate = adapted_framerate / 2;
2323 stats_proxy_->SetMockStats(stats);
2324 video_stream_encoder_->TriggerCpuNormalUsage();
2325 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2326 EXPECT_EQ(
2327 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2328 kFramerate);
2329
2330 video_stream_encoder_->Stop();
2331}
2332
2333TEST_F(VideoStreamEncoderTest,
2334 OveruseDetectorUpdatedRespectsFramerateAfterUnderuse) {
2335 const int kFrameWidth = 1280;
2336 const int kFrameHeight = 720;
2337 const int kLowFramerate = 15;
2338 const int kHighFramerate = 25;
2339
2340 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
2341 test::FrameForwarder source;
2342 video_stream_encoder_->SetSource(
2343 &source, VideoSendStream::DegradationPreference::kMaintainResolution);
2344
2345 // Trigger initial configuration.
2346 VideoEncoderConfig video_encoder_config;
Niels Möller259a4972018-04-05 15:36:51 +02002347 video_encoder_config.codec_type = kVideoCodecVP8;
Niels Möller7dc26b72017-12-06 10:27:48 +01002348 video_encoder_config.max_bitrate_bps = kTargetBitrateBps;
2349 video_encoder_config.number_of_streams = 1;
2350 video_encoder_config.video_stream_factory =
2351 new rtc::RefCountedObject<VideoStreamFactory>(1, kLowFramerate);
2352 source.IncomingCapturedFrame(CreateFrame(1, kFrameWidth, kFrameHeight));
2353 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
2354 kMaxPayloadLength, false);
2355 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2356
2357 EXPECT_EQ(
2358 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2359 kLowFramerate);
2360
2361 // Trigger overuse, max framerate should be reduced.
2362 VideoSendStream::Stats stats = stats_proxy_->GetStats();
2363 stats.input_frame_rate = kLowFramerate;
2364 stats_proxy_->SetMockStats(stats);
2365 video_stream_encoder_->TriggerCpuOveruse();
2366 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2367 int adapted_framerate =
2368 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate();
2369 EXPECT_LT(adapted_framerate, kLowFramerate);
2370
2371 // Reconfigure the encoder with a new (higher max framerate), max fps should
2372 // still respect the adaptation.
2373 video_encoder_config.video_stream_factory =
2374 new rtc::RefCountedObject<VideoStreamFactory>(1, kHighFramerate);
2375 source.IncomingCapturedFrame(CreateFrame(1, kFrameWidth, kFrameHeight));
2376 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
2377 kMaxPayloadLength, false);
2378 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2379
2380 EXPECT_EQ(
2381 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2382 adapted_framerate);
2383
2384 // Trigger underuse, max framerate should go back to codec configured fps.
2385 stats = stats_proxy_->GetStats();
2386 stats.input_frame_rate = adapted_framerate;
2387 stats_proxy_->SetMockStats(stats);
2388 video_stream_encoder_->TriggerCpuNormalUsage();
2389 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2390 EXPECT_EQ(
2391 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2392 kHighFramerate);
2393
2394 video_stream_encoder_->Stop();
2395}
2396
mflodmancc3d4422017-08-03 08:27:51 -07002397TEST_F(VideoStreamEncoderTest,
2398 OveruseDetectorUpdatedOnDegradationPreferenceChange) {
sprangfda496a2017-06-15 04:21:07 -07002399 const int kFrameWidth = 1280;
2400 const int kFrameHeight = 720;
2401 const int kFramerate = 24;
2402
mflodmancc3d4422017-08-03 08:27:51 -07002403 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
sprangfda496a2017-06-15 04:21:07 -07002404 test::FrameForwarder source;
mflodmancc3d4422017-08-03 08:27:51 -07002405 video_stream_encoder_->SetSource(
sprangfda496a2017-06-15 04:21:07 -07002406 &source, VideoSendStream::DegradationPreference::kMaintainResolution);
2407
2408 // Trigger initial configuration.
2409 VideoEncoderConfig video_encoder_config;
Niels Möller259a4972018-04-05 15:36:51 +02002410 video_encoder_config.codec_type = kVideoCodecVP8;
sprangfda496a2017-06-15 04:21:07 -07002411 video_encoder_config.max_bitrate_bps = kTargetBitrateBps;
2412 video_encoder_config.number_of_streams = 1;
2413 video_encoder_config.video_stream_factory =
2414 new rtc::RefCountedObject<VideoStreamFactory>(1, kFramerate);
2415 source.IncomingCapturedFrame(CreateFrame(1, kFrameWidth, kFrameHeight));
mflodmancc3d4422017-08-03 08:27:51 -07002416 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
2417 kMaxPayloadLength, false);
2418 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
sprangfda496a2017-06-15 04:21:07 -07002419
Niels Möller7dc26b72017-12-06 10:27:48 +01002420 EXPECT_EQ(
2421 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2422 kFramerate);
sprangfda496a2017-06-15 04:21:07 -07002423
2424 // Trigger overuse, max framerate should be reduced.
2425 VideoSendStream::Stats stats = stats_proxy_->GetStats();
2426 stats.input_frame_rate = kFramerate;
2427 stats_proxy_->SetMockStats(stats);
mflodmancc3d4422017-08-03 08:27:51 -07002428 video_stream_encoder_->TriggerCpuOveruse();
2429 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
Niels Möller7dc26b72017-12-06 10:27:48 +01002430 int adapted_framerate =
2431 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate();
sprangfda496a2017-06-15 04:21:07 -07002432 EXPECT_LT(adapted_framerate, kFramerate);
2433
2434 // Change degradation preference to not enable framerate scaling. Target
2435 // framerate should be changed to codec defined limit.
mflodmancc3d4422017-08-03 08:27:51 -07002436 video_stream_encoder_->SetSource(
sprangfda496a2017-06-15 04:21:07 -07002437 &source, VideoSendStream::DegradationPreference::kMaintainFramerate);
mflodmancc3d4422017-08-03 08:27:51 -07002438 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
Niels Möller7dc26b72017-12-06 10:27:48 +01002439 EXPECT_EQ(
2440 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2441 kFramerate);
sprangfda496a2017-06-15 04:21:07 -07002442
mflodmancc3d4422017-08-03 08:27:51 -07002443 video_stream_encoder_->Stop();
sprangfda496a2017-06-15 04:21:07 -07002444}
2445
mflodmancc3d4422017-08-03 08:27:51 -07002446TEST_F(VideoStreamEncoderTest, DropsFramesAndScalesWhenBitrateIsTooLow) {
asaperssonfab67072017-04-04 05:51:49 -07002447 const int kTooLowBitrateForFrameSizeBps = 10000;
mflodmancc3d4422017-08-03 08:27:51 -07002448 video_stream_encoder_->OnBitrateUpdated(kTooLowBitrateForFrameSizeBps, 0, 0);
asaperssonfab67072017-04-04 05:51:49 -07002449 const int kWidth = 640;
2450 const int kHeight = 360;
kthelgason2bc68642017-02-07 07:02:22 -08002451
asaperssonfab67072017-04-04 05:51:49 -07002452 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
kthelgason2bc68642017-02-07 07:02:22 -08002453
2454 // Expect to drop this frame, the wait should time out.
sprang4847ae62017-06-27 07:06:52 -07002455 ExpectDroppedFrame();
kthelgason2bc68642017-02-07 07:02:22 -08002456
2457 // Expect the sink_wants to specify a scaled frame.
asapersson0944a802017-04-07 00:57:58 -07002458 EXPECT_LT(video_source_.sink_wants().max_pixel_count, kWidth * kHeight);
kthelgason2bc68642017-02-07 07:02:22 -08002459
sprangc5d62e22017-04-02 23:53:04 -07002460 int last_pixel_count = video_source_.sink_wants().max_pixel_count;
kthelgason2bc68642017-02-07 07:02:22 -08002461
asaperssonfab67072017-04-04 05:51:49 -07002462 // Next frame is scaled.
kthelgason2bc68642017-02-07 07:02:22 -08002463 video_source_.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07002464 CreateFrame(2, kWidth * 3 / 4, kHeight * 3 / 4));
kthelgason2bc68642017-02-07 07:02:22 -08002465
2466 // Expect to drop this frame, the wait should time out.
sprang4847ae62017-06-27 07:06:52 -07002467 ExpectDroppedFrame();
kthelgason2bc68642017-02-07 07:02:22 -08002468
sprangc5d62e22017-04-02 23:53:04 -07002469 EXPECT_LT(video_source_.sink_wants().max_pixel_count, last_pixel_count);
kthelgason2bc68642017-02-07 07:02:22 -08002470
mflodmancc3d4422017-08-03 08:27:51 -07002471 video_stream_encoder_->Stop();
kthelgason2bc68642017-02-07 07:02:22 -08002472}
2473
mflodmancc3d4422017-08-03 08:27:51 -07002474TEST_F(VideoStreamEncoderTest,
2475 NumberOfDroppedFramesLimitedWhenBitrateIsTooLow) {
asaperssonfab67072017-04-04 05:51:49 -07002476 const int kTooLowBitrateForFrameSizeBps = 10000;
mflodmancc3d4422017-08-03 08:27:51 -07002477 video_stream_encoder_->OnBitrateUpdated(kTooLowBitrateForFrameSizeBps, 0, 0);
asaperssonfab67072017-04-04 05:51:49 -07002478 const int kWidth = 640;
2479 const int kHeight = 360;
kthelgason2bc68642017-02-07 07:02:22 -08002480
2481 // We expect the n initial frames to get dropped.
2482 int i;
2483 for (i = 1; i <= kMaxInitialFramedrop; ++i) {
asaperssonfab67072017-04-04 05:51:49 -07002484 video_source_.IncomingCapturedFrame(CreateFrame(i, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002485 ExpectDroppedFrame();
kthelgason2bc68642017-02-07 07:02:22 -08002486 }
2487 // The n+1th frame should not be dropped, even though it's size is too large.
asaperssonfab67072017-04-04 05:51:49 -07002488 video_source_.IncomingCapturedFrame(CreateFrame(i, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002489 WaitForEncodedFrame(i);
kthelgason2bc68642017-02-07 07:02:22 -08002490
2491 // Expect the sink_wants to specify a scaled frame.
asaperssonfab67072017-04-04 05:51:49 -07002492 EXPECT_LT(video_source_.sink_wants().max_pixel_count, kWidth * kHeight);
kthelgason2bc68642017-02-07 07:02:22 -08002493
mflodmancc3d4422017-08-03 08:27:51 -07002494 video_stream_encoder_->Stop();
kthelgason2bc68642017-02-07 07:02:22 -08002495}
2496
mflodmancc3d4422017-08-03 08:27:51 -07002497TEST_F(VideoStreamEncoderTest,
2498 InitialFrameDropOffWithMaintainResolutionPreference) {
asaperssonfab67072017-04-04 05:51:49 -07002499 const int kWidth = 640;
2500 const int kHeight = 360;
mflodmancc3d4422017-08-03 08:27:51 -07002501 video_stream_encoder_->OnBitrateUpdated(kLowTargetBitrateBps, 0, 0);
kthelgason2bc68642017-02-07 07:02:22 -08002502
2503 // Set degradation preference.
mflodmancc3d4422017-08-03 08:27:51 -07002504 video_stream_encoder_->SetSource(
kthelgason2bc68642017-02-07 07:02:22 -08002505 &video_source_,
2506 VideoSendStream::DegradationPreference::kMaintainResolution);
2507
asaperssonfab67072017-04-04 05:51:49 -07002508 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
kthelgason2bc68642017-02-07 07:02:22 -08002509 // Frame should not be dropped, even if it's too large.
sprang4847ae62017-06-27 07:06:52 -07002510 WaitForEncodedFrame(1);
kthelgason2bc68642017-02-07 07:02:22 -08002511
mflodmancc3d4422017-08-03 08:27:51 -07002512 video_stream_encoder_->Stop();
kthelgason2bc68642017-02-07 07:02:22 -08002513}
2514
mflodmancc3d4422017-08-03 08:27:51 -07002515TEST_F(VideoStreamEncoderTest, InitialFrameDropOffWhenEncoderDisabledScaling) {
asaperssonfab67072017-04-04 05:51:49 -07002516 const int kWidth = 640;
2517 const int kHeight = 360;
kthelgasonad9010c2017-02-14 00:46:51 -08002518 fake_encoder_.SetQualityScaling(false);
mflodmancc3d4422017-08-03 08:27:51 -07002519 video_stream_encoder_->OnBitrateUpdated(kLowTargetBitrateBps, 0, 0);
asapersson09f05612017-05-15 23:40:18 -07002520
kthelgasonb83797b2017-02-14 11:57:25 -08002521 // Force quality scaler reconfiguration by resetting the source.
mflodmancc3d4422017-08-03 08:27:51 -07002522 video_stream_encoder_->SetSource(
2523 &video_source_,
2524 VideoSendStream::DegradationPreference::kBalanced);
kthelgasonad9010c2017-02-14 00:46:51 -08002525
asaperssonfab67072017-04-04 05:51:49 -07002526 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
kthelgasonad9010c2017-02-14 00:46:51 -08002527 // Frame should not be dropped, even if it's too large.
sprang4847ae62017-06-27 07:06:52 -07002528 WaitForEncodedFrame(1);
kthelgasonad9010c2017-02-14 00:46:51 -08002529
mflodmancc3d4422017-08-03 08:27:51 -07002530 video_stream_encoder_->Stop();
kthelgasonad9010c2017-02-14 00:46:51 -08002531 fake_encoder_.SetQualityScaling(true);
2532}
2533
mflodmancc3d4422017-08-03 08:27:51 -07002534TEST_F(VideoStreamEncoderTest,
asaperssond0de2952017-04-21 01:47:31 -07002535 ResolutionNotAdaptedForTooSmallFrame_MaintainFramerateMode) {
2536 const int kTooSmallWidth = 10;
2537 const int kTooSmallHeight = 10;
mflodmancc3d4422017-08-03 08:27:51 -07002538 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssond0de2952017-04-21 01:47:31 -07002539
2540 // Enable kMaintainFramerate preference, no initial limitation.
2541 test::FrameForwarder source;
mflodmancc3d4422017-08-03 08:27:51 -07002542 video_stream_encoder_->SetSource(
asaperssond0de2952017-04-21 01:47:31 -07002543 &source, VideoSendStream::DegradationPreference::kMaintainFramerate);
2544 VerifyNoLimitation(source.sink_wants());
2545 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2546
2547 // Trigger adapt down, too small frame, expect no change.
2548 source.IncomingCapturedFrame(CreateFrame(1, kTooSmallWidth, kTooSmallHeight));
sprang4847ae62017-06-27 07:06:52 -07002549 WaitForEncodedFrame(1);
mflodmancc3d4422017-08-03 08:27:51 -07002550 video_stream_encoder_->TriggerCpuOveruse();
asaperssond0de2952017-04-21 01:47:31 -07002551 VerifyNoLimitation(source.sink_wants());
2552 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2553 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2554
mflodmancc3d4422017-08-03 08:27:51 -07002555 video_stream_encoder_->Stop();
asaperssond0de2952017-04-21 01:47:31 -07002556}
2557
mflodmancc3d4422017-08-03 08:27:51 -07002558TEST_F(VideoStreamEncoderTest,
2559 ResolutionNotAdaptedForTooSmallFrame_BalancedMode) {
asaperssonf7e294d2017-06-13 23:25:22 -07002560 const int kTooSmallWidth = 10;
2561 const int kTooSmallHeight = 10;
2562 const int kFpsLimit = 7;
mflodmancc3d4422017-08-03 08:27:51 -07002563 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -07002564
2565 // Enable kBalanced preference, no initial limitation.
2566 test::FrameForwarder source;
mflodmancc3d4422017-08-03 08:27:51 -07002567 video_stream_encoder_->SetSource(
2568 &source,
2569 VideoSendStream::DegradationPreference::kBalanced);
asaperssonf7e294d2017-06-13 23:25:22 -07002570 VerifyNoLimitation(source.sink_wants());
2571 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2572 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2573
2574 // Trigger adapt down, expect limited framerate.
2575 source.IncomingCapturedFrame(CreateFrame(1, kTooSmallWidth, kTooSmallHeight));
sprang4847ae62017-06-27 07:06:52 -07002576 WaitForEncodedFrame(1);
mflodmancc3d4422017-08-03 08:27:51 -07002577 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002578 VerifyFpsEqResolutionMax(source.sink_wants(), kFpsLimit);
2579 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2580 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2581 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2582
2583 // Trigger adapt down, too small frame, expect no change.
2584 source.IncomingCapturedFrame(CreateFrame(2, kTooSmallWidth, kTooSmallHeight));
sprang4847ae62017-06-27 07:06:52 -07002585 WaitForEncodedFrame(2);
mflodmancc3d4422017-08-03 08:27:51 -07002586 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002587 VerifyFpsEqResolutionMax(source.sink_wants(), kFpsLimit);
2588 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2589 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2590 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2591
mflodmancc3d4422017-08-03 08:27:51 -07002592 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07002593}
2594
mflodmancc3d4422017-08-03 08:27:51 -07002595TEST_F(VideoStreamEncoderTest, FailingInitEncodeDoesntCauseCrash) {
asapersson02465b82017-04-10 01:12:52 -07002596 fake_encoder_.ForceInitEncodeFailure(true);
mflodmancc3d4422017-08-03 08:27:51 -07002597 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
emircanbbcc3562017-08-18 00:28:40 -07002598 ResetEncoder("VP8", 2, 1, 1, true, false);
asapersson02465b82017-04-10 01:12:52 -07002599 const int kFrameWidth = 1280;
2600 const int kFrameHeight = 720;
2601 video_source_.IncomingCapturedFrame(
2602 CreateFrame(1, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002603 ExpectDroppedFrame();
mflodmancc3d4422017-08-03 08:27:51 -07002604 video_stream_encoder_->Stop();
asapersson02465b82017-04-10 01:12:52 -07002605}
2606
sprangb1ca0732017-02-01 08:38:12 -08002607// TODO(sprang): Extend this with fps throttling and any "balanced" extensions.
mflodmancc3d4422017-08-03 08:27:51 -07002608TEST_F(VideoStreamEncoderTest,
2609 AdaptsResolutionOnOveruse_MaintainFramerateMode) {
2610 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
sprangb1ca0732017-02-01 08:38:12 -08002611
2612 const int kFrameWidth = 1280;
2613 const int kFrameHeight = 720;
2614 // Enabled default VideoAdapter downscaling. First step is 3/4, not 3/5 as
mflodmancc3d4422017-08-03 08:27:51 -07002615 // requested by
2616 // VideoStreamEncoder::VideoSourceProxy::RequestResolutionLowerThan().
sprangb1ca0732017-02-01 08:38:12 -08002617 video_source_.set_adaptation_enabled(true);
2618
2619 video_source_.IncomingCapturedFrame(
2620 CreateFrame(1, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002621 WaitForEncodedFrame(kFrameWidth, kFrameHeight);
sprangb1ca0732017-02-01 08:38:12 -08002622
2623 // Trigger CPU overuse, downscale by 3/4.
mflodmancc3d4422017-08-03 08:27:51 -07002624 video_stream_encoder_->TriggerCpuOveruse();
sprangb1ca0732017-02-01 08:38:12 -08002625 video_source_.IncomingCapturedFrame(
2626 CreateFrame(2, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002627 WaitForEncodedFrame((kFrameWidth * 3) / 4, (kFrameHeight * 3) / 4);
sprangb1ca0732017-02-01 08:38:12 -08002628
asaperssonfab67072017-04-04 05:51:49 -07002629 // Trigger CPU normal use, return to original resolution.
mflodmancc3d4422017-08-03 08:27:51 -07002630 video_stream_encoder_->TriggerCpuNormalUsage();
sprangb1ca0732017-02-01 08:38:12 -08002631 video_source_.IncomingCapturedFrame(
2632 CreateFrame(3, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002633 WaitForEncodedFrame(kFrameWidth, kFrameHeight);
sprangb1ca0732017-02-01 08:38:12 -08002634
mflodmancc3d4422017-08-03 08:27:51 -07002635 video_stream_encoder_->Stop();
sprangb1ca0732017-02-01 08:38:12 -08002636}
sprangfe627f32017-03-29 08:24:59 -07002637
mflodmancc3d4422017-08-03 08:27:51 -07002638TEST_F(VideoStreamEncoderTest,
2639 AdaptsFramerateOnOveruse_MaintainResolutionMode) {
sprangc5d62e22017-04-02 23:53:04 -07002640 const int kFrameWidth = 1280;
2641 const int kFrameHeight = 720;
sprang4847ae62017-06-27 07:06:52 -07002642 int kFrameIntervalMs = rtc::kNumMillisecsPerSec / max_framerate_;
sprangc5d62e22017-04-02 23:53:04 -07002643
mflodmancc3d4422017-08-03 08:27:51 -07002644 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
2645 video_stream_encoder_->SetSource(
sprangc5d62e22017-04-02 23:53:04 -07002646 &video_source_,
2647 VideoSendStream::DegradationPreference::kMaintainResolution);
2648 video_source_.set_adaptation_enabled(true);
2649
sprang4847ae62017-06-27 07:06:52 -07002650 int64_t timestamp_ms = fake_clock_.TimeNanos() / rtc::kNumNanosecsPerMillisec;
sprangc5d62e22017-04-02 23:53:04 -07002651
2652 video_source_.IncomingCapturedFrame(
2653 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002654 WaitForEncodedFrame(timestamp_ms);
sprangc5d62e22017-04-02 23:53:04 -07002655
2656 // Try to trigger overuse. No fps estimate available => no effect.
mflodmancc3d4422017-08-03 08:27:51 -07002657 video_stream_encoder_->TriggerCpuOveruse();
sprangc5d62e22017-04-02 23:53:04 -07002658
2659 // Insert frames for one second to get a stable estimate.
sprang4847ae62017-06-27 07:06:52 -07002660 for (int i = 0; i < max_framerate_; ++i) {
sprangc5d62e22017-04-02 23:53:04 -07002661 timestamp_ms += kFrameIntervalMs;
sprangc5d62e22017-04-02 23:53:04 -07002662 video_source_.IncomingCapturedFrame(
2663 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002664 WaitForEncodedFrame(timestamp_ms);
sprangc5d62e22017-04-02 23:53:04 -07002665 }
2666
2667 // Trigger CPU overuse, reduce framerate by 2/3.
mflodmancc3d4422017-08-03 08:27:51 -07002668 video_stream_encoder_->TriggerCpuOveruse();
sprangc5d62e22017-04-02 23:53:04 -07002669 int num_frames_dropped = 0;
sprang4847ae62017-06-27 07:06:52 -07002670 for (int i = 0; i < max_framerate_; ++i) {
sprangc5d62e22017-04-02 23:53:04 -07002671 timestamp_ms += kFrameIntervalMs;
sprangc5d62e22017-04-02 23:53:04 -07002672 video_source_.IncomingCapturedFrame(
2673 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002674 if (!WaitForFrame(kFrameTimeoutMs)) {
sprangc5d62e22017-04-02 23:53:04 -07002675 ++num_frames_dropped;
2676 } else {
Åsa Perssonc74d8da2017-12-04 14:13:56 +01002677 sink_.CheckLastFrameSizeMatches(kFrameWidth, kFrameHeight);
sprangc5d62e22017-04-02 23:53:04 -07002678 }
2679 }
2680
sprang4847ae62017-06-27 07:06:52 -07002681 // Add some slack to account for frames dropped by the frame dropper.
2682 const int kErrorMargin = 1;
2683 EXPECT_NEAR(num_frames_dropped, max_framerate_ - (max_framerate_ * 2 / 3),
sprangc5d62e22017-04-02 23:53:04 -07002684 kErrorMargin);
2685
2686 // Trigger CPU overuse, reduce framerate by 2/3 again.
mflodmancc3d4422017-08-03 08:27:51 -07002687 video_stream_encoder_->TriggerCpuOveruse();
sprangc5d62e22017-04-02 23:53:04 -07002688 num_frames_dropped = 0;
sprang4847ae62017-06-27 07:06:52 -07002689 for (int i = 0; i < max_framerate_; ++i) {
sprangc5d62e22017-04-02 23:53:04 -07002690 timestamp_ms += kFrameIntervalMs;
sprangc5d62e22017-04-02 23:53:04 -07002691 video_source_.IncomingCapturedFrame(
2692 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002693 if (!WaitForFrame(kFrameTimeoutMs)) {
sprangc5d62e22017-04-02 23:53:04 -07002694 ++num_frames_dropped;
2695 } else {
Åsa Perssonc74d8da2017-12-04 14:13:56 +01002696 sink_.CheckLastFrameSizeMatches(kFrameWidth, kFrameHeight);
sprangc5d62e22017-04-02 23:53:04 -07002697 }
2698 }
sprang4847ae62017-06-27 07:06:52 -07002699 EXPECT_NEAR(num_frames_dropped, max_framerate_ - (max_framerate_ * 4 / 9),
sprangc5d62e22017-04-02 23:53:04 -07002700 kErrorMargin);
2701
2702 // Go back up one step.
mflodmancc3d4422017-08-03 08:27:51 -07002703 video_stream_encoder_->TriggerCpuNormalUsage();
sprangc5d62e22017-04-02 23:53:04 -07002704 num_frames_dropped = 0;
sprang4847ae62017-06-27 07:06:52 -07002705 for (int i = 0; i < max_framerate_; ++i) {
sprangc5d62e22017-04-02 23:53:04 -07002706 timestamp_ms += kFrameIntervalMs;
sprangc5d62e22017-04-02 23:53:04 -07002707 video_source_.IncomingCapturedFrame(
2708 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002709 if (!WaitForFrame(kFrameTimeoutMs)) {
sprangc5d62e22017-04-02 23:53:04 -07002710 ++num_frames_dropped;
2711 } else {
Åsa Perssonc74d8da2017-12-04 14:13:56 +01002712 sink_.CheckLastFrameSizeMatches(kFrameWidth, kFrameHeight);
sprangc5d62e22017-04-02 23:53:04 -07002713 }
2714 }
sprang4847ae62017-06-27 07:06:52 -07002715 EXPECT_NEAR(num_frames_dropped, max_framerate_ - (max_framerate_ * 2 / 3),
sprangc5d62e22017-04-02 23:53:04 -07002716 kErrorMargin);
2717
2718 // Go back up to original mode.
mflodmancc3d4422017-08-03 08:27:51 -07002719 video_stream_encoder_->TriggerCpuNormalUsage();
sprangc5d62e22017-04-02 23:53:04 -07002720 num_frames_dropped = 0;
sprang4847ae62017-06-27 07:06:52 -07002721 for (int i = 0; i < max_framerate_; ++i) {
sprangc5d62e22017-04-02 23:53:04 -07002722 timestamp_ms += kFrameIntervalMs;
sprangc5d62e22017-04-02 23:53:04 -07002723 video_source_.IncomingCapturedFrame(
2724 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002725 if (!WaitForFrame(kFrameTimeoutMs)) {
sprangc5d62e22017-04-02 23:53:04 -07002726 ++num_frames_dropped;
2727 } else {
Åsa Perssonc74d8da2017-12-04 14:13:56 +01002728 sink_.CheckLastFrameSizeMatches(kFrameWidth, kFrameHeight);
sprangc5d62e22017-04-02 23:53:04 -07002729 }
2730 }
2731 EXPECT_NEAR(num_frames_dropped, 0, kErrorMargin);
2732
mflodmancc3d4422017-08-03 08:27:51 -07002733 video_stream_encoder_->Stop();
sprangc5d62e22017-04-02 23:53:04 -07002734}
2735
mflodmancc3d4422017-08-03 08:27:51 -07002736TEST_F(VideoStreamEncoderTest, DoesntAdaptDownPastMinFramerate) {
sprangc5d62e22017-04-02 23:53:04 -07002737 const int kFramerateFps = 5;
2738 const int kFrameIntervalMs = rtc::kNumMillisecsPerSec / kFramerateFps;
sprangc5d62e22017-04-02 23:53:04 -07002739 const int kFrameWidth = 1280;
2740 const int kFrameHeight = 720;
2741
sprang4847ae62017-06-27 07:06:52 -07002742 // Reconfigure encoder with two temporal layers and screensharing, which will
2743 // disable frame dropping and make testing easier.
emircanbbcc3562017-08-18 00:28:40 -07002744 ResetEncoder("VP8", 1, 2, 1, true, true);
sprang4847ae62017-06-27 07:06:52 -07002745
mflodmancc3d4422017-08-03 08:27:51 -07002746 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
2747 video_stream_encoder_->SetSource(
sprangc5d62e22017-04-02 23:53:04 -07002748 &video_source_,
2749 VideoSendStream::DegradationPreference::kMaintainResolution);
2750 video_source_.set_adaptation_enabled(true);
2751
sprang4847ae62017-06-27 07:06:52 -07002752 int64_t timestamp_ms = fake_clock_.TimeNanos() / rtc::kNumNanosecsPerMillisec;
sprangc5d62e22017-04-02 23:53:04 -07002753
2754 // Trigger overuse as much as we can.
Jonathan Yubc771b72017-12-08 17:04:29 -08002755 rtc::VideoSinkWants last_wants;
2756 do {
2757 last_wants = video_source_.sink_wants();
2758
sprangc5d62e22017-04-02 23:53:04 -07002759 // Insert frames to get a new fps estimate...
2760 for (int j = 0; j < kFramerateFps; ++j) {
2761 video_source_.IncomingCapturedFrame(
2762 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
Jonathan Yubc771b72017-12-08 17:04:29 -08002763 if (video_source_.last_sent_width()) {
2764 sink_.WaitForEncodedFrame(timestamp_ms);
2765 }
sprangc5d62e22017-04-02 23:53:04 -07002766 timestamp_ms += kFrameIntervalMs;
Jonathan Yubc771b72017-12-08 17:04:29 -08002767 fake_clock_.AdvanceTimeMicros(
2768 kFrameIntervalMs * rtc::kNumMicrosecsPerMillisec);
sprangc5d62e22017-04-02 23:53:04 -07002769 }
2770 // ...and then try to adapt again.
mflodmancc3d4422017-08-03 08:27:51 -07002771 video_stream_encoder_->TriggerCpuOveruse();
Jonathan Yubc771b72017-12-08 17:04:29 -08002772 } while (video_source_.sink_wants().max_framerate_fps <
2773 last_wants.max_framerate_fps);
sprangc5d62e22017-04-02 23:53:04 -07002774
Jonathan Yubc771b72017-12-08 17:04:29 -08002775 VerifyFpsEqResolutionMax(video_source_.sink_wants(), kMinFramerateFps);
asaperssonf7e294d2017-06-13 23:25:22 -07002776
mflodmancc3d4422017-08-03 08:27:51 -07002777 video_stream_encoder_->Stop();
sprangc5d62e22017-04-02 23:53:04 -07002778}
asaperssonf7e294d2017-06-13 23:25:22 -07002779
mflodmancc3d4422017-08-03 08:27:51 -07002780TEST_F(VideoStreamEncoderTest,
2781 AdaptsResolutionAndFramerateForLowQuality_BalancedMode) {
asaperssonf7e294d2017-06-13 23:25:22 -07002782 const int kWidth = 1280;
2783 const int kHeight = 720;
2784 const int64_t kFrameIntervalMs = 150;
2785 int64_t timestamp_ms = kFrameIntervalMs;
mflodmancc3d4422017-08-03 08:27:51 -07002786 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -07002787
2788 // Enable kBalanced preference, no initial limitation.
2789 AdaptingFrameForwarder source;
2790 source.set_adaptation_enabled(true);
mflodmancc3d4422017-08-03 08:27:51 -07002791 video_stream_encoder_->SetSource(
2792 &source,
2793 VideoSendStream::DegradationPreference::kBalanced);
asaperssonf7e294d2017-06-13 23:25:22 -07002794 timestamp_ms += kFrameIntervalMs;
2795 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002796 WaitForEncodedFrame(kWidth, kHeight);
asaperssonf7e294d2017-06-13 23:25:22 -07002797 VerifyNoLimitation(source.sink_wants());
2798 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2799 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2800 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2801
2802 // Trigger adapt down, expect scaled down resolution (960x540@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002803 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002804 timestamp_ms += kFrameIntervalMs;
2805 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002806 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002807 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
2808 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2809 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2810 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2811
2812 // Trigger adapt down, expect scaled down resolution (640x360@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002813 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002814 timestamp_ms += kFrameIntervalMs;
2815 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002816 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002817 VerifyFpsMaxResolutionLt(source.sink_wants(), source.last_wants());
2818 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2819 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2820 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2821
2822 // Trigger adapt down, expect reduced fps (640x360@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07002823 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002824 timestamp_ms += kFrameIntervalMs;
2825 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002826 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002827 VerifyFpsLtResolutionEq(source.sink_wants(), source.last_wants());
2828 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2829 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2830 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2831
2832 // Trigger adapt down, expect scaled down resolution (480x270@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07002833 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002834 timestamp_ms += kFrameIntervalMs;
2835 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002836 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002837 VerifyFpsEqResolutionLt(source.sink_wants(), source.last_wants());
2838 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2839 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2840 EXPECT_EQ(4, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2841
2842 // Restrict bitrate, trigger adapt down, expect reduced fps (480x270@10fps).
mflodmancc3d4422017-08-03 08:27:51 -07002843 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002844 timestamp_ms += kFrameIntervalMs;
2845 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002846 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002847 VerifyFpsLtResolutionEq(source.sink_wants(), source.last_wants());
2848 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2849 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2850 EXPECT_EQ(5, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2851
2852 // Trigger adapt down, expect scaled down resolution (320x180@10fps).
mflodmancc3d4422017-08-03 08:27:51 -07002853 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002854 timestamp_ms += kFrameIntervalMs;
2855 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002856 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002857 VerifyFpsEqResolutionLt(source.sink_wants(), source.last_wants());
2858 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2859 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2860 EXPECT_EQ(6, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2861
2862 // Trigger adapt down, expect reduced fps (320x180@7fps).
mflodmancc3d4422017-08-03 08:27:51 -07002863 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002864 timestamp_ms += kFrameIntervalMs;
2865 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002866 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002867 VerifyFpsLtResolutionEq(source.sink_wants(), source.last_wants());
2868 rtc::VideoSinkWants last_wants = source.sink_wants();
2869 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2870 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2871 EXPECT_EQ(7, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2872
2873 // Trigger adapt down, min resolution reached, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07002874 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002875 timestamp_ms += kFrameIntervalMs;
2876 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002877 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002878 VerifyFpsEqResolutionEq(source.sink_wants(), last_wants);
2879 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2880 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2881 EXPECT_EQ(7, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2882
2883 // Trigger adapt down, expect expect increased fps (320x180@10fps).
mflodmancc3d4422017-08-03 08:27:51 -07002884 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002885 timestamp_ms += kFrameIntervalMs;
2886 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002887 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002888 VerifyFpsGtResolutionEq(source.sink_wants(), source.last_wants());
2889 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2890 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2891 EXPECT_EQ(8, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2892
2893 // Trigger adapt up, expect upscaled resolution (480x270@10fps).
mflodmancc3d4422017-08-03 08:27:51 -07002894 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002895 timestamp_ms += kFrameIntervalMs;
2896 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002897 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002898 VerifyFpsEqResolutionGt(source.sink_wants(), source.last_wants());
2899 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2900 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2901 EXPECT_EQ(9, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2902
2903 // Increase bitrate, trigger adapt up, expect increased fps (480x270@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07002904 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002905 timestamp_ms += kFrameIntervalMs;
2906 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002907 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002908 VerifyFpsGtResolutionEq(source.sink_wants(), source.last_wants());
2909 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2910 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2911 EXPECT_EQ(10, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2912
2913 // Trigger adapt up, expect upscaled resolution (640x360@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07002914 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002915 timestamp_ms += kFrameIntervalMs;
2916 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002917 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002918 VerifyFpsEqResolutionGt(source.sink_wants(), source.last_wants());
2919 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2920 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2921 EXPECT_EQ(11, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2922
2923 // Trigger adapt up, expect increased fps (640x360@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002924 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002925 timestamp_ms += kFrameIntervalMs;
2926 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002927 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002928 VerifyFpsMaxResolutionEq(source.sink_wants(), source.last_wants());
2929 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2930 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2931 EXPECT_EQ(12, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2932
2933 // Trigger adapt up, expect upscaled resolution (960x540@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002934 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002935 timestamp_ms += kFrameIntervalMs;
2936 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002937 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002938 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
2939 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2940 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2941 EXPECT_EQ(13, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2942
2943 // Trigger adapt up, expect no restriction (1280x720fps@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002944 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002945 timestamp_ms += kFrameIntervalMs;
2946 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002947 WaitForEncodedFrame(kWidth, kHeight);
asaperssonf7e294d2017-06-13 23:25:22 -07002948 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
2949 VerifyNoLimitation(source.sink_wants());
2950 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2951 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2952 EXPECT_EQ(14, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2953
2954 // Trigger adapt up, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07002955 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002956 VerifyNoLimitation(source.sink_wants());
2957 EXPECT_EQ(14, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2958
mflodmancc3d4422017-08-03 08:27:51 -07002959 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07002960}
2961
mflodmancc3d4422017-08-03 08:27:51 -07002962TEST_F(VideoStreamEncoderTest, AdaptWithTwoReasonsAndDifferentOrder_Framerate) {
asaperssonf7e294d2017-06-13 23:25:22 -07002963 const int kWidth = 1280;
2964 const int kHeight = 720;
2965 const int64_t kFrameIntervalMs = 150;
2966 int64_t timestamp_ms = kFrameIntervalMs;
mflodmancc3d4422017-08-03 08:27:51 -07002967 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -07002968
2969 // Enable kBalanced preference, no initial limitation.
2970 AdaptingFrameForwarder source;
2971 source.set_adaptation_enabled(true);
mflodmancc3d4422017-08-03 08:27:51 -07002972 video_stream_encoder_->SetSource(
2973 &source,
2974 VideoSendStream::DegradationPreference::kBalanced);
asaperssonf7e294d2017-06-13 23:25:22 -07002975 timestamp_ms += kFrameIntervalMs;
2976 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002977 WaitForEncodedFrame(kWidth, kHeight);
asaperssonf7e294d2017-06-13 23:25:22 -07002978 VerifyNoLimitation(source.sink_wants());
2979 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2980 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2981 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2982 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
2983 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2984 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2985
2986 // Trigger cpu adapt down, expect scaled down resolution (960x540@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002987 video_stream_encoder_->TriggerCpuOveruse();
asaperssonf7e294d2017-06-13 23:25:22 -07002988 timestamp_ms += kFrameIntervalMs;
2989 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002990 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002991 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
2992 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2993 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2994 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2995 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
2996 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2997 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2998
2999 // Trigger cpu adapt down, expect scaled down resolution (640x360@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07003000 video_stream_encoder_->TriggerCpuOveruse();
asaperssonf7e294d2017-06-13 23:25:22 -07003001 timestamp_ms += kFrameIntervalMs;
3002 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003003 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07003004 VerifyFpsMaxResolutionLt(source.sink_wants(), source.last_wants());
3005 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
3006 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
3007 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
3008 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
3009 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
3010 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3011
3012 // Trigger quality adapt down, expect reduced fps (640x360@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07003013 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07003014 timestamp_ms += kFrameIntervalMs;
3015 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003016 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07003017 VerifyFpsLtResolutionEq(source.sink_wants(), source.last_wants());
3018 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
3019 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
3020 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
3021 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
3022 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
3023 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3024
3025 // Trigger cpu adapt up, expect increased fps (640x360@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07003026 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssonf7e294d2017-06-13 23:25:22 -07003027 timestamp_ms += kFrameIntervalMs;
3028 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003029 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07003030 VerifyFpsMaxResolutionEq(source.sink_wants(), source.last_wants());
3031 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
3032 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
3033 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
3034 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
3035 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
3036 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3037
3038 // Trigger quality adapt up, expect upscaled resolution (960x540@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07003039 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07003040 timestamp_ms += kFrameIntervalMs;
3041 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003042 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07003043 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
3044 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
3045 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
3046 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
3047 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
3048 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
3049 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3050
3051 // Trigger cpu adapt up, expect no restriction (1280x720fps@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07003052 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssonf7e294d2017-06-13 23:25:22 -07003053 timestamp_ms += kFrameIntervalMs;
3054 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003055 WaitForEncodedFrame(kWidth, kHeight);
asaperssonf7e294d2017-06-13 23:25:22 -07003056 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
3057 VerifyNoLimitation(source.sink_wants());
3058 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
3059 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
3060 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
3061 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
3062 EXPECT_EQ(4, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
3063 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3064
3065 // Trigger adapt up, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07003066 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07003067 VerifyNoLimitation(source.sink_wants());
3068 EXPECT_EQ(4, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
3069 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3070
mflodmancc3d4422017-08-03 08:27:51 -07003071 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07003072}
3073
mflodmancc3d4422017-08-03 08:27:51 -07003074TEST_F(VideoStreamEncoderTest,
3075 AdaptWithTwoReasonsAndDifferentOrder_Resolution) {
asaperssonf7e294d2017-06-13 23:25:22 -07003076 const int kWidth = 640;
3077 const int kHeight = 360;
3078 const int kFpsLimit = 15;
3079 const int64_t kFrameIntervalMs = 150;
3080 int64_t timestamp_ms = kFrameIntervalMs;
mflodmancc3d4422017-08-03 08:27:51 -07003081 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -07003082
3083 // Enable kBalanced preference, no initial limitation.
3084 AdaptingFrameForwarder source;
3085 source.set_adaptation_enabled(true);
mflodmancc3d4422017-08-03 08:27:51 -07003086 video_stream_encoder_->SetSource(
3087 &source,
3088 VideoSendStream::DegradationPreference::kBalanced);
asaperssonf7e294d2017-06-13 23:25:22 -07003089 timestamp_ms += kFrameIntervalMs;
3090 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003091 WaitForEncodedFrame(kWidth, kHeight);
asaperssonf7e294d2017-06-13 23:25:22 -07003092 VerifyNoLimitation(source.sink_wants());
3093 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
3094 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
3095 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
3096 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
3097 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
3098 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3099
3100 // Trigger cpu adapt down, expect scaled down framerate (640x360@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07003101 video_stream_encoder_->TriggerCpuOveruse();
asaperssonf7e294d2017-06-13 23:25:22 -07003102 timestamp_ms += kFrameIntervalMs;
3103 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003104 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07003105 VerifyFpsEqResolutionMax(source.sink_wants(), kFpsLimit);
3106 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
3107 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
3108 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
3109 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_framerate);
3110 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
3111 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3112
3113 // Trigger quality adapt down, expect scaled down resolution (480x270@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07003114 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07003115 timestamp_ms += kFrameIntervalMs;
3116 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003117 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07003118 VerifyFpsEqResolutionLt(source.sink_wants(), source.last_wants());
3119 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
3120 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
3121 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
3122 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_framerate);
3123 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
3124 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3125
3126 // Trigger cpu adapt up, expect upscaled resolution (640x360@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07003127 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssonf7e294d2017-06-13 23:25:22 -07003128 timestamp_ms += kFrameIntervalMs;
3129 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003130 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07003131 VerifyFpsEqResolutionGt(source.sink_wants(), source.last_wants());
3132 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
3133 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
3134 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
3135 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
3136 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
3137 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3138
3139 // Trigger quality adapt up, expect increased fps (640x360@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07003140 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07003141 timestamp_ms += kFrameIntervalMs;
3142 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003143 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07003144 VerifyNoLimitation(source.sink_wants());
3145 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
3146 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
3147 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
3148 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
3149 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
3150 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3151
3152 // Trigger adapt up, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07003153 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07003154 VerifyNoLimitation(source.sink_wants());
3155 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
3156 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3157
mflodmancc3d4422017-08-03 08:27:51 -07003158 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07003159}
3160
mflodmancc3d4422017-08-03 08:27:51 -07003161TEST_F(VideoStreamEncoderTest, AcceptsFullHdAdaptedDownSimulcastFrames) {
ilnik6b826ef2017-06-16 06:53:48 -07003162 // Simulates simulcast behavior and makes highest stream resolutions divisible
3163 // by 4.
3164 class CroppingVideoStreamFactory
3165 : public VideoEncoderConfig::VideoStreamFactoryInterface {
3166 public:
3167 explicit CroppingVideoStreamFactory(size_t num_temporal_layers,
3168 int framerate)
3169 : num_temporal_layers_(num_temporal_layers), framerate_(framerate) {
3170 EXPECT_GT(num_temporal_layers, 0u);
3171 EXPECT_GT(framerate, 0);
3172 }
3173
3174 private:
3175 std::vector<VideoStream> CreateEncoderStreams(
3176 int width,
3177 int height,
3178 const VideoEncoderConfig& encoder_config) override {
3179 std::vector<VideoStream> streams =
3180 test::CreateVideoStreams(width - width % 4, height - height % 4,
3181 encoder_config);
3182 for (VideoStream& stream : streams) {
Sergey Silkina796a7e2018-03-01 15:11:29 +01003183 stream.num_temporal_layers = num_temporal_layers_;
ilnik6b826ef2017-06-16 06:53:48 -07003184 stream.max_framerate = framerate_;
3185 }
3186 return streams;
3187 }
3188
3189 const size_t num_temporal_layers_;
3190 const int framerate_;
3191 };
3192
3193 const int kFrameWidth = 1920;
3194 const int kFrameHeight = 1080;
3195 // 3/4 of 1920.
3196 const int kAdaptedFrameWidth = 1440;
3197 // 3/4 of 1080 rounded down to multiple of 4.
3198 const int kAdaptedFrameHeight = 808;
3199 const int kFramerate = 24;
3200
mflodmancc3d4422017-08-03 08:27:51 -07003201 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
ilnik6b826ef2017-06-16 06:53:48 -07003202 // Trigger reconfigure encoder (without resetting the entire instance).
3203 VideoEncoderConfig video_encoder_config;
Niels Möller259a4972018-04-05 15:36:51 +02003204 video_encoder_config.codec_type = kVideoCodecVP8;
ilnik6b826ef2017-06-16 06:53:48 -07003205 video_encoder_config.max_bitrate_bps = kTargetBitrateBps;
3206 video_encoder_config.number_of_streams = 1;
3207 video_encoder_config.video_stream_factory =
3208 new rtc::RefCountedObject<CroppingVideoStreamFactory>(1, kFramerate);
mflodmancc3d4422017-08-03 08:27:51 -07003209 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
3210 kMaxPayloadLength, false);
3211 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
ilnik6b826ef2017-06-16 06:53:48 -07003212
3213 video_source_.set_adaptation_enabled(true);
3214
3215 video_source_.IncomingCapturedFrame(
3216 CreateFrame(1, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07003217 WaitForEncodedFrame(kFrameWidth, kFrameHeight);
ilnik6b826ef2017-06-16 06:53:48 -07003218
3219 // Trigger CPU overuse, downscale by 3/4.
mflodmancc3d4422017-08-03 08:27:51 -07003220 video_stream_encoder_->TriggerCpuOveruse();
ilnik6b826ef2017-06-16 06:53:48 -07003221 video_source_.IncomingCapturedFrame(
3222 CreateFrame(2, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07003223 WaitForEncodedFrame(kAdaptedFrameWidth, kAdaptedFrameHeight);
ilnik6b826ef2017-06-16 06:53:48 -07003224
mflodmancc3d4422017-08-03 08:27:51 -07003225 video_stream_encoder_->Stop();
ilnik6b826ef2017-06-16 06:53:48 -07003226}
3227
mflodmancc3d4422017-08-03 08:27:51 -07003228TEST_F(VideoStreamEncoderTest, PeriodicallyUpdatesChannelParameters) {
sprang4847ae62017-06-27 07:06:52 -07003229 const int kFrameWidth = 1280;
3230 const int kFrameHeight = 720;
3231 const int kLowFps = 2;
3232 const int kHighFps = 30;
3233
mflodmancc3d4422017-08-03 08:27:51 -07003234 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
sprang4847ae62017-06-27 07:06:52 -07003235
3236 int64_t timestamp_ms = fake_clock_.TimeNanos() / rtc::kNumNanosecsPerMillisec;
3237 max_framerate_ = kLowFps;
3238
3239 // Insert 2 seconds of 2fps video.
3240 for (int i = 0; i < kLowFps * 2; ++i) {
3241 video_source_.IncomingCapturedFrame(
3242 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
3243 WaitForEncodedFrame(timestamp_ms);
3244 timestamp_ms += 1000 / kLowFps;
3245 }
3246
3247 // Make sure encoder is updated with new target.
mflodmancc3d4422017-08-03 08:27:51 -07003248 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
sprang4847ae62017-06-27 07:06:52 -07003249 video_source_.IncomingCapturedFrame(
3250 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
3251 WaitForEncodedFrame(timestamp_ms);
3252 timestamp_ms += 1000 / kLowFps;
3253
3254 EXPECT_EQ(kLowFps, fake_encoder_.GetConfiguredInputFramerate());
3255
3256 // Insert 30fps frames for just a little more than the forced update period.
3257 const int kVcmTimerIntervalFrames =
3258 (vcm::VCMProcessTimer::kDefaultProcessIntervalMs * kHighFps) / 1000;
3259 const int kFrameIntervalMs = 1000 / kHighFps;
3260 max_framerate_ = kHighFps;
3261 for (int i = 0; i < kVcmTimerIntervalFrames + 2; ++i) {
3262 video_source_.IncomingCapturedFrame(
3263 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
3264 // Wait for encoded frame, but skip ahead if it doesn't arrive as it might
3265 // be dropped if the encoder hans't been updated with the new higher target
3266 // framerate yet, causing it to overshoot the target bitrate and then
3267 // suffering the wrath of the media optimizer.
3268 TimedWaitForEncodedFrame(timestamp_ms, 2 * kFrameIntervalMs);
3269 timestamp_ms += kFrameIntervalMs;
3270 }
3271
3272 // Don expect correct measurement just yet, but it should be higher than
3273 // before.
3274 EXPECT_GT(fake_encoder_.GetConfiguredInputFramerate(), kLowFps);
3275
mflodmancc3d4422017-08-03 08:27:51 -07003276 video_stream_encoder_->Stop();
sprang4847ae62017-06-27 07:06:52 -07003277}
3278
mflodmancc3d4422017-08-03 08:27:51 -07003279TEST_F(VideoStreamEncoderTest, DoesNotUpdateBitrateAllocationWhenSuspended) {
sprang4847ae62017-06-27 07:06:52 -07003280 const int kFrameWidth = 1280;
3281 const int kFrameHeight = 720;
3282 const int kTargetBitrateBps = 1000000;
3283
3284 MockBitrateObserver bitrate_observer;
mflodmancc3d4422017-08-03 08:27:51 -07003285 video_stream_encoder_->SetBitrateObserver(&bitrate_observer);
sprang4847ae62017-06-27 07:06:52 -07003286
3287 EXPECT_CALL(bitrate_observer, OnBitrateAllocationUpdated(_)).Times(1);
3288 // Initial bitrate update.
mflodmancc3d4422017-08-03 08:27:51 -07003289 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
3290 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
sprang4847ae62017-06-27 07:06:52 -07003291
3292 // Insert a first video frame, causes another bitrate update.
3293 int64_t timestamp_ms = fake_clock_.TimeNanos() / rtc::kNumNanosecsPerMillisec;
3294 EXPECT_CALL(bitrate_observer, OnBitrateAllocationUpdated(_)).Times(1);
3295 video_source_.IncomingCapturedFrame(
3296 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
3297 WaitForEncodedFrame(timestamp_ms);
3298
3299 // Next, simulate video suspension due to pacer queue overrun.
mflodmancc3d4422017-08-03 08:27:51 -07003300 video_stream_encoder_->OnBitrateUpdated(0, 0, 1);
sprang4847ae62017-06-27 07:06:52 -07003301
3302 // Skip ahead until a new periodic parameter update should have occured.
3303 timestamp_ms += vcm::VCMProcessTimer::kDefaultProcessIntervalMs;
3304 fake_clock_.AdvanceTimeMicros(
3305 vcm::VCMProcessTimer::kDefaultProcessIntervalMs *
3306 rtc::kNumMicrosecsPerMillisec);
3307
3308 // Bitrate observer should not be called.
3309 EXPECT_CALL(bitrate_observer, OnBitrateAllocationUpdated(_)).Times(0);
3310 video_source_.IncomingCapturedFrame(
3311 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
3312 ExpectDroppedFrame();
3313
mflodmancc3d4422017-08-03 08:27:51 -07003314 video_stream_encoder_->Stop();
sprang4847ae62017-06-27 07:06:52 -07003315}
ilnik6b826ef2017-06-16 06:53:48 -07003316
perkj26091b12016-09-01 01:17:40 -07003317} // namespace webrtc