blob: b42d8e7588ad3fab147c33e2711afbb30803ac19 [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:
70 CpuOveruseDetectorProxy(const CpuOveruseOptions& options,
Niels Möller7dc26b72017-12-06 10:27:48 +010071 CpuOveruseMetricsObserver* metrics_observer)
72 : OveruseFrameDetector(options,
Niels Möller7dc26b72017-12-06 10:27:48 +010073 metrics_observer),
74 last_target_framerate_fps_(-1) {}
75 virtual ~CpuOveruseDetectorProxy() {}
76
77 void OnTargetFramerateUpdated(int framerate_fps) override {
78 rtc::CritScope cs(&lock_);
79 last_target_framerate_fps_ = framerate_fps;
80 OveruseFrameDetector::OnTargetFramerateUpdated(framerate_fps);
81 }
82
83 int GetLastTargetFramerate() {
84 rtc::CritScope cs(&lock_);
85 return last_target_framerate_fps_;
86 }
87
88 private:
89 rtc::CriticalSection lock_;
90 int last_target_framerate_fps_ RTC_GUARDED_BY(lock_);
91};
92
mflodmancc3d4422017-08-03 08:27:51 -070093class VideoStreamEncoderUnderTest : public VideoStreamEncoder {
perkj803d97f2016-11-01 11:45:46 -070094 public:
Niels Möller7dc26b72017-12-06 10:27:48 +010095 VideoStreamEncoderUnderTest(SendStatisticsProxy* stats_proxy,
96 const VideoSendStream::Config::EncoderSettings& settings)
mflodmancc3d4422017-08-03 08:27:51 -070097 : VideoStreamEncoder(
98 1 /* number_of_cores */,
99 stats_proxy,
100 settings,
101 nullptr /* pre_encode_callback */,
mflodmancc3d4422017-08-03 08:27:51 -0700102 std::unique_ptr<OveruseFrameDetector>(
Niels Möller7dc26b72017-12-06 10:27:48 +0100103 overuse_detector_proxy_ = new CpuOveruseDetectorProxy(
Niels Möller73f29cb2018-01-31 16:09:31 +0100104 CpuOveruseOptions(),
mflodmancc3d4422017-08-03 08:27:51 -0700105 stats_proxy))) {}
perkj803d97f2016-11-01 11:45:46 -0700106
sprangb1ca0732017-02-01 08:38:12 -0800107 void PostTaskAndWait(bool down, AdaptReason reason) {
perkj803d97f2016-11-01 11:45:46 -0700108 rtc::Event event(false, false);
kthelgason876222f2016-11-29 01:44:11 -0800109 encoder_queue()->PostTask([this, &event, reason, down] {
sprangb1ca0732017-02-01 08:38:12 -0800110 down ? AdaptDown(reason) : AdaptUp(reason);
perkj803d97f2016-11-01 11:45:46 -0700111 event.Set();
112 });
perkj070ba852017-02-16 15:46:27 -0800113 ASSERT_TRUE(event.Wait(5000));
perkj803d97f2016-11-01 11:45:46 -0700114 }
115
kthelgason2fc52542017-03-03 00:24:41 -0800116 // This is used as a synchronisation mechanism, to make sure that the
117 // encoder queue is not blocked before we start sending it frames.
118 void WaitUntilTaskQueueIsIdle() {
119 rtc::Event event(false, false);
120 encoder_queue()->PostTask([&event] {
121 event.Set();
122 });
123 ASSERT_TRUE(event.Wait(5000));
124 }
125
sprangb1ca0732017-02-01 08:38:12 -0800126 void TriggerCpuOveruse() { PostTaskAndWait(true, AdaptReason::kCpu); }
kthelgason876222f2016-11-29 01:44:11 -0800127
sprangb1ca0732017-02-01 08:38:12 -0800128 void TriggerCpuNormalUsage() { PostTaskAndWait(false, AdaptReason::kCpu); }
kthelgason876222f2016-11-29 01:44:11 -0800129
sprangb1ca0732017-02-01 08:38:12 -0800130 void TriggerQualityLow() { PostTaskAndWait(true, AdaptReason::kQuality); }
kthelgason876222f2016-11-29 01:44:11 -0800131
sprangb1ca0732017-02-01 08:38:12 -0800132 void TriggerQualityHigh() { PostTaskAndWait(false, AdaptReason::kQuality); }
sprangfda496a2017-06-15 04:21:07 -0700133
Niels Möller7dc26b72017-12-06 10:27:48 +0100134 CpuOveruseDetectorProxy* overuse_detector_proxy_;
perkj803d97f2016-11-01 11:45:46 -0700135};
136
asapersson5f7226f2016-11-25 04:37:00 -0800137class VideoStreamFactory
138 : public VideoEncoderConfig::VideoStreamFactoryInterface {
139 public:
sprangfda496a2017-06-15 04:21:07 -0700140 explicit VideoStreamFactory(size_t num_temporal_layers, int framerate)
141 : num_temporal_layers_(num_temporal_layers), framerate_(framerate) {
asapersson5f7226f2016-11-25 04:37:00 -0800142 EXPECT_GT(num_temporal_layers, 0u);
sprangfda496a2017-06-15 04:21:07 -0700143 EXPECT_GT(framerate, 0);
asapersson5f7226f2016-11-25 04:37:00 -0800144 }
145
146 private:
147 std::vector<VideoStream> CreateEncoderStreams(
148 int width,
149 int height,
150 const VideoEncoderConfig& encoder_config) override {
151 std::vector<VideoStream> streams =
152 test::CreateVideoStreams(width, height, encoder_config);
153 for (VideoStream& stream : streams) {
Sergey Silkina796a7e2018-03-01 15:11:29 +0100154 stream.num_temporal_layers = num_temporal_layers_;
sprangfda496a2017-06-15 04:21:07 -0700155 stream.max_framerate = framerate_;
asapersson5f7226f2016-11-25 04:37:00 -0800156 }
157 return streams;
158 }
sprangfda496a2017-06-15 04:21:07 -0700159
asapersson5f7226f2016-11-25 04:37:00 -0800160 const size_t num_temporal_layers_;
sprangfda496a2017-06-15 04:21:07 -0700161 const int framerate_;
asapersson5f7226f2016-11-25 04:37:00 -0800162};
163
ilnik6b826ef2017-06-16 06:53:48 -0700164
sprangb1ca0732017-02-01 08:38:12 -0800165class AdaptingFrameForwarder : public test::FrameForwarder {
166 public:
167 AdaptingFrameForwarder() : adaptation_enabled_(false) {}
asaperssonfab67072017-04-04 05:51:49 -0700168 ~AdaptingFrameForwarder() override {}
sprangb1ca0732017-02-01 08:38:12 -0800169
170 void set_adaptation_enabled(bool enabled) {
171 rtc::CritScope cs(&crit_);
172 adaptation_enabled_ = enabled;
173 }
174
asaperssonfab67072017-04-04 05:51:49 -0700175 bool adaption_enabled() const {
sprangb1ca0732017-02-01 08:38:12 -0800176 rtc::CritScope cs(&crit_);
177 return adaptation_enabled_;
178 }
179
asapersson09f05612017-05-15 23:40:18 -0700180 rtc::VideoSinkWants last_wants() const {
181 rtc::CritScope cs(&crit_);
182 return last_wants_;
183 }
184
Jonathan Yubc771b72017-12-08 17:04:29 -0800185 rtc::Optional<int> last_sent_width() const { return last_width_; }
186 rtc::Optional<int> last_sent_height() const { return last_height_; }
187
sprangb1ca0732017-02-01 08:38:12 -0800188 void IncomingCapturedFrame(const VideoFrame& video_frame) override {
189 int cropped_width = 0;
190 int cropped_height = 0;
191 int out_width = 0;
192 int out_height = 0;
sprangc5d62e22017-04-02 23:53:04 -0700193 if (adaption_enabled()) {
194 if (adapter_.AdaptFrameResolution(
195 video_frame.width(), video_frame.height(),
196 video_frame.timestamp_us() * 1000, &cropped_width,
197 &cropped_height, &out_width, &out_height)) {
198 VideoFrame adapted_frame(new rtc::RefCountedObject<TestBuffer>(
199 nullptr, out_width, out_height),
200 99, 99, kVideoRotation_0);
201 adapted_frame.set_ntp_time_ms(video_frame.ntp_time_ms());
202 test::FrameForwarder::IncomingCapturedFrame(adapted_frame);
Jonathan Yubc771b72017-12-08 17:04:29 -0800203 last_width_.emplace(adapted_frame.width());
204 last_height_.emplace(adapted_frame.height());
205 } else {
206 last_width_ = rtc::nullopt;
207 last_height_ = rtc::nullopt;
sprangc5d62e22017-04-02 23:53:04 -0700208 }
sprangb1ca0732017-02-01 08:38:12 -0800209 } else {
210 test::FrameForwarder::IncomingCapturedFrame(video_frame);
Jonathan Yubc771b72017-12-08 17:04:29 -0800211 last_width_.emplace(video_frame.width());
212 last_height_.emplace(video_frame.height());
sprangb1ca0732017-02-01 08:38:12 -0800213 }
214 }
215
216 void AddOrUpdateSink(rtc::VideoSinkInterface<VideoFrame>* sink,
217 const rtc::VideoSinkWants& wants) override {
218 rtc::CritScope cs(&crit_);
asapersson09f05612017-05-15 23:40:18 -0700219 last_wants_ = sink_wants();
sprangc5d62e22017-04-02 23:53:04 -0700220 adapter_.OnResolutionFramerateRequest(wants.target_pixel_count,
221 wants.max_pixel_count,
222 wants.max_framerate_fps);
sprangb1ca0732017-02-01 08:38:12 -0800223 test::FrameForwarder::AddOrUpdateSink(sink, wants);
224 }
sprangb1ca0732017-02-01 08:38:12 -0800225 cricket::VideoAdapter adapter_;
danilchapa37de392017-09-09 04:17:22 -0700226 bool adaptation_enabled_ RTC_GUARDED_BY(crit_);
227 rtc::VideoSinkWants last_wants_ RTC_GUARDED_BY(crit_);
Jonathan Yubc771b72017-12-08 17:04:29 -0800228 rtc::Optional<int> last_width_;
229 rtc::Optional<int> last_height_;
sprangb1ca0732017-02-01 08:38:12 -0800230};
sprangc5d62e22017-04-02 23:53:04 -0700231
232class MockableSendStatisticsProxy : public SendStatisticsProxy {
233 public:
234 MockableSendStatisticsProxy(Clock* clock,
235 const VideoSendStream::Config& config,
236 VideoEncoderConfig::ContentType content_type)
237 : SendStatisticsProxy(clock, config, content_type) {}
238
239 VideoSendStream::Stats GetStats() override {
240 rtc::CritScope cs(&lock_);
241 if (mock_stats_)
242 return *mock_stats_;
243 return SendStatisticsProxy::GetStats();
244 }
245
246 void SetMockStats(const VideoSendStream::Stats& stats) {
247 rtc::CritScope cs(&lock_);
248 mock_stats_.emplace(stats);
249 }
250
251 void ResetMockStats() {
252 rtc::CritScope cs(&lock_);
253 mock_stats_.reset();
254 }
255
256 private:
257 rtc::CriticalSection lock_;
danilchapa37de392017-09-09 04:17:22 -0700258 rtc::Optional<VideoSendStream::Stats> mock_stats_ RTC_GUARDED_BY(lock_);
sprangc5d62e22017-04-02 23:53:04 -0700259};
260
sprang4847ae62017-06-27 07:06:52 -0700261class MockBitrateObserver : public VideoBitrateAllocationObserver {
262 public:
263 MOCK_METHOD1(OnBitrateAllocationUpdated, void(const BitrateAllocation&));
264};
265
perkj803d97f2016-11-01 11:45:46 -0700266} // namespace
267
mflodmancc3d4422017-08-03 08:27:51 -0700268class VideoStreamEncoderTest : public ::testing::Test {
perkj26091b12016-09-01 01:17:40 -0700269 public:
270 static const int kDefaultTimeoutMs = 30 * 1000;
271
mflodmancc3d4422017-08-03 08:27:51 -0700272 VideoStreamEncoderTest()
perkj26091b12016-09-01 01:17:40 -0700273 : video_send_config_(VideoSendStream::Config(nullptr)),
perkjfa10b552016-10-02 23:45:26 -0700274 codec_width_(320),
275 codec_height_(240),
sprang4847ae62017-06-27 07:06:52 -0700276 max_framerate_(30),
perkj26091b12016-09-01 01:17:40 -0700277 fake_encoder_(),
sprangc5d62e22017-04-02 23:53:04 -0700278 stats_proxy_(new MockableSendStatisticsProxy(
perkj803d97f2016-11-01 11:45:46 -0700279 Clock::GetRealTimeClock(),
280 video_send_config_,
281 webrtc::VideoEncoderConfig::ContentType::kRealtimeVideo)),
perkj26091b12016-09-01 01:17:40 -0700282 sink_(&fake_encoder_) {}
283
284 void SetUp() override {
perkj803d97f2016-11-01 11:45:46 -0700285 metrics::Reset();
perkj26091b12016-09-01 01:17:40 -0700286 video_send_config_ = VideoSendStream::Config(nullptr);
287 video_send_config_.encoder_settings.encoder = &fake_encoder_;
Niels Möller259a4972018-04-05 15:36:51 +0200288 video_send_config_.rtp.payload_name = "FAKE";
289 video_send_config_.rtp.payload_type = 125;
perkj26091b12016-09-01 01:17:40 -0700290
Per512ecb32016-09-23 15:52:06 +0200291 VideoEncoderConfig video_encoder_config;
Niels Möller259a4972018-04-05 15:36:51 +0200292 test::FillEncoderConfiguration(kVideoCodecVP8, 1, &video_encoder_config);
sprang4847ae62017-06-27 07:06:52 -0700293 video_encoder_config.video_stream_factory =
294 new rtc::RefCountedObject<VideoStreamFactory>(1, max_framerate_);
Erik Språng08127a92016-11-16 16:41:30 +0100295 video_encoder_config_ = video_encoder_config.Copy();
sprang4847ae62017-06-27 07:06:52 -0700296
297 // Framerate limit is specified by the VideoStreamFactory.
298 std::vector<VideoStream> streams =
299 video_encoder_config.video_stream_factory->CreateEncoderStreams(
300 codec_width_, codec_height_, video_encoder_config);
301 max_framerate_ = streams[0].max_framerate;
302 fake_clock_.SetTimeMicros(1234);
303
asapersson5f7226f2016-11-25 04:37:00 -0800304 ConfigureEncoder(std::move(video_encoder_config), true /* nack_enabled */);
305 }
306
307 void ConfigureEncoder(VideoEncoderConfig video_encoder_config,
308 bool nack_enabled) {
mflodmancc3d4422017-08-03 08:27:51 -0700309 if (video_stream_encoder_)
310 video_stream_encoder_->Stop();
311 video_stream_encoder_.reset(new VideoStreamEncoderUnderTest(
perkj803d97f2016-11-01 11:45:46 -0700312 stats_proxy_.get(), video_send_config_.encoder_settings));
mflodmancc3d4422017-08-03 08:27:51 -0700313 video_stream_encoder_->SetSink(&sink_, false /* rotation_applied */);
314 video_stream_encoder_->SetSource(
sprangc5d62e22017-04-02 23:53:04 -0700315 &video_source_,
316 VideoSendStream::DegradationPreference::kMaintainFramerate);
mflodmancc3d4422017-08-03 08:27:51 -0700317 video_stream_encoder_->SetStartBitrate(kTargetBitrateBps);
318 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
319 kMaxPayloadLength, nack_enabled);
320 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
asapersson5f7226f2016-11-25 04:37:00 -0800321 }
322
323 void ResetEncoder(const std::string& payload_name,
324 size_t num_streams,
325 size_t num_temporal_layers,
emircanbbcc3562017-08-18 00:28:40 -0700326 unsigned char num_spatial_layers,
sprang4847ae62017-06-27 07:06:52 -0700327 bool nack_enabled,
328 bool screenshare) {
Niels Möller259a4972018-04-05 15:36:51 +0200329 video_send_config_.rtp.payload_name = payload_name;
asapersson5f7226f2016-11-25 04:37:00 -0800330
331 VideoEncoderConfig video_encoder_config;
Niels Möller259a4972018-04-05 15:36:51 +0200332 video_encoder_config.codec_type = PayloadStringToCodecType(payload_name);
asapersson5f7226f2016-11-25 04:37:00 -0800333 video_encoder_config.number_of_streams = num_streams;
kthelgason2bc68642017-02-07 07:02:22 -0800334 video_encoder_config.max_bitrate_bps = kTargetBitrateBps;
asapersson5f7226f2016-11-25 04:37:00 -0800335 video_encoder_config.video_stream_factory =
sprangfda496a2017-06-15 04:21:07 -0700336 new rtc::RefCountedObject<VideoStreamFactory>(num_temporal_layers,
337 kDefaultFramerate);
sprang4847ae62017-06-27 07:06:52 -0700338 video_encoder_config.content_type =
339 screenshare ? VideoEncoderConfig::ContentType::kScreen
340 : VideoEncoderConfig::ContentType::kRealtimeVideo;
emircanbbcc3562017-08-18 00:28:40 -0700341 if (payload_name == "VP9") {
342 VideoCodecVP9 vp9_settings = VideoEncoder::GetDefaultVp9Settings();
343 vp9_settings.numberOfSpatialLayers = num_spatial_layers;
344 video_encoder_config.encoder_specific_settings =
345 new rtc::RefCountedObject<
346 VideoEncoderConfig::Vp9EncoderSpecificSettings>(vp9_settings);
347 }
asapersson5f7226f2016-11-25 04:37:00 -0800348 ConfigureEncoder(std::move(video_encoder_config), nack_enabled);
perkj26091b12016-09-01 01:17:40 -0700349 }
350
sprang57c2fff2017-01-16 06:24:02 -0800351 VideoFrame CreateFrame(int64_t ntp_time_ms,
352 rtc::Event* destruction_event) const {
Per512ecb32016-09-23 15:52:06 +0200353 VideoFrame frame(new rtc::RefCountedObject<TestBuffer>(
354 destruction_event, codec_width_, codec_height_),
355 99, 99, kVideoRotation_0);
sprang57c2fff2017-01-16 06:24:02 -0800356 frame.set_ntp_time_ms(ntp_time_ms);
perkj26091b12016-09-01 01:17:40 -0700357 return frame;
358 }
359
sprang57c2fff2017-01-16 06:24:02 -0800360 VideoFrame CreateFrame(int64_t ntp_time_ms, int width, int height) const {
perkj803d97f2016-11-01 11:45:46 -0700361 VideoFrame frame(
362 new rtc::RefCountedObject<TestBuffer>(nullptr, width, height), 99, 99,
363 kVideoRotation_0);
sprang57c2fff2017-01-16 06:24:02 -0800364 frame.set_ntp_time_ms(ntp_time_ms);
sprangc5d62e22017-04-02 23:53:04 -0700365 frame.set_timestamp_us(ntp_time_ms * 1000);
perkj803d97f2016-11-01 11:45:46 -0700366 return frame;
367 }
368
asapersson02465b82017-04-10 01:12:52 -0700369 void VerifyNoLimitation(const rtc::VideoSinkWants& wants) {
asapersson02465b82017-04-10 01:12:52 -0700370 EXPECT_EQ(std::numeric_limits<int>::max(), wants.max_framerate_fps);
asapersson09f05612017-05-15 23:40:18 -0700371 EXPECT_EQ(std::numeric_limits<int>::max(), wants.max_pixel_count);
372 EXPECT_FALSE(wants.target_pixel_count);
asapersson02465b82017-04-10 01:12:52 -0700373 }
374
asapersson09f05612017-05-15 23:40:18 -0700375 void VerifyFpsEqResolutionEq(const rtc::VideoSinkWants& wants1,
376 const rtc::VideoSinkWants& wants2) {
377 EXPECT_EQ(wants1.max_framerate_fps, wants2.max_framerate_fps);
378 EXPECT_EQ(wants1.max_pixel_count, wants2.max_pixel_count);
379 }
380
381 void VerifyFpsMaxResolutionLt(const rtc::VideoSinkWants& wants1,
382 const rtc::VideoSinkWants& wants2) {
383 EXPECT_EQ(std::numeric_limits<int>::max(), wants1.max_framerate_fps);
384 EXPECT_LT(wants1.max_pixel_count, wants2.max_pixel_count);
385 EXPECT_GT(wants1.max_pixel_count, 0);
386 }
387
388 void VerifyFpsMaxResolutionGt(const rtc::VideoSinkWants& wants1,
389 const rtc::VideoSinkWants& wants2) {
390 EXPECT_EQ(std::numeric_limits<int>::max(), wants1.max_framerate_fps);
391 EXPECT_GT(wants1.max_pixel_count, wants2.max_pixel_count);
392 }
393
asaperssonf7e294d2017-06-13 23:25:22 -0700394 void VerifyFpsMaxResolutionEq(const rtc::VideoSinkWants& wants1,
395 const rtc::VideoSinkWants& wants2) {
396 EXPECT_EQ(std::numeric_limits<int>::max(), wants1.max_framerate_fps);
397 EXPECT_EQ(wants1.max_pixel_count, wants2.max_pixel_count);
398 }
399
400 void VerifyFpsLtResolutionEq(const rtc::VideoSinkWants& wants1,
401 const rtc::VideoSinkWants& wants2) {
402 EXPECT_LT(wants1.max_framerate_fps, wants2.max_framerate_fps);
403 EXPECT_EQ(wants1.max_pixel_count, wants2.max_pixel_count);
404 }
405
406 void VerifyFpsGtResolutionEq(const rtc::VideoSinkWants& wants1,
407 const rtc::VideoSinkWants& wants2) {
408 EXPECT_GT(wants1.max_framerate_fps, wants2.max_framerate_fps);
409 EXPECT_EQ(wants1.max_pixel_count, wants2.max_pixel_count);
410 }
411
412 void VerifyFpsEqResolutionLt(const rtc::VideoSinkWants& wants1,
413 const rtc::VideoSinkWants& wants2) {
414 EXPECT_EQ(wants1.max_framerate_fps, wants2.max_framerate_fps);
415 EXPECT_LT(wants1.max_pixel_count, wants2.max_pixel_count);
416 EXPECT_GT(wants1.max_pixel_count, 0);
417 }
418
419 void VerifyFpsEqResolutionGt(const rtc::VideoSinkWants& wants1,
420 const rtc::VideoSinkWants& wants2) {
421 EXPECT_EQ(wants1.max_framerate_fps, wants2.max_framerate_fps);
422 EXPECT_GT(wants1.max_pixel_count, wants2.max_pixel_count);
423 }
424
asapersson09f05612017-05-15 23:40:18 -0700425 void VerifyFpsMaxResolutionLt(const rtc::VideoSinkWants& wants,
426 int pixel_count) {
427 EXPECT_EQ(std::numeric_limits<int>::max(), wants.max_framerate_fps);
asapersson02465b82017-04-10 01:12:52 -0700428 EXPECT_LT(wants.max_pixel_count, pixel_count);
429 EXPECT_GT(wants.max_pixel_count, 0);
asapersson09f05612017-05-15 23:40:18 -0700430 }
431
432 void VerifyFpsLtResolutionMax(const rtc::VideoSinkWants& wants, int fps) {
433 EXPECT_LT(wants.max_framerate_fps, fps);
434 EXPECT_EQ(std::numeric_limits<int>::max(), wants.max_pixel_count);
435 EXPECT_FALSE(wants.target_pixel_count);
asapersson02465b82017-04-10 01:12:52 -0700436 }
437
asaperssonf7e294d2017-06-13 23:25:22 -0700438 void VerifyFpsEqResolutionMax(const rtc::VideoSinkWants& wants,
439 int expected_fps) {
440 EXPECT_EQ(expected_fps, wants.max_framerate_fps);
441 EXPECT_EQ(std::numeric_limits<int>::max(), wants.max_pixel_count);
442 EXPECT_FALSE(wants.target_pixel_count);
443 }
444
Jonathan Yubc771b72017-12-08 17:04:29 -0800445 void VerifyBalancedModeFpsRange(const rtc::VideoSinkWants& wants,
446 int last_frame_pixels) {
447 // Balanced mode should always scale FPS to the desired range before
448 // attempting to scale resolution.
449 int fps_limit = wants.max_framerate_fps;
450 if (last_frame_pixels <= 320 * 240) {
451 EXPECT_TRUE(7 <= fps_limit && fps_limit <= 10);
452 } else if (last_frame_pixels <= 480 * 270) {
453 EXPECT_TRUE(10 <= fps_limit && fps_limit <= 15);
454 } else if (last_frame_pixels <= 640 * 480) {
455 EXPECT_LE(15, fps_limit);
456 } else {
457 EXPECT_EQ(std::numeric_limits<int>::max(), fps_limit);
458 }
459 }
460
sprang4847ae62017-06-27 07:06:52 -0700461 void WaitForEncodedFrame(int64_t expected_ntp_time) {
462 sink_.WaitForEncodedFrame(expected_ntp_time);
463 fake_clock_.AdvanceTimeMicros(rtc::kNumMicrosecsPerSec / max_framerate_);
464 }
465
466 bool TimedWaitForEncodedFrame(int64_t expected_ntp_time, int64_t timeout_ms) {
467 bool ok = sink_.TimedWaitForEncodedFrame(expected_ntp_time, timeout_ms);
468 fake_clock_.AdvanceTimeMicros(rtc::kNumMicrosecsPerSec / max_framerate_);
469 return ok;
470 }
471
472 void WaitForEncodedFrame(uint32_t expected_width, uint32_t expected_height) {
473 sink_.WaitForEncodedFrame(expected_width, expected_height);
474 fake_clock_.AdvanceTimeMicros(rtc::kNumMicrosecsPerSec / max_framerate_);
475 }
476
477 void ExpectDroppedFrame() {
478 sink_.ExpectDroppedFrame();
479 fake_clock_.AdvanceTimeMicros(rtc::kNumMicrosecsPerSec / max_framerate_);
480 }
481
482 bool WaitForFrame(int64_t timeout_ms) {
483 bool ok = sink_.WaitForFrame(timeout_ms);
484 fake_clock_.AdvanceTimeMicros(rtc::kNumMicrosecsPerSec / max_framerate_);
485 return ok;
486 }
487
perkj26091b12016-09-01 01:17:40 -0700488 class TestEncoder : public test::FakeEncoder {
489 public:
490 TestEncoder()
491 : FakeEncoder(Clock::GetRealTimeClock()),
492 continue_encode_event_(false, false) {}
493
asaperssonfab67072017-04-04 05:51:49 -0700494 VideoCodec codec_config() const {
brandtre78d2662017-01-16 05:57:16 -0800495 rtc::CritScope lock(&crit_sect_);
perkjfa10b552016-10-02 23:45:26 -0700496 return config_;
497 }
498
499 void BlockNextEncode() {
brandtre78d2662017-01-16 05:57:16 -0800500 rtc::CritScope lock(&local_crit_sect_);
perkjfa10b552016-10-02 23:45:26 -0700501 block_next_encode_ = true;
502 }
503
kthelgason876222f2016-11-29 01:44:11 -0800504 VideoEncoder::ScalingSettings GetScalingSettings() const override {
kthelgason2fc52542017-03-03 00:24:41 -0800505 rtc::CritScope lock(&local_crit_sect_);
kthelgasonad9010c2017-02-14 00:46:51 -0800506 if (quality_scaling_)
Niels Möller225c7872018-02-22 15:03:53 +0100507 return VideoEncoder::ScalingSettings(1, 2, kMinPixelsPerFrame);
508 return VideoEncoder::ScalingSettings::kOff;
kthelgason876222f2016-11-29 01:44:11 -0800509 }
510
perkjfa10b552016-10-02 23:45:26 -0700511 void ContinueEncode() { continue_encode_event_.Set(); }
512
513 void CheckLastTimeStampsMatch(int64_t ntp_time_ms,
514 uint32_t timestamp) const {
brandtre78d2662017-01-16 05:57:16 -0800515 rtc::CritScope lock(&local_crit_sect_);
perkjfa10b552016-10-02 23:45:26 -0700516 EXPECT_EQ(timestamp_, timestamp);
517 EXPECT_EQ(ntp_time_ms_, ntp_time_ms);
518 }
519
kthelgason2fc52542017-03-03 00:24:41 -0800520 void SetQualityScaling(bool b) {
521 rtc::CritScope lock(&local_crit_sect_);
522 quality_scaling_ = b;
523 }
kthelgasonad9010c2017-02-14 00:46:51 -0800524
sprangfe627f32017-03-29 08:24:59 -0700525 void ForceInitEncodeFailure(bool force_failure) {
526 rtc::CritScope lock(&local_crit_sect_);
527 force_init_encode_failed_ = force_failure;
528 }
529
perkjfa10b552016-10-02 23:45:26 -0700530 private:
perkj26091b12016-09-01 01:17:40 -0700531 int32_t Encode(const VideoFrame& input_image,
532 const CodecSpecificInfo* codec_specific_info,
533 const std::vector<FrameType>* frame_types) override {
534 bool block_encode;
535 {
brandtre78d2662017-01-16 05:57:16 -0800536 rtc::CritScope lock(&local_crit_sect_);
perkj26091b12016-09-01 01:17:40 -0700537 EXPECT_GT(input_image.timestamp(), timestamp_);
538 EXPECT_GT(input_image.ntp_time_ms(), ntp_time_ms_);
539 EXPECT_EQ(input_image.timestamp(), input_image.ntp_time_ms() * 90);
540
541 timestamp_ = input_image.timestamp();
542 ntp_time_ms_ = input_image.ntp_time_ms();
perkj803d97f2016-11-01 11:45:46 -0700543 last_input_width_ = input_image.width();
544 last_input_height_ = input_image.height();
perkj26091b12016-09-01 01:17:40 -0700545 block_encode = block_next_encode_;
546 block_next_encode_ = false;
547 }
548 int32_t result =
549 FakeEncoder::Encode(input_image, codec_specific_info, frame_types);
550 if (block_encode)
perkja49cbd32016-09-16 07:53:41 -0700551 EXPECT_TRUE(continue_encode_event_.Wait(kDefaultTimeoutMs));
perkj26091b12016-09-01 01:17:40 -0700552 return result;
553 }
554
sprangfe627f32017-03-29 08:24:59 -0700555 int32_t InitEncode(const VideoCodec* config,
556 int32_t number_of_cores,
557 size_t max_payload_size) override {
558 int res =
559 FakeEncoder::InitEncode(config, number_of_cores, max_payload_size);
560 rtc::CritScope lock(&local_crit_sect_);
Erik Språng82fad3d2018-03-21 09:57:23 +0100561 if (config->codecType == kVideoCodecVP8) {
sprangfe627f32017-03-29 08:24:59 -0700562 // Simulate setting up temporal layers, in order to validate the life
563 // cycle of these objects.
564 int num_streams = std::max<int>(1, config->numberOfSimulcastStreams);
sprangfe627f32017-03-29 08:24:59 -0700565 for (int i = 0; i < num_streams; ++i) {
566 allocated_temporal_layers_.emplace_back(
Niels Möller150dcb02018-03-27 14:16:55 +0200567 TemporalLayers::CreateTemporalLayers(*config, i));
sprangfe627f32017-03-29 08:24:59 -0700568 }
569 }
570 if (force_init_encode_failed_)
571 return -1;
572 return res;
573 }
574
brandtre78d2662017-01-16 05:57:16 -0800575 rtc::CriticalSection local_crit_sect_;
danilchapa37de392017-09-09 04:17:22 -0700576 bool block_next_encode_ RTC_GUARDED_BY(local_crit_sect_) = false;
perkj26091b12016-09-01 01:17:40 -0700577 rtc::Event continue_encode_event_;
danilchapa37de392017-09-09 04:17:22 -0700578 uint32_t timestamp_ RTC_GUARDED_BY(local_crit_sect_) = 0;
579 int64_t ntp_time_ms_ RTC_GUARDED_BY(local_crit_sect_) = 0;
580 int last_input_width_ RTC_GUARDED_BY(local_crit_sect_) = 0;
581 int last_input_height_ RTC_GUARDED_BY(local_crit_sect_) = 0;
582 bool quality_scaling_ RTC_GUARDED_BY(local_crit_sect_) = true;
sprangfe627f32017-03-29 08:24:59 -0700583 std::vector<std::unique_ptr<TemporalLayers>> allocated_temporal_layers_
danilchapa37de392017-09-09 04:17:22 -0700584 RTC_GUARDED_BY(local_crit_sect_);
585 bool force_init_encode_failed_ RTC_GUARDED_BY(local_crit_sect_) = false;
perkj26091b12016-09-01 01:17:40 -0700586 };
587
mflodmancc3d4422017-08-03 08:27:51 -0700588 class TestSink : public VideoStreamEncoder::EncoderSink {
perkj26091b12016-09-01 01:17:40 -0700589 public:
590 explicit TestSink(TestEncoder* test_encoder)
591 : test_encoder_(test_encoder), encoded_frame_event_(false, false) {}
592
perkj26091b12016-09-01 01:17:40 -0700593 void WaitForEncodedFrame(int64_t expected_ntp_time) {
sprang4847ae62017-06-27 07:06:52 -0700594 EXPECT_TRUE(
595 TimedWaitForEncodedFrame(expected_ntp_time, kDefaultTimeoutMs));
596 }
597
598 bool TimedWaitForEncodedFrame(int64_t expected_ntp_time,
599 int64_t timeout_ms) {
perkj26091b12016-09-01 01:17:40 -0700600 uint32_t timestamp = 0;
sprang4847ae62017-06-27 07:06:52 -0700601 if (!encoded_frame_event_.Wait(timeout_ms))
602 return false;
perkj26091b12016-09-01 01:17:40 -0700603 {
604 rtc::CritScope lock(&crit_);
sprangb1ca0732017-02-01 08:38:12 -0800605 timestamp = last_timestamp_;
perkj26091b12016-09-01 01:17:40 -0700606 }
607 test_encoder_->CheckLastTimeStampsMatch(expected_ntp_time, timestamp);
sprang4847ae62017-06-27 07:06:52 -0700608 return true;
perkj26091b12016-09-01 01:17:40 -0700609 }
610
sprangb1ca0732017-02-01 08:38:12 -0800611 void WaitForEncodedFrame(uint32_t expected_width,
612 uint32_t expected_height) {
sprangc5d62e22017-04-02 23:53:04 -0700613 EXPECT_TRUE(encoded_frame_event_.Wait(kDefaultTimeoutMs));
Åsa Perssonc74d8da2017-12-04 14:13:56 +0100614 CheckLastFrameSizeMatches(expected_width, expected_height);
sprangc5d62e22017-04-02 23:53:04 -0700615 }
616
Åsa Perssonc74d8da2017-12-04 14:13:56 +0100617 void CheckLastFrameSizeMatches(uint32_t expected_width,
sprangc5d62e22017-04-02 23:53:04 -0700618 uint32_t expected_height) {
sprangb1ca0732017-02-01 08:38:12 -0800619 uint32_t width = 0;
620 uint32_t height = 0;
sprangb1ca0732017-02-01 08:38:12 -0800621 {
622 rtc::CritScope lock(&crit_);
623 width = last_width_;
624 height = last_height_;
625 }
626 EXPECT_EQ(expected_height, height);
627 EXPECT_EQ(expected_width, width);
628 }
629
kthelgason2fc52542017-03-03 00:24:41 -0800630 void ExpectDroppedFrame() { EXPECT_FALSE(encoded_frame_event_.Wait(100)); }
kthelgason2bc68642017-02-07 07:02:22 -0800631
sprangc5d62e22017-04-02 23:53:04 -0700632 bool WaitForFrame(int64_t timeout_ms) {
633 return encoded_frame_event_.Wait(timeout_ms);
634 }
635
perkj26091b12016-09-01 01:17:40 -0700636 void SetExpectNoFrames() {
637 rtc::CritScope lock(&crit_);
638 expect_frames_ = false;
639 }
640
asaperssonfab67072017-04-04 05:51:49 -0700641 int number_of_reconfigurations() const {
Per512ecb32016-09-23 15:52:06 +0200642 rtc::CritScope lock(&crit_);
643 return number_of_reconfigurations_;
644 }
645
asaperssonfab67072017-04-04 05:51:49 -0700646 int last_min_transmit_bitrate() const {
Per512ecb32016-09-23 15:52:06 +0200647 rtc::CritScope lock(&crit_);
648 return min_transmit_bitrate_bps_;
649 }
650
perkj26091b12016-09-01 01:17:40 -0700651 private:
sergeyu2cb155a2016-11-04 11:39:29 -0700652 Result OnEncodedImage(
653 const EncodedImage& encoded_image,
654 const CodecSpecificInfo* codec_specific_info,
655 const RTPFragmentationHeader* fragmentation) override {
Per512ecb32016-09-23 15:52:06 +0200656 rtc::CritScope lock(&crit_);
657 EXPECT_TRUE(expect_frames_);
sprangb1ca0732017-02-01 08:38:12 -0800658 last_timestamp_ = encoded_image._timeStamp;
659 last_width_ = encoded_image._encodedWidth;
660 last_height_ = encoded_image._encodedHeight;
Per512ecb32016-09-23 15:52:06 +0200661 encoded_frame_event_.Set();
sprangb1ca0732017-02-01 08:38:12 -0800662 return Result(Result::OK, last_timestamp_);
Per512ecb32016-09-23 15:52:06 +0200663 }
664
665 void OnEncoderConfigurationChanged(std::vector<VideoStream> streams,
666 int min_transmit_bitrate_bps) override {
667 rtc::CriticalSection crit_;
668 ++number_of_reconfigurations_;
669 min_transmit_bitrate_bps_ = min_transmit_bitrate_bps;
670 }
671
perkj26091b12016-09-01 01:17:40 -0700672 rtc::CriticalSection crit_;
673 TestEncoder* test_encoder_;
674 rtc::Event encoded_frame_event_;
sprangb1ca0732017-02-01 08:38:12 -0800675 uint32_t last_timestamp_ = 0;
676 uint32_t last_height_ = 0;
677 uint32_t last_width_ = 0;
perkj26091b12016-09-01 01:17:40 -0700678 bool expect_frames_ = true;
Per512ecb32016-09-23 15:52:06 +0200679 int number_of_reconfigurations_ = 0;
680 int min_transmit_bitrate_bps_ = 0;
perkj26091b12016-09-01 01:17:40 -0700681 };
682
683 VideoSendStream::Config video_send_config_;
Erik Språng08127a92016-11-16 16:41:30 +0100684 VideoEncoderConfig video_encoder_config_;
Per512ecb32016-09-23 15:52:06 +0200685 int codec_width_;
686 int codec_height_;
sprang4847ae62017-06-27 07:06:52 -0700687 int max_framerate_;
perkj26091b12016-09-01 01:17:40 -0700688 TestEncoder fake_encoder_;
sprangc5d62e22017-04-02 23:53:04 -0700689 std::unique_ptr<MockableSendStatisticsProxy> stats_proxy_;
perkj26091b12016-09-01 01:17:40 -0700690 TestSink sink_;
sprangb1ca0732017-02-01 08:38:12 -0800691 AdaptingFrameForwarder video_source_;
mflodmancc3d4422017-08-03 08:27:51 -0700692 std::unique_ptr<VideoStreamEncoderUnderTest> video_stream_encoder_;
sprang4847ae62017-06-27 07:06:52 -0700693 rtc::ScopedFakeClock fake_clock_;
perkj26091b12016-09-01 01:17:40 -0700694};
695
mflodmancc3d4422017-08-03 08:27:51 -0700696TEST_F(VideoStreamEncoderTest, EncodeOneFrame) {
697 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkj26091b12016-09-01 01:17:40 -0700698 rtc::Event frame_destroyed_event(false, false);
perkja49cbd32016-09-16 07:53:41 -0700699 video_source_.IncomingCapturedFrame(CreateFrame(1, &frame_destroyed_event));
sprang4847ae62017-06-27 07:06:52 -0700700 WaitForEncodedFrame(1);
perkja49cbd32016-09-16 07:53:41 -0700701 EXPECT_TRUE(frame_destroyed_event.Wait(kDefaultTimeoutMs));
mflodmancc3d4422017-08-03 08:27:51 -0700702 video_stream_encoder_->Stop();
perkj26091b12016-09-01 01:17:40 -0700703}
704
mflodmancc3d4422017-08-03 08:27:51 -0700705TEST_F(VideoStreamEncoderTest, DropsFramesBeforeFirstOnBitrateUpdated) {
perkj26091b12016-09-01 01:17:40 -0700706 // Dropped since no target bitrate has been set.
707 rtc::Event frame_destroyed_event(false, false);
perkja49cbd32016-09-16 07:53:41 -0700708 video_source_.IncomingCapturedFrame(CreateFrame(1, &frame_destroyed_event));
709 EXPECT_TRUE(frame_destroyed_event.Wait(kDefaultTimeoutMs));
perkj26091b12016-09-01 01:17:40 -0700710
mflodmancc3d4422017-08-03 08:27:51 -0700711 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkj26091b12016-09-01 01:17:40 -0700712
perkja49cbd32016-09-16 07:53:41 -0700713 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700714 WaitForEncodedFrame(2);
mflodmancc3d4422017-08-03 08:27:51 -0700715 video_stream_encoder_->Stop();
perkj26091b12016-09-01 01:17:40 -0700716}
717
mflodmancc3d4422017-08-03 08:27:51 -0700718TEST_F(VideoStreamEncoderTest, DropsFramesWhenRateSetToZero) {
719 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkja49cbd32016-09-16 07:53:41 -0700720 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700721 WaitForEncodedFrame(1);
perkj26091b12016-09-01 01:17:40 -0700722
mflodmancc3d4422017-08-03 08:27:51 -0700723 video_stream_encoder_->OnBitrateUpdated(0, 0, 0);
perkj26091b12016-09-01 01:17:40 -0700724 // Dropped since bitrate is zero.
perkja49cbd32016-09-16 07:53:41 -0700725 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
perkj26091b12016-09-01 01:17:40 -0700726
mflodmancc3d4422017-08-03 08:27:51 -0700727 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkja49cbd32016-09-16 07:53:41 -0700728 video_source_.IncomingCapturedFrame(CreateFrame(3, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700729 WaitForEncodedFrame(3);
mflodmancc3d4422017-08-03 08:27:51 -0700730 video_stream_encoder_->Stop();
perkj26091b12016-09-01 01:17:40 -0700731}
732
mflodmancc3d4422017-08-03 08:27:51 -0700733TEST_F(VideoStreamEncoderTest, DropsFramesWithSameOrOldNtpTimestamp) {
734 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkja49cbd32016-09-16 07:53:41 -0700735 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700736 WaitForEncodedFrame(1);
perkj26091b12016-09-01 01:17:40 -0700737
738 // This frame will be dropped since it has the same ntp timestamp.
perkja49cbd32016-09-16 07:53:41 -0700739 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
perkj26091b12016-09-01 01:17:40 -0700740
perkja49cbd32016-09-16 07:53:41 -0700741 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700742 WaitForEncodedFrame(2);
mflodmancc3d4422017-08-03 08:27:51 -0700743 video_stream_encoder_->Stop();
perkj26091b12016-09-01 01:17:40 -0700744}
745
mflodmancc3d4422017-08-03 08:27:51 -0700746TEST_F(VideoStreamEncoderTest, DropsFrameAfterStop) {
747 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkj26091b12016-09-01 01:17:40 -0700748
perkja49cbd32016-09-16 07:53:41 -0700749 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700750 WaitForEncodedFrame(1);
perkj26091b12016-09-01 01:17:40 -0700751
mflodmancc3d4422017-08-03 08:27:51 -0700752 video_stream_encoder_->Stop();
perkj26091b12016-09-01 01:17:40 -0700753 sink_.SetExpectNoFrames();
754 rtc::Event frame_destroyed_event(false, false);
perkja49cbd32016-09-16 07:53:41 -0700755 video_source_.IncomingCapturedFrame(CreateFrame(2, &frame_destroyed_event));
756 EXPECT_TRUE(frame_destroyed_event.Wait(kDefaultTimeoutMs));
perkj26091b12016-09-01 01:17:40 -0700757}
758
mflodmancc3d4422017-08-03 08:27:51 -0700759TEST_F(VideoStreamEncoderTest, DropsPendingFramesOnSlowEncode) {
760 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkj26091b12016-09-01 01:17:40 -0700761
762 fake_encoder_.BlockNextEncode();
perkja49cbd32016-09-16 07:53:41 -0700763 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700764 WaitForEncodedFrame(1);
perkj26091b12016-09-01 01:17:40 -0700765 // Here, the encoder thread will be blocked in the TestEncoder waiting for a
766 // call to ContinueEncode.
perkja49cbd32016-09-16 07:53:41 -0700767 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
768 video_source_.IncomingCapturedFrame(CreateFrame(3, nullptr));
perkj26091b12016-09-01 01:17:40 -0700769 fake_encoder_.ContinueEncode();
sprang4847ae62017-06-27 07:06:52 -0700770 WaitForEncodedFrame(3);
perkj26091b12016-09-01 01:17:40 -0700771
mflodmancc3d4422017-08-03 08:27:51 -0700772 video_stream_encoder_->Stop();
perkj26091b12016-09-01 01:17:40 -0700773}
774
mflodmancc3d4422017-08-03 08:27:51 -0700775TEST_F(VideoStreamEncoderTest,
776 ConfigureEncoderTriggersOnEncoderConfigurationChanged) {
777 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
Per21d45d22016-10-30 21:37:57 +0100778 EXPECT_EQ(0, sink_.number_of_reconfigurations());
Per512ecb32016-09-23 15:52:06 +0200779
780 // Capture a frame and wait for it to synchronize with the encoder thread.
Perf8c5f2b2016-09-23 16:24:55 +0200781 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700782 WaitForEncodedFrame(1);
Per21d45d22016-10-30 21:37:57 +0100783 // The encoder will have been configured once when the first frame is
784 // received.
785 EXPECT_EQ(1, sink_.number_of_reconfigurations());
Per512ecb32016-09-23 15:52:06 +0200786
787 VideoEncoderConfig video_encoder_config;
Niels Möller259a4972018-04-05 15:36:51 +0200788 test::FillEncoderConfiguration(kVideoCodecVP8, 1, &video_encoder_config);
Per512ecb32016-09-23 15:52:06 +0200789 video_encoder_config.min_transmit_bitrate_bps = 9999;
mflodmancc3d4422017-08-03 08:27:51 -0700790 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
791 kMaxPayloadLength,
792 true /* nack_enabled */);
Per512ecb32016-09-23 15:52:06 +0200793
794 // Capture a frame and wait for it to synchronize with the encoder thread.
Perf8c5f2b2016-09-23 16:24:55 +0200795 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700796 WaitForEncodedFrame(2);
Per21d45d22016-10-30 21:37:57 +0100797 EXPECT_EQ(2, sink_.number_of_reconfigurations());
perkj3b703ed2016-09-29 23:25:40 -0700798 EXPECT_EQ(9999, sink_.last_min_transmit_bitrate());
perkj26105b42016-09-29 22:39:10 -0700799
mflodmancc3d4422017-08-03 08:27:51 -0700800 video_stream_encoder_->Stop();
perkj26105b42016-09-29 22:39:10 -0700801}
802
mflodmancc3d4422017-08-03 08:27:51 -0700803TEST_F(VideoStreamEncoderTest, FrameResolutionChangeReconfigureEncoder) {
804 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkjfa10b552016-10-02 23:45:26 -0700805
806 // Capture a frame and wait for it to synchronize with the encoder thread.
807 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700808 WaitForEncodedFrame(1);
Per21d45d22016-10-30 21:37:57 +0100809 // The encoder will have been configured once.
810 EXPECT_EQ(1, sink_.number_of_reconfigurations());
perkjfa10b552016-10-02 23:45:26 -0700811 EXPECT_EQ(codec_width_, fake_encoder_.codec_config().width);
812 EXPECT_EQ(codec_height_, fake_encoder_.codec_config().height);
813
814 codec_width_ *= 2;
815 codec_height_ *= 2;
816 // Capture a frame with a higher resolution and wait for it to synchronize
817 // with the encoder thread.
818 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700819 WaitForEncodedFrame(2);
perkjfa10b552016-10-02 23:45:26 -0700820 EXPECT_EQ(codec_width_, fake_encoder_.codec_config().width);
821 EXPECT_EQ(codec_height_, fake_encoder_.codec_config().height);
Per21d45d22016-10-30 21:37:57 +0100822 EXPECT_EQ(2, sink_.number_of_reconfigurations());
perkjfa10b552016-10-02 23:45:26 -0700823
mflodmancc3d4422017-08-03 08:27:51 -0700824 video_stream_encoder_->Stop();
perkjfa10b552016-10-02 23:45:26 -0700825}
826
mflodmancc3d4422017-08-03 08:27:51 -0700827TEST_F(VideoStreamEncoderTest, Vp8ResilienceIsOffFor1S1TLWithNackEnabled) {
asapersson5f7226f2016-11-25 04:37:00 -0800828 const bool kNackEnabled = true;
829 const size_t kNumStreams = 1;
830 const size_t kNumTl = 1;
emircanbbcc3562017-08-18 00:28:40 -0700831 ResetEncoder("VP8", kNumStreams, kNumTl, kNumSlDummy, kNackEnabled, false);
mflodmancc3d4422017-08-03 08:27:51 -0700832 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson5f7226f2016-11-25 04:37:00 -0800833
834 // Capture a frame and wait for it to synchronize with the encoder thread.
835 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700836 WaitForEncodedFrame(1);
asapersson5f7226f2016-11-25 04:37:00 -0800837 // The encoder have been configured once when the first frame is received.
838 EXPECT_EQ(1, sink_.number_of_reconfigurations());
839 EXPECT_EQ(kVideoCodecVP8, fake_encoder_.codec_config().codecType);
840 EXPECT_EQ(kNumStreams, fake_encoder_.codec_config().numberOfSimulcastStreams);
841 EXPECT_EQ(kNumTl, fake_encoder_.codec_config().VP8()->numberOfTemporalLayers);
842 // Resilience is off for no temporal layers with nack on.
843 EXPECT_EQ(kResilienceOff, fake_encoder_.codec_config().VP8()->resilience);
mflodmancc3d4422017-08-03 08:27:51 -0700844 video_stream_encoder_->Stop();
asapersson5f7226f2016-11-25 04:37:00 -0800845}
846
mflodmancc3d4422017-08-03 08:27:51 -0700847TEST_F(VideoStreamEncoderTest, Vp8ResilienceIsOffFor2S1TlWithNackEnabled) {
asapersson5f7226f2016-11-25 04:37:00 -0800848 const bool kNackEnabled = true;
849 const size_t kNumStreams = 2;
850 const size_t kNumTl = 1;
emircanbbcc3562017-08-18 00:28:40 -0700851 ResetEncoder("VP8", kNumStreams, kNumTl, kNumSlDummy, kNackEnabled, false);
mflodmancc3d4422017-08-03 08:27:51 -0700852 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson5f7226f2016-11-25 04:37:00 -0800853
854 // Capture a frame and wait for it to synchronize with the encoder thread.
855 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700856 WaitForEncodedFrame(1);
asapersson5f7226f2016-11-25 04:37:00 -0800857 // The encoder have been configured once when the first frame is received.
858 EXPECT_EQ(1, sink_.number_of_reconfigurations());
859 EXPECT_EQ(kVideoCodecVP8, fake_encoder_.codec_config().codecType);
860 EXPECT_EQ(kNumStreams, fake_encoder_.codec_config().numberOfSimulcastStreams);
861 EXPECT_EQ(kNumTl, fake_encoder_.codec_config().VP8()->numberOfTemporalLayers);
862 // Resilience is off for no temporal layers and >1 streams with nack on.
863 EXPECT_EQ(kResilienceOff, fake_encoder_.codec_config().VP8()->resilience);
mflodmancc3d4422017-08-03 08:27:51 -0700864 video_stream_encoder_->Stop();
asapersson5f7226f2016-11-25 04:37:00 -0800865}
866
mflodmancc3d4422017-08-03 08:27:51 -0700867TEST_F(VideoStreamEncoderTest, Vp8ResilienceIsOnFor1S1TLWithNackDisabled) {
asapersson5f7226f2016-11-25 04:37:00 -0800868 const bool kNackEnabled = false;
869 const size_t kNumStreams = 1;
870 const size_t kNumTl = 1;
emircanbbcc3562017-08-18 00:28:40 -0700871 ResetEncoder("VP8", kNumStreams, kNumTl, kNumSlDummy, kNackEnabled, false);
mflodmancc3d4422017-08-03 08:27:51 -0700872 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson5f7226f2016-11-25 04:37:00 -0800873
874 // Capture a frame and wait for it to synchronize with the encoder thread.
875 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700876 WaitForEncodedFrame(1);
asapersson5f7226f2016-11-25 04:37:00 -0800877 // The encoder have been configured once when the first frame is received.
878 EXPECT_EQ(1, sink_.number_of_reconfigurations());
879 EXPECT_EQ(kVideoCodecVP8, fake_encoder_.codec_config().codecType);
880 EXPECT_EQ(kNumStreams, fake_encoder_.codec_config().numberOfSimulcastStreams);
881 EXPECT_EQ(kNumTl, fake_encoder_.codec_config().VP8()->numberOfTemporalLayers);
882 // Resilience is on for no temporal layers with nack off.
883 EXPECT_EQ(kResilientStream, fake_encoder_.codec_config().VP8()->resilience);
mflodmancc3d4422017-08-03 08:27:51 -0700884 video_stream_encoder_->Stop();
asapersson5f7226f2016-11-25 04:37:00 -0800885}
886
mflodmancc3d4422017-08-03 08:27:51 -0700887TEST_F(VideoStreamEncoderTest, Vp8ResilienceIsOnFor1S2TlWithNackEnabled) {
asapersson5f7226f2016-11-25 04:37:00 -0800888 const bool kNackEnabled = true;
889 const size_t kNumStreams = 1;
890 const size_t kNumTl = 2;
emircanbbcc3562017-08-18 00:28:40 -0700891 ResetEncoder("VP8", kNumStreams, kNumTl, kNumSlDummy, kNackEnabled, false);
mflodmancc3d4422017-08-03 08:27:51 -0700892 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson5f7226f2016-11-25 04:37:00 -0800893
894 // Capture a frame and wait for it to synchronize with the encoder thread.
895 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700896 WaitForEncodedFrame(1);
asapersson5f7226f2016-11-25 04:37:00 -0800897 // The encoder have been configured once when the first frame is received.
898 EXPECT_EQ(1, sink_.number_of_reconfigurations());
899 EXPECT_EQ(kVideoCodecVP8, fake_encoder_.codec_config().codecType);
900 EXPECT_EQ(kNumStreams, fake_encoder_.codec_config().numberOfSimulcastStreams);
901 EXPECT_EQ(kNumTl, fake_encoder_.codec_config().VP8()->numberOfTemporalLayers);
902 // Resilience is on for temporal layers.
903 EXPECT_EQ(kResilientStream, fake_encoder_.codec_config().VP8()->resilience);
mflodmancc3d4422017-08-03 08:27:51 -0700904 video_stream_encoder_->Stop();
asapersson5f7226f2016-11-25 04:37:00 -0800905}
906
emircanbbcc3562017-08-18 00:28:40 -0700907TEST_F(VideoStreamEncoderTest, Vp9ResilienceIsOffFor1SL1TLWithNackEnabled) {
908 const bool kNackEnabled = true;
909 const size_t kNumStreams = 1;
910 const size_t kNumTl = 1;
911 const unsigned char kNumSl = 1;
912 ResetEncoder("VP9", kNumStreams, kNumTl, kNumSl, kNackEnabled, false);
913 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
914
915 // Capture a frame and wait for it to synchronize with the encoder thread.
916 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
917 sink_.WaitForEncodedFrame(1);
918 // The encoder have been configured once when the first frame is received.
919 EXPECT_EQ(1, sink_.number_of_reconfigurations());
920 EXPECT_EQ(kVideoCodecVP9, fake_encoder_.codec_config().codecType);
921 EXPECT_EQ(kNumStreams, fake_encoder_.codec_config().numberOfSimulcastStreams);
922 EXPECT_EQ(kNumTl, fake_encoder_.codec_config().VP9()->numberOfTemporalLayers);
923 EXPECT_EQ(kNumSl, fake_encoder_.codec_config().VP9()->numberOfSpatialLayers);
924 // Resilience is off for no spatial and temporal layers with nack on.
925 EXPECT_FALSE(fake_encoder_.codec_config().VP9()->resilienceOn);
926 video_stream_encoder_->Stop();
927}
928
929TEST_F(VideoStreamEncoderTest, Vp9ResilienceIsOnFor1SL1TLWithNackDisabled) {
930 const bool kNackEnabled = false;
931 const size_t kNumStreams = 1;
932 const size_t kNumTl = 1;
933 const unsigned char kNumSl = 1;
934 ResetEncoder("VP9", kNumStreams, kNumTl, kNumSl, kNackEnabled, false);
935 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
936
937 // Capture a frame and wait for it to synchronize with the encoder thread.
938 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
939 sink_.WaitForEncodedFrame(1);
940 // The encoder have been configured once when the first frame is received.
941 EXPECT_EQ(1, sink_.number_of_reconfigurations());
942 EXPECT_EQ(kVideoCodecVP9, fake_encoder_.codec_config().codecType);
943 EXPECT_EQ(kNumStreams, fake_encoder_.codec_config().numberOfSimulcastStreams);
944 EXPECT_EQ(kNumTl, fake_encoder_.codec_config().VP9()->numberOfTemporalLayers);
945 EXPECT_EQ(kNumSl, fake_encoder_.codec_config().VP9()->numberOfSpatialLayers);
946 // Resilience is on if nack is off.
947 EXPECT_TRUE(fake_encoder_.codec_config().VP9()->resilienceOn);
948 video_stream_encoder_->Stop();
949}
950
951TEST_F(VideoStreamEncoderTest, Vp9ResilienceIsOnFor2SL1TLWithNackEnabled) {
952 const bool kNackEnabled = true;
953 const size_t kNumStreams = 1;
954 const size_t kNumTl = 1;
955 const unsigned char kNumSl = 2;
Sergey Silkin86684962018-03-28 19:32:37 +0200956 const int kFrameWidth = kMinVp9SpatialLayerWidth << (kNumSl - 1);
957 const int kFrameHeight = kMinVp9SpatialLayerHeight << (kNumSl - 1);
emircanbbcc3562017-08-18 00:28:40 -0700958 ResetEncoder("VP9", kNumStreams, kNumTl, kNumSl, kNackEnabled, false);
959 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
960
961 // Capture a frame and wait for it to synchronize with the encoder thread.
Sergey Silkin86684962018-03-28 19:32:37 +0200962 video_source_.IncomingCapturedFrame(
963 CreateFrame(1, kFrameWidth, kFrameHeight));
emircanbbcc3562017-08-18 00:28:40 -0700964 sink_.WaitForEncodedFrame(1);
965 // The encoder have been configured once when the first frame is received.
966 EXPECT_EQ(1, sink_.number_of_reconfigurations());
967 EXPECT_EQ(kVideoCodecVP9, fake_encoder_.codec_config().codecType);
968 EXPECT_EQ(kNumStreams, fake_encoder_.codec_config().numberOfSimulcastStreams);
969 EXPECT_EQ(kNumTl, fake_encoder_.codec_config().VP9()->numberOfTemporalLayers);
970 EXPECT_EQ(kNumSl, fake_encoder_.codec_config().VP9()->numberOfSpatialLayers);
971 // Resilience is on for spatial layers.
972 EXPECT_TRUE(fake_encoder_.codec_config().VP9()->resilienceOn);
973 video_stream_encoder_->Stop();
974}
975
976TEST_F(VideoStreamEncoderTest, Vp9ResilienceIsOnFor1SL2TLWithNackEnabled) {
977 const bool kNackEnabled = true;
978 const size_t kNumStreams = 1;
979 const size_t kNumTl = 2;
980 const unsigned char kNumSl = 1;
981 ResetEncoder("VP9", kNumStreams, kNumTl, kNumSl, kNackEnabled, false);
982 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
983
984 // Capture a frame and wait for it to synchronize with the encoder thread.
985 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
986 sink_.WaitForEncodedFrame(1);
987 // The encoder have been configured once when the first frame is received.
988 EXPECT_EQ(1, sink_.number_of_reconfigurations());
989 EXPECT_EQ(kVideoCodecVP9, fake_encoder_.codec_config().codecType);
990 EXPECT_EQ(kNumStreams, fake_encoder_.codec_config().numberOfSimulcastStreams);
991 EXPECT_EQ(kNumTl, fake_encoder_.codec_config().VP9()->numberOfTemporalLayers);
992 EXPECT_EQ(kNumSl, fake_encoder_.codec_config().VP9()->numberOfSpatialLayers);
993 // Resilience is on for temporal layers.
994 EXPECT_TRUE(fake_encoder_.codec_config().VP9()->resilienceOn);
995 video_stream_encoder_->Stop();
996}
997
mflodmancc3d4422017-08-03 08:27:51 -0700998TEST_F(VideoStreamEncoderTest, SwitchSourceDeregisterEncoderAsSink) {
perkj803d97f2016-11-01 11:45:46 -0700999 EXPECT_TRUE(video_source_.has_sinks());
1000 test::FrameForwarder new_video_source;
mflodmancc3d4422017-08-03 08:27:51 -07001001 video_stream_encoder_->SetSource(
sprangc5d62e22017-04-02 23:53:04 -07001002 &new_video_source,
1003 VideoSendStream::DegradationPreference::kMaintainFramerate);
perkj803d97f2016-11-01 11:45:46 -07001004 EXPECT_FALSE(video_source_.has_sinks());
1005 EXPECT_TRUE(new_video_source.has_sinks());
1006
mflodmancc3d4422017-08-03 08:27:51 -07001007 video_stream_encoder_->Stop();
perkj803d97f2016-11-01 11:45:46 -07001008}
1009
mflodmancc3d4422017-08-03 08:27:51 -07001010TEST_F(VideoStreamEncoderTest, SinkWantsRotationApplied) {
perkj803d97f2016-11-01 11:45:46 -07001011 EXPECT_FALSE(video_source_.sink_wants().rotation_applied);
mflodmancc3d4422017-08-03 08:27:51 -07001012 video_stream_encoder_->SetSink(&sink_, true /*rotation_applied*/);
perkj803d97f2016-11-01 11:45:46 -07001013 EXPECT_TRUE(video_source_.sink_wants().rotation_applied);
mflodmancc3d4422017-08-03 08:27:51 -07001014 video_stream_encoder_->Stop();
perkj803d97f2016-11-01 11:45:46 -07001015}
1016
Jonathan Yubc771b72017-12-08 17:04:29 -08001017TEST_F(VideoStreamEncoderTest, TestCpuDowngrades_BalancedMode) {
1018 const int kFramerateFps = 30;
asaperssonf7e294d2017-06-13 23:25:22 -07001019 const int kWidth = 1280;
1020 const int kHeight = 720;
Jonathan Yubc771b72017-12-08 17:04:29 -08001021
1022 // We rely on the automatic resolution adaptation, but we handle framerate
1023 // adaptation manually by mocking the stats proxy.
1024 video_source_.set_adaptation_enabled(true);
asaperssonf7e294d2017-06-13 23:25:22 -07001025
1026 // Enable kBalanced preference, no initial limitation.
Jonathan Yubc771b72017-12-08 17:04:29 -08001027 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
mflodmancc3d4422017-08-03 08:27:51 -07001028 video_stream_encoder_->SetSource(
Jonathan Yubc771b72017-12-08 17:04:29 -08001029 &video_source_,
mflodmancc3d4422017-08-03 08:27:51 -07001030 VideoSendStream::DegradationPreference::kBalanced);
Jonathan Yubc771b72017-12-08 17:04:29 -08001031 VerifyNoLimitation(video_source_.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07001032 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
Jonathan Yubc771b72017-12-08 17:04:29 -08001033 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
asaperssonf7e294d2017-06-13 23:25:22 -07001034 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1035
Jonathan Yubc771b72017-12-08 17:04:29 -08001036 // Adapt down as far as possible.
1037 rtc::VideoSinkWants last_wants;
1038 int64_t t = 1;
1039 int loop_count = 0;
1040 do {
1041 ++loop_count;
1042 last_wants = video_source_.sink_wants();
1043
1044 // Simulate the framerate we've been asked to adapt to.
1045 const int fps = std::min(kFramerateFps, last_wants.max_framerate_fps);
1046 const int frame_interval_ms = rtc::kNumMillisecsPerSec / fps;
1047 VideoSendStream::Stats mock_stats = stats_proxy_->GetStats();
1048 mock_stats.input_frame_rate = fps;
1049 stats_proxy_->SetMockStats(mock_stats);
1050
1051 video_source_.IncomingCapturedFrame(CreateFrame(t, kWidth, kHeight));
1052 sink_.WaitForEncodedFrame(t);
1053 t += frame_interval_ms;
1054
mflodmancc3d4422017-08-03 08:27:51 -07001055 video_stream_encoder_->TriggerCpuOveruse();
Jonathan Yubc771b72017-12-08 17:04:29 -08001056 VerifyBalancedModeFpsRange(
1057 video_source_.sink_wants(),
1058 *video_source_.last_sent_width() * *video_source_.last_sent_height());
1059 } while (video_source_.sink_wants().max_pixel_count <
1060 last_wants.max_pixel_count ||
1061 video_source_.sink_wants().max_framerate_fps <
1062 last_wants.max_framerate_fps);
asaperssonf7e294d2017-06-13 23:25:22 -07001063
Jonathan Yubc771b72017-12-08 17:04:29 -08001064 // Verify that we've adapted all the way down.
1065 stats_proxy_->ResetMockStats();
asaperssonf7e294d2017-06-13 23:25:22 -07001066 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
Jonathan Yubc771b72017-12-08 17:04:29 -08001067 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_framerate);
1068 EXPECT_EQ(loop_count - 1,
asaperssonf7e294d2017-06-13 23:25:22 -07001069 stats_proxy_->GetStats().number_of_cpu_adapt_changes);
Jonathan Yubc771b72017-12-08 17:04:29 -08001070 EXPECT_EQ(kMinPixelsPerFrame, *video_source_.last_sent_width() *
1071 *video_source_.last_sent_height());
1072 EXPECT_EQ(kMinBalancedFramerateFps,
1073 video_source_.sink_wants().max_framerate_fps);
asaperssonf7e294d2017-06-13 23:25:22 -07001074
Jonathan Yubc771b72017-12-08 17:04:29 -08001075 // Adapt back up the same number of times we adapted down.
1076 for (int i = 0; i < loop_count - 1; ++i) {
1077 last_wants = video_source_.sink_wants();
1078
1079 // Simulate the framerate we've been asked to adapt to.
1080 const int fps = std::min(kFramerateFps, last_wants.max_framerate_fps);
1081 const int frame_interval_ms = rtc::kNumMillisecsPerSec / fps;
1082 VideoSendStream::Stats mock_stats = stats_proxy_->GetStats();
1083 mock_stats.input_frame_rate = fps;
1084 stats_proxy_->SetMockStats(mock_stats);
1085
1086 video_source_.IncomingCapturedFrame(CreateFrame(t, kWidth, kHeight));
1087 sink_.WaitForEncodedFrame(t);
1088 t += frame_interval_ms;
1089
mflodmancc3d4422017-08-03 08:27:51 -07001090 video_stream_encoder_->TriggerCpuNormalUsage();
Jonathan Yubc771b72017-12-08 17:04:29 -08001091 VerifyBalancedModeFpsRange(
1092 video_source_.sink_wants(),
1093 *video_source_.last_sent_width() * *video_source_.last_sent_height());
1094 EXPECT_TRUE(video_source_.sink_wants().max_pixel_count >
1095 last_wants.max_pixel_count ||
1096 video_source_.sink_wants().max_framerate_fps >
1097 last_wants.max_framerate_fps);
asaperssonf7e294d2017-06-13 23:25:22 -07001098 }
1099
Jonathan Yubc771b72017-12-08 17:04:29 -08001100 VerifyNoLimitation(video_source_.sink_wants());
1101 stats_proxy_->ResetMockStats();
asaperssonf7e294d2017-06-13 23:25:22 -07001102 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
Jonathan Yubc771b72017-12-08 17:04:29 -08001103 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
1104 EXPECT_EQ((loop_count - 1) * 2,
1105 stats_proxy_->GetStats().number_of_cpu_adapt_changes);
asaperssonf7e294d2017-06-13 23:25:22 -07001106
mflodmancc3d4422017-08-03 08:27:51 -07001107 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07001108}
mflodmancc3d4422017-08-03 08:27:51 -07001109TEST_F(VideoStreamEncoderTest, SinkWantsStoredByDegradationPreference) {
1110 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson02465b82017-04-10 01:12:52 -07001111 VerifyNoLimitation(video_source_.sink_wants());
perkj803d97f2016-11-01 11:45:46 -07001112
sprangc5d62e22017-04-02 23:53:04 -07001113 const int kFrameWidth = 1280;
1114 const int kFrameHeight = 720;
1115 const int kFrameIntervalMs = 1000 / 30;
1116
1117 int frame_timestamp = 1;
perkj803d97f2016-11-01 11:45:46 -07001118
kthelgason5e13d412016-12-01 03:59:51 -08001119 video_source_.IncomingCapturedFrame(
sprangc5d62e22017-04-02 23:53:04 -07001120 CreateFrame(frame_timestamp, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07001121 WaitForEncodedFrame(frame_timestamp);
sprangc5d62e22017-04-02 23:53:04 -07001122 frame_timestamp += kFrameIntervalMs;
1123
perkj803d97f2016-11-01 11:45:46 -07001124 // Trigger CPU overuse.
mflodmancc3d4422017-08-03 08:27:51 -07001125 video_stream_encoder_->TriggerCpuOveruse();
perkj803d97f2016-11-01 11:45:46 -07001126 video_source_.IncomingCapturedFrame(
sprangc5d62e22017-04-02 23:53:04 -07001127 CreateFrame(frame_timestamp, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07001128 WaitForEncodedFrame(frame_timestamp);
sprangc5d62e22017-04-02 23:53:04 -07001129 frame_timestamp += kFrameIntervalMs;
sprang3ea3c772017-03-30 07:23:48 -07001130
asapersson0944a802017-04-07 00:57:58 -07001131 // Default degradation preference is maintain-framerate, so will lower max
sprangc5d62e22017-04-02 23:53:04 -07001132 // wanted resolution.
1133 EXPECT_FALSE(video_source_.sink_wants().target_pixel_count);
1134 EXPECT_LT(video_source_.sink_wants().max_pixel_count,
1135 kFrameWidth * kFrameHeight);
1136 EXPECT_EQ(std::numeric_limits<int>::max(),
1137 video_source_.sink_wants().max_framerate_fps);
1138
1139 // Set new source, switch to maintain-resolution.
perkj803d97f2016-11-01 11:45:46 -07001140 test::FrameForwarder new_video_source;
mflodmancc3d4422017-08-03 08:27:51 -07001141 video_stream_encoder_->SetSource(
perkj803d97f2016-11-01 11:45:46 -07001142 &new_video_source,
1143 VideoSendStream::DegradationPreference::kMaintainResolution);
1144
sprangc5d62e22017-04-02 23:53:04 -07001145 // Initially no degradation registered.
asapersson02465b82017-04-10 01:12:52 -07001146 VerifyNoLimitation(new_video_source.sink_wants());
perkj803d97f2016-11-01 11:45:46 -07001147
sprangc5d62e22017-04-02 23:53:04 -07001148 // Force an input frame rate to be available, or the adaptation call won't
1149 // know what framerate to adapt form.
asapersson02465b82017-04-10 01:12:52 -07001150 const int kInputFps = 30;
sprangc5d62e22017-04-02 23:53:04 -07001151 VideoSendStream::Stats stats = stats_proxy_->GetStats();
asapersson02465b82017-04-10 01:12:52 -07001152 stats.input_frame_rate = kInputFps;
sprangc5d62e22017-04-02 23:53:04 -07001153 stats_proxy_->SetMockStats(stats);
1154
mflodmancc3d4422017-08-03 08:27:51 -07001155 video_stream_encoder_->TriggerCpuOveruse();
perkj803d97f2016-11-01 11:45:46 -07001156 new_video_source.IncomingCapturedFrame(
sprangc5d62e22017-04-02 23:53:04 -07001157 CreateFrame(frame_timestamp, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07001158 WaitForEncodedFrame(frame_timestamp);
sprangc5d62e22017-04-02 23:53:04 -07001159 frame_timestamp += kFrameIntervalMs;
1160
1161 // Some framerate constraint should be set.
sprang84a37592017-02-10 07:04:27 -08001162 EXPECT_FALSE(new_video_source.sink_wants().target_pixel_count);
sprangc5d62e22017-04-02 23:53:04 -07001163 EXPECT_EQ(std::numeric_limits<int>::max(),
1164 new_video_source.sink_wants().max_pixel_count);
asapersson02465b82017-04-10 01:12:52 -07001165 EXPECT_LT(new_video_source.sink_wants().max_framerate_fps, kInputFps);
sprangc5d62e22017-04-02 23:53:04 -07001166
asapersson02465b82017-04-10 01:12:52 -07001167 // Turn off degradation completely.
mflodmancc3d4422017-08-03 08:27:51 -07001168 video_stream_encoder_->SetSource(
sprangc5d62e22017-04-02 23:53:04 -07001169 &new_video_source,
1170 VideoSendStream::DegradationPreference::kDegradationDisabled);
asapersson02465b82017-04-10 01:12:52 -07001171 VerifyNoLimitation(new_video_source.sink_wants());
sprangc5d62e22017-04-02 23:53:04 -07001172
mflodmancc3d4422017-08-03 08:27:51 -07001173 video_stream_encoder_->TriggerCpuOveruse();
sprangc5d62e22017-04-02 23:53:04 -07001174 new_video_source.IncomingCapturedFrame(
1175 CreateFrame(frame_timestamp, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07001176 WaitForEncodedFrame(frame_timestamp);
sprangc5d62e22017-04-02 23:53:04 -07001177 frame_timestamp += kFrameIntervalMs;
1178
1179 // Still no degradation.
asapersson02465b82017-04-10 01:12:52 -07001180 VerifyNoLimitation(new_video_source.sink_wants());
perkj803d97f2016-11-01 11:45:46 -07001181
1182 // Calling SetSource with resolution scaling enabled apply the old SinkWants.
mflodmancc3d4422017-08-03 08:27:51 -07001183 video_stream_encoder_->SetSource(
sprangc5d62e22017-04-02 23:53:04 -07001184 &new_video_source,
1185 VideoSendStream::DegradationPreference::kMaintainFramerate);
1186 EXPECT_LT(new_video_source.sink_wants().max_pixel_count,
1187 kFrameWidth * kFrameHeight);
sprang84a37592017-02-10 07:04:27 -08001188 EXPECT_FALSE(new_video_source.sink_wants().target_pixel_count);
sprangc5d62e22017-04-02 23:53:04 -07001189 EXPECT_EQ(std::numeric_limits<int>::max(),
1190 new_video_source.sink_wants().max_framerate_fps);
1191
1192 // Calling SetSource with framerate scaling enabled apply the old SinkWants.
mflodmancc3d4422017-08-03 08:27:51 -07001193 video_stream_encoder_->SetSource(
sprangc5d62e22017-04-02 23:53:04 -07001194 &new_video_source,
1195 VideoSendStream::DegradationPreference::kMaintainResolution);
1196 EXPECT_FALSE(new_video_source.sink_wants().target_pixel_count);
1197 EXPECT_EQ(std::numeric_limits<int>::max(),
1198 new_video_source.sink_wants().max_pixel_count);
asapersson02465b82017-04-10 01:12:52 -07001199 EXPECT_LT(new_video_source.sink_wants().max_framerate_fps, kInputFps);
perkj803d97f2016-11-01 11:45:46 -07001200
mflodmancc3d4422017-08-03 08:27:51 -07001201 video_stream_encoder_->Stop();
perkj803d97f2016-11-01 11:45:46 -07001202}
1203
mflodmancc3d4422017-08-03 08:27:51 -07001204TEST_F(VideoStreamEncoderTest, StatsTracksQualityAdaptationStats) {
1205 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkj803d97f2016-11-01 11:45:46 -07001206
asaperssonfab67072017-04-04 05:51:49 -07001207 const int kWidth = 1280;
1208 const int kHeight = 720;
asaperssonfab67072017-04-04 05:51:49 -07001209 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001210 WaitForEncodedFrame(1);
asaperssonfab67072017-04-04 05:51:49 -07001211 VideoSendStream::Stats stats = stats_proxy_->GetStats();
1212 EXPECT_FALSE(stats.bw_limited_resolution);
1213 EXPECT_EQ(0, stats.number_of_quality_adapt_changes);
1214
1215 // Trigger adapt down.
mflodmancc3d4422017-08-03 08:27:51 -07001216 video_stream_encoder_->TriggerQualityLow();
asaperssonfab67072017-04-04 05:51:49 -07001217 video_source_.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001218 WaitForEncodedFrame(2);
asaperssonfab67072017-04-04 05:51:49 -07001219
1220 stats = stats_proxy_->GetStats();
1221 EXPECT_TRUE(stats.bw_limited_resolution);
1222 EXPECT_EQ(1, stats.number_of_quality_adapt_changes);
1223
1224 // Trigger adapt up.
mflodmancc3d4422017-08-03 08:27:51 -07001225 video_stream_encoder_->TriggerQualityHigh();
asaperssonfab67072017-04-04 05:51:49 -07001226 video_source_.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001227 WaitForEncodedFrame(3);
asaperssonfab67072017-04-04 05:51:49 -07001228
1229 stats = stats_proxy_->GetStats();
1230 EXPECT_FALSE(stats.bw_limited_resolution);
1231 EXPECT_EQ(2, stats.number_of_quality_adapt_changes);
1232 EXPECT_EQ(0, stats.number_of_cpu_adapt_changes);
1233
mflodmancc3d4422017-08-03 08:27:51 -07001234 video_stream_encoder_->Stop();
asaperssonfab67072017-04-04 05:51:49 -07001235}
1236
mflodmancc3d4422017-08-03 08:27:51 -07001237TEST_F(VideoStreamEncoderTest, StatsTracksCpuAdaptationStats) {
1238 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonfab67072017-04-04 05:51:49 -07001239
1240 const int kWidth = 1280;
1241 const int kHeight = 720;
asaperssonfab67072017-04-04 05:51:49 -07001242 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001243 WaitForEncodedFrame(1);
perkj803d97f2016-11-01 11:45:46 -07001244 VideoSendStream::Stats stats = stats_proxy_->GetStats();
1245 EXPECT_FALSE(stats.cpu_limited_resolution);
1246 EXPECT_EQ(0, stats.number_of_cpu_adapt_changes);
1247
1248 // Trigger CPU overuse.
mflodmancc3d4422017-08-03 08:27:51 -07001249 video_stream_encoder_->TriggerCpuOveruse();
asaperssonfab67072017-04-04 05:51:49 -07001250 video_source_.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001251 WaitForEncodedFrame(2);
perkj803d97f2016-11-01 11:45:46 -07001252
1253 stats = stats_proxy_->GetStats();
1254 EXPECT_TRUE(stats.cpu_limited_resolution);
1255 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1256
1257 // Trigger CPU normal use.
mflodmancc3d4422017-08-03 08:27:51 -07001258 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssonfab67072017-04-04 05:51:49 -07001259 video_source_.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001260 WaitForEncodedFrame(3);
perkj803d97f2016-11-01 11:45:46 -07001261
1262 stats = stats_proxy_->GetStats();
1263 EXPECT_FALSE(stats.cpu_limited_resolution);
1264 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
asaperssonfab67072017-04-04 05:51:49 -07001265 EXPECT_EQ(0, stats.number_of_quality_adapt_changes);
perkj803d97f2016-11-01 11:45:46 -07001266
mflodmancc3d4422017-08-03 08:27:51 -07001267 video_stream_encoder_->Stop();
perkj803d97f2016-11-01 11:45:46 -07001268}
1269
mflodmancc3d4422017-08-03 08:27:51 -07001270TEST_F(VideoStreamEncoderTest, SwitchingSourceKeepsCpuAdaptation) {
1271 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
kthelgason876222f2016-11-29 01:44:11 -08001272
asaperssonfab67072017-04-04 05:51:49 -07001273 const int kWidth = 1280;
1274 const int kHeight = 720;
1275 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001276 WaitForEncodedFrame(1);
kthelgason876222f2016-11-29 01:44:11 -08001277 VideoSendStream::Stats stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001278 EXPECT_FALSE(stats.bw_limited_resolution);
kthelgason876222f2016-11-29 01:44:11 -08001279 EXPECT_FALSE(stats.cpu_limited_resolution);
1280 EXPECT_EQ(0, stats.number_of_cpu_adapt_changes);
1281
asaperssonfab67072017-04-04 05:51:49 -07001282 // Trigger CPU overuse.
mflodmancc3d4422017-08-03 08:27:51 -07001283 video_stream_encoder_->TriggerCpuOveruse();
asaperssonfab67072017-04-04 05:51:49 -07001284 video_source_.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001285 WaitForEncodedFrame(2);
kthelgason876222f2016-11-29 01:44:11 -08001286 stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001287 EXPECT_FALSE(stats.bw_limited_resolution);
kthelgason876222f2016-11-29 01:44:11 -08001288 EXPECT_TRUE(stats.cpu_limited_resolution);
1289 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1290
1291 // Set new source with adaptation still enabled.
1292 test::FrameForwarder new_video_source;
mflodmancc3d4422017-08-03 08:27:51 -07001293 video_stream_encoder_->SetSource(
sprangc5d62e22017-04-02 23:53:04 -07001294 &new_video_source,
1295 VideoSendStream::DegradationPreference::kMaintainFramerate);
kthelgason876222f2016-11-29 01:44:11 -08001296
asaperssonfab67072017-04-04 05:51:49 -07001297 new_video_source.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001298 WaitForEncodedFrame(3);
kthelgason876222f2016-11-29 01:44:11 -08001299 stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001300 EXPECT_FALSE(stats.bw_limited_resolution);
kthelgason876222f2016-11-29 01:44:11 -08001301 EXPECT_TRUE(stats.cpu_limited_resolution);
1302 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1303
1304 // Set adaptation disabled.
mflodmancc3d4422017-08-03 08:27:51 -07001305 video_stream_encoder_->SetSource(
kthelgason876222f2016-11-29 01:44:11 -08001306 &new_video_source,
sprangc5d62e22017-04-02 23:53:04 -07001307 VideoSendStream::DegradationPreference::kDegradationDisabled);
kthelgason876222f2016-11-29 01:44:11 -08001308
asaperssonfab67072017-04-04 05:51:49 -07001309 new_video_source.IncomingCapturedFrame(CreateFrame(4, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001310 WaitForEncodedFrame(4);
kthelgason876222f2016-11-29 01:44:11 -08001311 stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001312 EXPECT_FALSE(stats.bw_limited_resolution);
kthelgason876222f2016-11-29 01:44:11 -08001313 EXPECT_FALSE(stats.cpu_limited_resolution);
1314 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1315
1316 // Set adaptation back to enabled.
mflodmancc3d4422017-08-03 08:27:51 -07001317 video_stream_encoder_->SetSource(
sprangc5d62e22017-04-02 23:53:04 -07001318 &new_video_source,
1319 VideoSendStream::DegradationPreference::kMaintainFramerate);
kthelgason876222f2016-11-29 01:44:11 -08001320
asaperssonfab67072017-04-04 05:51:49 -07001321 new_video_source.IncomingCapturedFrame(CreateFrame(5, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001322 WaitForEncodedFrame(5);
kthelgason876222f2016-11-29 01:44:11 -08001323 stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001324 EXPECT_FALSE(stats.bw_limited_resolution);
kthelgason876222f2016-11-29 01:44:11 -08001325 EXPECT_TRUE(stats.cpu_limited_resolution);
1326 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1327
asaperssonfab67072017-04-04 05:51:49 -07001328 // Trigger CPU normal use.
mflodmancc3d4422017-08-03 08:27:51 -07001329 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssonfab67072017-04-04 05:51:49 -07001330 new_video_source.IncomingCapturedFrame(CreateFrame(6, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001331 WaitForEncodedFrame(6);
kthelgason876222f2016-11-29 01:44:11 -08001332 stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001333 EXPECT_FALSE(stats.bw_limited_resolution);
kthelgason876222f2016-11-29 01:44:11 -08001334 EXPECT_FALSE(stats.cpu_limited_resolution);
1335 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
asapersson02465b82017-04-10 01:12:52 -07001336 EXPECT_EQ(0, stats.number_of_quality_adapt_changes);
kthelgason876222f2016-11-29 01:44:11 -08001337
mflodmancc3d4422017-08-03 08:27:51 -07001338 video_stream_encoder_->Stop();
kthelgason876222f2016-11-29 01:44:11 -08001339}
1340
mflodmancc3d4422017-08-03 08:27:51 -07001341TEST_F(VideoStreamEncoderTest, SwitchingSourceKeepsQualityAdaptation) {
1342 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
kthelgason876222f2016-11-29 01:44:11 -08001343
asaperssonfab67072017-04-04 05:51:49 -07001344 const int kWidth = 1280;
1345 const int kHeight = 720;
1346 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001347 WaitForEncodedFrame(1);
kthelgason876222f2016-11-29 01:44:11 -08001348 VideoSendStream::Stats stats = stats_proxy_->GetStats();
kthelgason876222f2016-11-29 01:44:11 -08001349 EXPECT_FALSE(stats.bw_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001350 EXPECT_FALSE(stats.bw_limited_framerate);
asaperssonfab67072017-04-04 05:51:49 -07001351 EXPECT_EQ(0, stats.number_of_quality_adapt_changes);
kthelgason876222f2016-11-29 01:44:11 -08001352
1353 // Set new source with adaptation still enabled.
1354 test::FrameForwarder new_video_source;
mflodmancc3d4422017-08-03 08:27:51 -07001355 video_stream_encoder_->SetSource(
1356 &new_video_source,
1357 VideoSendStream::DegradationPreference::kBalanced);
kthelgason876222f2016-11-29 01:44:11 -08001358
asaperssonfab67072017-04-04 05:51:49 -07001359 new_video_source.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001360 WaitForEncodedFrame(2);
kthelgason876222f2016-11-29 01:44:11 -08001361 stats = stats_proxy_->GetStats();
kthelgason876222f2016-11-29 01:44:11 -08001362 EXPECT_FALSE(stats.bw_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001363 EXPECT_FALSE(stats.bw_limited_framerate);
asaperssonfab67072017-04-04 05:51:49 -07001364 EXPECT_EQ(0, stats.number_of_quality_adapt_changes);
kthelgason876222f2016-11-29 01:44:11 -08001365
asaperssonfab67072017-04-04 05:51:49 -07001366 // Trigger adapt down.
mflodmancc3d4422017-08-03 08:27:51 -07001367 video_stream_encoder_->TriggerQualityLow();
asaperssonfab67072017-04-04 05:51:49 -07001368 new_video_source.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001369 WaitForEncodedFrame(3);
kthelgason876222f2016-11-29 01:44:11 -08001370 stats = stats_proxy_->GetStats();
kthelgason876222f2016-11-29 01:44:11 -08001371 EXPECT_TRUE(stats.bw_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001372 EXPECT_FALSE(stats.bw_limited_framerate);
asaperssonfab67072017-04-04 05:51:49 -07001373 EXPECT_EQ(1, stats.number_of_quality_adapt_changes);
kthelgason876222f2016-11-29 01:44:11 -08001374
asaperssonfab67072017-04-04 05:51:49 -07001375 // Set new source with adaptation still enabled.
mflodmancc3d4422017-08-03 08:27:51 -07001376 video_stream_encoder_->SetSource(
1377 &new_video_source,
1378 VideoSendStream::DegradationPreference::kBalanced);
kthelgason876222f2016-11-29 01:44:11 -08001379
asaperssonfab67072017-04-04 05:51:49 -07001380 new_video_source.IncomingCapturedFrame(CreateFrame(4, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001381 WaitForEncodedFrame(4);
kthelgason876222f2016-11-29 01:44:11 -08001382 stats = stats_proxy_->GetStats();
kthelgason876222f2016-11-29 01:44:11 -08001383 EXPECT_TRUE(stats.bw_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001384 EXPECT_FALSE(stats.bw_limited_framerate);
asaperssonfab67072017-04-04 05:51:49 -07001385 EXPECT_EQ(1, stats.number_of_quality_adapt_changes);
kthelgason876222f2016-11-29 01:44:11 -08001386
asapersson02465b82017-04-10 01:12:52 -07001387 // Disable resolution scaling.
mflodmancc3d4422017-08-03 08:27:51 -07001388 video_stream_encoder_->SetSource(
kthelgason876222f2016-11-29 01:44:11 -08001389 &new_video_source,
1390 VideoSendStream::DegradationPreference::kMaintainResolution);
1391
asaperssonfab67072017-04-04 05:51:49 -07001392 new_video_source.IncomingCapturedFrame(CreateFrame(5, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001393 WaitForEncodedFrame(5);
kthelgason876222f2016-11-29 01:44:11 -08001394 stats = stats_proxy_->GetStats();
kthelgason876222f2016-11-29 01:44:11 -08001395 EXPECT_FALSE(stats.bw_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001396 EXPECT_FALSE(stats.bw_limited_framerate);
asaperssonfab67072017-04-04 05:51:49 -07001397 EXPECT_EQ(1, stats.number_of_quality_adapt_changes);
1398 EXPECT_EQ(0, stats.number_of_cpu_adapt_changes);
kthelgason876222f2016-11-29 01:44:11 -08001399
mflodmancc3d4422017-08-03 08:27:51 -07001400 video_stream_encoder_->Stop();
kthelgason876222f2016-11-29 01:44:11 -08001401}
1402
mflodmancc3d4422017-08-03 08:27:51 -07001403TEST_F(VideoStreamEncoderTest,
1404 QualityAdaptationStatsAreResetWhenScalerIsDisabled) {
1405 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson36e9eb42017-03-31 05:29:12 -07001406
1407 const int kWidth = 1280;
1408 const int kHeight = 720;
1409 video_source_.set_adaptation_enabled(true);
1410 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001411 WaitForEncodedFrame(1);
asapersson36e9eb42017-03-31 05:29:12 -07001412 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1413 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1414 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1415
1416 // Trigger adapt down.
mflodmancc3d4422017-08-03 08:27:51 -07001417 video_stream_encoder_->TriggerQualityLow();
asapersson36e9eb42017-03-31 05:29:12 -07001418 video_source_.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001419 WaitForEncodedFrame(2);
asapersson36e9eb42017-03-31 05:29:12 -07001420 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1421 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1422 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1423
1424 // Trigger overuse.
mflodmancc3d4422017-08-03 08:27:51 -07001425 video_stream_encoder_->TriggerCpuOveruse();
asapersson36e9eb42017-03-31 05:29:12 -07001426 video_source_.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001427 WaitForEncodedFrame(3);
asapersson36e9eb42017-03-31 05:29:12 -07001428 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1429 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1430 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1431
1432 // Set source with adaptation still enabled but quality scaler is off.
1433 fake_encoder_.SetQualityScaling(false);
mflodmancc3d4422017-08-03 08:27:51 -07001434 video_stream_encoder_->SetSource(
sprangc5d62e22017-04-02 23:53:04 -07001435 &video_source_,
1436 VideoSendStream::DegradationPreference::kMaintainFramerate);
asapersson36e9eb42017-03-31 05:29:12 -07001437
1438 video_source_.IncomingCapturedFrame(CreateFrame(4, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001439 WaitForEncodedFrame(4);
asapersson36e9eb42017-03-31 05:29:12 -07001440 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1441 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1442 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1443
mflodmancc3d4422017-08-03 08:27:51 -07001444 video_stream_encoder_->Stop();
asapersson36e9eb42017-03-31 05:29:12 -07001445}
1446
mflodmancc3d4422017-08-03 08:27:51 -07001447TEST_F(VideoStreamEncoderTest,
1448 StatsTracksCpuAdaptationStatsWhenSwitchingSource) {
1449 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkj803d97f2016-11-01 11:45:46 -07001450
asapersson0944a802017-04-07 00:57:58 -07001451 const int kWidth = 1280;
1452 const int kHeight = 720;
sprang84a37592017-02-10 07:04:27 -08001453 int sequence = 1;
perkj803d97f2016-11-01 11:45:46 -07001454
asaperssonfab67072017-04-04 05:51:49 -07001455 video_source_.IncomingCapturedFrame(CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001456 WaitForEncodedFrame(sequence++);
perkj803d97f2016-11-01 11:45:46 -07001457 VideoSendStream::Stats stats = stats_proxy_->GetStats();
sprang84a37592017-02-10 07:04:27 -08001458 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001459 EXPECT_FALSE(stats.cpu_limited_framerate);
sprang84a37592017-02-10 07:04:27 -08001460 EXPECT_EQ(0, stats.number_of_cpu_adapt_changes);
1461
asapersson02465b82017-04-10 01:12:52 -07001462 // Trigger CPU overuse, should now adapt down.
mflodmancc3d4422017-08-03 08:27:51 -07001463 video_stream_encoder_->TriggerCpuOveruse();
asaperssonfab67072017-04-04 05:51:49 -07001464 video_source_.IncomingCapturedFrame(CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001465 WaitForEncodedFrame(sequence++);
sprang84a37592017-02-10 07:04:27 -08001466 stats = stats_proxy_->GetStats();
perkj803d97f2016-11-01 11:45:46 -07001467 EXPECT_TRUE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001468 EXPECT_FALSE(stats.cpu_limited_framerate);
perkj803d97f2016-11-01 11:45:46 -07001469 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1470
1471 // Set new source with adaptation still enabled.
1472 test::FrameForwarder new_video_source;
mflodmancc3d4422017-08-03 08:27:51 -07001473 video_stream_encoder_->SetSource(
sprangc5d62e22017-04-02 23:53:04 -07001474 &new_video_source,
1475 VideoSendStream::DegradationPreference::kMaintainFramerate);
perkj803d97f2016-11-01 11:45:46 -07001476
1477 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001478 CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001479 WaitForEncodedFrame(sequence++);
perkj803d97f2016-11-01 11:45:46 -07001480 stats = stats_proxy_->GetStats();
1481 EXPECT_TRUE(stats.cpu_limited_resolution);
asapersson09f05612017-05-15 23:40:18 -07001482 EXPECT_FALSE(stats.cpu_limited_framerate);
perkj803d97f2016-11-01 11:45:46 -07001483 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1484
sprangc5d62e22017-04-02 23:53:04 -07001485 // Set cpu adaptation by frame dropping.
mflodmancc3d4422017-08-03 08:27:51 -07001486 video_stream_encoder_->SetSource(
perkj803d97f2016-11-01 11:45:46 -07001487 &new_video_source,
1488 VideoSendStream::DegradationPreference::kMaintainResolution);
1489 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001490 CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001491 WaitForEncodedFrame(sequence++);
perkj803d97f2016-11-01 11:45:46 -07001492 stats = stats_proxy_->GetStats();
sprangc5d62e22017-04-02 23:53:04 -07001493 // Not adapted at first.
perkj803d97f2016-11-01 11:45:46 -07001494 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson09f05612017-05-15 23:40:18 -07001495 EXPECT_FALSE(stats.cpu_limited_framerate);
perkj803d97f2016-11-01 11:45:46 -07001496 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1497
sprangc5d62e22017-04-02 23:53:04 -07001498 // Force an input frame rate to be available, or the adaptation call won't
asapersson09f05612017-05-15 23:40:18 -07001499 // know what framerate to adapt from.
sprangc5d62e22017-04-02 23:53:04 -07001500 VideoSendStream::Stats mock_stats = stats_proxy_->GetStats();
1501 mock_stats.input_frame_rate = 30;
1502 stats_proxy_->SetMockStats(mock_stats);
mflodmancc3d4422017-08-03 08:27:51 -07001503 video_stream_encoder_->TriggerCpuOveruse();
sprangc5d62e22017-04-02 23:53:04 -07001504 stats_proxy_->ResetMockStats();
1505
1506 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001507 CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001508 WaitForEncodedFrame(sequence++);
sprangc5d62e22017-04-02 23:53:04 -07001509
1510 // Framerate now adapted.
1511 stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001512 EXPECT_FALSE(stats.cpu_limited_resolution);
1513 EXPECT_TRUE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001514 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
1515
1516 // Disable CPU adaptation.
mflodmancc3d4422017-08-03 08:27:51 -07001517 video_stream_encoder_->SetSource(
sprangc5d62e22017-04-02 23:53:04 -07001518 &new_video_source,
1519 VideoSendStream::DegradationPreference::kDegradationDisabled);
1520 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001521 CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001522 WaitForEncodedFrame(sequence++);
sprangc5d62e22017-04-02 23:53:04 -07001523
1524 stats = stats_proxy_->GetStats();
1525 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001526 EXPECT_FALSE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001527 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
1528
1529 // Try to trigger overuse. Should not succeed.
1530 stats_proxy_->SetMockStats(mock_stats);
mflodmancc3d4422017-08-03 08:27:51 -07001531 video_stream_encoder_->TriggerCpuOveruse();
sprangc5d62e22017-04-02 23:53:04 -07001532 stats_proxy_->ResetMockStats();
1533
1534 stats = stats_proxy_->GetStats();
1535 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001536 EXPECT_FALSE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001537 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
1538
1539 // Switch back the source with resolution adaptation enabled.
mflodmancc3d4422017-08-03 08:27:51 -07001540 video_stream_encoder_->SetSource(
sprangc5d62e22017-04-02 23:53:04 -07001541 &video_source_,
1542 VideoSendStream::DegradationPreference::kMaintainFramerate);
asaperssonfab67072017-04-04 05:51:49 -07001543 video_source_.IncomingCapturedFrame(CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001544 WaitForEncodedFrame(sequence++);
perkj803d97f2016-11-01 11:45:46 -07001545 stats = stats_proxy_->GetStats();
1546 EXPECT_TRUE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001547 EXPECT_FALSE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001548 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
perkj803d97f2016-11-01 11:45:46 -07001549
1550 // Trigger CPU normal usage.
mflodmancc3d4422017-08-03 08:27:51 -07001551 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssonfab67072017-04-04 05:51:49 -07001552 video_source_.IncomingCapturedFrame(CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001553 WaitForEncodedFrame(sequence++);
perkj803d97f2016-11-01 11:45:46 -07001554 stats = stats_proxy_->GetStats();
1555 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001556 EXPECT_FALSE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001557 EXPECT_EQ(3, stats.number_of_cpu_adapt_changes);
1558
1559 // Back to the source with adaptation off, set it back to maintain-resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001560 video_stream_encoder_->SetSource(
sprangc5d62e22017-04-02 23:53:04 -07001561 &new_video_source,
1562 VideoSendStream::DegradationPreference::kMaintainResolution);
1563 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001564 CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001565 WaitForEncodedFrame(sequence++);
sprangc5d62e22017-04-02 23:53:04 -07001566 stats = stats_proxy_->GetStats();
asapersson13874762017-06-07 00:01:02 -07001567 // Disabled, since we previously switched the source to disabled.
sprangc5d62e22017-04-02 23:53:04 -07001568 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001569 EXPECT_TRUE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001570 EXPECT_EQ(3, stats.number_of_cpu_adapt_changes);
1571
1572 // Trigger CPU normal usage.
mflodmancc3d4422017-08-03 08:27:51 -07001573 video_stream_encoder_->TriggerCpuNormalUsage();
sprangc5d62e22017-04-02 23:53:04 -07001574 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001575 CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001576 WaitForEncodedFrame(sequence++);
sprangc5d62e22017-04-02 23:53:04 -07001577 stats = stats_proxy_->GetStats();
1578 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001579 EXPECT_FALSE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001580 EXPECT_EQ(4, stats.number_of_cpu_adapt_changes);
asapersson02465b82017-04-10 01:12:52 -07001581 EXPECT_EQ(0, stats.number_of_quality_adapt_changes);
perkj803d97f2016-11-01 11:45:46 -07001582
mflodmancc3d4422017-08-03 08:27:51 -07001583 video_stream_encoder_->Stop();
perkj803d97f2016-11-01 11:45:46 -07001584}
1585
mflodmancc3d4422017-08-03 08:27:51 -07001586TEST_F(VideoStreamEncoderTest, StatsTracksPreferredBitrate) {
1587 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
Erik Språng08127a92016-11-16 16:41:30 +01001588
asaperssonfab67072017-04-04 05:51:49 -07001589 const int kWidth = 1280;
1590 const int kHeight = 720;
1591 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001592 WaitForEncodedFrame(1);
Erik Språng08127a92016-11-16 16:41:30 +01001593
1594 VideoSendStream::Stats stats = stats_proxy_->GetStats();
1595 EXPECT_EQ(video_encoder_config_.max_bitrate_bps,
1596 stats.preferred_media_bitrate_bps);
1597
mflodmancc3d4422017-08-03 08:27:51 -07001598 video_stream_encoder_->Stop();
Erik Språng08127a92016-11-16 16:41:30 +01001599}
1600
mflodmancc3d4422017-08-03 08:27:51 -07001601TEST_F(VideoStreamEncoderTest,
1602 ScalingUpAndDownDoesNothingWithMaintainResolution) {
asaperssonfab67072017-04-04 05:51:49 -07001603 const int kWidth = 1280;
1604 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001605 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
kthelgason876222f2016-11-29 01:44:11 -08001606
asaperssonfab67072017-04-04 05:51:49 -07001607 // Expect no scaling to begin with.
asapersson02465b82017-04-10 01:12:52 -07001608 VerifyNoLimitation(video_source_.sink_wants());
kthelgason876222f2016-11-29 01:44:11 -08001609
asaperssonfab67072017-04-04 05:51:49 -07001610 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001611 WaitForEncodedFrame(1);
kthelgason876222f2016-11-29 01:44:11 -08001612
asaperssonfab67072017-04-04 05:51:49 -07001613 // Trigger scale down.
mflodmancc3d4422017-08-03 08:27:51 -07001614 video_stream_encoder_->TriggerQualityLow();
kthelgason5e13d412016-12-01 03:59:51 -08001615
asaperssonfab67072017-04-04 05:51:49 -07001616 video_source_.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001617 WaitForEncodedFrame(2);
kthelgason5e13d412016-12-01 03:59:51 -08001618
kthelgason876222f2016-11-29 01:44:11 -08001619 // Expect a scale down.
1620 EXPECT_TRUE(video_source_.sink_wants().max_pixel_count);
asaperssonfab67072017-04-04 05:51:49 -07001621 EXPECT_LT(video_source_.sink_wants().max_pixel_count, kWidth * kHeight);
kthelgason876222f2016-11-29 01:44:11 -08001622
asapersson02465b82017-04-10 01:12:52 -07001623 // Set resolution scaling disabled.
kthelgason876222f2016-11-29 01:44:11 -08001624 test::FrameForwarder new_video_source;
mflodmancc3d4422017-08-03 08:27:51 -07001625 video_stream_encoder_->SetSource(
kthelgason876222f2016-11-29 01:44:11 -08001626 &new_video_source,
1627 VideoSendStream::DegradationPreference::kMaintainResolution);
1628
asaperssonfab67072017-04-04 05:51:49 -07001629 // Trigger scale down.
mflodmancc3d4422017-08-03 08:27:51 -07001630 video_stream_encoder_->TriggerQualityLow();
asaperssonfab67072017-04-04 05:51:49 -07001631 new_video_source.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001632 WaitForEncodedFrame(3);
kthelgason876222f2016-11-29 01:44:11 -08001633
asaperssonfab67072017-04-04 05:51:49 -07001634 // Expect no scaling.
sprangc5d62e22017-04-02 23:53:04 -07001635 EXPECT_EQ(std::numeric_limits<int>::max(),
1636 new_video_source.sink_wants().max_pixel_count);
kthelgason876222f2016-11-29 01:44:11 -08001637
asaperssonfab67072017-04-04 05:51:49 -07001638 // Trigger scale up.
mflodmancc3d4422017-08-03 08:27:51 -07001639 video_stream_encoder_->TriggerQualityHigh();
asaperssonfab67072017-04-04 05:51:49 -07001640 new_video_source.IncomingCapturedFrame(CreateFrame(4, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001641 WaitForEncodedFrame(4);
kthelgason876222f2016-11-29 01:44:11 -08001642
asapersson02465b82017-04-10 01:12:52 -07001643 // Expect nothing to change, still no scaling.
sprangc5d62e22017-04-02 23:53:04 -07001644 EXPECT_EQ(std::numeric_limits<int>::max(),
1645 new_video_source.sink_wants().max_pixel_count);
kthelgason876222f2016-11-29 01:44:11 -08001646
mflodmancc3d4422017-08-03 08:27:51 -07001647 video_stream_encoder_->Stop();
kthelgason876222f2016-11-29 01:44:11 -08001648}
1649
mflodmancc3d4422017-08-03 08:27:51 -07001650TEST_F(VideoStreamEncoderTest,
1651 SkipsSameAdaptDownRequest_MaintainFramerateMode) {
asapersson02465b82017-04-10 01:12:52 -07001652 const int kWidth = 1280;
1653 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001654 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson02465b82017-04-10 01:12:52 -07001655
1656 // Enable kMaintainFramerate preference, no initial limitation.
1657 test::FrameForwarder source;
mflodmancc3d4422017-08-03 08:27:51 -07001658 video_stream_encoder_->SetSource(
asapersson02465b82017-04-10 01:12:52 -07001659 &source, VideoSendStream::DegradationPreference::kMaintainFramerate);
1660
1661 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001662 WaitForEncodedFrame(1);
asapersson02465b82017-04-10 01:12:52 -07001663 VerifyNoLimitation(source.sink_wants());
1664 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1665 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1666
1667 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001668 video_stream_encoder_->TriggerCpuOveruse();
asapersson09f05612017-05-15 23:40:18 -07001669 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
asapersson02465b82017-04-10 01:12:52 -07001670 const int kLastMaxPixelCount = source.sink_wants().max_pixel_count;
1671 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1672 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1673
1674 // Trigger adapt down for same input resolution, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07001675 video_stream_encoder_->TriggerCpuOveruse();
asapersson02465b82017-04-10 01:12:52 -07001676 EXPECT_EQ(kLastMaxPixelCount, source.sink_wants().max_pixel_count);
1677 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1678 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1679
mflodmancc3d4422017-08-03 08:27:51 -07001680 video_stream_encoder_->Stop();
asapersson02465b82017-04-10 01:12:52 -07001681}
1682
mflodmancc3d4422017-08-03 08:27:51 -07001683TEST_F(VideoStreamEncoderTest, SkipsSameOrLargerAdaptDownRequest_BalancedMode) {
asaperssonf7e294d2017-06-13 23:25:22 -07001684 const int kWidth = 1280;
1685 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001686 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -07001687
1688 // Enable kBalanced preference, no initial limitation.
1689 test::FrameForwarder source;
mflodmancc3d4422017-08-03 08:27:51 -07001690 video_stream_encoder_->SetSource(
1691 &source,
1692 VideoSendStream::DegradationPreference::kBalanced);
asaperssonf7e294d2017-06-13 23:25:22 -07001693 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
1694 sink_.WaitForEncodedFrame(1);
1695 VerifyNoLimitation(source.sink_wants());
1696
1697 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001698 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07001699 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
1700 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1701 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1702 const int kLastMaxPixelCount = source.sink_wants().max_pixel_count;
1703
1704 // Trigger adapt down for same input resolution, expect no change.
1705 source.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
1706 sink_.WaitForEncodedFrame(2);
mflodmancc3d4422017-08-03 08:27:51 -07001707 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07001708 EXPECT_EQ(kLastMaxPixelCount, source.sink_wants().max_pixel_count);
1709 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1710 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1711
1712 // Trigger adapt down for larger input resolution, expect no change.
1713 source.IncomingCapturedFrame(CreateFrame(3, kWidth + 1, kHeight + 1));
1714 sink_.WaitForEncodedFrame(3);
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
mflodmancc3d4422017-08-03 08:27:51 -07001720 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07001721}
1722
mflodmancc3d4422017-08-03 08:27:51 -07001723TEST_F(VideoStreamEncoderTest,
1724 NoChangeForInitialNormalUsage_MaintainFramerateMode) {
asapersson02465b82017-04-10 01:12:52 -07001725 const int kWidth = 1280;
1726 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001727 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson02465b82017-04-10 01:12:52 -07001728
1729 // Enable kMaintainFramerate preference, no initial limitation.
1730 test::FrameForwarder source;
mflodmancc3d4422017-08-03 08:27:51 -07001731 video_stream_encoder_->SetSource(
asapersson02465b82017-04-10 01:12:52 -07001732 &source, VideoSendStream::DegradationPreference::kMaintainFramerate);
1733
1734 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001735 WaitForEncodedFrame(kWidth, kHeight);
asapersson02465b82017-04-10 01:12:52 -07001736 VerifyNoLimitation(source.sink_wants());
1737 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1738 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1739
1740 // Trigger adapt up, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07001741 video_stream_encoder_->TriggerCpuNormalUsage();
asapersson02465b82017-04-10 01:12:52 -07001742 VerifyNoLimitation(source.sink_wants());
1743 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1744 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1745
mflodmancc3d4422017-08-03 08:27:51 -07001746 video_stream_encoder_->Stop();
asapersson02465b82017-04-10 01:12:52 -07001747}
1748
mflodmancc3d4422017-08-03 08:27:51 -07001749TEST_F(VideoStreamEncoderTest,
1750 NoChangeForInitialNormalUsage_MaintainResolutionMode) {
asapersson02465b82017-04-10 01:12:52 -07001751 const int kWidth = 1280;
1752 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001753 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson02465b82017-04-10 01:12:52 -07001754
1755 // Enable kMaintainResolution preference, no initial limitation.
1756 test::FrameForwarder source;
mflodmancc3d4422017-08-03 08:27:51 -07001757 video_stream_encoder_->SetSource(
asapersson02465b82017-04-10 01:12:52 -07001758 &source, VideoSendStream::DegradationPreference::kMaintainResolution);
1759
1760 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001761 WaitForEncodedFrame(kWidth, kHeight);
asapersson02465b82017-04-10 01:12:52 -07001762 VerifyNoLimitation(source.sink_wants());
asapersson09f05612017-05-15 23:40:18 -07001763 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
asapersson02465b82017-04-10 01:12:52 -07001764 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1765
1766 // Trigger adapt up, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07001767 video_stream_encoder_->TriggerCpuNormalUsage();
asapersson02465b82017-04-10 01:12:52 -07001768 VerifyNoLimitation(source.sink_wants());
asapersson09f05612017-05-15 23:40:18 -07001769 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
asapersson02465b82017-04-10 01:12:52 -07001770 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1771
mflodmancc3d4422017-08-03 08:27:51 -07001772 video_stream_encoder_->Stop();
asapersson02465b82017-04-10 01:12:52 -07001773}
1774
mflodmancc3d4422017-08-03 08:27:51 -07001775TEST_F(VideoStreamEncoderTest, NoChangeForInitialNormalUsage_BalancedMode) {
asaperssonf7e294d2017-06-13 23:25:22 -07001776 const int kWidth = 1280;
1777 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001778 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -07001779
1780 // Enable kBalanced preference, no initial limitation.
1781 test::FrameForwarder source;
mflodmancc3d4422017-08-03 08:27:51 -07001782 video_stream_encoder_->SetSource(
1783 &source,
1784 VideoSendStream::DegradationPreference::kBalanced);
asaperssonf7e294d2017-06-13 23:25:22 -07001785
1786 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
1787 sink_.WaitForEncodedFrame(kWidth, kHeight);
1788 VerifyNoLimitation(source.sink_wants());
1789 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1790 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
1791 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1792
1793 // Trigger adapt up, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07001794 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07001795 VerifyNoLimitation(source.sink_wants());
1796 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1797 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
1798 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1799
mflodmancc3d4422017-08-03 08:27:51 -07001800 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07001801}
1802
mflodmancc3d4422017-08-03 08:27:51 -07001803TEST_F(VideoStreamEncoderTest, NoChangeForInitialNormalUsage_DisabledMode) {
asapersson09f05612017-05-15 23:40:18 -07001804 const int kWidth = 1280;
1805 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001806 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson09f05612017-05-15 23:40:18 -07001807
1808 // Enable kDegradationDisabled preference, no initial limitation.
1809 test::FrameForwarder source;
mflodmancc3d4422017-08-03 08:27:51 -07001810 video_stream_encoder_->SetSource(
asapersson09f05612017-05-15 23:40:18 -07001811 &source, VideoSendStream::DegradationPreference::kDegradationDisabled);
1812
1813 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
1814 sink_.WaitForEncodedFrame(kWidth, kHeight);
1815 VerifyNoLimitation(source.sink_wants());
1816 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1817 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
1818 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1819
1820 // Trigger adapt up, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07001821 video_stream_encoder_->TriggerQualityHigh();
asapersson09f05612017-05-15 23:40:18 -07001822 VerifyNoLimitation(source.sink_wants());
1823 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1824 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
1825 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1826
mflodmancc3d4422017-08-03 08:27:51 -07001827 video_stream_encoder_->Stop();
asapersson09f05612017-05-15 23:40:18 -07001828}
1829
mflodmancc3d4422017-08-03 08:27:51 -07001830TEST_F(VideoStreamEncoderTest,
1831 AdaptsResolutionForLowQuality_MaintainFramerateMode) {
asapersson02465b82017-04-10 01:12:52 -07001832 const int kWidth = 1280;
1833 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001834 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson02465b82017-04-10 01:12:52 -07001835
1836 // Enable kMaintainFramerate preference, no initial limitation.
1837 AdaptingFrameForwarder source;
1838 source.set_adaptation_enabled(true);
mflodmancc3d4422017-08-03 08:27:51 -07001839 video_stream_encoder_->SetSource(
asapersson02465b82017-04-10 01:12:52 -07001840 &source, VideoSendStream::DegradationPreference::kMaintainFramerate);
1841
1842 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001843 WaitForEncodedFrame(1);
asapersson02465b82017-04-10 01:12:52 -07001844 VerifyNoLimitation(source.sink_wants());
1845 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1846 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1847
1848 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001849 video_stream_encoder_->TriggerQualityLow();
asapersson02465b82017-04-10 01:12:52 -07001850 source.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001851 WaitForEncodedFrame(2);
asapersson09f05612017-05-15 23:40:18 -07001852 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
asapersson02465b82017-04-10 01:12:52 -07001853 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1854 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1855
1856 // Trigger adapt up, expect no restriction.
mflodmancc3d4422017-08-03 08:27:51 -07001857 video_stream_encoder_->TriggerQualityHigh();
asapersson02465b82017-04-10 01:12:52 -07001858 VerifyNoLimitation(source.sink_wants());
1859 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1860 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1861 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1862
mflodmancc3d4422017-08-03 08:27:51 -07001863 video_stream_encoder_->Stop();
asapersson02465b82017-04-10 01:12:52 -07001864}
1865
mflodmancc3d4422017-08-03 08:27:51 -07001866TEST_F(VideoStreamEncoderTest,
1867 AdaptsFramerateForLowQuality_MaintainResolutionMode) {
asapersson09f05612017-05-15 23:40:18 -07001868 const int kWidth = 1280;
1869 const int kHeight = 720;
1870 const int kInputFps = 30;
mflodmancc3d4422017-08-03 08:27:51 -07001871 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson09f05612017-05-15 23:40:18 -07001872
1873 VideoSendStream::Stats stats = stats_proxy_->GetStats();
1874 stats.input_frame_rate = kInputFps;
1875 stats_proxy_->SetMockStats(stats);
1876
1877 // Expect no scaling to begin with (preference: kMaintainFramerate).
1878 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
1879 sink_.WaitForEncodedFrame(1);
1880 VerifyNoLimitation(video_source_.sink_wants());
1881
1882 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001883 video_stream_encoder_->TriggerQualityLow();
asapersson09f05612017-05-15 23:40:18 -07001884 video_source_.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
1885 sink_.WaitForEncodedFrame(2);
1886 VerifyFpsMaxResolutionLt(video_source_.sink_wants(), kWidth * kHeight);
1887
1888 // Enable kMaintainResolution preference.
1889 test::FrameForwarder new_video_source;
mflodmancc3d4422017-08-03 08:27:51 -07001890 video_stream_encoder_->SetSource(
asapersson09f05612017-05-15 23:40:18 -07001891 &new_video_source,
1892 VideoSendStream::DegradationPreference::kMaintainResolution);
1893 VerifyNoLimitation(new_video_source.sink_wants());
1894
1895 // Trigger adapt down, expect reduced framerate.
mflodmancc3d4422017-08-03 08:27:51 -07001896 video_stream_encoder_->TriggerQualityLow();
asapersson09f05612017-05-15 23:40:18 -07001897 new_video_source.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
1898 sink_.WaitForEncodedFrame(3);
1899 VerifyFpsLtResolutionMax(new_video_source.sink_wants(), kInputFps);
1900
1901 // Trigger adapt up, expect no restriction.
mflodmancc3d4422017-08-03 08:27:51 -07001902 video_stream_encoder_->TriggerQualityHigh();
asapersson09f05612017-05-15 23:40:18 -07001903 VerifyNoLimitation(new_video_source.sink_wants());
1904
mflodmancc3d4422017-08-03 08:27:51 -07001905 video_stream_encoder_->Stop();
asapersson09f05612017-05-15 23:40:18 -07001906}
1907
mflodmancc3d4422017-08-03 08:27:51 -07001908TEST_F(VideoStreamEncoderTest, DoesNotScaleBelowSetResolutionLimit) {
asaperssond0de2952017-04-21 01:47:31 -07001909 const int kWidth = 1280;
1910 const int kHeight = 720;
1911 const size_t kNumFrames = 10;
1912
mflodmancc3d4422017-08-03 08:27:51 -07001913 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
kthelgason5e13d412016-12-01 03:59:51 -08001914
asaperssond0de2952017-04-21 01:47:31 -07001915 // Enable adapter, expected input resolutions when downscaling:
asapersson142fcc92017-08-17 08:58:54 -07001916 // 1280x720 -> 960x540 -> 640x360 -> 480x270 -> 320x180 (kMinPixelsPerFrame)
asaperssond0de2952017-04-21 01:47:31 -07001917 video_source_.set_adaptation_enabled(true);
1918
1919 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1920 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1921
1922 int downscales = 0;
1923 for (size_t i = 1; i <= kNumFrames; i++) {
1924 video_source_.IncomingCapturedFrame(CreateFrame(i, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001925 WaitForEncodedFrame(i);
asaperssond0de2952017-04-21 01:47:31 -07001926
asaperssonfab67072017-04-04 05:51:49 -07001927 // Trigger scale down.
asaperssond0de2952017-04-21 01:47:31 -07001928 rtc::VideoSinkWants last_wants = video_source_.sink_wants();
mflodmancc3d4422017-08-03 08:27:51 -07001929 video_stream_encoder_->TriggerQualityLow();
sprangc5d62e22017-04-02 23:53:04 -07001930 EXPECT_GE(video_source_.sink_wants().max_pixel_count, kMinPixelsPerFrame);
asaperssond0de2952017-04-21 01:47:31 -07001931
1932 if (video_source_.sink_wants().max_pixel_count < last_wants.max_pixel_count)
1933 ++downscales;
1934
1935 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1936 EXPECT_EQ(downscales,
1937 stats_proxy_->GetStats().number_of_quality_adapt_changes);
1938 EXPECT_GT(downscales, 0);
kthelgason5e13d412016-12-01 03:59:51 -08001939 }
mflodmancc3d4422017-08-03 08:27:51 -07001940 video_stream_encoder_->Stop();
asaperssond0de2952017-04-21 01:47:31 -07001941}
1942
mflodmancc3d4422017-08-03 08:27:51 -07001943TEST_F(VideoStreamEncoderTest,
asaperssond0de2952017-04-21 01:47:31 -07001944 AdaptsResolutionUpAndDownTwiceOnOveruse_MaintainFramerateMode) {
1945 const int kWidth = 1280;
1946 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001947 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssond0de2952017-04-21 01:47:31 -07001948
1949 // Enable kMaintainFramerate preference, no initial limitation.
1950 AdaptingFrameForwarder source;
1951 source.set_adaptation_enabled(true);
mflodmancc3d4422017-08-03 08:27:51 -07001952 video_stream_encoder_->SetSource(
asaperssond0de2952017-04-21 01:47:31 -07001953 &source, VideoSendStream::DegradationPreference::kMaintainFramerate);
1954
1955 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001956 WaitForEncodedFrame(kWidth, kHeight);
asaperssond0de2952017-04-21 01:47:31 -07001957 VerifyNoLimitation(source.sink_wants());
1958 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1959 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1960
1961 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001962 video_stream_encoder_->TriggerCpuOveruse();
asaperssond0de2952017-04-21 01:47:31 -07001963 source.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001964 WaitForEncodedFrame(2);
asapersson09f05612017-05-15 23:40:18 -07001965 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
asaperssond0de2952017-04-21 01:47:31 -07001966 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1967 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1968
1969 // Trigger adapt up, expect no restriction.
mflodmancc3d4422017-08-03 08:27:51 -07001970 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssond0de2952017-04-21 01:47:31 -07001971 source.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001972 WaitForEncodedFrame(kWidth, kHeight);
asaperssond0de2952017-04-21 01:47:31 -07001973 VerifyNoLimitation(source.sink_wants());
1974 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1975 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1976
1977 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001978 video_stream_encoder_->TriggerCpuOveruse();
asaperssond0de2952017-04-21 01:47:31 -07001979 source.IncomingCapturedFrame(CreateFrame(4, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001980 WaitForEncodedFrame(4);
asapersson09f05612017-05-15 23:40:18 -07001981 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
asaperssond0de2952017-04-21 01:47:31 -07001982 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1983 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1984
1985 // Trigger adapt up, expect no restriction.
mflodmancc3d4422017-08-03 08:27:51 -07001986 video_stream_encoder_->TriggerCpuNormalUsage();
asapersson09f05612017-05-15 23:40:18 -07001987 source.IncomingCapturedFrame(CreateFrame(5, kWidth, kHeight));
1988 sink_.WaitForEncodedFrame(kWidth, kHeight);
asaperssond0de2952017-04-21 01:47:31 -07001989 VerifyNoLimitation(source.sink_wants());
1990 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1991 EXPECT_EQ(4, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1992
mflodmancc3d4422017-08-03 08:27:51 -07001993 video_stream_encoder_->Stop();
asaperssond0de2952017-04-21 01:47:31 -07001994}
1995
mflodmancc3d4422017-08-03 08:27:51 -07001996TEST_F(VideoStreamEncoderTest,
asaperssonf7e294d2017-06-13 23:25:22 -07001997 AdaptsResolutionUpAndDownTwiceForLowQuality_BalancedMode_NoFpsLimit) {
1998 const int kWidth = 1280;
1999 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07002000 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -07002001
2002 // Enable kBalanced preference, no initial limitation.
2003 AdaptingFrameForwarder source;
2004 source.set_adaptation_enabled(true);
mflodmancc3d4422017-08-03 08:27:51 -07002005 video_stream_encoder_->SetSource(
2006 &source,
2007 VideoSendStream::DegradationPreference::kBalanced);
asaperssonf7e294d2017-06-13 23:25:22 -07002008
2009 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
2010 sink_.WaitForEncodedFrame(kWidth, kHeight);
2011 VerifyNoLimitation(source.sink_wants());
2012 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2013 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2014
2015 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07002016 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002017 source.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
2018 sink_.WaitForEncodedFrame(2);
2019 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
2020 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2021 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2022
2023 // Trigger adapt up, expect no restriction.
mflodmancc3d4422017-08-03 08:27:51 -07002024 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002025 source.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
2026 sink_.WaitForEncodedFrame(kWidth, kHeight);
2027 VerifyNoLimitation(source.sink_wants());
2028 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2029 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2030
2031 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07002032 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002033 source.IncomingCapturedFrame(CreateFrame(4, kWidth, kHeight));
2034 sink_.WaitForEncodedFrame(4);
2035 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
2036 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2037 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2038
2039 // Trigger adapt up, expect no restriction.
mflodmancc3d4422017-08-03 08:27:51 -07002040 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002041 source.IncomingCapturedFrame(CreateFrame(5, kWidth, kHeight));
2042 sink_.WaitForEncodedFrame(kWidth, kHeight);
2043 VerifyNoLimitation(source.sink_wants());
2044 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2045 EXPECT_EQ(4, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2046
mflodmancc3d4422017-08-03 08:27:51 -07002047 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07002048}
2049
mflodmancc3d4422017-08-03 08:27:51 -07002050TEST_F(VideoStreamEncoderTest,
asaperssond0de2952017-04-21 01:47:31 -07002051 AdaptsResolutionOnOveruseAndLowQuality_MaintainFramerateMode) {
2052 const int kWidth = 1280;
2053 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07002054 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssond0de2952017-04-21 01:47:31 -07002055
2056 // Enable kMaintainFramerate preference, no initial limitation.
2057 AdaptingFrameForwarder source;
2058 source.set_adaptation_enabled(true);
mflodmancc3d4422017-08-03 08:27:51 -07002059 video_stream_encoder_->SetSource(
asaperssond0de2952017-04-21 01:47:31 -07002060 &source, VideoSendStream::DegradationPreference::kMaintainFramerate);
2061
2062 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002063 WaitForEncodedFrame(kWidth, kHeight);
asaperssond0de2952017-04-21 01:47:31 -07002064 VerifyNoLimitation(source.sink_wants());
2065 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2066 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2067 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2068 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2069
2070 // Trigger cpu adapt down, expect scaled down resolution (960x540).
mflodmancc3d4422017-08-03 08:27:51 -07002071 video_stream_encoder_->TriggerCpuOveruse();
asaperssond0de2952017-04-21 01:47:31 -07002072 source.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002073 WaitForEncodedFrame(2);
asapersson09f05612017-05-15 23:40:18 -07002074 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
asaperssond0de2952017-04-21 01:47:31 -07002075 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2076 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2077 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2078 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2079
2080 // Trigger cpu adapt down, expect scaled down resolution (640x360).
mflodmancc3d4422017-08-03 08:27:51 -07002081 video_stream_encoder_->TriggerCpuOveruse();
asaperssond0de2952017-04-21 01:47:31 -07002082 source.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002083 WaitForEncodedFrame(3);
asapersson09f05612017-05-15 23:40:18 -07002084 VerifyFpsMaxResolutionLt(source.sink_wants(), source.last_wants());
asaperssond0de2952017-04-21 01:47:31 -07002085 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2086 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2087 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2088 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2089
Jonathan Yubc771b72017-12-08 17:04:29 -08002090 // Trigger cpu adapt down, expect scaled down resolution (480x270).
mflodmancc3d4422017-08-03 08:27:51 -07002091 video_stream_encoder_->TriggerCpuOveruse();
asaperssond0de2952017-04-21 01:47:31 -07002092 source.IncomingCapturedFrame(CreateFrame(4, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002093 WaitForEncodedFrame(4);
Jonathan Yubc771b72017-12-08 17:04:29 -08002094 VerifyFpsMaxResolutionLt(source.sink_wants(), source.last_wants());
asaperssond0de2952017-04-21 01:47:31 -07002095 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2096 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
Jonathan Yubc771b72017-12-08 17:04:29 -08002097 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
asaperssond0de2952017-04-21 01:47:31 -07002098 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2099
Jonathan Yubc771b72017-12-08 17:04:29 -08002100 // Trigger quality adapt down, expect scaled down resolution (320x180).
mflodmancc3d4422017-08-03 08:27:51 -07002101 video_stream_encoder_->TriggerQualityLow();
asaperssond0de2952017-04-21 01:47:31 -07002102 source.IncomingCapturedFrame(CreateFrame(5, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002103 WaitForEncodedFrame(5);
asapersson09f05612017-05-15 23:40:18 -07002104 VerifyFpsMaxResolutionLt(source.sink_wants(), source.last_wants());
Jonathan Yubc771b72017-12-08 17:04:29 -08002105 rtc::VideoSinkWants last_wants = source.sink_wants();
asaperssond0de2952017-04-21 01:47:31 -07002106 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2107 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2108 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2109 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2110
Jonathan Yubc771b72017-12-08 17:04:29 -08002111 // Trigger quality adapt down, expect no change (min resolution reached).
2112 video_stream_encoder_->TriggerQualityLow();
2113 source.IncomingCapturedFrame(CreateFrame(6, kWidth, kHeight));
2114 WaitForEncodedFrame(6);
2115 VerifyFpsMaxResolutionEq(source.sink_wants(), last_wants);
2116 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2117 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2118 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2119 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2120
2121 // Trigger cpu adapt up, expect upscaled resolution (480x270).
mflodmancc3d4422017-08-03 08:27:51 -07002122 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssond0de2952017-04-21 01:47:31 -07002123 source.IncomingCapturedFrame(CreateFrame(7, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002124 WaitForEncodedFrame(7);
asapersson09f05612017-05-15 23:40:18 -07002125 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
Jonathan Yubc771b72017-12-08 17:04:29 -08002126 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2127 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2128 EXPECT_EQ(4, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2129 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2130
2131 // Trigger cpu adapt up, expect upscaled resolution (640x360).
2132 video_stream_encoder_->TriggerCpuNormalUsage();
2133 source.IncomingCapturedFrame(CreateFrame(8, kWidth, kHeight));
2134 WaitForEncodedFrame(8);
2135 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
2136 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2137 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2138 EXPECT_EQ(5, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2139 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2140
2141 // Trigger cpu adapt up, expect upscaled resolution (960x540).
2142 video_stream_encoder_->TriggerCpuNormalUsage();
2143 source.IncomingCapturedFrame(CreateFrame(9, kWidth, kHeight));
2144 WaitForEncodedFrame(9);
2145 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
asaperssond0de2952017-04-21 01:47:31 -07002146 last_wants = source.sink_wants();
2147 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2148 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
Jonathan Yubc771b72017-12-08 17:04:29 -08002149 EXPECT_EQ(6, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
asaperssond0de2952017-04-21 01:47:31 -07002150 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2151
2152 // Trigger cpu adapt up, no cpu downgrades, expect no change (960x540).
mflodmancc3d4422017-08-03 08:27:51 -07002153 video_stream_encoder_->TriggerCpuNormalUsage();
Jonathan Yubc771b72017-12-08 17:04:29 -08002154 source.IncomingCapturedFrame(CreateFrame(10, kWidth, kHeight));
2155 WaitForEncodedFrame(10);
asapersson09f05612017-05-15 23:40:18 -07002156 VerifyFpsEqResolutionEq(source.sink_wants(), last_wants);
asaperssond0de2952017-04-21 01:47:31 -07002157 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2158 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
Jonathan Yubc771b72017-12-08 17:04:29 -08002159 EXPECT_EQ(6, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
asaperssond0de2952017-04-21 01:47:31 -07002160 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2161
2162 // Trigger quality adapt up, expect no restriction (1280x720).
mflodmancc3d4422017-08-03 08:27:51 -07002163 video_stream_encoder_->TriggerQualityHigh();
Jonathan Yubc771b72017-12-08 17:04:29 -08002164 source.IncomingCapturedFrame(CreateFrame(11, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002165 WaitForEncodedFrame(kWidth, kHeight);
asapersson09f05612017-05-15 23:40:18 -07002166 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
asaperssond0de2952017-04-21 01:47:31 -07002167 VerifyNoLimitation(source.sink_wants());
2168 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2169 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
Jonathan Yubc771b72017-12-08 17:04:29 -08002170 EXPECT_EQ(6, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
asaperssond0de2952017-04-21 01:47:31 -07002171 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
kthelgason5e13d412016-12-01 03:59:51 -08002172
mflodmancc3d4422017-08-03 08:27:51 -07002173 video_stream_encoder_->Stop();
kthelgason5e13d412016-12-01 03:59:51 -08002174}
2175
mflodmancc3d4422017-08-03 08:27:51 -07002176TEST_F(VideoStreamEncoderTest, CpuLimitedHistogramIsReported) {
asaperssonfab67072017-04-04 05:51:49 -07002177 const int kWidth = 640;
2178 const int kHeight = 360;
perkj803d97f2016-11-01 11:45:46 -07002179
mflodmancc3d4422017-08-03 08:27:51 -07002180 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
sprang4847ae62017-06-27 07:06:52 -07002181
perkj803d97f2016-11-01 11:45:46 -07002182 for (int i = 1; i <= SendStatisticsProxy::kMinRequiredMetricsSamples; ++i) {
asaperssonfab67072017-04-04 05:51:49 -07002183 video_source_.IncomingCapturedFrame(CreateFrame(i, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002184 WaitForEncodedFrame(i);
perkj803d97f2016-11-01 11:45:46 -07002185 }
2186
mflodmancc3d4422017-08-03 08:27:51 -07002187 video_stream_encoder_->TriggerCpuOveruse();
perkj803d97f2016-11-01 11:45:46 -07002188 for (int i = 1; i <= SendStatisticsProxy::kMinRequiredMetricsSamples; ++i) {
asaperssonfab67072017-04-04 05:51:49 -07002189 video_source_.IncomingCapturedFrame(CreateFrame(
2190 SendStatisticsProxy::kMinRequiredMetricsSamples + i, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002191 WaitForEncodedFrame(SendStatisticsProxy::kMinRequiredMetricsSamples + i);
perkj803d97f2016-11-01 11:45:46 -07002192 }
2193
mflodmancc3d4422017-08-03 08:27:51 -07002194 video_stream_encoder_->Stop();
2195 video_stream_encoder_.reset();
perkj803d97f2016-11-01 11:45:46 -07002196 stats_proxy_.reset();
sprangf8ee65e2017-02-28 08:49:33 -08002197
perkj803d97f2016-11-01 11:45:46 -07002198 EXPECT_EQ(1,
2199 metrics::NumSamples("WebRTC.Video.CpuLimitedResolutionInPercent"));
2200 EXPECT_EQ(
2201 1, metrics::NumEvents("WebRTC.Video.CpuLimitedResolutionInPercent", 50));
2202}
2203
mflodmancc3d4422017-08-03 08:27:51 -07002204TEST_F(VideoStreamEncoderTest,
2205 CpuLimitedHistogramIsNotReportedForDisabledDegradation) {
2206 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonf4e44af2017-04-19 02:01:06 -07002207 const int kWidth = 640;
2208 const int kHeight = 360;
2209
mflodmancc3d4422017-08-03 08:27:51 -07002210 video_stream_encoder_->SetSource(
asaperssonf4e44af2017-04-19 02:01:06 -07002211 &video_source_,
2212 VideoSendStream::DegradationPreference::kDegradationDisabled);
2213
2214 for (int i = 1; i <= SendStatisticsProxy::kMinRequiredMetricsSamples; ++i) {
2215 video_source_.IncomingCapturedFrame(CreateFrame(i, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002216 WaitForEncodedFrame(i);
asaperssonf4e44af2017-04-19 02:01:06 -07002217 }
2218
mflodmancc3d4422017-08-03 08:27:51 -07002219 video_stream_encoder_->Stop();
2220 video_stream_encoder_.reset();
asaperssonf4e44af2017-04-19 02:01:06 -07002221 stats_proxy_.reset();
2222
2223 EXPECT_EQ(0,
2224 metrics::NumSamples("WebRTC.Video.CpuLimitedResolutionInPercent"));
2225}
2226
mflodmancc3d4422017-08-03 08:27:51 -07002227TEST_F(VideoStreamEncoderTest, CallsBitrateObserver) {
sprang4847ae62017-06-27 07:06:52 -07002228 MockBitrateObserver bitrate_observer;
mflodmancc3d4422017-08-03 08:27:51 -07002229 video_stream_encoder_->SetBitrateObserver(&bitrate_observer);
sprang57c2fff2017-01-16 06:24:02 -08002230
2231 const int kDefaultFps = 30;
2232 const BitrateAllocation expected_bitrate =
2233 DefaultVideoBitrateAllocator(fake_encoder_.codec_config())
kthelgason2bc68642017-02-07 07:02:22 -08002234 .GetAllocation(kLowTargetBitrateBps, kDefaultFps);
sprang57c2fff2017-01-16 06:24:02 -08002235
2236 // First called on bitrate updated, then again on first frame.
2237 EXPECT_CALL(bitrate_observer, OnBitrateAllocationUpdated(expected_bitrate))
2238 .Times(2);
mflodmancc3d4422017-08-03 08:27:51 -07002239 video_stream_encoder_->OnBitrateUpdated(kLowTargetBitrateBps, 0, 0);
sprang57c2fff2017-01-16 06:24:02 -08002240
2241 const int64_t kStartTimeMs = 1;
2242 video_source_.IncomingCapturedFrame(
2243 CreateFrame(kStartTimeMs, codec_width_, codec_height_));
sprang4847ae62017-06-27 07:06:52 -07002244 WaitForEncodedFrame(kStartTimeMs);
sprang57c2fff2017-01-16 06:24:02 -08002245
2246 // Not called on second frame.
2247 EXPECT_CALL(bitrate_observer, OnBitrateAllocationUpdated(expected_bitrate))
2248 .Times(0);
2249 video_source_.IncomingCapturedFrame(
2250 CreateFrame(kStartTimeMs + 1, codec_width_, codec_height_));
sprang4847ae62017-06-27 07:06:52 -07002251 WaitForEncodedFrame(kStartTimeMs + 1);
sprang57c2fff2017-01-16 06:24:02 -08002252
2253 // Called after a process interval.
2254 const int64_t kProcessIntervalMs =
2255 vcm::VCMProcessTimer::kDefaultProcessIntervalMs;
sprang4847ae62017-06-27 07:06:52 -07002256 fake_clock_.AdvanceTimeMicros(rtc::kNumMicrosecsPerMillisec *
2257 (kProcessIntervalMs + (1000 / kDefaultFps)));
sprang57c2fff2017-01-16 06:24:02 -08002258 EXPECT_CALL(bitrate_observer, OnBitrateAllocationUpdated(expected_bitrate))
2259 .Times(1);
2260 video_source_.IncomingCapturedFrame(CreateFrame(
2261 kStartTimeMs + kProcessIntervalMs, codec_width_, codec_height_));
sprang4847ae62017-06-27 07:06:52 -07002262 WaitForEncodedFrame(kStartTimeMs + kProcessIntervalMs);
sprang57c2fff2017-01-16 06:24:02 -08002263
mflodmancc3d4422017-08-03 08:27:51 -07002264 video_stream_encoder_->Stop();
sprang57c2fff2017-01-16 06:24:02 -08002265}
2266
Niels Möller7dc26b72017-12-06 10:27:48 +01002267TEST_F(VideoStreamEncoderTest, OveruseDetectorUpdatedOnReconfigureAndAdaption) {
2268 const int kFrameWidth = 1280;
2269 const int kFrameHeight = 720;
2270 const int kFramerate = 24;
2271
2272 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
2273 test::FrameForwarder source;
2274 video_stream_encoder_->SetSource(
2275 &source, VideoSendStream::DegradationPreference::kMaintainResolution);
2276
2277 // Insert a single frame, triggering initial configuration.
2278 source.IncomingCapturedFrame(CreateFrame(1, kFrameWidth, kFrameHeight));
2279 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2280
2281 EXPECT_EQ(
2282 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2283 kDefaultFramerate);
2284
2285 // Trigger reconfigure encoder (without resetting the entire instance).
2286 VideoEncoderConfig video_encoder_config;
Niels Möller259a4972018-04-05 15:36:51 +02002287 video_encoder_config.codec_type = kVideoCodecVP8;
Niels Möller7dc26b72017-12-06 10:27:48 +01002288 video_encoder_config.max_bitrate_bps = kTargetBitrateBps;
2289 video_encoder_config.number_of_streams = 1;
2290 video_encoder_config.video_stream_factory =
2291 new rtc::RefCountedObject<VideoStreamFactory>(1, kFramerate);
2292 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
2293 kMaxPayloadLength, false);
2294 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2295
2296 // Detector should be updated with fps limit from codec config.
2297 EXPECT_EQ(
2298 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2299 kFramerate);
2300
2301 // Trigger overuse, max framerate should be reduced.
2302 VideoSendStream::Stats stats = stats_proxy_->GetStats();
2303 stats.input_frame_rate = kFramerate;
2304 stats_proxy_->SetMockStats(stats);
2305 video_stream_encoder_->TriggerCpuOveruse();
2306 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2307 int adapted_framerate =
2308 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate();
2309 EXPECT_LT(adapted_framerate, kFramerate);
2310
2311 // Trigger underuse, max framerate should go back to codec configured fps.
2312 // Set extra low fps, to make sure it's actually reset, not just incremented.
2313 stats = stats_proxy_->GetStats();
2314 stats.input_frame_rate = adapted_framerate / 2;
2315 stats_proxy_->SetMockStats(stats);
2316 video_stream_encoder_->TriggerCpuNormalUsage();
2317 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2318 EXPECT_EQ(
2319 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2320 kFramerate);
2321
2322 video_stream_encoder_->Stop();
2323}
2324
2325TEST_F(VideoStreamEncoderTest,
2326 OveruseDetectorUpdatedRespectsFramerateAfterUnderuse) {
2327 const int kFrameWidth = 1280;
2328 const int kFrameHeight = 720;
2329 const int kLowFramerate = 15;
2330 const int kHighFramerate = 25;
2331
2332 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
2333 test::FrameForwarder source;
2334 video_stream_encoder_->SetSource(
2335 &source, VideoSendStream::DegradationPreference::kMaintainResolution);
2336
2337 // Trigger initial configuration.
2338 VideoEncoderConfig video_encoder_config;
Niels Möller259a4972018-04-05 15:36:51 +02002339 video_encoder_config.codec_type = kVideoCodecVP8;
Niels Möller7dc26b72017-12-06 10:27:48 +01002340 video_encoder_config.max_bitrate_bps = kTargetBitrateBps;
2341 video_encoder_config.number_of_streams = 1;
2342 video_encoder_config.video_stream_factory =
2343 new rtc::RefCountedObject<VideoStreamFactory>(1, kLowFramerate);
2344 source.IncomingCapturedFrame(CreateFrame(1, kFrameWidth, kFrameHeight));
2345 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
2346 kMaxPayloadLength, false);
2347 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2348
2349 EXPECT_EQ(
2350 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2351 kLowFramerate);
2352
2353 // Trigger overuse, max framerate should be reduced.
2354 VideoSendStream::Stats stats = stats_proxy_->GetStats();
2355 stats.input_frame_rate = kLowFramerate;
2356 stats_proxy_->SetMockStats(stats);
2357 video_stream_encoder_->TriggerCpuOveruse();
2358 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2359 int adapted_framerate =
2360 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate();
2361 EXPECT_LT(adapted_framerate, kLowFramerate);
2362
2363 // Reconfigure the encoder with a new (higher max framerate), max fps should
2364 // still respect the adaptation.
2365 video_encoder_config.video_stream_factory =
2366 new rtc::RefCountedObject<VideoStreamFactory>(1, kHighFramerate);
2367 source.IncomingCapturedFrame(CreateFrame(1, kFrameWidth, kFrameHeight));
2368 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
2369 kMaxPayloadLength, false);
2370 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2371
2372 EXPECT_EQ(
2373 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2374 adapted_framerate);
2375
2376 // Trigger underuse, max framerate should go back to codec configured fps.
2377 stats = stats_proxy_->GetStats();
2378 stats.input_frame_rate = adapted_framerate;
2379 stats_proxy_->SetMockStats(stats);
2380 video_stream_encoder_->TriggerCpuNormalUsage();
2381 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2382 EXPECT_EQ(
2383 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2384 kHighFramerate);
2385
2386 video_stream_encoder_->Stop();
2387}
2388
mflodmancc3d4422017-08-03 08:27:51 -07002389TEST_F(VideoStreamEncoderTest,
2390 OveruseDetectorUpdatedOnDegradationPreferenceChange) {
sprangfda496a2017-06-15 04:21:07 -07002391 const int kFrameWidth = 1280;
2392 const int kFrameHeight = 720;
2393 const int kFramerate = 24;
2394
mflodmancc3d4422017-08-03 08:27:51 -07002395 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
sprangfda496a2017-06-15 04:21:07 -07002396 test::FrameForwarder source;
mflodmancc3d4422017-08-03 08:27:51 -07002397 video_stream_encoder_->SetSource(
sprangfda496a2017-06-15 04:21:07 -07002398 &source, VideoSendStream::DegradationPreference::kMaintainResolution);
2399
2400 // Trigger initial configuration.
2401 VideoEncoderConfig video_encoder_config;
Niels Möller259a4972018-04-05 15:36:51 +02002402 video_encoder_config.codec_type = kVideoCodecVP8;
sprangfda496a2017-06-15 04:21:07 -07002403 video_encoder_config.max_bitrate_bps = kTargetBitrateBps;
2404 video_encoder_config.number_of_streams = 1;
2405 video_encoder_config.video_stream_factory =
2406 new rtc::RefCountedObject<VideoStreamFactory>(1, kFramerate);
2407 source.IncomingCapturedFrame(CreateFrame(1, kFrameWidth, kFrameHeight));
mflodmancc3d4422017-08-03 08:27:51 -07002408 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
2409 kMaxPayloadLength, false);
2410 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
sprangfda496a2017-06-15 04:21:07 -07002411
Niels Möller7dc26b72017-12-06 10:27:48 +01002412 EXPECT_EQ(
2413 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2414 kFramerate);
sprangfda496a2017-06-15 04:21:07 -07002415
2416 // Trigger overuse, max framerate should be reduced.
2417 VideoSendStream::Stats stats = stats_proxy_->GetStats();
2418 stats.input_frame_rate = kFramerate;
2419 stats_proxy_->SetMockStats(stats);
mflodmancc3d4422017-08-03 08:27:51 -07002420 video_stream_encoder_->TriggerCpuOveruse();
2421 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
Niels Möller7dc26b72017-12-06 10:27:48 +01002422 int adapted_framerate =
2423 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate();
sprangfda496a2017-06-15 04:21:07 -07002424 EXPECT_LT(adapted_framerate, kFramerate);
2425
2426 // Change degradation preference to not enable framerate scaling. Target
2427 // framerate should be changed to codec defined limit.
mflodmancc3d4422017-08-03 08:27:51 -07002428 video_stream_encoder_->SetSource(
sprangfda496a2017-06-15 04:21:07 -07002429 &source, VideoSendStream::DegradationPreference::kMaintainFramerate);
mflodmancc3d4422017-08-03 08:27:51 -07002430 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
Niels Möller7dc26b72017-12-06 10:27:48 +01002431 EXPECT_EQ(
2432 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2433 kFramerate);
sprangfda496a2017-06-15 04:21:07 -07002434
mflodmancc3d4422017-08-03 08:27:51 -07002435 video_stream_encoder_->Stop();
sprangfda496a2017-06-15 04:21:07 -07002436}
2437
mflodmancc3d4422017-08-03 08:27:51 -07002438TEST_F(VideoStreamEncoderTest, DropsFramesAndScalesWhenBitrateIsTooLow) {
asaperssonfab67072017-04-04 05:51:49 -07002439 const int kTooLowBitrateForFrameSizeBps = 10000;
mflodmancc3d4422017-08-03 08:27:51 -07002440 video_stream_encoder_->OnBitrateUpdated(kTooLowBitrateForFrameSizeBps, 0, 0);
asaperssonfab67072017-04-04 05:51:49 -07002441 const int kWidth = 640;
2442 const int kHeight = 360;
kthelgason2bc68642017-02-07 07:02:22 -08002443
asaperssonfab67072017-04-04 05:51:49 -07002444 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
kthelgason2bc68642017-02-07 07:02:22 -08002445
2446 // Expect to drop this frame, the wait should time out.
sprang4847ae62017-06-27 07:06:52 -07002447 ExpectDroppedFrame();
kthelgason2bc68642017-02-07 07:02:22 -08002448
2449 // Expect the sink_wants to specify a scaled frame.
asapersson0944a802017-04-07 00:57:58 -07002450 EXPECT_LT(video_source_.sink_wants().max_pixel_count, kWidth * kHeight);
kthelgason2bc68642017-02-07 07:02:22 -08002451
sprangc5d62e22017-04-02 23:53:04 -07002452 int last_pixel_count = video_source_.sink_wants().max_pixel_count;
kthelgason2bc68642017-02-07 07:02:22 -08002453
asaperssonfab67072017-04-04 05:51:49 -07002454 // Next frame is scaled.
kthelgason2bc68642017-02-07 07:02:22 -08002455 video_source_.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07002456 CreateFrame(2, kWidth * 3 / 4, kHeight * 3 / 4));
kthelgason2bc68642017-02-07 07:02:22 -08002457
2458 // Expect to drop this frame, the wait should time out.
sprang4847ae62017-06-27 07:06:52 -07002459 ExpectDroppedFrame();
kthelgason2bc68642017-02-07 07:02:22 -08002460
sprangc5d62e22017-04-02 23:53:04 -07002461 EXPECT_LT(video_source_.sink_wants().max_pixel_count, last_pixel_count);
kthelgason2bc68642017-02-07 07:02:22 -08002462
mflodmancc3d4422017-08-03 08:27:51 -07002463 video_stream_encoder_->Stop();
kthelgason2bc68642017-02-07 07:02:22 -08002464}
2465
mflodmancc3d4422017-08-03 08:27:51 -07002466TEST_F(VideoStreamEncoderTest,
2467 NumberOfDroppedFramesLimitedWhenBitrateIsTooLow) {
asaperssonfab67072017-04-04 05:51:49 -07002468 const int kTooLowBitrateForFrameSizeBps = 10000;
mflodmancc3d4422017-08-03 08:27:51 -07002469 video_stream_encoder_->OnBitrateUpdated(kTooLowBitrateForFrameSizeBps, 0, 0);
asaperssonfab67072017-04-04 05:51:49 -07002470 const int kWidth = 640;
2471 const int kHeight = 360;
kthelgason2bc68642017-02-07 07:02:22 -08002472
2473 // We expect the n initial frames to get dropped.
2474 int i;
2475 for (i = 1; i <= kMaxInitialFramedrop; ++i) {
asaperssonfab67072017-04-04 05:51:49 -07002476 video_source_.IncomingCapturedFrame(CreateFrame(i, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002477 ExpectDroppedFrame();
kthelgason2bc68642017-02-07 07:02:22 -08002478 }
2479 // The n+1th frame should not be dropped, even though it's size is too large.
asaperssonfab67072017-04-04 05:51:49 -07002480 video_source_.IncomingCapturedFrame(CreateFrame(i, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002481 WaitForEncodedFrame(i);
kthelgason2bc68642017-02-07 07:02:22 -08002482
2483 // Expect the sink_wants to specify a scaled frame.
asaperssonfab67072017-04-04 05:51:49 -07002484 EXPECT_LT(video_source_.sink_wants().max_pixel_count, kWidth * kHeight);
kthelgason2bc68642017-02-07 07:02:22 -08002485
mflodmancc3d4422017-08-03 08:27:51 -07002486 video_stream_encoder_->Stop();
kthelgason2bc68642017-02-07 07:02:22 -08002487}
2488
mflodmancc3d4422017-08-03 08:27:51 -07002489TEST_F(VideoStreamEncoderTest,
2490 InitialFrameDropOffWithMaintainResolutionPreference) {
asaperssonfab67072017-04-04 05:51:49 -07002491 const int kWidth = 640;
2492 const int kHeight = 360;
mflodmancc3d4422017-08-03 08:27:51 -07002493 video_stream_encoder_->OnBitrateUpdated(kLowTargetBitrateBps, 0, 0);
kthelgason2bc68642017-02-07 07:02:22 -08002494
2495 // Set degradation preference.
mflodmancc3d4422017-08-03 08:27:51 -07002496 video_stream_encoder_->SetSource(
kthelgason2bc68642017-02-07 07:02:22 -08002497 &video_source_,
2498 VideoSendStream::DegradationPreference::kMaintainResolution);
2499
asaperssonfab67072017-04-04 05:51:49 -07002500 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
kthelgason2bc68642017-02-07 07:02:22 -08002501 // Frame should not be dropped, even if it's too large.
sprang4847ae62017-06-27 07:06:52 -07002502 WaitForEncodedFrame(1);
kthelgason2bc68642017-02-07 07:02:22 -08002503
mflodmancc3d4422017-08-03 08:27:51 -07002504 video_stream_encoder_->Stop();
kthelgason2bc68642017-02-07 07:02:22 -08002505}
2506
mflodmancc3d4422017-08-03 08:27:51 -07002507TEST_F(VideoStreamEncoderTest, InitialFrameDropOffWhenEncoderDisabledScaling) {
asaperssonfab67072017-04-04 05:51:49 -07002508 const int kWidth = 640;
2509 const int kHeight = 360;
kthelgasonad9010c2017-02-14 00:46:51 -08002510 fake_encoder_.SetQualityScaling(false);
mflodmancc3d4422017-08-03 08:27:51 -07002511 video_stream_encoder_->OnBitrateUpdated(kLowTargetBitrateBps, 0, 0);
asapersson09f05612017-05-15 23:40:18 -07002512
kthelgasonb83797b2017-02-14 11:57:25 -08002513 // Force quality scaler reconfiguration by resetting the source.
mflodmancc3d4422017-08-03 08:27:51 -07002514 video_stream_encoder_->SetSource(
2515 &video_source_,
2516 VideoSendStream::DegradationPreference::kBalanced);
kthelgasonad9010c2017-02-14 00:46:51 -08002517
asaperssonfab67072017-04-04 05:51:49 -07002518 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
kthelgasonad9010c2017-02-14 00:46:51 -08002519 // Frame should not be dropped, even if it's too large.
sprang4847ae62017-06-27 07:06:52 -07002520 WaitForEncodedFrame(1);
kthelgasonad9010c2017-02-14 00:46:51 -08002521
mflodmancc3d4422017-08-03 08:27:51 -07002522 video_stream_encoder_->Stop();
kthelgasonad9010c2017-02-14 00:46:51 -08002523 fake_encoder_.SetQualityScaling(true);
2524}
2525
mflodmancc3d4422017-08-03 08:27:51 -07002526TEST_F(VideoStreamEncoderTest,
asaperssond0de2952017-04-21 01:47:31 -07002527 ResolutionNotAdaptedForTooSmallFrame_MaintainFramerateMode) {
2528 const int kTooSmallWidth = 10;
2529 const int kTooSmallHeight = 10;
mflodmancc3d4422017-08-03 08:27:51 -07002530 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssond0de2952017-04-21 01:47:31 -07002531
2532 // Enable kMaintainFramerate preference, no initial limitation.
2533 test::FrameForwarder source;
mflodmancc3d4422017-08-03 08:27:51 -07002534 video_stream_encoder_->SetSource(
asaperssond0de2952017-04-21 01:47:31 -07002535 &source, VideoSendStream::DegradationPreference::kMaintainFramerate);
2536 VerifyNoLimitation(source.sink_wants());
2537 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2538
2539 // Trigger adapt down, too small frame, expect no change.
2540 source.IncomingCapturedFrame(CreateFrame(1, kTooSmallWidth, kTooSmallHeight));
sprang4847ae62017-06-27 07:06:52 -07002541 WaitForEncodedFrame(1);
mflodmancc3d4422017-08-03 08:27:51 -07002542 video_stream_encoder_->TriggerCpuOveruse();
asaperssond0de2952017-04-21 01:47:31 -07002543 VerifyNoLimitation(source.sink_wants());
2544 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2545 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2546
mflodmancc3d4422017-08-03 08:27:51 -07002547 video_stream_encoder_->Stop();
asaperssond0de2952017-04-21 01:47:31 -07002548}
2549
mflodmancc3d4422017-08-03 08:27:51 -07002550TEST_F(VideoStreamEncoderTest,
2551 ResolutionNotAdaptedForTooSmallFrame_BalancedMode) {
asaperssonf7e294d2017-06-13 23:25:22 -07002552 const int kTooSmallWidth = 10;
2553 const int kTooSmallHeight = 10;
2554 const int kFpsLimit = 7;
mflodmancc3d4422017-08-03 08:27:51 -07002555 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -07002556
2557 // Enable kBalanced preference, no initial limitation.
2558 test::FrameForwarder source;
mflodmancc3d4422017-08-03 08:27:51 -07002559 video_stream_encoder_->SetSource(
2560 &source,
2561 VideoSendStream::DegradationPreference::kBalanced);
asaperssonf7e294d2017-06-13 23:25:22 -07002562 VerifyNoLimitation(source.sink_wants());
2563 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2564 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2565
2566 // Trigger adapt down, expect limited framerate.
2567 source.IncomingCapturedFrame(CreateFrame(1, kTooSmallWidth, kTooSmallHeight));
sprang4847ae62017-06-27 07:06:52 -07002568 WaitForEncodedFrame(1);
mflodmancc3d4422017-08-03 08:27:51 -07002569 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002570 VerifyFpsEqResolutionMax(source.sink_wants(), kFpsLimit);
2571 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2572 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2573 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2574
2575 // Trigger adapt down, too small frame, expect no change.
2576 source.IncomingCapturedFrame(CreateFrame(2, kTooSmallWidth, kTooSmallHeight));
sprang4847ae62017-06-27 07:06:52 -07002577 WaitForEncodedFrame(2);
mflodmancc3d4422017-08-03 08:27:51 -07002578 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002579 VerifyFpsEqResolutionMax(source.sink_wants(), kFpsLimit);
2580 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2581 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2582 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2583
mflodmancc3d4422017-08-03 08:27:51 -07002584 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07002585}
2586
mflodmancc3d4422017-08-03 08:27:51 -07002587TEST_F(VideoStreamEncoderTest, FailingInitEncodeDoesntCauseCrash) {
asapersson02465b82017-04-10 01:12:52 -07002588 fake_encoder_.ForceInitEncodeFailure(true);
mflodmancc3d4422017-08-03 08:27:51 -07002589 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
emircanbbcc3562017-08-18 00:28:40 -07002590 ResetEncoder("VP8", 2, 1, 1, true, false);
asapersson02465b82017-04-10 01:12:52 -07002591 const int kFrameWidth = 1280;
2592 const int kFrameHeight = 720;
2593 video_source_.IncomingCapturedFrame(
2594 CreateFrame(1, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002595 ExpectDroppedFrame();
mflodmancc3d4422017-08-03 08:27:51 -07002596 video_stream_encoder_->Stop();
asapersson02465b82017-04-10 01:12:52 -07002597}
2598
sprangb1ca0732017-02-01 08:38:12 -08002599// TODO(sprang): Extend this with fps throttling and any "balanced" extensions.
mflodmancc3d4422017-08-03 08:27:51 -07002600TEST_F(VideoStreamEncoderTest,
2601 AdaptsResolutionOnOveruse_MaintainFramerateMode) {
2602 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
sprangb1ca0732017-02-01 08:38:12 -08002603
2604 const int kFrameWidth = 1280;
2605 const int kFrameHeight = 720;
2606 // Enabled default VideoAdapter downscaling. First step is 3/4, not 3/5 as
mflodmancc3d4422017-08-03 08:27:51 -07002607 // requested by
2608 // VideoStreamEncoder::VideoSourceProxy::RequestResolutionLowerThan().
sprangb1ca0732017-02-01 08:38:12 -08002609 video_source_.set_adaptation_enabled(true);
2610
2611 video_source_.IncomingCapturedFrame(
2612 CreateFrame(1, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002613 WaitForEncodedFrame(kFrameWidth, kFrameHeight);
sprangb1ca0732017-02-01 08:38:12 -08002614
2615 // Trigger CPU overuse, downscale by 3/4.
mflodmancc3d4422017-08-03 08:27:51 -07002616 video_stream_encoder_->TriggerCpuOveruse();
sprangb1ca0732017-02-01 08:38:12 -08002617 video_source_.IncomingCapturedFrame(
2618 CreateFrame(2, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002619 WaitForEncodedFrame((kFrameWidth * 3) / 4, (kFrameHeight * 3) / 4);
sprangb1ca0732017-02-01 08:38:12 -08002620
asaperssonfab67072017-04-04 05:51:49 -07002621 // Trigger CPU normal use, return to original resolution.
mflodmancc3d4422017-08-03 08:27:51 -07002622 video_stream_encoder_->TriggerCpuNormalUsage();
sprangb1ca0732017-02-01 08:38:12 -08002623 video_source_.IncomingCapturedFrame(
2624 CreateFrame(3, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002625 WaitForEncodedFrame(kFrameWidth, kFrameHeight);
sprangb1ca0732017-02-01 08:38:12 -08002626
mflodmancc3d4422017-08-03 08:27:51 -07002627 video_stream_encoder_->Stop();
sprangb1ca0732017-02-01 08:38:12 -08002628}
sprangfe627f32017-03-29 08:24:59 -07002629
mflodmancc3d4422017-08-03 08:27:51 -07002630TEST_F(VideoStreamEncoderTest,
2631 AdaptsFramerateOnOveruse_MaintainResolutionMode) {
sprangc5d62e22017-04-02 23:53:04 -07002632 const int kFrameWidth = 1280;
2633 const int kFrameHeight = 720;
sprang4847ae62017-06-27 07:06:52 -07002634 int kFrameIntervalMs = rtc::kNumMillisecsPerSec / max_framerate_;
sprangc5d62e22017-04-02 23:53:04 -07002635
mflodmancc3d4422017-08-03 08:27:51 -07002636 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
2637 video_stream_encoder_->SetSource(
sprangc5d62e22017-04-02 23:53:04 -07002638 &video_source_,
2639 VideoSendStream::DegradationPreference::kMaintainResolution);
2640 video_source_.set_adaptation_enabled(true);
2641
sprang4847ae62017-06-27 07:06:52 -07002642 int64_t timestamp_ms = fake_clock_.TimeNanos() / rtc::kNumNanosecsPerMillisec;
sprangc5d62e22017-04-02 23:53:04 -07002643
2644 video_source_.IncomingCapturedFrame(
2645 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002646 WaitForEncodedFrame(timestamp_ms);
sprangc5d62e22017-04-02 23:53:04 -07002647
2648 // Try to trigger overuse. No fps estimate available => no effect.
mflodmancc3d4422017-08-03 08:27:51 -07002649 video_stream_encoder_->TriggerCpuOveruse();
sprangc5d62e22017-04-02 23:53:04 -07002650
2651 // Insert frames for one second to get a stable estimate.
sprang4847ae62017-06-27 07:06:52 -07002652 for (int i = 0; i < max_framerate_; ++i) {
sprangc5d62e22017-04-02 23:53:04 -07002653 timestamp_ms += kFrameIntervalMs;
sprangc5d62e22017-04-02 23:53:04 -07002654 video_source_.IncomingCapturedFrame(
2655 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002656 WaitForEncodedFrame(timestamp_ms);
sprangc5d62e22017-04-02 23:53:04 -07002657 }
2658
2659 // Trigger CPU overuse, reduce framerate by 2/3.
mflodmancc3d4422017-08-03 08:27:51 -07002660 video_stream_encoder_->TriggerCpuOveruse();
sprangc5d62e22017-04-02 23:53:04 -07002661 int num_frames_dropped = 0;
sprang4847ae62017-06-27 07:06:52 -07002662 for (int i = 0; i < max_framerate_; ++i) {
sprangc5d62e22017-04-02 23:53:04 -07002663 timestamp_ms += kFrameIntervalMs;
sprangc5d62e22017-04-02 23:53:04 -07002664 video_source_.IncomingCapturedFrame(
2665 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002666 if (!WaitForFrame(kFrameTimeoutMs)) {
sprangc5d62e22017-04-02 23:53:04 -07002667 ++num_frames_dropped;
2668 } else {
Åsa Perssonc74d8da2017-12-04 14:13:56 +01002669 sink_.CheckLastFrameSizeMatches(kFrameWidth, kFrameHeight);
sprangc5d62e22017-04-02 23:53:04 -07002670 }
2671 }
2672
sprang4847ae62017-06-27 07:06:52 -07002673 // Add some slack to account for frames dropped by the frame dropper.
2674 const int kErrorMargin = 1;
2675 EXPECT_NEAR(num_frames_dropped, max_framerate_ - (max_framerate_ * 2 / 3),
sprangc5d62e22017-04-02 23:53:04 -07002676 kErrorMargin);
2677
2678 // Trigger CPU overuse, reduce framerate by 2/3 again.
mflodmancc3d4422017-08-03 08:27:51 -07002679 video_stream_encoder_->TriggerCpuOveruse();
sprangc5d62e22017-04-02 23:53:04 -07002680 num_frames_dropped = 0;
sprang4847ae62017-06-27 07:06:52 -07002681 for (int i = 0; i < max_framerate_; ++i) {
sprangc5d62e22017-04-02 23:53:04 -07002682 timestamp_ms += kFrameIntervalMs;
sprangc5d62e22017-04-02 23:53:04 -07002683 video_source_.IncomingCapturedFrame(
2684 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002685 if (!WaitForFrame(kFrameTimeoutMs)) {
sprangc5d62e22017-04-02 23:53:04 -07002686 ++num_frames_dropped;
2687 } else {
Åsa Perssonc74d8da2017-12-04 14:13:56 +01002688 sink_.CheckLastFrameSizeMatches(kFrameWidth, kFrameHeight);
sprangc5d62e22017-04-02 23:53:04 -07002689 }
2690 }
sprang4847ae62017-06-27 07:06:52 -07002691 EXPECT_NEAR(num_frames_dropped, max_framerate_ - (max_framerate_ * 4 / 9),
sprangc5d62e22017-04-02 23:53:04 -07002692 kErrorMargin);
2693
2694 // Go back up one step.
mflodmancc3d4422017-08-03 08:27:51 -07002695 video_stream_encoder_->TriggerCpuNormalUsage();
sprangc5d62e22017-04-02 23:53:04 -07002696 num_frames_dropped = 0;
sprang4847ae62017-06-27 07:06:52 -07002697 for (int i = 0; i < max_framerate_; ++i) {
sprangc5d62e22017-04-02 23:53:04 -07002698 timestamp_ms += kFrameIntervalMs;
sprangc5d62e22017-04-02 23:53:04 -07002699 video_source_.IncomingCapturedFrame(
2700 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002701 if (!WaitForFrame(kFrameTimeoutMs)) {
sprangc5d62e22017-04-02 23:53:04 -07002702 ++num_frames_dropped;
2703 } else {
Åsa Perssonc74d8da2017-12-04 14:13:56 +01002704 sink_.CheckLastFrameSizeMatches(kFrameWidth, kFrameHeight);
sprangc5d62e22017-04-02 23:53:04 -07002705 }
2706 }
sprang4847ae62017-06-27 07:06:52 -07002707 EXPECT_NEAR(num_frames_dropped, max_framerate_ - (max_framerate_ * 2 / 3),
sprangc5d62e22017-04-02 23:53:04 -07002708 kErrorMargin);
2709
2710 // Go back up to original mode.
mflodmancc3d4422017-08-03 08:27:51 -07002711 video_stream_encoder_->TriggerCpuNormalUsage();
sprangc5d62e22017-04-02 23:53:04 -07002712 num_frames_dropped = 0;
sprang4847ae62017-06-27 07:06:52 -07002713 for (int i = 0; i < max_framerate_; ++i) {
sprangc5d62e22017-04-02 23:53:04 -07002714 timestamp_ms += kFrameIntervalMs;
sprangc5d62e22017-04-02 23:53:04 -07002715 video_source_.IncomingCapturedFrame(
2716 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002717 if (!WaitForFrame(kFrameTimeoutMs)) {
sprangc5d62e22017-04-02 23:53:04 -07002718 ++num_frames_dropped;
2719 } else {
Åsa Perssonc74d8da2017-12-04 14:13:56 +01002720 sink_.CheckLastFrameSizeMatches(kFrameWidth, kFrameHeight);
sprangc5d62e22017-04-02 23:53:04 -07002721 }
2722 }
2723 EXPECT_NEAR(num_frames_dropped, 0, kErrorMargin);
2724
mflodmancc3d4422017-08-03 08:27:51 -07002725 video_stream_encoder_->Stop();
sprangc5d62e22017-04-02 23:53:04 -07002726}
2727
mflodmancc3d4422017-08-03 08:27:51 -07002728TEST_F(VideoStreamEncoderTest, DoesntAdaptDownPastMinFramerate) {
sprangc5d62e22017-04-02 23:53:04 -07002729 const int kFramerateFps = 5;
2730 const int kFrameIntervalMs = rtc::kNumMillisecsPerSec / kFramerateFps;
sprangc5d62e22017-04-02 23:53:04 -07002731 const int kFrameWidth = 1280;
2732 const int kFrameHeight = 720;
2733
sprang4847ae62017-06-27 07:06:52 -07002734 // Reconfigure encoder with two temporal layers and screensharing, which will
2735 // disable frame dropping and make testing easier.
emircanbbcc3562017-08-18 00:28:40 -07002736 ResetEncoder("VP8", 1, 2, 1, true, true);
sprang4847ae62017-06-27 07:06:52 -07002737
mflodmancc3d4422017-08-03 08:27:51 -07002738 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
2739 video_stream_encoder_->SetSource(
sprangc5d62e22017-04-02 23:53:04 -07002740 &video_source_,
2741 VideoSendStream::DegradationPreference::kMaintainResolution);
2742 video_source_.set_adaptation_enabled(true);
2743
sprang4847ae62017-06-27 07:06:52 -07002744 int64_t timestamp_ms = fake_clock_.TimeNanos() / rtc::kNumNanosecsPerMillisec;
sprangc5d62e22017-04-02 23:53:04 -07002745
2746 // Trigger overuse as much as we can.
Jonathan Yubc771b72017-12-08 17:04:29 -08002747 rtc::VideoSinkWants last_wants;
2748 do {
2749 last_wants = video_source_.sink_wants();
2750
sprangc5d62e22017-04-02 23:53:04 -07002751 // Insert frames to get a new fps estimate...
2752 for (int j = 0; j < kFramerateFps; ++j) {
2753 video_source_.IncomingCapturedFrame(
2754 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
Jonathan Yubc771b72017-12-08 17:04:29 -08002755 if (video_source_.last_sent_width()) {
2756 sink_.WaitForEncodedFrame(timestamp_ms);
2757 }
sprangc5d62e22017-04-02 23:53:04 -07002758 timestamp_ms += kFrameIntervalMs;
Jonathan Yubc771b72017-12-08 17:04:29 -08002759 fake_clock_.AdvanceTimeMicros(
2760 kFrameIntervalMs * rtc::kNumMicrosecsPerMillisec);
sprangc5d62e22017-04-02 23:53:04 -07002761 }
2762 // ...and then try to adapt again.
mflodmancc3d4422017-08-03 08:27:51 -07002763 video_stream_encoder_->TriggerCpuOveruse();
Jonathan Yubc771b72017-12-08 17:04:29 -08002764 } while (video_source_.sink_wants().max_framerate_fps <
2765 last_wants.max_framerate_fps);
sprangc5d62e22017-04-02 23:53:04 -07002766
Jonathan Yubc771b72017-12-08 17:04:29 -08002767 VerifyFpsEqResolutionMax(video_source_.sink_wants(), kMinFramerateFps);
asaperssonf7e294d2017-06-13 23:25:22 -07002768
mflodmancc3d4422017-08-03 08:27:51 -07002769 video_stream_encoder_->Stop();
sprangc5d62e22017-04-02 23:53:04 -07002770}
asaperssonf7e294d2017-06-13 23:25:22 -07002771
mflodmancc3d4422017-08-03 08:27:51 -07002772TEST_F(VideoStreamEncoderTest,
2773 AdaptsResolutionAndFramerateForLowQuality_BalancedMode) {
asaperssonf7e294d2017-06-13 23:25:22 -07002774 const int kWidth = 1280;
2775 const int kHeight = 720;
2776 const int64_t kFrameIntervalMs = 150;
2777 int64_t timestamp_ms = kFrameIntervalMs;
mflodmancc3d4422017-08-03 08:27:51 -07002778 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -07002779
2780 // Enable kBalanced preference, no initial limitation.
2781 AdaptingFrameForwarder source;
2782 source.set_adaptation_enabled(true);
mflodmancc3d4422017-08-03 08:27:51 -07002783 video_stream_encoder_->SetSource(
2784 &source,
2785 VideoSendStream::DegradationPreference::kBalanced);
asaperssonf7e294d2017-06-13 23:25:22 -07002786 timestamp_ms += kFrameIntervalMs;
2787 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002788 WaitForEncodedFrame(kWidth, kHeight);
asaperssonf7e294d2017-06-13 23:25:22 -07002789 VerifyNoLimitation(source.sink_wants());
2790 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2791 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2792 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2793
2794 // Trigger adapt down, expect scaled down resolution (960x540@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002795 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002796 timestamp_ms += kFrameIntervalMs;
2797 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002798 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002799 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
2800 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2801 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2802 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2803
2804 // Trigger adapt down, expect scaled down resolution (640x360@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002805 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002806 timestamp_ms += kFrameIntervalMs;
2807 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002808 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002809 VerifyFpsMaxResolutionLt(source.sink_wants(), source.last_wants());
2810 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2811 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2812 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2813
2814 // Trigger adapt down, expect reduced fps (640x360@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07002815 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002816 timestamp_ms += kFrameIntervalMs;
2817 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002818 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002819 VerifyFpsLtResolutionEq(source.sink_wants(), source.last_wants());
2820 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2821 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2822 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2823
2824 // Trigger adapt down, expect scaled down resolution (480x270@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07002825 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002826 timestamp_ms += kFrameIntervalMs;
2827 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002828 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002829 VerifyFpsEqResolutionLt(source.sink_wants(), source.last_wants());
2830 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2831 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2832 EXPECT_EQ(4, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2833
2834 // Restrict bitrate, trigger adapt down, expect reduced fps (480x270@10fps).
mflodmancc3d4422017-08-03 08:27:51 -07002835 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002836 timestamp_ms += kFrameIntervalMs;
2837 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002838 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002839 VerifyFpsLtResolutionEq(source.sink_wants(), source.last_wants());
2840 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2841 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2842 EXPECT_EQ(5, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2843
2844 // Trigger adapt down, expect scaled down resolution (320x180@10fps).
mflodmancc3d4422017-08-03 08:27:51 -07002845 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002846 timestamp_ms += kFrameIntervalMs;
2847 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002848 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002849 VerifyFpsEqResolutionLt(source.sink_wants(), source.last_wants());
2850 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2851 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2852 EXPECT_EQ(6, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2853
2854 // Trigger adapt down, expect reduced fps (320x180@7fps).
mflodmancc3d4422017-08-03 08:27:51 -07002855 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002856 timestamp_ms += kFrameIntervalMs;
2857 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002858 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002859 VerifyFpsLtResolutionEq(source.sink_wants(), source.last_wants());
2860 rtc::VideoSinkWants last_wants = source.sink_wants();
2861 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2862 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2863 EXPECT_EQ(7, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2864
2865 // Trigger adapt down, min resolution reached, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07002866 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002867 timestamp_ms += kFrameIntervalMs;
2868 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002869 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002870 VerifyFpsEqResolutionEq(source.sink_wants(), last_wants);
2871 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2872 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2873 EXPECT_EQ(7, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2874
2875 // Trigger adapt down, expect expect increased fps (320x180@10fps).
mflodmancc3d4422017-08-03 08:27:51 -07002876 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002877 timestamp_ms += kFrameIntervalMs;
2878 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002879 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002880 VerifyFpsGtResolutionEq(source.sink_wants(), source.last_wants());
2881 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2882 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2883 EXPECT_EQ(8, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2884
2885 // Trigger adapt up, expect upscaled resolution (480x270@10fps).
mflodmancc3d4422017-08-03 08:27:51 -07002886 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002887 timestamp_ms += kFrameIntervalMs;
2888 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002889 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002890 VerifyFpsEqResolutionGt(source.sink_wants(), source.last_wants());
2891 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2892 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2893 EXPECT_EQ(9, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2894
2895 // Increase bitrate, trigger adapt up, expect increased fps (480x270@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07002896 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002897 timestamp_ms += kFrameIntervalMs;
2898 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002899 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002900 VerifyFpsGtResolutionEq(source.sink_wants(), source.last_wants());
2901 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2902 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2903 EXPECT_EQ(10, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2904
2905 // Trigger adapt up, expect upscaled resolution (640x360@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07002906 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002907 timestamp_ms += kFrameIntervalMs;
2908 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002909 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002910 VerifyFpsEqResolutionGt(source.sink_wants(), source.last_wants());
2911 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2912 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2913 EXPECT_EQ(11, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2914
2915 // Trigger adapt up, expect increased fps (640x360@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002916 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002917 timestamp_ms += kFrameIntervalMs;
2918 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002919 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002920 VerifyFpsMaxResolutionEq(source.sink_wants(), source.last_wants());
2921 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2922 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2923 EXPECT_EQ(12, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2924
2925 // Trigger adapt up, expect upscaled resolution (960x540@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002926 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002927 timestamp_ms += kFrameIntervalMs;
2928 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002929 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002930 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
2931 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2932 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2933 EXPECT_EQ(13, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2934
2935 // Trigger adapt up, expect no restriction (1280x720fps@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002936 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002937 timestamp_ms += kFrameIntervalMs;
2938 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002939 WaitForEncodedFrame(kWidth, kHeight);
asaperssonf7e294d2017-06-13 23:25:22 -07002940 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
2941 VerifyNoLimitation(source.sink_wants());
2942 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2943 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2944 EXPECT_EQ(14, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2945
2946 // Trigger adapt up, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07002947 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002948 VerifyNoLimitation(source.sink_wants());
2949 EXPECT_EQ(14, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2950
mflodmancc3d4422017-08-03 08:27:51 -07002951 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07002952}
2953
mflodmancc3d4422017-08-03 08:27:51 -07002954TEST_F(VideoStreamEncoderTest, AdaptWithTwoReasonsAndDifferentOrder_Framerate) {
asaperssonf7e294d2017-06-13 23:25:22 -07002955 const int kWidth = 1280;
2956 const int kHeight = 720;
2957 const int64_t kFrameIntervalMs = 150;
2958 int64_t timestamp_ms = kFrameIntervalMs;
mflodmancc3d4422017-08-03 08:27:51 -07002959 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -07002960
2961 // Enable kBalanced preference, no initial limitation.
2962 AdaptingFrameForwarder source;
2963 source.set_adaptation_enabled(true);
mflodmancc3d4422017-08-03 08:27:51 -07002964 video_stream_encoder_->SetSource(
2965 &source,
2966 VideoSendStream::DegradationPreference::kBalanced);
asaperssonf7e294d2017-06-13 23:25:22 -07002967 timestamp_ms += kFrameIntervalMs;
2968 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002969 WaitForEncodedFrame(kWidth, kHeight);
asaperssonf7e294d2017-06-13 23:25:22 -07002970 VerifyNoLimitation(source.sink_wants());
2971 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2972 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2973 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2974 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
2975 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2976 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2977
2978 // Trigger cpu adapt down, expect scaled down resolution (960x540@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002979 video_stream_encoder_->TriggerCpuOveruse();
asaperssonf7e294d2017-06-13 23:25:22 -07002980 timestamp_ms += kFrameIntervalMs;
2981 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002982 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002983 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
2984 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2985 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2986 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2987 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
2988 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2989 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2990
2991 // Trigger cpu adapt down, expect scaled down resolution (640x360@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002992 video_stream_encoder_->TriggerCpuOveruse();
asaperssonf7e294d2017-06-13 23:25:22 -07002993 timestamp_ms += kFrameIntervalMs;
2994 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002995 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002996 VerifyFpsMaxResolutionLt(source.sink_wants(), source.last_wants());
2997 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2998 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2999 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
3000 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
3001 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
3002 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3003
3004 // Trigger quality adapt down, expect reduced fps (640x360@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07003005 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07003006 timestamp_ms += kFrameIntervalMs;
3007 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003008 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07003009 VerifyFpsLtResolutionEq(source.sink_wants(), source.last_wants());
3010 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
3011 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
3012 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
3013 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
3014 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
3015 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3016
3017 // Trigger cpu adapt up, expect increased fps (640x360@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07003018 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssonf7e294d2017-06-13 23:25:22 -07003019 timestamp_ms += kFrameIntervalMs;
3020 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003021 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07003022 VerifyFpsMaxResolutionEq(source.sink_wants(), source.last_wants());
3023 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
3024 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
3025 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
3026 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
3027 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
3028 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3029
3030 // Trigger quality adapt up, expect upscaled resolution (960x540@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07003031 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07003032 timestamp_ms += kFrameIntervalMs;
3033 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003034 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07003035 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
3036 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
3037 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
3038 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
3039 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
3040 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
3041 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3042
3043 // Trigger cpu adapt up, expect no restriction (1280x720fps@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07003044 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssonf7e294d2017-06-13 23:25:22 -07003045 timestamp_ms += kFrameIntervalMs;
3046 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003047 WaitForEncodedFrame(kWidth, kHeight);
asaperssonf7e294d2017-06-13 23:25:22 -07003048 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
3049 VerifyNoLimitation(source.sink_wants());
3050 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
3051 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
3052 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
3053 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
3054 EXPECT_EQ(4, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
3055 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3056
3057 // Trigger adapt up, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07003058 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07003059 VerifyNoLimitation(source.sink_wants());
3060 EXPECT_EQ(4, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
3061 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3062
mflodmancc3d4422017-08-03 08:27:51 -07003063 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07003064}
3065
mflodmancc3d4422017-08-03 08:27:51 -07003066TEST_F(VideoStreamEncoderTest,
3067 AdaptWithTwoReasonsAndDifferentOrder_Resolution) {
asaperssonf7e294d2017-06-13 23:25:22 -07003068 const int kWidth = 640;
3069 const int kHeight = 360;
3070 const int kFpsLimit = 15;
3071 const int64_t kFrameIntervalMs = 150;
3072 int64_t timestamp_ms = kFrameIntervalMs;
mflodmancc3d4422017-08-03 08:27:51 -07003073 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -07003074
3075 // Enable kBalanced preference, no initial limitation.
3076 AdaptingFrameForwarder source;
3077 source.set_adaptation_enabled(true);
mflodmancc3d4422017-08-03 08:27:51 -07003078 video_stream_encoder_->SetSource(
3079 &source,
3080 VideoSendStream::DegradationPreference::kBalanced);
asaperssonf7e294d2017-06-13 23:25:22 -07003081 timestamp_ms += kFrameIntervalMs;
3082 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003083 WaitForEncodedFrame(kWidth, kHeight);
asaperssonf7e294d2017-06-13 23:25:22 -07003084 VerifyNoLimitation(source.sink_wants());
3085 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
3086 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
3087 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
3088 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
3089 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
3090 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3091
3092 // Trigger cpu adapt down, expect scaled down framerate (640x360@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07003093 video_stream_encoder_->TriggerCpuOveruse();
asaperssonf7e294d2017-06-13 23:25:22 -07003094 timestamp_ms += kFrameIntervalMs;
3095 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003096 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07003097 VerifyFpsEqResolutionMax(source.sink_wants(), kFpsLimit);
3098 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
3099 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
3100 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
3101 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_framerate);
3102 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
3103 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3104
3105 // Trigger quality adapt down, expect scaled down resolution (480x270@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07003106 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07003107 timestamp_ms += kFrameIntervalMs;
3108 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003109 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07003110 VerifyFpsEqResolutionLt(source.sink_wants(), source.last_wants());
3111 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
3112 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
3113 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
3114 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_framerate);
3115 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
3116 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3117
3118 // Trigger cpu adapt up, expect upscaled resolution (640x360@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07003119 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssonf7e294d2017-06-13 23:25:22 -07003120 timestamp_ms += kFrameIntervalMs;
3121 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003122 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07003123 VerifyFpsEqResolutionGt(source.sink_wants(), source.last_wants());
3124 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
3125 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
3126 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
3127 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
3128 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
3129 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3130
3131 // Trigger quality adapt up, expect increased fps (640x360@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07003132 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07003133 timestamp_ms += kFrameIntervalMs;
3134 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003135 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07003136 VerifyNoLimitation(source.sink_wants());
3137 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
3138 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
3139 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
3140 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
3141 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
3142 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3143
3144 // Trigger adapt up, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07003145 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07003146 VerifyNoLimitation(source.sink_wants());
3147 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
3148 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3149
mflodmancc3d4422017-08-03 08:27:51 -07003150 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07003151}
3152
mflodmancc3d4422017-08-03 08:27:51 -07003153TEST_F(VideoStreamEncoderTest, AcceptsFullHdAdaptedDownSimulcastFrames) {
ilnik6b826ef2017-06-16 06:53:48 -07003154 // Simulates simulcast behavior and makes highest stream resolutions divisible
3155 // by 4.
3156 class CroppingVideoStreamFactory
3157 : public VideoEncoderConfig::VideoStreamFactoryInterface {
3158 public:
3159 explicit CroppingVideoStreamFactory(size_t num_temporal_layers,
3160 int framerate)
3161 : num_temporal_layers_(num_temporal_layers), framerate_(framerate) {
3162 EXPECT_GT(num_temporal_layers, 0u);
3163 EXPECT_GT(framerate, 0);
3164 }
3165
3166 private:
3167 std::vector<VideoStream> CreateEncoderStreams(
3168 int width,
3169 int height,
3170 const VideoEncoderConfig& encoder_config) override {
3171 std::vector<VideoStream> streams =
3172 test::CreateVideoStreams(width - width % 4, height - height % 4,
3173 encoder_config);
3174 for (VideoStream& stream : streams) {
Sergey Silkina796a7e2018-03-01 15:11:29 +01003175 stream.num_temporal_layers = num_temporal_layers_;
ilnik6b826ef2017-06-16 06:53:48 -07003176 stream.max_framerate = framerate_;
3177 }
3178 return streams;
3179 }
3180
3181 const size_t num_temporal_layers_;
3182 const int framerate_;
3183 };
3184
3185 const int kFrameWidth = 1920;
3186 const int kFrameHeight = 1080;
3187 // 3/4 of 1920.
3188 const int kAdaptedFrameWidth = 1440;
3189 // 3/4 of 1080 rounded down to multiple of 4.
3190 const int kAdaptedFrameHeight = 808;
3191 const int kFramerate = 24;
3192
mflodmancc3d4422017-08-03 08:27:51 -07003193 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
ilnik6b826ef2017-06-16 06:53:48 -07003194 // Trigger reconfigure encoder (without resetting the entire instance).
3195 VideoEncoderConfig video_encoder_config;
Niels Möller259a4972018-04-05 15:36:51 +02003196 video_encoder_config.codec_type = kVideoCodecVP8;
ilnik6b826ef2017-06-16 06:53:48 -07003197 video_encoder_config.max_bitrate_bps = kTargetBitrateBps;
3198 video_encoder_config.number_of_streams = 1;
3199 video_encoder_config.video_stream_factory =
3200 new rtc::RefCountedObject<CroppingVideoStreamFactory>(1, kFramerate);
mflodmancc3d4422017-08-03 08:27:51 -07003201 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
3202 kMaxPayloadLength, false);
3203 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
ilnik6b826ef2017-06-16 06:53:48 -07003204
3205 video_source_.set_adaptation_enabled(true);
3206
3207 video_source_.IncomingCapturedFrame(
3208 CreateFrame(1, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07003209 WaitForEncodedFrame(kFrameWidth, kFrameHeight);
ilnik6b826ef2017-06-16 06:53:48 -07003210
3211 // Trigger CPU overuse, downscale by 3/4.
mflodmancc3d4422017-08-03 08:27:51 -07003212 video_stream_encoder_->TriggerCpuOveruse();
ilnik6b826ef2017-06-16 06:53:48 -07003213 video_source_.IncomingCapturedFrame(
3214 CreateFrame(2, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07003215 WaitForEncodedFrame(kAdaptedFrameWidth, kAdaptedFrameHeight);
ilnik6b826ef2017-06-16 06:53:48 -07003216
mflodmancc3d4422017-08-03 08:27:51 -07003217 video_stream_encoder_->Stop();
ilnik6b826ef2017-06-16 06:53:48 -07003218}
3219
mflodmancc3d4422017-08-03 08:27:51 -07003220TEST_F(VideoStreamEncoderTest, PeriodicallyUpdatesChannelParameters) {
sprang4847ae62017-06-27 07:06:52 -07003221 const int kFrameWidth = 1280;
3222 const int kFrameHeight = 720;
3223 const int kLowFps = 2;
3224 const int kHighFps = 30;
3225
mflodmancc3d4422017-08-03 08:27:51 -07003226 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
sprang4847ae62017-06-27 07:06:52 -07003227
3228 int64_t timestamp_ms = fake_clock_.TimeNanos() / rtc::kNumNanosecsPerMillisec;
3229 max_framerate_ = kLowFps;
3230
3231 // Insert 2 seconds of 2fps video.
3232 for (int i = 0; i < kLowFps * 2; ++i) {
3233 video_source_.IncomingCapturedFrame(
3234 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
3235 WaitForEncodedFrame(timestamp_ms);
3236 timestamp_ms += 1000 / kLowFps;
3237 }
3238
3239 // Make sure encoder is updated with new target.
mflodmancc3d4422017-08-03 08:27:51 -07003240 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
sprang4847ae62017-06-27 07:06:52 -07003241 video_source_.IncomingCapturedFrame(
3242 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
3243 WaitForEncodedFrame(timestamp_ms);
3244 timestamp_ms += 1000 / kLowFps;
3245
3246 EXPECT_EQ(kLowFps, fake_encoder_.GetConfiguredInputFramerate());
3247
3248 // Insert 30fps frames for just a little more than the forced update period.
3249 const int kVcmTimerIntervalFrames =
3250 (vcm::VCMProcessTimer::kDefaultProcessIntervalMs * kHighFps) / 1000;
3251 const int kFrameIntervalMs = 1000 / kHighFps;
3252 max_framerate_ = kHighFps;
3253 for (int i = 0; i < kVcmTimerIntervalFrames + 2; ++i) {
3254 video_source_.IncomingCapturedFrame(
3255 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
3256 // Wait for encoded frame, but skip ahead if it doesn't arrive as it might
3257 // be dropped if the encoder hans't been updated with the new higher target
3258 // framerate yet, causing it to overshoot the target bitrate and then
3259 // suffering the wrath of the media optimizer.
3260 TimedWaitForEncodedFrame(timestamp_ms, 2 * kFrameIntervalMs);
3261 timestamp_ms += kFrameIntervalMs;
3262 }
3263
3264 // Don expect correct measurement just yet, but it should be higher than
3265 // before.
3266 EXPECT_GT(fake_encoder_.GetConfiguredInputFramerate(), kLowFps);
3267
mflodmancc3d4422017-08-03 08:27:51 -07003268 video_stream_encoder_->Stop();
sprang4847ae62017-06-27 07:06:52 -07003269}
3270
mflodmancc3d4422017-08-03 08:27:51 -07003271TEST_F(VideoStreamEncoderTest, DoesNotUpdateBitrateAllocationWhenSuspended) {
sprang4847ae62017-06-27 07:06:52 -07003272 const int kFrameWidth = 1280;
3273 const int kFrameHeight = 720;
3274 const int kTargetBitrateBps = 1000000;
3275
3276 MockBitrateObserver bitrate_observer;
mflodmancc3d4422017-08-03 08:27:51 -07003277 video_stream_encoder_->SetBitrateObserver(&bitrate_observer);
sprang4847ae62017-06-27 07:06:52 -07003278
3279 EXPECT_CALL(bitrate_observer, OnBitrateAllocationUpdated(_)).Times(1);
3280 // Initial bitrate update.
mflodmancc3d4422017-08-03 08:27:51 -07003281 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
3282 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
sprang4847ae62017-06-27 07:06:52 -07003283
3284 // Insert a first video frame, causes another bitrate update.
3285 int64_t timestamp_ms = fake_clock_.TimeNanos() / rtc::kNumNanosecsPerMillisec;
3286 EXPECT_CALL(bitrate_observer, OnBitrateAllocationUpdated(_)).Times(1);
3287 video_source_.IncomingCapturedFrame(
3288 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
3289 WaitForEncodedFrame(timestamp_ms);
3290
3291 // Next, simulate video suspension due to pacer queue overrun.
mflodmancc3d4422017-08-03 08:27:51 -07003292 video_stream_encoder_->OnBitrateUpdated(0, 0, 1);
sprang4847ae62017-06-27 07:06:52 -07003293
3294 // Skip ahead until a new periodic parameter update should have occured.
3295 timestamp_ms += vcm::VCMProcessTimer::kDefaultProcessIntervalMs;
3296 fake_clock_.AdvanceTimeMicros(
3297 vcm::VCMProcessTimer::kDefaultProcessIntervalMs *
3298 rtc::kNumMicrosecsPerMillisec);
3299
3300 // Bitrate observer should not be called.
3301 EXPECT_CALL(bitrate_observer, OnBitrateAllocationUpdated(_)).Times(0);
3302 video_source_.IncomingCapturedFrame(
3303 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
3304 ExpectDroppedFrame();
3305
mflodmancc3d4422017-08-03 08:27:51 -07003306 video_stream_encoder_->Stop();
sprang4847ae62017-06-27 07:06:52 -07003307}
ilnik6b826ef2017-06-16 06:53:48 -07003308
perkj26091b12016-09-01 01:17:40 -07003309} // namespace webrtc