blob: ab2d8af99c9fbdfd0c84303b91bcfb8d628fd038 [file] [log] [blame]
perkj26091b12016-09-01 01:17:40 -07001/*
2 * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved.
3 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
sprangfe627f32017-03-29 08:24:59 -070011#include <algorithm>
perkj803d97f2016-11-01 11:45:46 -070012#include <limits>
Per512ecb32016-09-23 15:52:06 +020013#include <utility>
14
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020015#include "api/video/i420_buffer.h"
16#include "media/base/videoadapter.h"
17#include "modules/video_coding/codecs/vp8/temporal_layers.h"
Sergey Silkin86684962018-03-28 19:32:37 +020018#include "modules/video_coding/codecs/vp9/include/vp9_globals.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020019#include "modules/video_coding/utility/default_video_bitrate_allocator.h"
20#include "rtc_base/fakeclock.h"
21#include "rtc_base/logging.h"
22#include "system_wrappers/include/metrics_default.h"
23#include "system_wrappers/include/sleep.h"
Niels Möller4db138e2018-04-19 09:04:13 +020024#include "test/encoder_proxy_factory.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020025#include "test/encoder_settings.h"
26#include "test/fake_encoder.h"
27#include "test/frame_generator.h"
28#include "test/gmock.h"
29#include "test/gtest.h"
30#include "video/send_statistics_proxy.h"
31#include "video/video_stream_encoder.h"
perkj26091b12016-09-01 01:17:40 -070032
kthelgason33ce8892016-12-09 03:53:59 -080033namespace {
kthelgason33ce8892016-12-09 03:53:59 -080034const int kMinPixelsPerFrame = 320 * 180;
sprangc5d62e22017-04-02 23:53:04 -070035const int kMinFramerateFps = 2;
Jonathan Yubc771b72017-12-08 17:04:29 -080036const int kMinBalancedFramerateFps = 7;
sprangc5d62e22017-04-02 23:53:04 -070037const int64_t kFrameTimeoutMs = 100;
38} // namespace
kthelgason33ce8892016-12-09 03:53:59 -080039
perkj26091b12016-09-01 01:17:40 -070040namespace webrtc {
41
kthelgason876222f2016-11-29 01:44:11 -080042using DegredationPreference = VideoSendStream::DegradationPreference;
sprangb1ca0732017-02-01 08:38:12 -080043using ScaleReason = AdaptationObserverInterface::AdaptReason;
sprang57c2fff2017-01-16 06:24:02 -080044using ::testing::_;
45using ::testing::Return;
kthelgason876222f2016-11-29 01:44:11 -080046
perkj803d97f2016-11-01 11:45:46 -070047namespace {
asapersson5f7226f2016-11-25 04:37:00 -080048const size_t kMaxPayloadLength = 1440;
kthelgason2bc68642017-02-07 07:02:22 -080049const int kTargetBitrateBps = 1000000;
50const int kLowTargetBitrateBps = kTargetBitrateBps / 10;
51const int kMaxInitialFramedrop = 4;
sprangfda496a2017-06-15 04:21:07 -070052const int kDefaultFramerate = 30;
asapersson5f7226f2016-11-25 04:37:00 -080053
perkj803d97f2016-11-01 11:45:46 -070054class TestBuffer : public webrtc::I420Buffer {
55 public:
56 TestBuffer(rtc::Event* event, int width, int height)
57 : I420Buffer(width, height), event_(event) {}
58
59 private:
60 friend class rtc::RefCountedObject<TestBuffer>;
61 ~TestBuffer() override {
62 if (event_)
63 event_->Set();
64 }
65 rtc::Event* const event_;
66};
67
Niels Möller7dc26b72017-12-06 10:27:48 +010068class CpuOveruseDetectorProxy : public OveruseFrameDetector {
69 public:
Niels Möllerd1f7eb62018-03-28 16:40:58 +020070 explicit CpuOveruseDetectorProxy(CpuOveruseMetricsObserver* metrics_observer)
71 : OveruseFrameDetector(metrics_observer),
Niels Möller7dc26b72017-12-06 10:27:48 +010072 last_target_framerate_fps_(-1) {}
73 virtual ~CpuOveruseDetectorProxy() {}
74
75 void OnTargetFramerateUpdated(int framerate_fps) override {
76 rtc::CritScope cs(&lock_);
77 last_target_framerate_fps_ = framerate_fps;
78 OveruseFrameDetector::OnTargetFramerateUpdated(framerate_fps);
79 }
80
81 int GetLastTargetFramerate() {
82 rtc::CritScope cs(&lock_);
83 return last_target_framerate_fps_;
84 }
85
Niels Möller4db138e2018-04-19 09:04:13 +020086 CpuOveruseOptions GetOptions() { return options_; }
87
Niels Möller7dc26b72017-12-06 10:27:48 +010088 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(
mflodmancc3d4422017-08-03 08:27:51 -0700104 stats_proxy))) {}
perkj803d97f2016-11-01 11:45:46 -0700105
sprangb1ca0732017-02-01 08:38:12 -0800106 void PostTaskAndWait(bool down, AdaptReason reason) {
perkj803d97f2016-11-01 11:45:46 -0700107 rtc::Event event(false, false);
kthelgason876222f2016-11-29 01:44:11 -0800108 encoder_queue()->PostTask([this, &event, reason, down] {
sprangb1ca0732017-02-01 08:38:12 -0800109 down ? AdaptDown(reason) : AdaptUp(reason);
perkj803d97f2016-11-01 11:45:46 -0700110 event.Set();
111 });
perkj070ba852017-02-16 15:46:27 -0800112 ASSERT_TRUE(event.Wait(5000));
perkj803d97f2016-11-01 11:45:46 -0700113 }
114
kthelgason2fc52542017-03-03 00:24:41 -0800115 // This is used as a synchronisation mechanism, to make sure that the
116 // encoder queue is not blocked before we start sending it frames.
117 void WaitUntilTaskQueueIsIdle() {
118 rtc::Event event(false, false);
119 encoder_queue()->PostTask([&event] {
120 event.Set();
121 });
122 ASSERT_TRUE(event.Wait(5000));
123 }
124
sprangb1ca0732017-02-01 08:38:12 -0800125 void TriggerCpuOveruse() { PostTaskAndWait(true, AdaptReason::kCpu); }
kthelgason876222f2016-11-29 01:44:11 -0800126
sprangb1ca0732017-02-01 08:38:12 -0800127 void TriggerCpuNormalUsage() { PostTaskAndWait(false, AdaptReason::kCpu); }
kthelgason876222f2016-11-29 01:44:11 -0800128
sprangb1ca0732017-02-01 08:38:12 -0800129 void TriggerQualityLow() { PostTaskAndWait(true, AdaptReason::kQuality); }
kthelgason876222f2016-11-29 01:44:11 -0800130
sprangb1ca0732017-02-01 08:38:12 -0800131 void TriggerQualityHigh() { PostTaskAndWait(false, AdaptReason::kQuality); }
sprangfda496a2017-06-15 04:21:07 -0700132
Niels Möller7dc26b72017-12-06 10:27:48 +0100133 CpuOveruseDetectorProxy* overuse_detector_proxy_;
perkj803d97f2016-11-01 11:45:46 -0700134};
135
asapersson5f7226f2016-11-25 04:37:00 -0800136class VideoStreamFactory
137 : public VideoEncoderConfig::VideoStreamFactoryInterface {
138 public:
sprangfda496a2017-06-15 04:21:07 -0700139 explicit VideoStreamFactory(size_t num_temporal_layers, int framerate)
140 : num_temporal_layers_(num_temporal_layers), framerate_(framerate) {
asapersson5f7226f2016-11-25 04:37:00 -0800141 EXPECT_GT(num_temporal_layers, 0u);
sprangfda496a2017-06-15 04:21:07 -0700142 EXPECT_GT(framerate, 0);
asapersson5f7226f2016-11-25 04:37:00 -0800143 }
144
145 private:
146 std::vector<VideoStream> CreateEncoderStreams(
147 int width,
148 int height,
149 const VideoEncoderConfig& encoder_config) override {
150 std::vector<VideoStream> streams =
151 test::CreateVideoStreams(width, height, encoder_config);
152 for (VideoStream& stream : streams) {
Sergey Silkina796a7e2018-03-01 15:11:29 +0100153 stream.num_temporal_layers = num_temporal_layers_;
sprangfda496a2017-06-15 04:21:07 -0700154 stream.max_framerate = framerate_;
asapersson5f7226f2016-11-25 04:37:00 -0800155 }
156 return streams;
157 }
sprangfda496a2017-06-15 04:21:07 -0700158
asapersson5f7226f2016-11-25 04:37:00 -0800159 const size_t num_temporal_layers_;
sprangfda496a2017-06-15 04:21:07 -0700160 const int framerate_;
asapersson5f7226f2016-11-25 04:37:00 -0800161};
162
ilnik6b826ef2017-06-16 06:53:48 -0700163
sprangb1ca0732017-02-01 08:38:12 -0800164class AdaptingFrameForwarder : public test::FrameForwarder {
165 public:
166 AdaptingFrameForwarder() : adaptation_enabled_(false) {}
asaperssonfab67072017-04-04 05:51:49 -0700167 ~AdaptingFrameForwarder() override {}
sprangb1ca0732017-02-01 08:38:12 -0800168
169 void set_adaptation_enabled(bool enabled) {
170 rtc::CritScope cs(&crit_);
171 adaptation_enabled_ = enabled;
172 }
173
asaperssonfab67072017-04-04 05:51:49 -0700174 bool adaption_enabled() const {
sprangb1ca0732017-02-01 08:38:12 -0800175 rtc::CritScope cs(&crit_);
176 return adaptation_enabled_;
177 }
178
asapersson09f05612017-05-15 23:40:18 -0700179 rtc::VideoSinkWants last_wants() const {
180 rtc::CritScope cs(&crit_);
181 return last_wants_;
182 }
183
Jonathan Yubc771b72017-12-08 17:04:29 -0800184 rtc::Optional<int> last_sent_width() const { return last_width_; }
185 rtc::Optional<int> last_sent_height() const { return last_height_; }
186
sprangb1ca0732017-02-01 08:38:12 -0800187 void IncomingCapturedFrame(const VideoFrame& video_frame) override {
188 int cropped_width = 0;
189 int cropped_height = 0;
190 int out_width = 0;
191 int out_height = 0;
sprangc5d62e22017-04-02 23:53:04 -0700192 if (adaption_enabled()) {
193 if (adapter_.AdaptFrameResolution(
194 video_frame.width(), video_frame.height(),
195 video_frame.timestamp_us() * 1000, &cropped_width,
196 &cropped_height, &out_width, &out_height)) {
197 VideoFrame adapted_frame(new rtc::RefCountedObject<TestBuffer>(
198 nullptr, out_width, out_height),
199 99, 99, kVideoRotation_0);
200 adapted_frame.set_ntp_time_ms(video_frame.ntp_time_ms());
201 test::FrameForwarder::IncomingCapturedFrame(adapted_frame);
Jonathan Yubc771b72017-12-08 17:04:29 -0800202 last_width_.emplace(adapted_frame.width());
203 last_height_.emplace(adapted_frame.height());
204 } else {
205 last_width_ = rtc::nullopt;
206 last_height_ = rtc::nullopt;
sprangc5d62e22017-04-02 23:53:04 -0700207 }
sprangb1ca0732017-02-01 08:38:12 -0800208 } else {
209 test::FrameForwarder::IncomingCapturedFrame(video_frame);
Jonathan Yubc771b72017-12-08 17:04:29 -0800210 last_width_.emplace(video_frame.width());
211 last_height_.emplace(video_frame.height());
sprangb1ca0732017-02-01 08:38:12 -0800212 }
213 }
214
215 void AddOrUpdateSink(rtc::VideoSinkInterface<VideoFrame>* sink,
216 const rtc::VideoSinkWants& wants) override {
217 rtc::CritScope cs(&crit_);
asapersson09f05612017-05-15 23:40:18 -0700218 last_wants_ = sink_wants();
sprangc5d62e22017-04-02 23:53:04 -0700219 adapter_.OnResolutionFramerateRequest(wants.target_pixel_count,
220 wants.max_pixel_count,
221 wants.max_framerate_fps);
sprangb1ca0732017-02-01 08:38:12 -0800222 test::FrameForwarder::AddOrUpdateSink(sink, wants);
223 }
sprangb1ca0732017-02-01 08:38:12 -0800224 cricket::VideoAdapter adapter_;
danilchapa37de392017-09-09 04:17:22 -0700225 bool adaptation_enabled_ RTC_GUARDED_BY(crit_);
226 rtc::VideoSinkWants last_wants_ RTC_GUARDED_BY(crit_);
Jonathan Yubc771b72017-12-08 17:04:29 -0800227 rtc::Optional<int> last_width_;
228 rtc::Optional<int> last_height_;
sprangb1ca0732017-02-01 08:38:12 -0800229};
sprangc5d62e22017-04-02 23:53:04 -0700230
231class MockableSendStatisticsProxy : public SendStatisticsProxy {
232 public:
233 MockableSendStatisticsProxy(Clock* clock,
234 const VideoSendStream::Config& config,
235 VideoEncoderConfig::ContentType content_type)
236 : SendStatisticsProxy(clock, config, content_type) {}
237
238 VideoSendStream::Stats GetStats() override {
239 rtc::CritScope cs(&lock_);
240 if (mock_stats_)
241 return *mock_stats_;
242 return SendStatisticsProxy::GetStats();
243 }
244
245 void SetMockStats(const VideoSendStream::Stats& stats) {
246 rtc::CritScope cs(&lock_);
247 mock_stats_.emplace(stats);
248 }
249
250 void ResetMockStats() {
251 rtc::CritScope cs(&lock_);
252 mock_stats_.reset();
253 }
254
255 private:
256 rtc::CriticalSection lock_;
danilchapa37de392017-09-09 04:17:22 -0700257 rtc::Optional<VideoSendStream::Stats> mock_stats_ RTC_GUARDED_BY(lock_);
sprangc5d62e22017-04-02 23:53:04 -0700258};
259
sprang4847ae62017-06-27 07:06:52 -0700260class MockBitrateObserver : public VideoBitrateAllocationObserver {
261 public:
Erik Språng566124a2018-04-23 12:32:22 +0200262 MOCK_METHOD1(OnBitrateAllocationUpdated, void(const VideoBitrateAllocation&));
sprang4847ae62017-06-27 07:06:52 -0700263};
264
perkj803d97f2016-11-01 11:45:46 -0700265} // namespace
266
mflodmancc3d4422017-08-03 08:27:51 -0700267class VideoStreamEncoderTest : public ::testing::Test {
perkj26091b12016-09-01 01:17:40 -0700268 public:
269 static const int kDefaultTimeoutMs = 30 * 1000;
270
mflodmancc3d4422017-08-03 08:27:51 -0700271 VideoStreamEncoderTest()
perkj26091b12016-09-01 01:17:40 -0700272 : video_send_config_(VideoSendStream::Config(nullptr)),
perkjfa10b552016-10-02 23:45:26 -0700273 codec_width_(320),
274 codec_height_(240),
sprang4847ae62017-06-27 07:06:52 -0700275 max_framerate_(30),
perkj26091b12016-09-01 01:17:40 -0700276 fake_encoder_(),
Niels Möller4db138e2018-04-19 09:04:13 +0200277 encoder_factory_(&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);
Niels Möller4db138e2018-04-19 09:04:13 +0200287 video_send_config_.encoder_settings.encoder_factory = &encoder_factory_;
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
Niels Möllerf1338562018-04-26 09:51:47 +0200304 ConfigureEncoder(std::move(video_encoder_config));
asapersson5f7226f2016-11-25 04:37:00 -0800305 }
306
Niels Möllerf1338562018-04-26 09:51:47 +0200307 void ConfigureEncoder(VideoEncoderConfig video_encoder_config) {
mflodmancc3d4422017-08-03 08:27:51 -0700308 if (video_stream_encoder_)
309 video_stream_encoder_->Stop();
310 video_stream_encoder_.reset(new VideoStreamEncoderUnderTest(
perkj803d97f2016-11-01 11:45:46 -0700311 stats_proxy_.get(), video_send_config_.encoder_settings));
mflodmancc3d4422017-08-03 08:27:51 -0700312 video_stream_encoder_->SetSink(&sink_, false /* rotation_applied */);
313 video_stream_encoder_->SetSource(
sprangc5d62e22017-04-02 23:53:04 -0700314 &video_source_,
315 VideoSendStream::DegradationPreference::kMaintainFramerate);
mflodmancc3d4422017-08-03 08:27:51 -0700316 video_stream_encoder_->SetStartBitrate(kTargetBitrateBps);
317 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
Niels Möllerf1338562018-04-26 09:51:47 +0200318 kMaxPayloadLength);
mflodmancc3d4422017-08-03 08:27:51 -0700319 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
asapersson5f7226f2016-11-25 04:37:00 -0800320 }
321
322 void ResetEncoder(const std::string& payload_name,
323 size_t num_streams,
324 size_t num_temporal_layers,
emircanbbcc3562017-08-18 00:28:40 -0700325 unsigned char num_spatial_layers,
sprang4847ae62017-06-27 07:06:52 -0700326 bool screenshare) {
Niels Möller259a4972018-04-05 15:36:51 +0200327 video_send_config_.rtp.payload_name = payload_name;
asapersson5f7226f2016-11-25 04:37:00 -0800328
329 VideoEncoderConfig video_encoder_config;
Niels Möller259a4972018-04-05 15:36:51 +0200330 video_encoder_config.codec_type = PayloadStringToCodecType(payload_name);
asapersson5f7226f2016-11-25 04:37:00 -0800331 video_encoder_config.number_of_streams = num_streams;
kthelgason2bc68642017-02-07 07:02:22 -0800332 video_encoder_config.max_bitrate_bps = kTargetBitrateBps;
asapersson5f7226f2016-11-25 04:37:00 -0800333 video_encoder_config.video_stream_factory =
sprangfda496a2017-06-15 04:21:07 -0700334 new rtc::RefCountedObject<VideoStreamFactory>(num_temporal_layers,
335 kDefaultFramerate);
sprang4847ae62017-06-27 07:06:52 -0700336 video_encoder_config.content_type =
337 screenshare ? VideoEncoderConfig::ContentType::kScreen
338 : VideoEncoderConfig::ContentType::kRealtimeVideo;
emircanbbcc3562017-08-18 00:28:40 -0700339 if (payload_name == "VP9") {
340 VideoCodecVP9 vp9_settings = VideoEncoder::GetDefaultVp9Settings();
341 vp9_settings.numberOfSpatialLayers = num_spatial_layers;
342 video_encoder_config.encoder_specific_settings =
343 new rtc::RefCountedObject<
344 VideoEncoderConfig::Vp9EncoderSpecificSettings>(vp9_settings);
345 }
Niels Möllerf1338562018-04-26 09:51:47 +0200346 ConfigureEncoder(std::move(video_encoder_config));
perkj26091b12016-09-01 01:17:40 -0700347 }
348
sprang57c2fff2017-01-16 06:24:02 -0800349 VideoFrame CreateFrame(int64_t ntp_time_ms,
350 rtc::Event* destruction_event) const {
Per512ecb32016-09-23 15:52:06 +0200351 VideoFrame frame(new rtc::RefCountedObject<TestBuffer>(
352 destruction_event, codec_width_, codec_height_),
353 99, 99, kVideoRotation_0);
sprang57c2fff2017-01-16 06:24:02 -0800354 frame.set_ntp_time_ms(ntp_time_ms);
perkj26091b12016-09-01 01:17:40 -0700355 return frame;
356 }
357
sprang57c2fff2017-01-16 06:24:02 -0800358 VideoFrame CreateFrame(int64_t ntp_time_ms, int width, int height) const {
perkj803d97f2016-11-01 11:45:46 -0700359 VideoFrame frame(
360 new rtc::RefCountedObject<TestBuffer>(nullptr, width, height), 99, 99,
361 kVideoRotation_0);
sprang57c2fff2017-01-16 06:24:02 -0800362 frame.set_ntp_time_ms(ntp_time_ms);
sprangc5d62e22017-04-02 23:53:04 -0700363 frame.set_timestamp_us(ntp_time_ms * 1000);
perkj803d97f2016-11-01 11:45:46 -0700364 return frame;
365 }
366
asapersson02465b82017-04-10 01:12:52 -0700367 void VerifyNoLimitation(const rtc::VideoSinkWants& wants) {
asapersson02465b82017-04-10 01:12:52 -0700368 EXPECT_EQ(std::numeric_limits<int>::max(), wants.max_framerate_fps);
asapersson09f05612017-05-15 23:40:18 -0700369 EXPECT_EQ(std::numeric_limits<int>::max(), wants.max_pixel_count);
370 EXPECT_FALSE(wants.target_pixel_count);
asapersson02465b82017-04-10 01:12:52 -0700371 }
372
asapersson09f05612017-05-15 23:40:18 -0700373 void VerifyFpsEqResolutionEq(const rtc::VideoSinkWants& wants1,
374 const rtc::VideoSinkWants& wants2) {
375 EXPECT_EQ(wants1.max_framerate_fps, wants2.max_framerate_fps);
376 EXPECT_EQ(wants1.max_pixel_count, wants2.max_pixel_count);
377 }
378
379 void VerifyFpsMaxResolutionLt(const rtc::VideoSinkWants& wants1,
380 const rtc::VideoSinkWants& wants2) {
381 EXPECT_EQ(std::numeric_limits<int>::max(), wants1.max_framerate_fps);
382 EXPECT_LT(wants1.max_pixel_count, wants2.max_pixel_count);
383 EXPECT_GT(wants1.max_pixel_count, 0);
384 }
385
386 void VerifyFpsMaxResolutionGt(const rtc::VideoSinkWants& wants1,
387 const rtc::VideoSinkWants& wants2) {
388 EXPECT_EQ(std::numeric_limits<int>::max(), wants1.max_framerate_fps);
389 EXPECT_GT(wants1.max_pixel_count, wants2.max_pixel_count);
390 }
391
asaperssonf7e294d2017-06-13 23:25:22 -0700392 void VerifyFpsMaxResolutionEq(const rtc::VideoSinkWants& wants1,
393 const rtc::VideoSinkWants& wants2) {
394 EXPECT_EQ(std::numeric_limits<int>::max(), wants1.max_framerate_fps);
395 EXPECT_EQ(wants1.max_pixel_count, wants2.max_pixel_count);
396 }
397
398 void VerifyFpsLtResolutionEq(const rtc::VideoSinkWants& wants1,
399 const rtc::VideoSinkWants& wants2) {
400 EXPECT_LT(wants1.max_framerate_fps, wants2.max_framerate_fps);
401 EXPECT_EQ(wants1.max_pixel_count, wants2.max_pixel_count);
402 }
403
404 void VerifyFpsGtResolutionEq(const rtc::VideoSinkWants& wants1,
405 const rtc::VideoSinkWants& wants2) {
406 EXPECT_GT(wants1.max_framerate_fps, wants2.max_framerate_fps);
407 EXPECT_EQ(wants1.max_pixel_count, wants2.max_pixel_count);
408 }
409
410 void VerifyFpsEqResolutionLt(const rtc::VideoSinkWants& wants1,
411 const rtc::VideoSinkWants& wants2) {
412 EXPECT_EQ(wants1.max_framerate_fps, wants2.max_framerate_fps);
413 EXPECT_LT(wants1.max_pixel_count, wants2.max_pixel_count);
414 EXPECT_GT(wants1.max_pixel_count, 0);
415 }
416
417 void VerifyFpsEqResolutionGt(const rtc::VideoSinkWants& wants1,
418 const rtc::VideoSinkWants& wants2) {
419 EXPECT_EQ(wants1.max_framerate_fps, wants2.max_framerate_fps);
420 EXPECT_GT(wants1.max_pixel_count, wants2.max_pixel_count);
421 }
422
asapersson09f05612017-05-15 23:40:18 -0700423 void VerifyFpsMaxResolutionLt(const rtc::VideoSinkWants& wants,
424 int pixel_count) {
425 EXPECT_EQ(std::numeric_limits<int>::max(), wants.max_framerate_fps);
asapersson02465b82017-04-10 01:12:52 -0700426 EXPECT_LT(wants.max_pixel_count, pixel_count);
427 EXPECT_GT(wants.max_pixel_count, 0);
asapersson09f05612017-05-15 23:40:18 -0700428 }
429
430 void VerifyFpsLtResolutionMax(const rtc::VideoSinkWants& wants, int fps) {
431 EXPECT_LT(wants.max_framerate_fps, fps);
432 EXPECT_EQ(std::numeric_limits<int>::max(), wants.max_pixel_count);
433 EXPECT_FALSE(wants.target_pixel_count);
asapersson02465b82017-04-10 01:12:52 -0700434 }
435
asaperssonf7e294d2017-06-13 23:25:22 -0700436 void VerifyFpsEqResolutionMax(const rtc::VideoSinkWants& wants,
437 int expected_fps) {
438 EXPECT_EQ(expected_fps, wants.max_framerate_fps);
439 EXPECT_EQ(std::numeric_limits<int>::max(), wants.max_pixel_count);
440 EXPECT_FALSE(wants.target_pixel_count);
441 }
442
Jonathan Yubc771b72017-12-08 17:04:29 -0800443 void VerifyBalancedModeFpsRange(const rtc::VideoSinkWants& wants,
444 int last_frame_pixels) {
445 // Balanced mode should always scale FPS to the desired range before
446 // attempting to scale resolution.
447 int fps_limit = wants.max_framerate_fps;
448 if (last_frame_pixels <= 320 * 240) {
449 EXPECT_TRUE(7 <= fps_limit && fps_limit <= 10);
450 } else if (last_frame_pixels <= 480 * 270) {
451 EXPECT_TRUE(10 <= fps_limit && fps_limit <= 15);
452 } else if (last_frame_pixels <= 640 * 480) {
453 EXPECT_LE(15, fps_limit);
454 } else {
455 EXPECT_EQ(std::numeric_limits<int>::max(), fps_limit);
456 }
457 }
458
sprang4847ae62017-06-27 07:06:52 -0700459 void WaitForEncodedFrame(int64_t expected_ntp_time) {
460 sink_.WaitForEncodedFrame(expected_ntp_time);
461 fake_clock_.AdvanceTimeMicros(rtc::kNumMicrosecsPerSec / max_framerate_);
462 }
463
464 bool TimedWaitForEncodedFrame(int64_t expected_ntp_time, int64_t timeout_ms) {
465 bool ok = sink_.TimedWaitForEncodedFrame(expected_ntp_time, timeout_ms);
466 fake_clock_.AdvanceTimeMicros(rtc::kNumMicrosecsPerSec / max_framerate_);
467 return ok;
468 }
469
470 void WaitForEncodedFrame(uint32_t expected_width, uint32_t expected_height) {
471 sink_.WaitForEncodedFrame(expected_width, expected_height);
472 fake_clock_.AdvanceTimeMicros(rtc::kNumMicrosecsPerSec / max_framerate_);
473 }
474
475 void ExpectDroppedFrame() {
476 sink_.ExpectDroppedFrame();
477 fake_clock_.AdvanceTimeMicros(rtc::kNumMicrosecsPerSec / max_framerate_);
478 }
479
480 bool WaitForFrame(int64_t timeout_ms) {
481 bool ok = sink_.WaitForFrame(timeout_ms);
482 fake_clock_.AdvanceTimeMicros(rtc::kNumMicrosecsPerSec / max_framerate_);
483 return ok;
484 }
485
perkj26091b12016-09-01 01:17:40 -0700486 class TestEncoder : public test::FakeEncoder {
487 public:
488 TestEncoder()
489 : FakeEncoder(Clock::GetRealTimeClock()),
490 continue_encode_event_(false, false) {}
491
asaperssonfab67072017-04-04 05:51:49 -0700492 VideoCodec codec_config() const {
brandtre78d2662017-01-16 05:57:16 -0800493 rtc::CritScope lock(&crit_sect_);
perkjfa10b552016-10-02 23:45:26 -0700494 return config_;
495 }
496
497 void BlockNextEncode() {
brandtre78d2662017-01-16 05:57:16 -0800498 rtc::CritScope lock(&local_crit_sect_);
perkjfa10b552016-10-02 23:45:26 -0700499 block_next_encode_ = true;
500 }
501
kthelgason876222f2016-11-29 01:44:11 -0800502 VideoEncoder::ScalingSettings GetScalingSettings() const override {
kthelgason2fc52542017-03-03 00:24:41 -0800503 rtc::CritScope lock(&local_crit_sect_);
kthelgasonad9010c2017-02-14 00:46:51 -0800504 if (quality_scaling_)
Niels Möller225c7872018-02-22 15:03:53 +0100505 return VideoEncoder::ScalingSettings(1, 2, kMinPixelsPerFrame);
506 return VideoEncoder::ScalingSettings::kOff;
kthelgason876222f2016-11-29 01:44:11 -0800507 }
508
perkjfa10b552016-10-02 23:45:26 -0700509 void ContinueEncode() { continue_encode_event_.Set(); }
510
511 void CheckLastTimeStampsMatch(int64_t ntp_time_ms,
512 uint32_t timestamp) const {
brandtre78d2662017-01-16 05:57:16 -0800513 rtc::CritScope lock(&local_crit_sect_);
perkjfa10b552016-10-02 23:45:26 -0700514 EXPECT_EQ(timestamp_, timestamp);
515 EXPECT_EQ(ntp_time_ms_, ntp_time_ms);
516 }
517
kthelgason2fc52542017-03-03 00:24:41 -0800518 void SetQualityScaling(bool b) {
519 rtc::CritScope lock(&local_crit_sect_);
520 quality_scaling_ = b;
521 }
kthelgasonad9010c2017-02-14 00:46:51 -0800522
sprangfe627f32017-03-29 08:24:59 -0700523 void ForceInitEncodeFailure(bool force_failure) {
524 rtc::CritScope lock(&local_crit_sect_);
525 force_init_encode_failed_ = force_failure;
526 }
527
perkjfa10b552016-10-02 23:45:26 -0700528 private:
perkj26091b12016-09-01 01:17:40 -0700529 int32_t Encode(const VideoFrame& input_image,
530 const CodecSpecificInfo* codec_specific_info,
531 const std::vector<FrameType>* frame_types) override {
532 bool block_encode;
533 {
brandtre78d2662017-01-16 05:57:16 -0800534 rtc::CritScope lock(&local_crit_sect_);
perkj26091b12016-09-01 01:17:40 -0700535 EXPECT_GT(input_image.timestamp(), timestamp_);
536 EXPECT_GT(input_image.ntp_time_ms(), ntp_time_ms_);
537 EXPECT_EQ(input_image.timestamp(), input_image.ntp_time_ms() * 90);
538
539 timestamp_ = input_image.timestamp();
540 ntp_time_ms_ = input_image.ntp_time_ms();
perkj803d97f2016-11-01 11:45:46 -0700541 last_input_width_ = input_image.width();
542 last_input_height_ = input_image.height();
perkj26091b12016-09-01 01:17:40 -0700543 block_encode = block_next_encode_;
544 block_next_encode_ = false;
545 }
546 int32_t result =
547 FakeEncoder::Encode(input_image, codec_specific_info, frame_types);
548 if (block_encode)
perkja49cbd32016-09-16 07:53:41 -0700549 EXPECT_TRUE(continue_encode_event_.Wait(kDefaultTimeoutMs));
perkj26091b12016-09-01 01:17:40 -0700550 return result;
551 }
552
sprangfe627f32017-03-29 08:24:59 -0700553 int32_t InitEncode(const VideoCodec* config,
554 int32_t number_of_cores,
555 size_t max_payload_size) override {
556 int res =
557 FakeEncoder::InitEncode(config, number_of_cores, max_payload_size);
558 rtc::CritScope lock(&local_crit_sect_);
Erik Språng82fad3d2018-03-21 09:57:23 +0100559 if (config->codecType == kVideoCodecVP8) {
sprangfe627f32017-03-29 08:24:59 -0700560 // Simulate setting up temporal layers, in order to validate the life
561 // cycle of these objects.
562 int num_streams = std::max<int>(1, config->numberOfSimulcastStreams);
sprangfe627f32017-03-29 08:24:59 -0700563 for (int i = 0; i < num_streams; ++i) {
564 allocated_temporal_layers_.emplace_back(
Niels Möller150dcb02018-03-27 14:16:55 +0200565 TemporalLayers::CreateTemporalLayers(*config, i));
sprangfe627f32017-03-29 08:24:59 -0700566 }
567 }
568 if (force_init_encode_failed_)
569 return -1;
570 return res;
571 }
572
brandtre78d2662017-01-16 05:57:16 -0800573 rtc::CriticalSection local_crit_sect_;
danilchapa37de392017-09-09 04:17:22 -0700574 bool block_next_encode_ RTC_GUARDED_BY(local_crit_sect_) = false;
perkj26091b12016-09-01 01:17:40 -0700575 rtc::Event continue_encode_event_;
danilchapa37de392017-09-09 04:17:22 -0700576 uint32_t timestamp_ RTC_GUARDED_BY(local_crit_sect_) = 0;
577 int64_t ntp_time_ms_ RTC_GUARDED_BY(local_crit_sect_) = 0;
578 int last_input_width_ RTC_GUARDED_BY(local_crit_sect_) = 0;
579 int last_input_height_ RTC_GUARDED_BY(local_crit_sect_) = 0;
580 bool quality_scaling_ RTC_GUARDED_BY(local_crit_sect_) = true;
sprangfe627f32017-03-29 08:24:59 -0700581 std::vector<std::unique_ptr<TemporalLayers>> allocated_temporal_layers_
danilchapa37de392017-09-09 04:17:22 -0700582 RTC_GUARDED_BY(local_crit_sect_);
583 bool force_init_encode_failed_ RTC_GUARDED_BY(local_crit_sect_) = false;
perkj26091b12016-09-01 01:17:40 -0700584 };
585
mflodmancc3d4422017-08-03 08:27:51 -0700586 class TestSink : public VideoStreamEncoder::EncoderSink {
perkj26091b12016-09-01 01:17:40 -0700587 public:
588 explicit TestSink(TestEncoder* test_encoder)
589 : test_encoder_(test_encoder), encoded_frame_event_(false, false) {}
590
perkj26091b12016-09-01 01:17:40 -0700591 void WaitForEncodedFrame(int64_t expected_ntp_time) {
sprang4847ae62017-06-27 07:06:52 -0700592 EXPECT_TRUE(
593 TimedWaitForEncodedFrame(expected_ntp_time, kDefaultTimeoutMs));
594 }
595
596 bool TimedWaitForEncodedFrame(int64_t expected_ntp_time,
597 int64_t timeout_ms) {
perkj26091b12016-09-01 01:17:40 -0700598 uint32_t timestamp = 0;
sprang4847ae62017-06-27 07:06:52 -0700599 if (!encoded_frame_event_.Wait(timeout_ms))
600 return false;
perkj26091b12016-09-01 01:17:40 -0700601 {
602 rtc::CritScope lock(&crit_);
sprangb1ca0732017-02-01 08:38:12 -0800603 timestamp = last_timestamp_;
perkj26091b12016-09-01 01:17:40 -0700604 }
605 test_encoder_->CheckLastTimeStampsMatch(expected_ntp_time, timestamp);
sprang4847ae62017-06-27 07:06:52 -0700606 return true;
perkj26091b12016-09-01 01:17:40 -0700607 }
608
sprangb1ca0732017-02-01 08:38:12 -0800609 void WaitForEncodedFrame(uint32_t expected_width,
610 uint32_t expected_height) {
sprangc5d62e22017-04-02 23:53:04 -0700611 EXPECT_TRUE(encoded_frame_event_.Wait(kDefaultTimeoutMs));
Åsa Perssonc74d8da2017-12-04 14:13:56 +0100612 CheckLastFrameSizeMatches(expected_width, expected_height);
sprangc5d62e22017-04-02 23:53:04 -0700613 }
614
Åsa Perssonc74d8da2017-12-04 14:13:56 +0100615 void CheckLastFrameSizeMatches(uint32_t expected_width,
sprangc5d62e22017-04-02 23:53:04 -0700616 uint32_t expected_height) {
sprangb1ca0732017-02-01 08:38:12 -0800617 uint32_t width = 0;
618 uint32_t height = 0;
sprangb1ca0732017-02-01 08:38:12 -0800619 {
620 rtc::CritScope lock(&crit_);
621 width = last_width_;
622 height = last_height_;
623 }
624 EXPECT_EQ(expected_height, height);
625 EXPECT_EQ(expected_width, width);
626 }
627
kthelgason2fc52542017-03-03 00:24:41 -0800628 void ExpectDroppedFrame() { EXPECT_FALSE(encoded_frame_event_.Wait(100)); }
kthelgason2bc68642017-02-07 07:02:22 -0800629
sprangc5d62e22017-04-02 23:53:04 -0700630 bool WaitForFrame(int64_t timeout_ms) {
631 return encoded_frame_event_.Wait(timeout_ms);
632 }
633
perkj26091b12016-09-01 01:17:40 -0700634 void SetExpectNoFrames() {
635 rtc::CritScope lock(&crit_);
636 expect_frames_ = false;
637 }
638
asaperssonfab67072017-04-04 05:51:49 -0700639 int number_of_reconfigurations() const {
Per512ecb32016-09-23 15:52:06 +0200640 rtc::CritScope lock(&crit_);
641 return number_of_reconfigurations_;
642 }
643
asaperssonfab67072017-04-04 05:51:49 -0700644 int last_min_transmit_bitrate() const {
Per512ecb32016-09-23 15:52:06 +0200645 rtc::CritScope lock(&crit_);
646 return min_transmit_bitrate_bps_;
647 }
648
perkj26091b12016-09-01 01:17:40 -0700649 private:
sergeyu2cb155a2016-11-04 11:39:29 -0700650 Result OnEncodedImage(
651 const EncodedImage& encoded_image,
652 const CodecSpecificInfo* codec_specific_info,
653 const RTPFragmentationHeader* fragmentation) override {
Per512ecb32016-09-23 15:52:06 +0200654 rtc::CritScope lock(&crit_);
655 EXPECT_TRUE(expect_frames_);
sprangb1ca0732017-02-01 08:38:12 -0800656 last_timestamp_ = encoded_image._timeStamp;
657 last_width_ = encoded_image._encodedWidth;
658 last_height_ = encoded_image._encodedHeight;
Per512ecb32016-09-23 15:52:06 +0200659 encoded_frame_event_.Set();
sprangb1ca0732017-02-01 08:38:12 -0800660 return Result(Result::OK, last_timestamp_);
Per512ecb32016-09-23 15:52:06 +0200661 }
662
663 void OnEncoderConfigurationChanged(std::vector<VideoStream> streams,
664 int min_transmit_bitrate_bps) override {
665 rtc::CriticalSection crit_;
666 ++number_of_reconfigurations_;
667 min_transmit_bitrate_bps_ = min_transmit_bitrate_bps;
668 }
669
perkj26091b12016-09-01 01:17:40 -0700670 rtc::CriticalSection crit_;
671 TestEncoder* test_encoder_;
672 rtc::Event encoded_frame_event_;
sprangb1ca0732017-02-01 08:38:12 -0800673 uint32_t last_timestamp_ = 0;
674 uint32_t last_height_ = 0;
675 uint32_t last_width_ = 0;
perkj26091b12016-09-01 01:17:40 -0700676 bool expect_frames_ = true;
Per512ecb32016-09-23 15:52:06 +0200677 int number_of_reconfigurations_ = 0;
678 int min_transmit_bitrate_bps_ = 0;
perkj26091b12016-09-01 01:17:40 -0700679 };
680
681 VideoSendStream::Config video_send_config_;
Erik Språng08127a92016-11-16 16:41:30 +0100682 VideoEncoderConfig video_encoder_config_;
Per512ecb32016-09-23 15:52:06 +0200683 int codec_width_;
684 int codec_height_;
sprang4847ae62017-06-27 07:06:52 -0700685 int max_framerate_;
perkj26091b12016-09-01 01:17:40 -0700686 TestEncoder fake_encoder_;
Niels Möller4db138e2018-04-19 09:04:13 +0200687 test::EncoderProxyFactory encoder_factory_;
sprangc5d62e22017-04-02 23:53:04 -0700688 std::unique_ptr<MockableSendStatisticsProxy> stats_proxy_;
perkj26091b12016-09-01 01:17:40 -0700689 TestSink sink_;
sprangb1ca0732017-02-01 08:38:12 -0800690 AdaptingFrameForwarder video_source_;
mflodmancc3d4422017-08-03 08:27:51 -0700691 std::unique_ptr<VideoStreamEncoderUnderTest> video_stream_encoder_;
sprang4847ae62017-06-27 07:06:52 -0700692 rtc::ScopedFakeClock fake_clock_;
perkj26091b12016-09-01 01:17:40 -0700693};
694
mflodmancc3d4422017-08-03 08:27:51 -0700695TEST_F(VideoStreamEncoderTest, EncodeOneFrame) {
696 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkj26091b12016-09-01 01:17:40 -0700697 rtc::Event frame_destroyed_event(false, false);
perkja49cbd32016-09-16 07:53:41 -0700698 video_source_.IncomingCapturedFrame(CreateFrame(1, &frame_destroyed_event));
sprang4847ae62017-06-27 07:06:52 -0700699 WaitForEncodedFrame(1);
perkja49cbd32016-09-16 07:53:41 -0700700 EXPECT_TRUE(frame_destroyed_event.Wait(kDefaultTimeoutMs));
mflodmancc3d4422017-08-03 08:27:51 -0700701 video_stream_encoder_->Stop();
perkj26091b12016-09-01 01:17:40 -0700702}
703
mflodmancc3d4422017-08-03 08:27:51 -0700704TEST_F(VideoStreamEncoderTest, DropsFramesBeforeFirstOnBitrateUpdated) {
perkj26091b12016-09-01 01:17:40 -0700705 // Dropped since no target bitrate has been set.
706 rtc::Event frame_destroyed_event(false, false);
Sebastian Janssona3177052018-04-10 13:05:49 +0200707 // The encoder will cache up to one frame for a short duration. Adding two
708 // frames means that the first frame will be dropped and the second frame will
709 // be sent when the encoder is enabled.
perkja49cbd32016-09-16 07:53:41 -0700710 video_source_.IncomingCapturedFrame(CreateFrame(1, &frame_destroyed_event));
Sebastian Janssona3177052018-04-10 13:05:49 +0200711 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
perkja49cbd32016-09-16 07:53:41 -0700712 EXPECT_TRUE(frame_destroyed_event.Wait(kDefaultTimeoutMs));
perkj26091b12016-09-01 01:17:40 -0700713
mflodmancc3d4422017-08-03 08:27:51 -0700714 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkj26091b12016-09-01 01:17:40 -0700715
Sebastian Janssona3177052018-04-10 13:05:49 +0200716 // The pending frame should be received.
sprang4847ae62017-06-27 07:06:52 -0700717 WaitForEncodedFrame(2);
Sebastian Janssona3177052018-04-10 13:05:49 +0200718 video_source_.IncomingCapturedFrame(CreateFrame(3, nullptr));
719
720 WaitForEncodedFrame(3);
mflodmancc3d4422017-08-03 08:27:51 -0700721 video_stream_encoder_->Stop();
perkj26091b12016-09-01 01:17:40 -0700722}
723
mflodmancc3d4422017-08-03 08:27:51 -0700724TEST_F(VideoStreamEncoderTest, DropsFramesWhenRateSetToZero) {
725 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkja49cbd32016-09-16 07:53:41 -0700726 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700727 WaitForEncodedFrame(1);
perkj26091b12016-09-01 01:17:40 -0700728
mflodmancc3d4422017-08-03 08:27:51 -0700729 video_stream_encoder_->OnBitrateUpdated(0, 0, 0);
Sebastian Janssona3177052018-04-10 13:05:49 +0200730 // The encoder will cache up to one frame for a short duration. Adding two
731 // frames means that the first frame will be dropped and the second frame will
732 // be sent when the encoder is resumed.
perkja49cbd32016-09-16 07:53:41 -0700733 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
Sebastian Janssona3177052018-04-10 13:05:49 +0200734 video_source_.IncomingCapturedFrame(CreateFrame(3, nullptr));
perkj26091b12016-09-01 01:17:40 -0700735
mflodmancc3d4422017-08-03 08:27:51 -0700736 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
sprang4847ae62017-06-27 07:06:52 -0700737 WaitForEncodedFrame(3);
Sebastian Janssona3177052018-04-10 13:05:49 +0200738 video_source_.IncomingCapturedFrame(CreateFrame(4, nullptr));
739 WaitForEncodedFrame(4);
mflodmancc3d4422017-08-03 08:27:51 -0700740 video_stream_encoder_->Stop();
perkj26091b12016-09-01 01:17:40 -0700741}
742
mflodmancc3d4422017-08-03 08:27:51 -0700743TEST_F(VideoStreamEncoderTest, DropsFramesWithSameOrOldNtpTimestamp) {
744 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkja49cbd32016-09-16 07:53:41 -0700745 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700746 WaitForEncodedFrame(1);
perkj26091b12016-09-01 01:17:40 -0700747
748 // This frame will be dropped since it has the same ntp timestamp.
perkja49cbd32016-09-16 07:53:41 -0700749 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
perkj26091b12016-09-01 01:17:40 -0700750
perkja49cbd32016-09-16 07:53:41 -0700751 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700752 WaitForEncodedFrame(2);
mflodmancc3d4422017-08-03 08:27:51 -0700753 video_stream_encoder_->Stop();
perkj26091b12016-09-01 01:17:40 -0700754}
755
mflodmancc3d4422017-08-03 08:27:51 -0700756TEST_F(VideoStreamEncoderTest, DropsFrameAfterStop) {
757 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkj26091b12016-09-01 01:17:40 -0700758
perkja49cbd32016-09-16 07:53:41 -0700759 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700760 WaitForEncodedFrame(1);
perkj26091b12016-09-01 01:17:40 -0700761
mflodmancc3d4422017-08-03 08:27:51 -0700762 video_stream_encoder_->Stop();
perkj26091b12016-09-01 01:17:40 -0700763 sink_.SetExpectNoFrames();
764 rtc::Event frame_destroyed_event(false, false);
perkja49cbd32016-09-16 07:53:41 -0700765 video_source_.IncomingCapturedFrame(CreateFrame(2, &frame_destroyed_event));
766 EXPECT_TRUE(frame_destroyed_event.Wait(kDefaultTimeoutMs));
perkj26091b12016-09-01 01:17:40 -0700767}
768
mflodmancc3d4422017-08-03 08:27:51 -0700769TEST_F(VideoStreamEncoderTest, DropsPendingFramesOnSlowEncode) {
770 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkj26091b12016-09-01 01:17:40 -0700771
772 fake_encoder_.BlockNextEncode();
perkja49cbd32016-09-16 07:53:41 -0700773 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700774 WaitForEncodedFrame(1);
perkj26091b12016-09-01 01:17:40 -0700775 // Here, the encoder thread will be blocked in the TestEncoder waiting for a
776 // call to ContinueEncode.
perkja49cbd32016-09-16 07:53:41 -0700777 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
778 video_source_.IncomingCapturedFrame(CreateFrame(3, nullptr));
perkj26091b12016-09-01 01:17:40 -0700779 fake_encoder_.ContinueEncode();
sprang4847ae62017-06-27 07:06:52 -0700780 WaitForEncodedFrame(3);
perkj26091b12016-09-01 01:17:40 -0700781
mflodmancc3d4422017-08-03 08:27:51 -0700782 video_stream_encoder_->Stop();
perkj26091b12016-09-01 01:17:40 -0700783}
784
mflodmancc3d4422017-08-03 08:27:51 -0700785TEST_F(VideoStreamEncoderTest,
786 ConfigureEncoderTriggersOnEncoderConfigurationChanged) {
787 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
Per21d45d22016-10-30 21:37:57 +0100788 EXPECT_EQ(0, sink_.number_of_reconfigurations());
Per512ecb32016-09-23 15:52:06 +0200789
790 // Capture a frame and wait for it to synchronize with the encoder thread.
Perf8c5f2b2016-09-23 16:24:55 +0200791 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700792 WaitForEncodedFrame(1);
Per21d45d22016-10-30 21:37:57 +0100793 // The encoder will have been configured once when the first frame is
794 // received.
795 EXPECT_EQ(1, sink_.number_of_reconfigurations());
Per512ecb32016-09-23 15:52:06 +0200796
797 VideoEncoderConfig video_encoder_config;
Niels Möller259a4972018-04-05 15:36:51 +0200798 test::FillEncoderConfiguration(kVideoCodecVP8, 1, &video_encoder_config);
Per512ecb32016-09-23 15:52:06 +0200799 video_encoder_config.min_transmit_bitrate_bps = 9999;
mflodmancc3d4422017-08-03 08:27:51 -0700800 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
Niels Möllerf1338562018-04-26 09:51:47 +0200801 kMaxPayloadLength);
Per512ecb32016-09-23 15:52:06 +0200802
803 // Capture a frame and wait for it to synchronize with the encoder thread.
Perf8c5f2b2016-09-23 16:24:55 +0200804 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700805 WaitForEncodedFrame(2);
Per21d45d22016-10-30 21:37:57 +0100806 EXPECT_EQ(2, sink_.number_of_reconfigurations());
perkj3b703ed2016-09-29 23:25:40 -0700807 EXPECT_EQ(9999, sink_.last_min_transmit_bitrate());
perkj26105b42016-09-29 22:39:10 -0700808
mflodmancc3d4422017-08-03 08:27:51 -0700809 video_stream_encoder_->Stop();
perkj26105b42016-09-29 22:39:10 -0700810}
811
mflodmancc3d4422017-08-03 08:27:51 -0700812TEST_F(VideoStreamEncoderTest, FrameResolutionChangeReconfigureEncoder) {
813 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkjfa10b552016-10-02 23:45:26 -0700814
815 // Capture a frame and wait for it to synchronize with the encoder thread.
816 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700817 WaitForEncodedFrame(1);
Per21d45d22016-10-30 21:37:57 +0100818 // The encoder will have been configured once.
819 EXPECT_EQ(1, sink_.number_of_reconfigurations());
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);
822
823 codec_width_ *= 2;
824 codec_height_ *= 2;
825 // Capture a frame with a higher resolution and wait for it to synchronize
826 // with the encoder thread.
827 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700828 WaitForEncodedFrame(2);
perkjfa10b552016-10-02 23:45:26 -0700829 EXPECT_EQ(codec_width_, fake_encoder_.codec_config().width);
830 EXPECT_EQ(codec_height_, fake_encoder_.codec_config().height);
Per21d45d22016-10-30 21:37:57 +0100831 EXPECT_EQ(2, sink_.number_of_reconfigurations());
perkjfa10b552016-10-02 23:45:26 -0700832
mflodmancc3d4422017-08-03 08:27:51 -0700833 video_stream_encoder_->Stop();
perkjfa10b552016-10-02 23:45:26 -0700834}
835
mflodmancc3d4422017-08-03 08:27:51 -0700836TEST_F(VideoStreamEncoderTest, SwitchSourceDeregisterEncoderAsSink) {
perkj803d97f2016-11-01 11:45:46 -0700837 EXPECT_TRUE(video_source_.has_sinks());
838 test::FrameForwarder new_video_source;
mflodmancc3d4422017-08-03 08:27:51 -0700839 video_stream_encoder_->SetSource(
sprangc5d62e22017-04-02 23:53:04 -0700840 &new_video_source,
841 VideoSendStream::DegradationPreference::kMaintainFramerate);
perkj803d97f2016-11-01 11:45:46 -0700842 EXPECT_FALSE(video_source_.has_sinks());
843 EXPECT_TRUE(new_video_source.has_sinks());
844
mflodmancc3d4422017-08-03 08:27:51 -0700845 video_stream_encoder_->Stop();
perkj803d97f2016-11-01 11:45:46 -0700846}
847
mflodmancc3d4422017-08-03 08:27:51 -0700848TEST_F(VideoStreamEncoderTest, SinkWantsRotationApplied) {
perkj803d97f2016-11-01 11:45:46 -0700849 EXPECT_FALSE(video_source_.sink_wants().rotation_applied);
mflodmancc3d4422017-08-03 08:27:51 -0700850 video_stream_encoder_->SetSink(&sink_, true /*rotation_applied*/);
perkj803d97f2016-11-01 11:45:46 -0700851 EXPECT_TRUE(video_source_.sink_wants().rotation_applied);
mflodmancc3d4422017-08-03 08:27:51 -0700852 video_stream_encoder_->Stop();
perkj803d97f2016-11-01 11:45:46 -0700853}
854
Jonathan Yubc771b72017-12-08 17:04:29 -0800855TEST_F(VideoStreamEncoderTest, TestCpuDowngrades_BalancedMode) {
856 const int kFramerateFps = 30;
asaperssonf7e294d2017-06-13 23:25:22 -0700857 const int kWidth = 1280;
858 const int kHeight = 720;
Jonathan Yubc771b72017-12-08 17:04:29 -0800859
860 // We rely on the automatic resolution adaptation, but we handle framerate
861 // adaptation manually by mocking the stats proxy.
862 video_source_.set_adaptation_enabled(true);
asaperssonf7e294d2017-06-13 23:25:22 -0700863
864 // Enable kBalanced preference, no initial limitation.
Jonathan Yubc771b72017-12-08 17:04:29 -0800865 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
mflodmancc3d4422017-08-03 08:27:51 -0700866 video_stream_encoder_->SetSource(
Jonathan Yubc771b72017-12-08 17:04:29 -0800867 &video_source_,
mflodmancc3d4422017-08-03 08:27:51 -0700868 VideoSendStream::DegradationPreference::kBalanced);
Jonathan Yubc771b72017-12-08 17:04:29 -0800869 VerifyNoLimitation(video_source_.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -0700870 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
Jonathan Yubc771b72017-12-08 17:04:29 -0800871 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
asaperssonf7e294d2017-06-13 23:25:22 -0700872 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
873
Jonathan Yubc771b72017-12-08 17:04:29 -0800874 // Adapt down as far as possible.
875 rtc::VideoSinkWants last_wants;
876 int64_t t = 1;
877 int loop_count = 0;
878 do {
879 ++loop_count;
880 last_wants = video_source_.sink_wants();
881
882 // Simulate the framerate we've been asked to adapt to.
883 const int fps = std::min(kFramerateFps, last_wants.max_framerate_fps);
884 const int frame_interval_ms = rtc::kNumMillisecsPerSec / fps;
885 VideoSendStream::Stats mock_stats = stats_proxy_->GetStats();
886 mock_stats.input_frame_rate = fps;
887 stats_proxy_->SetMockStats(mock_stats);
888
889 video_source_.IncomingCapturedFrame(CreateFrame(t, kWidth, kHeight));
890 sink_.WaitForEncodedFrame(t);
891 t += frame_interval_ms;
892
mflodmancc3d4422017-08-03 08:27:51 -0700893 video_stream_encoder_->TriggerCpuOveruse();
Jonathan Yubc771b72017-12-08 17:04:29 -0800894 VerifyBalancedModeFpsRange(
895 video_source_.sink_wants(),
896 *video_source_.last_sent_width() * *video_source_.last_sent_height());
897 } while (video_source_.sink_wants().max_pixel_count <
898 last_wants.max_pixel_count ||
899 video_source_.sink_wants().max_framerate_fps <
900 last_wants.max_framerate_fps);
asaperssonf7e294d2017-06-13 23:25:22 -0700901
Jonathan Yubc771b72017-12-08 17:04:29 -0800902 // Verify that we've adapted all the way down.
903 stats_proxy_->ResetMockStats();
asaperssonf7e294d2017-06-13 23:25:22 -0700904 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
Jonathan Yubc771b72017-12-08 17:04:29 -0800905 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_framerate);
906 EXPECT_EQ(loop_count - 1,
asaperssonf7e294d2017-06-13 23:25:22 -0700907 stats_proxy_->GetStats().number_of_cpu_adapt_changes);
Jonathan Yubc771b72017-12-08 17:04:29 -0800908 EXPECT_EQ(kMinPixelsPerFrame, *video_source_.last_sent_width() *
909 *video_source_.last_sent_height());
910 EXPECT_EQ(kMinBalancedFramerateFps,
911 video_source_.sink_wants().max_framerate_fps);
asaperssonf7e294d2017-06-13 23:25:22 -0700912
Jonathan Yubc771b72017-12-08 17:04:29 -0800913 // Adapt back up the same number of times we adapted down.
914 for (int i = 0; i < loop_count - 1; ++i) {
915 last_wants = video_source_.sink_wants();
916
917 // Simulate the framerate we've been asked to adapt to.
918 const int fps = std::min(kFramerateFps, last_wants.max_framerate_fps);
919 const int frame_interval_ms = rtc::kNumMillisecsPerSec / fps;
920 VideoSendStream::Stats mock_stats = stats_proxy_->GetStats();
921 mock_stats.input_frame_rate = fps;
922 stats_proxy_->SetMockStats(mock_stats);
923
924 video_source_.IncomingCapturedFrame(CreateFrame(t, kWidth, kHeight));
925 sink_.WaitForEncodedFrame(t);
926 t += frame_interval_ms;
927
mflodmancc3d4422017-08-03 08:27:51 -0700928 video_stream_encoder_->TriggerCpuNormalUsage();
Jonathan Yubc771b72017-12-08 17:04:29 -0800929 VerifyBalancedModeFpsRange(
930 video_source_.sink_wants(),
931 *video_source_.last_sent_width() * *video_source_.last_sent_height());
932 EXPECT_TRUE(video_source_.sink_wants().max_pixel_count >
933 last_wants.max_pixel_count ||
934 video_source_.sink_wants().max_framerate_fps >
935 last_wants.max_framerate_fps);
asaperssonf7e294d2017-06-13 23:25:22 -0700936 }
937
Jonathan Yubc771b72017-12-08 17:04:29 -0800938 VerifyNoLimitation(video_source_.sink_wants());
939 stats_proxy_->ResetMockStats();
asaperssonf7e294d2017-06-13 23:25:22 -0700940 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
Jonathan Yubc771b72017-12-08 17:04:29 -0800941 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
942 EXPECT_EQ((loop_count - 1) * 2,
943 stats_proxy_->GetStats().number_of_cpu_adapt_changes);
asaperssonf7e294d2017-06-13 23:25:22 -0700944
mflodmancc3d4422017-08-03 08:27:51 -0700945 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -0700946}
mflodmancc3d4422017-08-03 08:27:51 -0700947TEST_F(VideoStreamEncoderTest, SinkWantsStoredByDegradationPreference) {
948 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson02465b82017-04-10 01:12:52 -0700949 VerifyNoLimitation(video_source_.sink_wants());
perkj803d97f2016-11-01 11:45:46 -0700950
sprangc5d62e22017-04-02 23:53:04 -0700951 const int kFrameWidth = 1280;
952 const int kFrameHeight = 720;
953 const int kFrameIntervalMs = 1000 / 30;
954
955 int frame_timestamp = 1;
perkj803d97f2016-11-01 11:45:46 -0700956
kthelgason5e13d412016-12-01 03:59:51 -0800957 video_source_.IncomingCapturedFrame(
sprangc5d62e22017-04-02 23:53:04 -0700958 CreateFrame(frame_timestamp, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -0700959 WaitForEncodedFrame(frame_timestamp);
sprangc5d62e22017-04-02 23:53:04 -0700960 frame_timestamp += kFrameIntervalMs;
961
perkj803d97f2016-11-01 11:45:46 -0700962 // Trigger CPU overuse.
mflodmancc3d4422017-08-03 08:27:51 -0700963 video_stream_encoder_->TriggerCpuOveruse();
perkj803d97f2016-11-01 11:45:46 -0700964 video_source_.IncomingCapturedFrame(
sprangc5d62e22017-04-02 23:53:04 -0700965 CreateFrame(frame_timestamp, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -0700966 WaitForEncodedFrame(frame_timestamp);
sprangc5d62e22017-04-02 23:53:04 -0700967 frame_timestamp += kFrameIntervalMs;
sprang3ea3c772017-03-30 07:23:48 -0700968
asapersson0944a802017-04-07 00:57:58 -0700969 // Default degradation preference is maintain-framerate, so will lower max
sprangc5d62e22017-04-02 23:53:04 -0700970 // wanted resolution.
971 EXPECT_FALSE(video_source_.sink_wants().target_pixel_count);
972 EXPECT_LT(video_source_.sink_wants().max_pixel_count,
973 kFrameWidth * kFrameHeight);
974 EXPECT_EQ(std::numeric_limits<int>::max(),
975 video_source_.sink_wants().max_framerate_fps);
976
977 // Set new source, switch to maintain-resolution.
perkj803d97f2016-11-01 11:45:46 -0700978 test::FrameForwarder new_video_source;
mflodmancc3d4422017-08-03 08:27:51 -0700979 video_stream_encoder_->SetSource(
perkj803d97f2016-11-01 11:45:46 -0700980 &new_video_source,
981 VideoSendStream::DegradationPreference::kMaintainResolution);
982
sprangc5d62e22017-04-02 23:53:04 -0700983 // Initially no degradation registered.
asapersson02465b82017-04-10 01:12:52 -0700984 VerifyNoLimitation(new_video_source.sink_wants());
perkj803d97f2016-11-01 11:45:46 -0700985
sprangc5d62e22017-04-02 23:53:04 -0700986 // Force an input frame rate to be available, or the adaptation call won't
987 // know what framerate to adapt form.
asapersson02465b82017-04-10 01:12:52 -0700988 const int kInputFps = 30;
sprangc5d62e22017-04-02 23:53:04 -0700989 VideoSendStream::Stats stats = stats_proxy_->GetStats();
asapersson02465b82017-04-10 01:12:52 -0700990 stats.input_frame_rate = kInputFps;
sprangc5d62e22017-04-02 23:53:04 -0700991 stats_proxy_->SetMockStats(stats);
992
mflodmancc3d4422017-08-03 08:27:51 -0700993 video_stream_encoder_->TriggerCpuOveruse();
perkj803d97f2016-11-01 11:45:46 -0700994 new_video_source.IncomingCapturedFrame(
sprangc5d62e22017-04-02 23:53:04 -0700995 CreateFrame(frame_timestamp, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -0700996 WaitForEncodedFrame(frame_timestamp);
sprangc5d62e22017-04-02 23:53:04 -0700997 frame_timestamp += kFrameIntervalMs;
998
999 // Some framerate constraint should be set.
sprang84a37592017-02-10 07:04:27 -08001000 EXPECT_FALSE(new_video_source.sink_wants().target_pixel_count);
sprangc5d62e22017-04-02 23:53:04 -07001001 EXPECT_EQ(std::numeric_limits<int>::max(),
1002 new_video_source.sink_wants().max_pixel_count);
asapersson02465b82017-04-10 01:12:52 -07001003 EXPECT_LT(new_video_source.sink_wants().max_framerate_fps, kInputFps);
sprangc5d62e22017-04-02 23:53:04 -07001004
asapersson02465b82017-04-10 01:12:52 -07001005 // Turn off degradation completely.
mflodmancc3d4422017-08-03 08:27:51 -07001006 video_stream_encoder_->SetSource(
sprangc5d62e22017-04-02 23:53:04 -07001007 &new_video_source,
1008 VideoSendStream::DegradationPreference::kDegradationDisabled);
asapersson02465b82017-04-10 01:12:52 -07001009 VerifyNoLimitation(new_video_source.sink_wants());
sprangc5d62e22017-04-02 23:53:04 -07001010
mflodmancc3d4422017-08-03 08:27:51 -07001011 video_stream_encoder_->TriggerCpuOveruse();
sprangc5d62e22017-04-02 23:53:04 -07001012 new_video_source.IncomingCapturedFrame(
1013 CreateFrame(frame_timestamp, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07001014 WaitForEncodedFrame(frame_timestamp);
sprangc5d62e22017-04-02 23:53:04 -07001015 frame_timestamp += kFrameIntervalMs;
1016
1017 // Still no degradation.
asapersson02465b82017-04-10 01:12:52 -07001018 VerifyNoLimitation(new_video_source.sink_wants());
perkj803d97f2016-11-01 11:45:46 -07001019
1020 // Calling SetSource with resolution scaling enabled apply the old SinkWants.
mflodmancc3d4422017-08-03 08:27:51 -07001021 video_stream_encoder_->SetSource(
sprangc5d62e22017-04-02 23:53:04 -07001022 &new_video_source,
1023 VideoSendStream::DegradationPreference::kMaintainFramerate);
1024 EXPECT_LT(new_video_source.sink_wants().max_pixel_count,
1025 kFrameWidth * kFrameHeight);
sprang84a37592017-02-10 07:04:27 -08001026 EXPECT_FALSE(new_video_source.sink_wants().target_pixel_count);
sprangc5d62e22017-04-02 23:53:04 -07001027 EXPECT_EQ(std::numeric_limits<int>::max(),
1028 new_video_source.sink_wants().max_framerate_fps);
1029
1030 // Calling SetSource with framerate scaling enabled apply the old SinkWants.
mflodmancc3d4422017-08-03 08:27:51 -07001031 video_stream_encoder_->SetSource(
sprangc5d62e22017-04-02 23:53:04 -07001032 &new_video_source,
1033 VideoSendStream::DegradationPreference::kMaintainResolution);
1034 EXPECT_FALSE(new_video_source.sink_wants().target_pixel_count);
1035 EXPECT_EQ(std::numeric_limits<int>::max(),
1036 new_video_source.sink_wants().max_pixel_count);
asapersson02465b82017-04-10 01:12:52 -07001037 EXPECT_LT(new_video_source.sink_wants().max_framerate_fps, kInputFps);
perkj803d97f2016-11-01 11:45:46 -07001038
mflodmancc3d4422017-08-03 08:27:51 -07001039 video_stream_encoder_->Stop();
perkj803d97f2016-11-01 11:45:46 -07001040}
1041
mflodmancc3d4422017-08-03 08:27:51 -07001042TEST_F(VideoStreamEncoderTest, StatsTracksQualityAdaptationStats) {
1043 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkj803d97f2016-11-01 11:45:46 -07001044
asaperssonfab67072017-04-04 05:51:49 -07001045 const int kWidth = 1280;
1046 const int kHeight = 720;
asaperssonfab67072017-04-04 05:51:49 -07001047 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001048 WaitForEncodedFrame(1);
asaperssonfab67072017-04-04 05:51:49 -07001049 VideoSendStream::Stats stats = stats_proxy_->GetStats();
1050 EXPECT_FALSE(stats.bw_limited_resolution);
1051 EXPECT_EQ(0, stats.number_of_quality_adapt_changes);
1052
1053 // Trigger adapt down.
mflodmancc3d4422017-08-03 08:27:51 -07001054 video_stream_encoder_->TriggerQualityLow();
asaperssonfab67072017-04-04 05:51:49 -07001055 video_source_.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001056 WaitForEncodedFrame(2);
asaperssonfab67072017-04-04 05:51:49 -07001057
1058 stats = stats_proxy_->GetStats();
1059 EXPECT_TRUE(stats.bw_limited_resolution);
1060 EXPECT_EQ(1, stats.number_of_quality_adapt_changes);
1061
1062 // Trigger adapt up.
mflodmancc3d4422017-08-03 08:27:51 -07001063 video_stream_encoder_->TriggerQualityHigh();
asaperssonfab67072017-04-04 05:51:49 -07001064 video_source_.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001065 WaitForEncodedFrame(3);
asaperssonfab67072017-04-04 05:51:49 -07001066
1067 stats = stats_proxy_->GetStats();
1068 EXPECT_FALSE(stats.bw_limited_resolution);
1069 EXPECT_EQ(2, stats.number_of_quality_adapt_changes);
1070 EXPECT_EQ(0, stats.number_of_cpu_adapt_changes);
1071
mflodmancc3d4422017-08-03 08:27:51 -07001072 video_stream_encoder_->Stop();
asaperssonfab67072017-04-04 05:51:49 -07001073}
1074
mflodmancc3d4422017-08-03 08:27:51 -07001075TEST_F(VideoStreamEncoderTest, StatsTracksCpuAdaptationStats) {
1076 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonfab67072017-04-04 05:51:49 -07001077
1078 const int kWidth = 1280;
1079 const int kHeight = 720;
asaperssonfab67072017-04-04 05:51:49 -07001080 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001081 WaitForEncodedFrame(1);
perkj803d97f2016-11-01 11:45:46 -07001082 VideoSendStream::Stats stats = stats_proxy_->GetStats();
1083 EXPECT_FALSE(stats.cpu_limited_resolution);
1084 EXPECT_EQ(0, stats.number_of_cpu_adapt_changes);
1085
1086 // Trigger CPU overuse.
mflodmancc3d4422017-08-03 08:27:51 -07001087 video_stream_encoder_->TriggerCpuOveruse();
asaperssonfab67072017-04-04 05:51:49 -07001088 video_source_.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001089 WaitForEncodedFrame(2);
perkj803d97f2016-11-01 11:45:46 -07001090
1091 stats = stats_proxy_->GetStats();
1092 EXPECT_TRUE(stats.cpu_limited_resolution);
1093 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1094
1095 // Trigger CPU normal use.
mflodmancc3d4422017-08-03 08:27:51 -07001096 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssonfab67072017-04-04 05:51:49 -07001097 video_source_.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001098 WaitForEncodedFrame(3);
perkj803d97f2016-11-01 11:45:46 -07001099
1100 stats = stats_proxy_->GetStats();
1101 EXPECT_FALSE(stats.cpu_limited_resolution);
1102 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
asaperssonfab67072017-04-04 05:51:49 -07001103 EXPECT_EQ(0, stats.number_of_quality_adapt_changes);
perkj803d97f2016-11-01 11:45:46 -07001104
mflodmancc3d4422017-08-03 08:27:51 -07001105 video_stream_encoder_->Stop();
perkj803d97f2016-11-01 11:45:46 -07001106}
1107
mflodmancc3d4422017-08-03 08:27:51 -07001108TEST_F(VideoStreamEncoderTest, SwitchingSourceKeepsCpuAdaptation) {
1109 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
kthelgason876222f2016-11-29 01:44:11 -08001110
asaperssonfab67072017-04-04 05:51:49 -07001111 const int kWidth = 1280;
1112 const int kHeight = 720;
1113 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001114 WaitForEncodedFrame(1);
kthelgason876222f2016-11-29 01:44:11 -08001115 VideoSendStream::Stats stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001116 EXPECT_FALSE(stats.bw_limited_resolution);
kthelgason876222f2016-11-29 01:44:11 -08001117 EXPECT_FALSE(stats.cpu_limited_resolution);
1118 EXPECT_EQ(0, stats.number_of_cpu_adapt_changes);
1119
asaperssonfab67072017-04-04 05:51:49 -07001120 // Trigger CPU overuse.
mflodmancc3d4422017-08-03 08:27:51 -07001121 video_stream_encoder_->TriggerCpuOveruse();
asaperssonfab67072017-04-04 05:51:49 -07001122 video_source_.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001123 WaitForEncodedFrame(2);
kthelgason876222f2016-11-29 01:44:11 -08001124 stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001125 EXPECT_FALSE(stats.bw_limited_resolution);
kthelgason876222f2016-11-29 01:44:11 -08001126 EXPECT_TRUE(stats.cpu_limited_resolution);
1127 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1128
1129 // Set new source with adaptation still enabled.
1130 test::FrameForwarder new_video_source;
mflodmancc3d4422017-08-03 08:27:51 -07001131 video_stream_encoder_->SetSource(
sprangc5d62e22017-04-02 23:53:04 -07001132 &new_video_source,
1133 VideoSendStream::DegradationPreference::kMaintainFramerate);
kthelgason876222f2016-11-29 01:44:11 -08001134
asaperssonfab67072017-04-04 05:51:49 -07001135 new_video_source.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001136 WaitForEncodedFrame(3);
kthelgason876222f2016-11-29 01:44:11 -08001137 stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001138 EXPECT_FALSE(stats.bw_limited_resolution);
kthelgason876222f2016-11-29 01:44:11 -08001139 EXPECT_TRUE(stats.cpu_limited_resolution);
1140 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1141
1142 // Set adaptation disabled.
mflodmancc3d4422017-08-03 08:27:51 -07001143 video_stream_encoder_->SetSource(
kthelgason876222f2016-11-29 01:44:11 -08001144 &new_video_source,
sprangc5d62e22017-04-02 23:53:04 -07001145 VideoSendStream::DegradationPreference::kDegradationDisabled);
kthelgason876222f2016-11-29 01:44:11 -08001146
asaperssonfab67072017-04-04 05:51:49 -07001147 new_video_source.IncomingCapturedFrame(CreateFrame(4, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001148 WaitForEncodedFrame(4);
kthelgason876222f2016-11-29 01:44:11 -08001149 stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001150 EXPECT_FALSE(stats.bw_limited_resolution);
kthelgason876222f2016-11-29 01:44:11 -08001151 EXPECT_FALSE(stats.cpu_limited_resolution);
1152 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1153
1154 // Set adaptation back to enabled.
mflodmancc3d4422017-08-03 08:27:51 -07001155 video_stream_encoder_->SetSource(
sprangc5d62e22017-04-02 23:53:04 -07001156 &new_video_source,
1157 VideoSendStream::DegradationPreference::kMaintainFramerate);
kthelgason876222f2016-11-29 01:44:11 -08001158
asaperssonfab67072017-04-04 05:51:49 -07001159 new_video_source.IncomingCapturedFrame(CreateFrame(5, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001160 WaitForEncodedFrame(5);
kthelgason876222f2016-11-29 01:44:11 -08001161 stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001162 EXPECT_FALSE(stats.bw_limited_resolution);
kthelgason876222f2016-11-29 01:44:11 -08001163 EXPECT_TRUE(stats.cpu_limited_resolution);
1164 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1165
asaperssonfab67072017-04-04 05:51:49 -07001166 // Trigger CPU normal use.
mflodmancc3d4422017-08-03 08:27:51 -07001167 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssonfab67072017-04-04 05:51:49 -07001168 new_video_source.IncomingCapturedFrame(CreateFrame(6, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001169 WaitForEncodedFrame(6);
kthelgason876222f2016-11-29 01:44:11 -08001170 stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001171 EXPECT_FALSE(stats.bw_limited_resolution);
kthelgason876222f2016-11-29 01:44:11 -08001172 EXPECT_FALSE(stats.cpu_limited_resolution);
1173 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
asapersson02465b82017-04-10 01:12:52 -07001174 EXPECT_EQ(0, stats.number_of_quality_adapt_changes);
kthelgason876222f2016-11-29 01:44:11 -08001175
mflodmancc3d4422017-08-03 08:27:51 -07001176 video_stream_encoder_->Stop();
kthelgason876222f2016-11-29 01:44:11 -08001177}
1178
mflodmancc3d4422017-08-03 08:27:51 -07001179TEST_F(VideoStreamEncoderTest, SwitchingSourceKeepsQualityAdaptation) {
1180 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
kthelgason876222f2016-11-29 01:44:11 -08001181
asaperssonfab67072017-04-04 05:51:49 -07001182 const int kWidth = 1280;
1183 const int kHeight = 720;
1184 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001185 WaitForEncodedFrame(1);
kthelgason876222f2016-11-29 01:44:11 -08001186 VideoSendStream::Stats stats = stats_proxy_->GetStats();
kthelgason876222f2016-11-29 01:44:11 -08001187 EXPECT_FALSE(stats.bw_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001188 EXPECT_FALSE(stats.bw_limited_framerate);
asaperssonfab67072017-04-04 05:51:49 -07001189 EXPECT_EQ(0, stats.number_of_quality_adapt_changes);
kthelgason876222f2016-11-29 01:44:11 -08001190
1191 // Set new source with adaptation still enabled.
1192 test::FrameForwarder new_video_source;
mflodmancc3d4422017-08-03 08:27:51 -07001193 video_stream_encoder_->SetSource(
1194 &new_video_source,
1195 VideoSendStream::DegradationPreference::kBalanced);
kthelgason876222f2016-11-29 01:44:11 -08001196
asaperssonfab67072017-04-04 05:51:49 -07001197 new_video_source.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001198 WaitForEncodedFrame(2);
kthelgason876222f2016-11-29 01:44:11 -08001199 stats = stats_proxy_->GetStats();
kthelgason876222f2016-11-29 01:44:11 -08001200 EXPECT_FALSE(stats.bw_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001201 EXPECT_FALSE(stats.bw_limited_framerate);
asaperssonfab67072017-04-04 05:51:49 -07001202 EXPECT_EQ(0, stats.number_of_quality_adapt_changes);
kthelgason876222f2016-11-29 01:44:11 -08001203
asaperssonfab67072017-04-04 05:51:49 -07001204 // Trigger adapt down.
mflodmancc3d4422017-08-03 08:27:51 -07001205 video_stream_encoder_->TriggerQualityLow();
asaperssonfab67072017-04-04 05:51:49 -07001206 new_video_source.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001207 WaitForEncodedFrame(3);
kthelgason876222f2016-11-29 01:44:11 -08001208 stats = stats_proxy_->GetStats();
kthelgason876222f2016-11-29 01:44:11 -08001209 EXPECT_TRUE(stats.bw_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001210 EXPECT_FALSE(stats.bw_limited_framerate);
asaperssonfab67072017-04-04 05:51:49 -07001211 EXPECT_EQ(1, stats.number_of_quality_adapt_changes);
kthelgason876222f2016-11-29 01:44:11 -08001212
asaperssonfab67072017-04-04 05:51:49 -07001213 // Set new source with adaptation still enabled.
mflodmancc3d4422017-08-03 08:27:51 -07001214 video_stream_encoder_->SetSource(
1215 &new_video_source,
1216 VideoSendStream::DegradationPreference::kBalanced);
kthelgason876222f2016-11-29 01:44:11 -08001217
asaperssonfab67072017-04-04 05:51:49 -07001218 new_video_source.IncomingCapturedFrame(CreateFrame(4, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001219 WaitForEncodedFrame(4);
kthelgason876222f2016-11-29 01:44:11 -08001220 stats = stats_proxy_->GetStats();
kthelgason876222f2016-11-29 01:44:11 -08001221 EXPECT_TRUE(stats.bw_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001222 EXPECT_FALSE(stats.bw_limited_framerate);
asaperssonfab67072017-04-04 05:51:49 -07001223 EXPECT_EQ(1, stats.number_of_quality_adapt_changes);
kthelgason876222f2016-11-29 01:44:11 -08001224
asapersson02465b82017-04-10 01:12:52 -07001225 // Disable resolution scaling.
mflodmancc3d4422017-08-03 08:27:51 -07001226 video_stream_encoder_->SetSource(
kthelgason876222f2016-11-29 01:44:11 -08001227 &new_video_source,
1228 VideoSendStream::DegradationPreference::kMaintainResolution);
1229
asaperssonfab67072017-04-04 05:51:49 -07001230 new_video_source.IncomingCapturedFrame(CreateFrame(5, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001231 WaitForEncodedFrame(5);
kthelgason876222f2016-11-29 01:44:11 -08001232 stats = stats_proxy_->GetStats();
kthelgason876222f2016-11-29 01:44:11 -08001233 EXPECT_FALSE(stats.bw_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001234 EXPECT_FALSE(stats.bw_limited_framerate);
asaperssonfab67072017-04-04 05:51:49 -07001235 EXPECT_EQ(1, stats.number_of_quality_adapt_changes);
1236 EXPECT_EQ(0, stats.number_of_cpu_adapt_changes);
kthelgason876222f2016-11-29 01:44:11 -08001237
mflodmancc3d4422017-08-03 08:27:51 -07001238 video_stream_encoder_->Stop();
kthelgason876222f2016-11-29 01:44:11 -08001239}
1240
mflodmancc3d4422017-08-03 08:27:51 -07001241TEST_F(VideoStreamEncoderTest,
1242 QualityAdaptationStatsAreResetWhenScalerIsDisabled) {
1243 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson36e9eb42017-03-31 05:29:12 -07001244
1245 const int kWidth = 1280;
1246 const int kHeight = 720;
1247 video_source_.set_adaptation_enabled(true);
1248 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001249 WaitForEncodedFrame(1);
asapersson36e9eb42017-03-31 05:29:12 -07001250 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1251 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1252 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1253
1254 // Trigger adapt down.
mflodmancc3d4422017-08-03 08:27:51 -07001255 video_stream_encoder_->TriggerQualityLow();
asapersson36e9eb42017-03-31 05:29:12 -07001256 video_source_.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001257 WaitForEncodedFrame(2);
asapersson36e9eb42017-03-31 05:29:12 -07001258 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1259 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1260 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1261
1262 // Trigger overuse.
mflodmancc3d4422017-08-03 08:27:51 -07001263 video_stream_encoder_->TriggerCpuOveruse();
asapersson36e9eb42017-03-31 05:29:12 -07001264 video_source_.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001265 WaitForEncodedFrame(3);
asapersson36e9eb42017-03-31 05:29:12 -07001266 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1267 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1268 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1269
Niels Möller4db138e2018-04-19 09:04:13 +02001270 // Leave source unchanged, but disable quality scaler.
asapersson36e9eb42017-03-31 05:29:12 -07001271 fake_encoder_.SetQualityScaling(false);
Niels Möller4db138e2018-04-19 09:04:13 +02001272
1273 VideoEncoderConfig video_encoder_config;
1274 test::FillEncoderConfiguration(kVideoCodecVP8, 1, &video_encoder_config);
1275 // Make format different, to force recreation of encoder.
1276 video_encoder_config.video_format.parameters["foo"] = "foo";
1277 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
Niels Möllerf1338562018-04-26 09:51:47 +02001278 kMaxPayloadLength);
asapersson36e9eb42017-03-31 05:29:12 -07001279
1280 video_source_.IncomingCapturedFrame(CreateFrame(4, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001281 WaitForEncodedFrame(4);
asapersson36e9eb42017-03-31 05:29:12 -07001282 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1283 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1284 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1285
mflodmancc3d4422017-08-03 08:27:51 -07001286 video_stream_encoder_->Stop();
asapersson36e9eb42017-03-31 05:29:12 -07001287}
1288
mflodmancc3d4422017-08-03 08:27:51 -07001289TEST_F(VideoStreamEncoderTest,
1290 StatsTracksCpuAdaptationStatsWhenSwitchingSource) {
1291 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkj803d97f2016-11-01 11:45:46 -07001292
asapersson0944a802017-04-07 00:57:58 -07001293 const int kWidth = 1280;
1294 const int kHeight = 720;
sprang84a37592017-02-10 07:04:27 -08001295 int sequence = 1;
perkj803d97f2016-11-01 11:45:46 -07001296
asaperssonfab67072017-04-04 05:51:49 -07001297 video_source_.IncomingCapturedFrame(CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001298 WaitForEncodedFrame(sequence++);
perkj803d97f2016-11-01 11:45:46 -07001299 VideoSendStream::Stats stats = stats_proxy_->GetStats();
sprang84a37592017-02-10 07:04:27 -08001300 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001301 EXPECT_FALSE(stats.cpu_limited_framerate);
sprang84a37592017-02-10 07:04:27 -08001302 EXPECT_EQ(0, stats.number_of_cpu_adapt_changes);
1303
asapersson02465b82017-04-10 01:12:52 -07001304 // Trigger CPU overuse, should now adapt down.
mflodmancc3d4422017-08-03 08:27:51 -07001305 video_stream_encoder_->TriggerCpuOveruse();
asaperssonfab67072017-04-04 05:51:49 -07001306 video_source_.IncomingCapturedFrame(CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001307 WaitForEncodedFrame(sequence++);
sprang84a37592017-02-10 07:04:27 -08001308 stats = stats_proxy_->GetStats();
perkj803d97f2016-11-01 11:45:46 -07001309 EXPECT_TRUE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001310 EXPECT_FALSE(stats.cpu_limited_framerate);
perkj803d97f2016-11-01 11:45:46 -07001311 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1312
1313 // Set new source with adaptation still enabled.
1314 test::FrameForwarder new_video_source;
mflodmancc3d4422017-08-03 08:27:51 -07001315 video_stream_encoder_->SetSource(
sprangc5d62e22017-04-02 23:53:04 -07001316 &new_video_source,
1317 VideoSendStream::DegradationPreference::kMaintainFramerate);
perkj803d97f2016-11-01 11:45:46 -07001318
1319 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001320 CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001321 WaitForEncodedFrame(sequence++);
perkj803d97f2016-11-01 11:45:46 -07001322 stats = stats_proxy_->GetStats();
1323 EXPECT_TRUE(stats.cpu_limited_resolution);
asapersson09f05612017-05-15 23:40:18 -07001324 EXPECT_FALSE(stats.cpu_limited_framerate);
perkj803d97f2016-11-01 11:45:46 -07001325 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1326
sprangc5d62e22017-04-02 23:53:04 -07001327 // Set cpu adaptation by frame dropping.
mflodmancc3d4422017-08-03 08:27:51 -07001328 video_stream_encoder_->SetSource(
perkj803d97f2016-11-01 11:45:46 -07001329 &new_video_source,
1330 VideoSendStream::DegradationPreference::kMaintainResolution);
1331 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001332 CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001333 WaitForEncodedFrame(sequence++);
perkj803d97f2016-11-01 11:45:46 -07001334 stats = stats_proxy_->GetStats();
sprangc5d62e22017-04-02 23:53:04 -07001335 // Not adapted at first.
perkj803d97f2016-11-01 11:45:46 -07001336 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson09f05612017-05-15 23:40:18 -07001337 EXPECT_FALSE(stats.cpu_limited_framerate);
perkj803d97f2016-11-01 11:45:46 -07001338 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1339
sprangc5d62e22017-04-02 23:53:04 -07001340 // Force an input frame rate to be available, or the adaptation call won't
asapersson09f05612017-05-15 23:40:18 -07001341 // know what framerate to adapt from.
sprangc5d62e22017-04-02 23:53:04 -07001342 VideoSendStream::Stats mock_stats = stats_proxy_->GetStats();
1343 mock_stats.input_frame_rate = 30;
1344 stats_proxy_->SetMockStats(mock_stats);
mflodmancc3d4422017-08-03 08:27:51 -07001345 video_stream_encoder_->TriggerCpuOveruse();
sprangc5d62e22017-04-02 23:53:04 -07001346 stats_proxy_->ResetMockStats();
1347
1348 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001349 CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001350 WaitForEncodedFrame(sequence++);
sprangc5d62e22017-04-02 23:53:04 -07001351
1352 // Framerate now adapted.
1353 stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001354 EXPECT_FALSE(stats.cpu_limited_resolution);
1355 EXPECT_TRUE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001356 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
1357
1358 // Disable CPU adaptation.
mflodmancc3d4422017-08-03 08:27:51 -07001359 video_stream_encoder_->SetSource(
sprangc5d62e22017-04-02 23:53:04 -07001360 &new_video_source,
1361 VideoSendStream::DegradationPreference::kDegradationDisabled);
1362 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001363 CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001364 WaitForEncodedFrame(sequence++);
sprangc5d62e22017-04-02 23:53:04 -07001365
1366 stats = stats_proxy_->GetStats();
1367 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001368 EXPECT_FALSE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001369 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
1370
1371 // Try to trigger overuse. Should not succeed.
1372 stats_proxy_->SetMockStats(mock_stats);
mflodmancc3d4422017-08-03 08:27:51 -07001373 video_stream_encoder_->TriggerCpuOveruse();
sprangc5d62e22017-04-02 23:53:04 -07001374 stats_proxy_->ResetMockStats();
1375
1376 stats = stats_proxy_->GetStats();
1377 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001378 EXPECT_FALSE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001379 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
1380
1381 // Switch back the source with resolution adaptation enabled.
mflodmancc3d4422017-08-03 08:27:51 -07001382 video_stream_encoder_->SetSource(
sprangc5d62e22017-04-02 23:53:04 -07001383 &video_source_,
1384 VideoSendStream::DegradationPreference::kMaintainFramerate);
asaperssonfab67072017-04-04 05:51:49 -07001385 video_source_.IncomingCapturedFrame(CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001386 WaitForEncodedFrame(sequence++);
perkj803d97f2016-11-01 11:45:46 -07001387 stats = stats_proxy_->GetStats();
1388 EXPECT_TRUE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001389 EXPECT_FALSE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001390 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
perkj803d97f2016-11-01 11:45:46 -07001391
1392 // Trigger CPU normal usage.
mflodmancc3d4422017-08-03 08:27:51 -07001393 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssonfab67072017-04-04 05:51:49 -07001394 video_source_.IncomingCapturedFrame(CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001395 WaitForEncodedFrame(sequence++);
perkj803d97f2016-11-01 11:45:46 -07001396 stats = stats_proxy_->GetStats();
1397 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001398 EXPECT_FALSE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001399 EXPECT_EQ(3, stats.number_of_cpu_adapt_changes);
1400
1401 // Back to the source with adaptation off, set it back to maintain-resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001402 video_stream_encoder_->SetSource(
sprangc5d62e22017-04-02 23:53:04 -07001403 &new_video_source,
1404 VideoSendStream::DegradationPreference::kMaintainResolution);
1405 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001406 CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001407 WaitForEncodedFrame(sequence++);
sprangc5d62e22017-04-02 23:53:04 -07001408 stats = stats_proxy_->GetStats();
asapersson13874762017-06-07 00:01:02 -07001409 // Disabled, since we previously switched the source to disabled.
sprangc5d62e22017-04-02 23:53:04 -07001410 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001411 EXPECT_TRUE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001412 EXPECT_EQ(3, stats.number_of_cpu_adapt_changes);
1413
1414 // Trigger CPU normal usage.
mflodmancc3d4422017-08-03 08:27:51 -07001415 video_stream_encoder_->TriggerCpuNormalUsage();
sprangc5d62e22017-04-02 23:53:04 -07001416 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001417 CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001418 WaitForEncodedFrame(sequence++);
sprangc5d62e22017-04-02 23:53:04 -07001419 stats = stats_proxy_->GetStats();
1420 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001421 EXPECT_FALSE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001422 EXPECT_EQ(4, stats.number_of_cpu_adapt_changes);
asapersson02465b82017-04-10 01:12:52 -07001423 EXPECT_EQ(0, stats.number_of_quality_adapt_changes);
perkj803d97f2016-11-01 11:45:46 -07001424
mflodmancc3d4422017-08-03 08:27:51 -07001425 video_stream_encoder_->Stop();
perkj803d97f2016-11-01 11:45:46 -07001426}
1427
mflodmancc3d4422017-08-03 08:27:51 -07001428TEST_F(VideoStreamEncoderTest, StatsTracksPreferredBitrate) {
1429 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
Erik Språng08127a92016-11-16 16:41:30 +01001430
asaperssonfab67072017-04-04 05:51:49 -07001431 const int kWidth = 1280;
1432 const int kHeight = 720;
1433 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001434 WaitForEncodedFrame(1);
Erik Språng08127a92016-11-16 16:41:30 +01001435
1436 VideoSendStream::Stats stats = stats_proxy_->GetStats();
1437 EXPECT_EQ(video_encoder_config_.max_bitrate_bps,
1438 stats.preferred_media_bitrate_bps);
1439
mflodmancc3d4422017-08-03 08:27:51 -07001440 video_stream_encoder_->Stop();
Erik Språng08127a92016-11-16 16:41:30 +01001441}
1442
mflodmancc3d4422017-08-03 08:27:51 -07001443TEST_F(VideoStreamEncoderTest,
1444 ScalingUpAndDownDoesNothingWithMaintainResolution) {
asaperssonfab67072017-04-04 05:51:49 -07001445 const int kWidth = 1280;
1446 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001447 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
kthelgason876222f2016-11-29 01:44:11 -08001448
asaperssonfab67072017-04-04 05:51:49 -07001449 // Expect no scaling to begin with.
asapersson02465b82017-04-10 01:12:52 -07001450 VerifyNoLimitation(video_source_.sink_wants());
kthelgason876222f2016-11-29 01:44:11 -08001451
asaperssonfab67072017-04-04 05:51:49 -07001452 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001453 WaitForEncodedFrame(1);
kthelgason876222f2016-11-29 01:44:11 -08001454
asaperssonfab67072017-04-04 05:51:49 -07001455 // Trigger scale down.
mflodmancc3d4422017-08-03 08:27:51 -07001456 video_stream_encoder_->TriggerQualityLow();
kthelgason5e13d412016-12-01 03:59:51 -08001457
asaperssonfab67072017-04-04 05:51:49 -07001458 video_source_.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001459 WaitForEncodedFrame(2);
kthelgason5e13d412016-12-01 03:59:51 -08001460
kthelgason876222f2016-11-29 01:44:11 -08001461 // Expect a scale down.
1462 EXPECT_TRUE(video_source_.sink_wants().max_pixel_count);
asaperssonfab67072017-04-04 05:51:49 -07001463 EXPECT_LT(video_source_.sink_wants().max_pixel_count, kWidth * kHeight);
kthelgason876222f2016-11-29 01:44:11 -08001464
asapersson02465b82017-04-10 01:12:52 -07001465 // Set resolution scaling disabled.
kthelgason876222f2016-11-29 01:44:11 -08001466 test::FrameForwarder new_video_source;
mflodmancc3d4422017-08-03 08:27:51 -07001467 video_stream_encoder_->SetSource(
kthelgason876222f2016-11-29 01:44:11 -08001468 &new_video_source,
1469 VideoSendStream::DegradationPreference::kMaintainResolution);
1470
asaperssonfab67072017-04-04 05:51:49 -07001471 // Trigger scale down.
mflodmancc3d4422017-08-03 08:27:51 -07001472 video_stream_encoder_->TriggerQualityLow();
asaperssonfab67072017-04-04 05:51:49 -07001473 new_video_source.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001474 WaitForEncodedFrame(3);
kthelgason876222f2016-11-29 01:44:11 -08001475
asaperssonfab67072017-04-04 05:51:49 -07001476 // Expect no scaling.
sprangc5d62e22017-04-02 23:53:04 -07001477 EXPECT_EQ(std::numeric_limits<int>::max(),
1478 new_video_source.sink_wants().max_pixel_count);
kthelgason876222f2016-11-29 01:44:11 -08001479
asaperssonfab67072017-04-04 05:51:49 -07001480 // Trigger scale up.
mflodmancc3d4422017-08-03 08:27:51 -07001481 video_stream_encoder_->TriggerQualityHigh();
asaperssonfab67072017-04-04 05:51:49 -07001482 new_video_source.IncomingCapturedFrame(CreateFrame(4, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001483 WaitForEncodedFrame(4);
kthelgason876222f2016-11-29 01:44:11 -08001484
asapersson02465b82017-04-10 01:12:52 -07001485 // Expect nothing to change, still no scaling.
sprangc5d62e22017-04-02 23:53:04 -07001486 EXPECT_EQ(std::numeric_limits<int>::max(),
1487 new_video_source.sink_wants().max_pixel_count);
kthelgason876222f2016-11-29 01:44:11 -08001488
mflodmancc3d4422017-08-03 08:27:51 -07001489 video_stream_encoder_->Stop();
kthelgason876222f2016-11-29 01:44:11 -08001490}
1491
mflodmancc3d4422017-08-03 08:27:51 -07001492TEST_F(VideoStreamEncoderTest,
1493 SkipsSameAdaptDownRequest_MaintainFramerateMode) {
asapersson02465b82017-04-10 01:12:52 -07001494 const int kWidth = 1280;
1495 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001496 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson02465b82017-04-10 01:12:52 -07001497
1498 // Enable kMaintainFramerate preference, no initial limitation.
1499 test::FrameForwarder source;
mflodmancc3d4422017-08-03 08:27:51 -07001500 video_stream_encoder_->SetSource(
asapersson02465b82017-04-10 01:12:52 -07001501 &source, VideoSendStream::DegradationPreference::kMaintainFramerate);
1502
1503 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001504 WaitForEncodedFrame(1);
asapersson02465b82017-04-10 01:12:52 -07001505 VerifyNoLimitation(source.sink_wants());
1506 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1507 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1508
1509 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001510 video_stream_encoder_->TriggerCpuOveruse();
asapersson09f05612017-05-15 23:40:18 -07001511 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
asapersson02465b82017-04-10 01:12:52 -07001512 const int kLastMaxPixelCount = source.sink_wants().max_pixel_count;
1513 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1514 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1515
1516 // Trigger adapt down for same input resolution, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07001517 video_stream_encoder_->TriggerCpuOveruse();
asapersson02465b82017-04-10 01:12:52 -07001518 EXPECT_EQ(kLastMaxPixelCount, source.sink_wants().max_pixel_count);
1519 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1520 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1521
mflodmancc3d4422017-08-03 08:27:51 -07001522 video_stream_encoder_->Stop();
asapersson02465b82017-04-10 01:12:52 -07001523}
1524
mflodmancc3d4422017-08-03 08:27:51 -07001525TEST_F(VideoStreamEncoderTest, SkipsSameOrLargerAdaptDownRequest_BalancedMode) {
asaperssonf7e294d2017-06-13 23:25:22 -07001526 const int kWidth = 1280;
1527 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001528 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -07001529
1530 // Enable kBalanced preference, no initial limitation.
1531 test::FrameForwarder source;
mflodmancc3d4422017-08-03 08:27:51 -07001532 video_stream_encoder_->SetSource(
1533 &source,
1534 VideoSendStream::DegradationPreference::kBalanced);
asaperssonf7e294d2017-06-13 23:25:22 -07001535 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
1536 sink_.WaitForEncodedFrame(1);
1537 VerifyNoLimitation(source.sink_wants());
1538
1539 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001540 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07001541 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
1542 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1543 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1544 const int kLastMaxPixelCount = source.sink_wants().max_pixel_count;
1545
1546 // Trigger adapt down for same input resolution, expect no change.
1547 source.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
1548 sink_.WaitForEncodedFrame(2);
mflodmancc3d4422017-08-03 08:27:51 -07001549 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07001550 EXPECT_EQ(kLastMaxPixelCount, source.sink_wants().max_pixel_count);
1551 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1552 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1553
1554 // Trigger adapt down for larger input resolution, expect no change.
1555 source.IncomingCapturedFrame(CreateFrame(3, kWidth + 1, kHeight + 1));
1556 sink_.WaitForEncodedFrame(3);
mflodmancc3d4422017-08-03 08:27:51 -07001557 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07001558 EXPECT_EQ(kLastMaxPixelCount, source.sink_wants().max_pixel_count);
1559 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1560 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1561
mflodmancc3d4422017-08-03 08:27:51 -07001562 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07001563}
1564
mflodmancc3d4422017-08-03 08:27:51 -07001565TEST_F(VideoStreamEncoderTest,
1566 NoChangeForInitialNormalUsage_MaintainFramerateMode) {
asapersson02465b82017-04-10 01:12:52 -07001567 const int kWidth = 1280;
1568 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001569 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson02465b82017-04-10 01:12:52 -07001570
1571 // Enable kMaintainFramerate preference, no initial limitation.
1572 test::FrameForwarder source;
mflodmancc3d4422017-08-03 08:27:51 -07001573 video_stream_encoder_->SetSource(
asapersson02465b82017-04-10 01:12:52 -07001574 &source, VideoSendStream::DegradationPreference::kMaintainFramerate);
1575
1576 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001577 WaitForEncodedFrame(kWidth, kHeight);
asapersson02465b82017-04-10 01:12:52 -07001578 VerifyNoLimitation(source.sink_wants());
1579 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1580 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1581
1582 // Trigger adapt up, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07001583 video_stream_encoder_->TriggerCpuNormalUsage();
asapersson02465b82017-04-10 01:12:52 -07001584 VerifyNoLimitation(source.sink_wants());
1585 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1586 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1587
mflodmancc3d4422017-08-03 08:27:51 -07001588 video_stream_encoder_->Stop();
asapersson02465b82017-04-10 01:12:52 -07001589}
1590
mflodmancc3d4422017-08-03 08:27:51 -07001591TEST_F(VideoStreamEncoderTest,
1592 NoChangeForInitialNormalUsage_MaintainResolutionMode) {
asapersson02465b82017-04-10 01:12:52 -07001593 const int kWidth = 1280;
1594 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001595 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson02465b82017-04-10 01:12:52 -07001596
1597 // Enable kMaintainResolution preference, no initial limitation.
1598 test::FrameForwarder source;
mflodmancc3d4422017-08-03 08:27:51 -07001599 video_stream_encoder_->SetSource(
asapersson02465b82017-04-10 01:12:52 -07001600 &source, VideoSendStream::DegradationPreference::kMaintainResolution);
1601
1602 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001603 WaitForEncodedFrame(kWidth, kHeight);
asapersson02465b82017-04-10 01:12:52 -07001604 VerifyNoLimitation(source.sink_wants());
asapersson09f05612017-05-15 23:40:18 -07001605 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
asapersson02465b82017-04-10 01:12:52 -07001606 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1607
1608 // Trigger adapt up, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07001609 video_stream_encoder_->TriggerCpuNormalUsage();
asapersson02465b82017-04-10 01:12:52 -07001610 VerifyNoLimitation(source.sink_wants());
asapersson09f05612017-05-15 23:40:18 -07001611 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
asapersson02465b82017-04-10 01:12:52 -07001612 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1613
mflodmancc3d4422017-08-03 08:27:51 -07001614 video_stream_encoder_->Stop();
asapersson02465b82017-04-10 01:12:52 -07001615}
1616
mflodmancc3d4422017-08-03 08:27:51 -07001617TEST_F(VideoStreamEncoderTest, NoChangeForInitialNormalUsage_BalancedMode) {
asaperssonf7e294d2017-06-13 23:25:22 -07001618 const int kWidth = 1280;
1619 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001620 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -07001621
1622 // Enable kBalanced preference, no initial limitation.
1623 test::FrameForwarder source;
mflodmancc3d4422017-08-03 08:27:51 -07001624 video_stream_encoder_->SetSource(
1625 &source,
1626 VideoSendStream::DegradationPreference::kBalanced);
asaperssonf7e294d2017-06-13 23:25:22 -07001627
1628 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
1629 sink_.WaitForEncodedFrame(kWidth, kHeight);
1630 VerifyNoLimitation(source.sink_wants());
1631 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1632 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
1633 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1634
1635 // Trigger adapt up, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07001636 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07001637 VerifyNoLimitation(source.sink_wants());
1638 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1639 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
1640 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1641
mflodmancc3d4422017-08-03 08:27:51 -07001642 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07001643}
1644
mflodmancc3d4422017-08-03 08:27:51 -07001645TEST_F(VideoStreamEncoderTest, NoChangeForInitialNormalUsage_DisabledMode) {
asapersson09f05612017-05-15 23:40:18 -07001646 const int kWidth = 1280;
1647 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001648 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson09f05612017-05-15 23:40:18 -07001649
1650 // Enable kDegradationDisabled preference, no initial limitation.
1651 test::FrameForwarder source;
mflodmancc3d4422017-08-03 08:27:51 -07001652 video_stream_encoder_->SetSource(
asapersson09f05612017-05-15 23:40:18 -07001653 &source, VideoSendStream::DegradationPreference::kDegradationDisabled);
1654
1655 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
1656 sink_.WaitForEncodedFrame(kWidth, kHeight);
1657 VerifyNoLimitation(source.sink_wants());
1658 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1659 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
1660 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1661
1662 // Trigger adapt up, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07001663 video_stream_encoder_->TriggerQualityHigh();
asapersson09f05612017-05-15 23:40:18 -07001664 VerifyNoLimitation(source.sink_wants());
1665 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1666 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
1667 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1668
mflodmancc3d4422017-08-03 08:27:51 -07001669 video_stream_encoder_->Stop();
asapersson09f05612017-05-15 23:40:18 -07001670}
1671
mflodmancc3d4422017-08-03 08:27:51 -07001672TEST_F(VideoStreamEncoderTest,
1673 AdaptsResolutionForLowQuality_MaintainFramerateMode) {
asapersson02465b82017-04-10 01:12:52 -07001674 const int kWidth = 1280;
1675 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001676 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson02465b82017-04-10 01:12:52 -07001677
1678 // Enable kMaintainFramerate preference, no initial limitation.
1679 AdaptingFrameForwarder source;
1680 source.set_adaptation_enabled(true);
mflodmancc3d4422017-08-03 08:27:51 -07001681 video_stream_encoder_->SetSource(
asapersson02465b82017-04-10 01:12:52 -07001682 &source, VideoSendStream::DegradationPreference::kMaintainFramerate);
1683
1684 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001685 WaitForEncodedFrame(1);
asapersson02465b82017-04-10 01:12:52 -07001686 VerifyNoLimitation(source.sink_wants());
1687 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1688 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1689
1690 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001691 video_stream_encoder_->TriggerQualityLow();
asapersson02465b82017-04-10 01:12:52 -07001692 source.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001693 WaitForEncodedFrame(2);
asapersson09f05612017-05-15 23:40:18 -07001694 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
asapersson02465b82017-04-10 01:12:52 -07001695 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1696 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1697
1698 // Trigger adapt up, expect no restriction.
mflodmancc3d4422017-08-03 08:27:51 -07001699 video_stream_encoder_->TriggerQualityHigh();
asapersson02465b82017-04-10 01:12:52 -07001700 VerifyNoLimitation(source.sink_wants());
1701 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1702 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1703 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1704
mflodmancc3d4422017-08-03 08:27:51 -07001705 video_stream_encoder_->Stop();
asapersson02465b82017-04-10 01:12:52 -07001706}
1707
mflodmancc3d4422017-08-03 08:27:51 -07001708TEST_F(VideoStreamEncoderTest,
1709 AdaptsFramerateForLowQuality_MaintainResolutionMode) {
asapersson09f05612017-05-15 23:40:18 -07001710 const int kWidth = 1280;
1711 const int kHeight = 720;
1712 const int kInputFps = 30;
mflodmancc3d4422017-08-03 08:27:51 -07001713 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson09f05612017-05-15 23:40:18 -07001714
1715 VideoSendStream::Stats stats = stats_proxy_->GetStats();
1716 stats.input_frame_rate = kInputFps;
1717 stats_proxy_->SetMockStats(stats);
1718
1719 // Expect no scaling to begin with (preference: kMaintainFramerate).
1720 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
1721 sink_.WaitForEncodedFrame(1);
1722 VerifyNoLimitation(video_source_.sink_wants());
1723
1724 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001725 video_stream_encoder_->TriggerQualityLow();
asapersson09f05612017-05-15 23:40:18 -07001726 video_source_.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
1727 sink_.WaitForEncodedFrame(2);
1728 VerifyFpsMaxResolutionLt(video_source_.sink_wants(), kWidth * kHeight);
1729
1730 // Enable kMaintainResolution preference.
1731 test::FrameForwarder new_video_source;
mflodmancc3d4422017-08-03 08:27:51 -07001732 video_stream_encoder_->SetSource(
asapersson09f05612017-05-15 23:40:18 -07001733 &new_video_source,
1734 VideoSendStream::DegradationPreference::kMaintainResolution);
1735 VerifyNoLimitation(new_video_source.sink_wants());
1736
1737 // Trigger adapt down, expect reduced framerate.
mflodmancc3d4422017-08-03 08:27:51 -07001738 video_stream_encoder_->TriggerQualityLow();
asapersson09f05612017-05-15 23:40:18 -07001739 new_video_source.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
1740 sink_.WaitForEncodedFrame(3);
1741 VerifyFpsLtResolutionMax(new_video_source.sink_wants(), kInputFps);
1742
1743 // Trigger adapt up, expect no restriction.
mflodmancc3d4422017-08-03 08:27:51 -07001744 video_stream_encoder_->TriggerQualityHigh();
asapersson09f05612017-05-15 23:40:18 -07001745 VerifyNoLimitation(new_video_source.sink_wants());
1746
mflodmancc3d4422017-08-03 08:27:51 -07001747 video_stream_encoder_->Stop();
asapersson09f05612017-05-15 23:40:18 -07001748}
1749
mflodmancc3d4422017-08-03 08:27:51 -07001750TEST_F(VideoStreamEncoderTest, DoesNotScaleBelowSetResolutionLimit) {
asaperssond0de2952017-04-21 01:47:31 -07001751 const int kWidth = 1280;
1752 const int kHeight = 720;
1753 const size_t kNumFrames = 10;
1754
mflodmancc3d4422017-08-03 08:27:51 -07001755 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
kthelgason5e13d412016-12-01 03:59:51 -08001756
asaperssond0de2952017-04-21 01:47:31 -07001757 // Enable adapter, expected input resolutions when downscaling:
asapersson142fcc92017-08-17 08:58:54 -07001758 // 1280x720 -> 960x540 -> 640x360 -> 480x270 -> 320x180 (kMinPixelsPerFrame)
asaperssond0de2952017-04-21 01:47:31 -07001759 video_source_.set_adaptation_enabled(true);
1760
1761 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1762 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1763
1764 int downscales = 0;
1765 for (size_t i = 1; i <= kNumFrames; i++) {
1766 video_source_.IncomingCapturedFrame(CreateFrame(i, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001767 WaitForEncodedFrame(i);
asaperssond0de2952017-04-21 01:47:31 -07001768
asaperssonfab67072017-04-04 05:51:49 -07001769 // Trigger scale down.
asaperssond0de2952017-04-21 01:47:31 -07001770 rtc::VideoSinkWants last_wants = video_source_.sink_wants();
mflodmancc3d4422017-08-03 08:27:51 -07001771 video_stream_encoder_->TriggerQualityLow();
sprangc5d62e22017-04-02 23:53:04 -07001772 EXPECT_GE(video_source_.sink_wants().max_pixel_count, kMinPixelsPerFrame);
asaperssond0de2952017-04-21 01:47:31 -07001773
1774 if (video_source_.sink_wants().max_pixel_count < last_wants.max_pixel_count)
1775 ++downscales;
1776
1777 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1778 EXPECT_EQ(downscales,
1779 stats_proxy_->GetStats().number_of_quality_adapt_changes);
1780 EXPECT_GT(downscales, 0);
kthelgason5e13d412016-12-01 03:59:51 -08001781 }
mflodmancc3d4422017-08-03 08:27:51 -07001782 video_stream_encoder_->Stop();
asaperssond0de2952017-04-21 01:47:31 -07001783}
1784
mflodmancc3d4422017-08-03 08:27:51 -07001785TEST_F(VideoStreamEncoderTest,
asaperssond0de2952017-04-21 01:47:31 -07001786 AdaptsResolutionUpAndDownTwiceOnOveruse_MaintainFramerateMode) {
1787 const int kWidth = 1280;
1788 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001789 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssond0de2952017-04-21 01:47:31 -07001790
1791 // Enable kMaintainFramerate preference, no initial limitation.
1792 AdaptingFrameForwarder source;
1793 source.set_adaptation_enabled(true);
mflodmancc3d4422017-08-03 08:27:51 -07001794 video_stream_encoder_->SetSource(
asaperssond0de2952017-04-21 01:47:31 -07001795 &source, VideoSendStream::DegradationPreference::kMaintainFramerate);
1796
1797 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001798 WaitForEncodedFrame(kWidth, kHeight);
asaperssond0de2952017-04-21 01:47:31 -07001799 VerifyNoLimitation(source.sink_wants());
1800 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1801 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1802
1803 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001804 video_stream_encoder_->TriggerCpuOveruse();
asaperssond0de2952017-04-21 01:47:31 -07001805 source.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001806 WaitForEncodedFrame(2);
asapersson09f05612017-05-15 23:40:18 -07001807 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
asaperssond0de2952017-04-21 01:47:31 -07001808 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1809 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1810
1811 // Trigger adapt up, expect no restriction.
mflodmancc3d4422017-08-03 08:27:51 -07001812 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssond0de2952017-04-21 01:47:31 -07001813 source.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001814 WaitForEncodedFrame(kWidth, kHeight);
asaperssond0de2952017-04-21 01:47:31 -07001815 VerifyNoLimitation(source.sink_wants());
1816 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1817 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1818
1819 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001820 video_stream_encoder_->TriggerCpuOveruse();
asaperssond0de2952017-04-21 01:47:31 -07001821 source.IncomingCapturedFrame(CreateFrame(4, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001822 WaitForEncodedFrame(4);
asapersson09f05612017-05-15 23:40:18 -07001823 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
asaperssond0de2952017-04-21 01:47:31 -07001824 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1825 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1826
1827 // Trigger adapt up, expect no restriction.
mflodmancc3d4422017-08-03 08:27:51 -07001828 video_stream_encoder_->TriggerCpuNormalUsage();
asapersson09f05612017-05-15 23:40:18 -07001829 source.IncomingCapturedFrame(CreateFrame(5, kWidth, kHeight));
1830 sink_.WaitForEncodedFrame(kWidth, kHeight);
asaperssond0de2952017-04-21 01:47:31 -07001831 VerifyNoLimitation(source.sink_wants());
1832 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1833 EXPECT_EQ(4, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1834
mflodmancc3d4422017-08-03 08:27:51 -07001835 video_stream_encoder_->Stop();
asaperssond0de2952017-04-21 01:47:31 -07001836}
1837
mflodmancc3d4422017-08-03 08:27:51 -07001838TEST_F(VideoStreamEncoderTest,
asaperssonf7e294d2017-06-13 23:25:22 -07001839 AdaptsResolutionUpAndDownTwiceForLowQuality_BalancedMode_NoFpsLimit) {
1840 const int kWidth = 1280;
1841 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001842 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -07001843
1844 // Enable kBalanced preference, no initial limitation.
1845 AdaptingFrameForwarder source;
1846 source.set_adaptation_enabled(true);
mflodmancc3d4422017-08-03 08:27:51 -07001847 video_stream_encoder_->SetSource(
1848 &source,
1849 VideoSendStream::DegradationPreference::kBalanced);
asaperssonf7e294d2017-06-13 23:25:22 -07001850
1851 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
1852 sink_.WaitForEncodedFrame(kWidth, kHeight);
1853 VerifyNoLimitation(source.sink_wants());
1854 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1855 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1856
1857 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001858 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07001859 source.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
1860 sink_.WaitForEncodedFrame(2);
1861 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
1862 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1863 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1864
1865 // Trigger adapt up, expect no restriction.
mflodmancc3d4422017-08-03 08:27:51 -07001866 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07001867 source.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
1868 sink_.WaitForEncodedFrame(kWidth, kHeight);
1869 VerifyNoLimitation(source.sink_wants());
1870 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1871 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1872
1873 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001874 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07001875 source.IncomingCapturedFrame(CreateFrame(4, kWidth, kHeight));
1876 sink_.WaitForEncodedFrame(4);
1877 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
1878 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1879 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1880
1881 // Trigger adapt up, expect no restriction.
mflodmancc3d4422017-08-03 08:27:51 -07001882 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07001883 source.IncomingCapturedFrame(CreateFrame(5, kWidth, kHeight));
1884 sink_.WaitForEncodedFrame(kWidth, kHeight);
1885 VerifyNoLimitation(source.sink_wants());
1886 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1887 EXPECT_EQ(4, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1888
mflodmancc3d4422017-08-03 08:27:51 -07001889 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07001890}
1891
mflodmancc3d4422017-08-03 08:27:51 -07001892TEST_F(VideoStreamEncoderTest,
asaperssond0de2952017-04-21 01:47:31 -07001893 AdaptsResolutionOnOveruseAndLowQuality_MaintainFramerateMode) {
1894 const int kWidth = 1280;
1895 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001896 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssond0de2952017-04-21 01:47:31 -07001897
1898 // Enable kMaintainFramerate preference, no initial limitation.
1899 AdaptingFrameForwarder source;
1900 source.set_adaptation_enabled(true);
mflodmancc3d4422017-08-03 08:27:51 -07001901 video_stream_encoder_->SetSource(
asaperssond0de2952017-04-21 01:47:31 -07001902 &source, VideoSendStream::DegradationPreference::kMaintainFramerate);
1903
1904 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001905 WaitForEncodedFrame(kWidth, kHeight);
asaperssond0de2952017-04-21 01:47:31 -07001906 VerifyNoLimitation(source.sink_wants());
1907 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1908 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1909 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1910 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1911
1912 // Trigger cpu adapt down, expect scaled down resolution (960x540).
mflodmancc3d4422017-08-03 08:27:51 -07001913 video_stream_encoder_->TriggerCpuOveruse();
asaperssond0de2952017-04-21 01:47:31 -07001914 source.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001915 WaitForEncodedFrame(2);
asapersson09f05612017-05-15 23:40:18 -07001916 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
asaperssond0de2952017-04-21 01:47:31 -07001917 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1918 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1919 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1920 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1921
1922 // Trigger cpu adapt down, expect scaled down resolution (640x360).
mflodmancc3d4422017-08-03 08:27:51 -07001923 video_stream_encoder_->TriggerCpuOveruse();
asaperssond0de2952017-04-21 01:47:31 -07001924 source.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001925 WaitForEncodedFrame(3);
asapersson09f05612017-05-15 23:40:18 -07001926 VerifyFpsMaxResolutionLt(source.sink_wants(), source.last_wants());
asaperssond0de2952017-04-21 01:47:31 -07001927 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1928 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1929 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1930 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1931
Jonathan Yubc771b72017-12-08 17:04:29 -08001932 // Trigger cpu adapt down, expect scaled down resolution (480x270).
mflodmancc3d4422017-08-03 08:27:51 -07001933 video_stream_encoder_->TriggerCpuOveruse();
asaperssond0de2952017-04-21 01:47:31 -07001934 source.IncomingCapturedFrame(CreateFrame(4, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001935 WaitForEncodedFrame(4);
Jonathan Yubc771b72017-12-08 17:04:29 -08001936 VerifyFpsMaxResolutionLt(source.sink_wants(), source.last_wants());
asaperssond0de2952017-04-21 01:47:31 -07001937 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1938 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
Jonathan Yubc771b72017-12-08 17:04:29 -08001939 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
asaperssond0de2952017-04-21 01:47:31 -07001940 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1941
Jonathan Yubc771b72017-12-08 17:04:29 -08001942 // Trigger quality adapt down, expect scaled down resolution (320x180).
mflodmancc3d4422017-08-03 08:27:51 -07001943 video_stream_encoder_->TriggerQualityLow();
asaperssond0de2952017-04-21 01:47:31 -07001944 source.IncomingCapturedFrame(CreateFrame(5, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001945 WaitForEncodedFrame(5);
asapersson09f05612017-05-15 23:40:18 -07001946 VerifyFpsMaxResolutionLt(source.sink_wants(), source.last_wants());
Jonathan Yubc771b72017-12-08 17:04:29 -08001947 rtc::VideoSinkWants last_wants = source.sink_wants();
asaperssond0de2952017-04-21 01:47:31 -07001948 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1949 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1950 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1951 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1952
Jonathan Yubc771b72017-12-08 17:04:29 -08001953 // Trigger quality adapt down, expect no change (min resolution reached).
1954 video_stream_encoder_->TriggerQualityLow();
1955 source.IncomingCapturedFrame(CreateFrame(6, kWidth, kHeight));
1956 WaitForEncodedFrame(6);
1957 VerifyFpsMaxResolutionEq(source.sink_wants(), last_wants);
1958 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1959 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1960 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1961 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1962
1963 // Trigger cpu adapt up, expect upscaled resolution (480x270).
mflodmancc3d4422017-08-03 08:27:51 -07001964 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssond0de2952017-04-21 01:47:31 -07001965 source.IncomingCapturedFrame(CreateFrame(7, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001966 WaitForEncodedFrame(7);
asapersson09f05612017-05-15 23:40:18 -07001967 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
Jonathan Yubc771b72017-12-08 17:04:29 -08001968 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1969 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1970 EXPECT_EQ(4, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1971 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1972
1973 // Trigger cpu adapt up, expect upscaled resolution (640x360).
1974 video_stream_encoder_->TriggerCpuNormalUsage();
1975 source.IncomingCapturedFrame(CreateFrame(8, kWidth, kHeight));
1976 WaitForEncodedFrame(8);
1977 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
1978 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1979 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1980 EXPECT_EQ(5, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1981 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1982
1983 // Trigger cpu adapt up, expect upscaled resolution (960x540).
1984 video_stream_encoder_->TriggerCpuNormalUsage();
1985 source.IncomingCapturedFrame(CreateFrame(9, kWidth, kHeight));
1986 WaitForEncodedFrame(9);
1987 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
asaperssond0de2952017-04-21 01:47:31 -07001988 last_wants = source.sink_wants();
1989 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1990 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
Jonathan Yubc771b72017-12-08 17:04:29 -08001991 EXPECT_EQ(6, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
asaperssond0de2952017-04-21 01:47:31 -07001992 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1993
1994 // Trigger cpu adapt up, no cpu downgrades, expect no change (960x540).
mflodmancc3d4422017-08-03 08:27:51 -07001995 video_stream_encoder_->TriggerCpuNormalUsage();
Jonathan Yubc771b72017-12-08 17:04:29 -08001996 source.IncomingCapturedFrame(CreateFrame(10, kWidth, kHeight));
1997 WaitForEncodedFrame(10);
asapersson09f05612017-05-15 23:40:18 -07001998 VerifyFpsEqResolutionEq(source.sink_wants(), last_wants);
asaperssond0de2952017-04-21 01:47:31 -07001999 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2000 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
Jonathan Yubc771b72017-12-08 17:04:29 -08002001 EXPECT_EQ(6, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
asaperssond0de2952017-04-21 01:47:31 -07002002 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2003
2004 // Trigger quality adapt up, expect no restriction (1280x720).
mflodmancc3d4422017-08-03 08:27:51 -07002005 video_stream_encoder_->TriggerQualityHigh();
Jonathan Yubc771b72017-12-08 17:04:29 -08002006 source.IncomingCapturedFrame(CreateFrame(11, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002007 WaitForEncodedFrame(kWidth, kHeight);
asapersson09f05612017-05-15 23:40:18 -07002008 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
asaperssond0de2952017-04-21 01:47:31 -07002009 VerifyNoLimitation(source.sink_wants());
2010 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2011 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
Jonathan Yubc771b72017-12-08 17:04:29 -08002012 EXPECT_EQ(6, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
asaperssond0de2952017-04-21 01:47:31 -07002013 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
kthelgason5e13d412016-12-01 03:59:51 -08002014
mflodmancc3d4422017-08-03 08:27:51 -07002015 video_stream_encoder_->Stop();
kthelgason5e13d412016-12-01 03:59:51 -08002016}
2017
mflodmancc3d4422017-08-03 08:27:51 -07002018TEST_F(VideoStreamEncoderTest, CpuLimitedHistogramIsReported) {
asaperssonfab67072017-04-04 05:51:49 -07002019 const int kWidth = 640;
2020 const int kHeight = 360;
perkj803d97f2016-11-01 11:45:46 -07002021
mflodmancc3d4422017-08-03 08:27:51 -07002022 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
sprang4847ae62017-06-27 07:06:52 -07002023
perkj803d97f2016-11-01 11:45:46 -07002024 for (int i = 1; i <= SendStatisticsProxy::kMinRequiredMetricsSamples; ++i) {
asaperssonfab67072017-04-04 05:51:49 -07002025 video_source_.IncomingCapturedFrame(CreateFrame(i, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002026 WaitForEncodedFrame(i);
perkj803d97f2016-11-01 11:45:46 -07002027 }
2028
mflodmancc3d4422017-08-03 08:27:51 -07002029 video_stream_encoder_->TriggerCpuOveruse();
perkj803d97f2016-11-01 11:45:46 -07002030 for (int i = 1; i <= SendStatisticsProxy::kMinRequiredMetricsSamples; ++i) {
asaperssonfab67072017-04-04 05:51:49 -07002031 video_source_.IncomingCapturedFrame(CreateFrame(
2032 SendStatisticsProxy::kMinRequiredMetricsSamples + i, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002033 WaitForEncodedFrame(SendStatisticsProxy::kMinRequiredMetricsSamples + i);
perkj803d97f2016-11-01 11:45:46 -07002034 }
2035
mflodmancc3d4422017-08-03 08:27:51 -07002036 video_stream_encoder_->Stop();
2037 video_stream_encoder_.reset();
perkj803d97f2016-11-01 11:45:46 -07002038 stats_proxy_.reset();
sprangf8ee65e2017-02-28 08:49:33 -08002039
perkj803d97f2016-11-01 11:45:46 -07002040 EXPECT_EQ(1,
2041 metrics::NumSamples("WebRTC.Video.CpuLimitedResolutionInPercent"));
2042 EXPECT_EQ(
2043 1, metrics::NumEvents("WebRTC.Video.CpuLimitedResolutionInPercent", 50));
2044}
2045
mflodmancc3d4422017-08-03 08:27:51 -07002046TEST_F(VideoStreamEncoderTest,
2047 CpuLimitedHistogramIsNotReportedForDisabledDegradation) {
2048 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonf4e44af2017-04-19 02:01:06 -07002049 const int kWidth = 640;
2050 const int kHeight = 360;
2051
mflodmancc3d4422017-08-03 08:27:51 -07002052 video_stream_encoder_->SetSource(
asaperssonf4e44af2017-04-19 02:01:06 -07002053 &video_source_,
2054 VideoSendStream::DegradationPreference::kDegradationDisabled);
2055
2056 for (int i = 1; i <= SendStatisticsProxy::kMinRequiredMetricsSamples; ++i) {
2057 video_source_.IncomingCapturedFrame(CreateFrame(i, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002058 WaitForEncodedFrame(i);
asaperssonf4e44af2017-04-19 02:01:06 -07002059 }
2060
mflodmancc3d4422017-08-03 08:27:51 -07002061 video_stream_encoder_->Stop();
2062 video_stream_encoder_.reset();
asaperssonf4e44af2017-04-19 02:01:06 -07002063 stats_proxy_.reset();
2064
2065 EXPECT_EQ(0,
2066 metrics::NumSamples("WebRTC.Video.CpuLimitedResolutionInPercent"));
2067}
2068
mflodmancc3d4422017-08-03 08:27:51 -07002069TEST_F(VideoStreamEncoderTest, CallsBitrateObserver) {
sprang4847ae62017-06-27 07:06:52 -07002070 MockBitrateObserver bitrate_observer;
mflodmancc3d4422017-08-03 08:27:51 -07002071 video_stream_encoder_->SetBitrateObserver(&bitrate_observer);
sprang57c2fff2017-01-16 06:24:02 -08002072
2073 const int kDefaultFps = 30;
Erik Språng566124a2018-04-23 12:32:22 +02002074 const VideoBitrateAllocation expected_bitrate =
sprang57c2fff2017-01-16 06:24:02 -08002075 DefaultVideoBitrateAllocator(fake_encoder_.codec_config())
kthelgason2bc68642017-02-07 07:02:22 -08002076 .GetAllocation(kLowTargetBitrateBps, kDefaultFps);
sprang57c2fff2017-01-16 06:24:02 -08002077
2078 // First called on bitrate updated, then again on first frame.
2079 EXPECT_CALL(bitrate_observer, OnBitrateAllocationUpdated(expected_bitrate))
2080 .Times(2);
mflodmancc3d4422017-08-03 08:27:51 -07002081 video_stream_encoder_->OnBitrateUpdated(kLowTargetBitrateBps, 0, 0);
sprang57c2fff2017-01-16 06:24:02 -08002082
2083 const int64_t kStartTimeMs = 1;
2084 video_source_.IncomingCapturedFrame(
2085 CreateFrame(kStartTimeMs, codec_width_, codec_height_));
sprang4847ae62017-06-27 07:06:52 -07002086 WaitForEncodedFrame(kStartTimeMs);
sprang57c2fff2017-01-16 06:24:02 -08002087
2088 // Not called on second frame.
2089 EXPECT_CALL(bitrate_observer, OnBitrateAllocationUpdated(expected_bitrate))
2090 .Times(0);
2091 video_source_.IncomingCapturedFrame(
2092 CreateFrame(kStartTimeMs + 1, codec_width_, codec_height_));
sprang4847ae62017-06-27 07:06:52 -07002093 WaitForEncodedFrame(kStartTimeMs + 1);
sprang57c2fff2017-01-16 06:24:02 -08002094
2095 // Called after a process interval.
2096 const int64_t kProcessIntervalMs =
2097 vcm::VCMProcessTimer::kDefaultProcessIntervalMs;
sprang4847ae62017-06-27 07:06:52 -07002098 fake_clock_.AdvanceTimeMicros(rtc::kNumMicrosecsPerMillisec *
2099 (kProcessIntervalMs + (1000 / kDefaultFps)));
sprang57c2fff2017-01-16 06:24:02 -08002100 EXPECT_CALL(bitrate_observer, OnBitrateAllocationUpdated(expected_bitrate))
2101 .Times(1);
2102 video_source_.IncomingCapturedFrame(CreateFrame(
2103 kStartTimeMs + kProcessIntervalMs, codec_width_, codec_height_));
sprang4847ae62017-06-27 07:06:52 -07002104 WaitForEncodedFrame(kStartTimeMs + kProcessIntervalMs);
sprang57c2fff2017-01-16 06:24:02 -08002105
mflodmancc3d4422017-08-03 08:27:51 -07002106 video_stream_encoder_->Stop();
sprang57c2fff2017-01-16 06:24:02 -08002107}
2108
Niels Möller7dc26b72017-12-06 10:27:48 +01002109TEST_F(VideoStreamEncoderTest, OveruseDetectorUpdatedOnReconfigureAndAdaption) {
2110 const int kFrameWidth = 1280;
2111 const int kFrameHeight = 720;
2112 const int kFramerate = 24;
2113
2114 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
2115 test::FrameForwarder source;
2116 video_stream_encoder_->SetSource(
2117 &source, VideoSendStream::DegradationPreference::kMaintainResolution);
2118
2119 // Insert a single frame, triggering initial configuration.
2120 source.IncomingCapturedFrame(CreateFrame(1, kFrameWidth, kFrameHeight));
2121 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2122
2123 EXPECT_EQ(
2124 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2125 kDefaultFramerate);
2126
2127 // Trigger reconfigure encoder (without resetting the entire instance).
2128 VideoEncoderConfig video_encoder_config;
Niels Möller259a4972018-04-05 15:36:51 +02002129 video_encoder_config.codec_type = kVideoCodecVP8;
Niels Möller7dc26b72017-12-06 10:27:48 +01002130 video_encoder_config.max_bitrate_bps = kTargetBitrateBps;
2131 video_encoder_config.number_of_streams = 1;
2132 video_encoder_config.video_stream_factory =
2133 new rtc::RefCountedObject<VideoStreamFactory>(1, kFramerate);
2134 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
Niels Möllerf1338562018-04-26 09:51:47 +02002135 kMaxPayloadLength);
Niels Möller7dc26b72017-12-06 10:27:48 +01002136 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2137
2138 // Detector should be updated with fps limit from codec config.
2139 EXPECT_EQ(
2140 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2141 kFramerate);
2142
2143 // Trigger overuse, max framerate should be reduced.
2144 VideoSendStream::Stats stats = stats_proxy_->GetStats();
2145 stats.input_frame_rate = kFramerate;
2146 stats_proxy_->SetMockStats(stats);
2147 video_stream_encoder_->TriggerCpuOveruse();
2148 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2149 int adapted_framerate =
2150 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate();
2151 EXPECT_LT(adapted_framerate, kFramerate);
2152
2153 // Trigger underuse, max framerate should go back to codec configured fps.
2154 // Set extra low fps, to make sure it's actually reset, not just incremented.
2155 stats = stats_proxy_->GetStats();
2156 stats.input_frame_rate = adapted_framerate / 2;
2157 stats_proxy_->SetMockStats(stats);
2158 video_stream_encoder_->TriggerCpuNormalUsage();
2159 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2160 EXPECT_EQ(
2161 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2162 kFramerate);
2163
2164 video_stream_encoder_->Stop();
2165}
2166
2167TEST_F(VideoStreamEncoderTest,
2168 OveruseDetectorUpdatedRespectsFramerateAfterUnderuse) {
2169 const int kFrameWidth = 1280;
2170 const int kFrameHeight = 720;
2171 const int kLowFramerate = 15;
2172 const int kHighFramerate = 25;
2173
2174 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
2175 test::FrameForwarder source;
2176 video_stream_encoder_->SetSource(
2177 &source, VideoSendStream::DegradationPreference::kMaintainResolution);
2178
2179 // Trigger initial configuration.
2180 VideoEncoderConfig video_encoder_config;
Niels Möller259a4972018-04-05 15:36:51 +02002181 video_encoder_config.codec_type = kVideoCodecVP8;
Niels Möller7dc26b72017-12-06 10:27:48 +01002182 video_encoder_config.max_bitrate_bps = kTargetBitrateBps;
2183 video_encoder_config.number_of_streams = 1;
2184 video_encoder_config.video_stream_factory =
2185 new rtc::RefCountedObject<VideoStreamFactory>(1, kLowFramerate);
2186 source.IncomingCapturedFrame(CreateFrame(1, kFrameWidth, kFrameHeight));
2187 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
Niels Möllerf1338562018-04-26 09:51:47 +02002188 kMaxPayloadLength);
Niels Möller7dc26b72017-12-06 10:27:48 +01002189 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2190
2191 EXPECT_EQ(
2192 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2193 kLowFramerate);
2194
2195 // Trigger overuse, max framerate should be reduced.
2196 VideoSendStream::Stats stats = stats_proxy_->GetStats();
2197 stats.input_frame_rate = kLowFramerate;
2198 stats_proxy_->SetMockStats(stats);
2199 video_stream_encoder_->TriggerCpuOveruse();
2200 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2201 int adapted_framerate =
2202 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate();
2203 EXPECT_LT(adapted_framerate, kLowFramerate);
2204
2205 // Reconfigure the encoder with a new (higher max framerate), max fps should
2206 // still respect the adaptation.
2207 video_encoder_config.video_stream_factory =
2208 new rtc::RefCountedObject<VideoStreamFactory>(1, kHighFramerate);
2209 source.IncomingCapturedFrame(CreateFrame(1, kFrameWidth, kFrameHeight));
2210 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
Niels Möllerf1338562018-04-26 09:51:47 +02002211 kMaxPayloadLength);
Niels Möller7dc26b72017-12-06 10:27:48 +01002212 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2213
2214 EXPECT_EQ(
2215 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2216 adapted_framerate);
2217
2218 // Trigger underuse, max framerate should go back to codec configured fps.
2219 stats = stats_proxy_->GetStats();
2220 stats.input_frame_rate = adapted_framerate;
2221 stats_proxy_->SetMockStats(stats);
2222 video_stream_encoder_->TriggerCpuNormalUsage();
2223 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2224 EXPECT_EQ(
2225 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2226 kHighFramerate);
2227
2228 video_stream_encoder_->Stop();
2229}
2230
mflodmancc3d4422017-08-03 08:27:51 -07002231TEST_F(VideoStreamEncoderTest,
2232 OveruseDetectorUpdatedOnDegradationPreferenceChange) {
sprangfda496a2017-06-15 04:21:07 -07002233 const int kFrameWidth = 1280;
2234 const int kFrameHeight = 720;
2235 const int kFramerate = 24;
2236
mflodmancc3d4422017-08-03 08:27:51 -07002237 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
sprangfda496a2017-06-15 04:21:07 -07002238 test::FrameForwarder source;
mflodmancc3d4422017-08-03 08:27:51 -07002239 video_stream_encoder_->SetSource(
sprangfda496a2017-06-15 04:21:07 -07002240 &source, VideoSendStream::DegradationPreference::kMaintainResolution);
2241
2242 // Trigger initial configuration.
2243 VideoEncoderConfig video_encoder_config;
Niels Möller259a4972018-04-05 15:36:51 +02002244 video_encoder_config.codec_type = kVideoCodecVP8;
sprangfda496a2017-06-15 04:21:07 -07002245 video_encoder_config.max_bitrate_bps = kTargetBitrateBps;
2246 video_encoder_config.number_of_streams = 1;
2247 video_encoder_config.video_stream_factory =
2248 new rtc::RefCountedObject<VideoStreamFactory>(1, kFramerate);
2249 source.IncomingCapturedFrame(CreateFrame(1, kFrameWidth, kFrameHeight));
mflodmancc3d4422017-08-03 08:27:51 -07002250 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
Niels Möllerf1338562018-04-26 09:51:47 +02002251 kMaxPayloadLength);
mflodmancc3d4422017-08-03 08:27:51 -07002252 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
sprangfda496a2017-06-15 04:21:07 -07002253
Niels Möller7dc26b72017-12-06 10:27:48 +01002254 EXPECT_EQ(
2255 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2256 kFramerate);
sprangfda496a2017-06-15 04:21:07 -07002257
2258 // Trigger overuse, max framerate should be reduced.
2259 VideoSendStream::Stats stats = stats_proxy_->GetStats();
2260 stats.input_frame_rate = kFramerate;
2261 stats_proxy_->SetMockStats(stats);
mflodmancc3d4422017-08-03 08:27:51 -07002262 video_stream_encoder_->TriggerCpuOveruse();
2263 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
Niels Möller7dc26b72017-12-06 10:27:48 +01002264 int adapted_framerate =
2265 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate();
sprangfda496a2017-06-15 04:21:07 -07002266 EXPECT_LT(adapted_framerate, kFramerate);
2267
2268 // Change degradation preference to not enable framerate scaling. Target
2269 // framerate should be changed to codec defined limit.
mflodmancc3d4422017-08-03 08:27:51 -07002270 video_stream_encoder_->SetSource(
sprangfda496a2017-06-15 04:21:07 -07002271 &source, VideoSendStream::DegradationPreference::kMaintainFramerate);
mflodmancc3d4422017-08-03 08:27:51 -07002272 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
Niels Möller7dc26b72017-12-06 10:27:48 +01002273 EXPECT_EQ(
2274 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2275 kFramerate);
sprangfda496a2017-06-15 04:21:07 -07002276
mflodmancc3d4422017-08-03 08:27:51 -07002277 video_stream_encoder_->Stop();
sprangfda496a2017-06-15 04:21:07 -07002278}
2279
mflodmancc3d4422017-08-03 08:27:51 -07002280TEST_F(VideoStreamEncoderTest, DropsFramesAndScalesWhenBitrateIsTooLow) {
asaperssonfab67072017-04-04 05:51:49 -07002281 const int kTooLowBitrateForFrameSizeBps = 10000;
mflodmancc3d4422017-08-03 08:27:51 -07002282 video_stream_encoder_->OnBitrateUpdated(kTooLowBitrateForFrameSizeBps, 0, 0);
asaperssonfab67072017-04-04 05:51:49 -07002283 const int kWidth = 640;
2284 const int kHeight = 360;
kthelgason2bc68642017-02-07 07:02:22 -08002285
asaperssonfab67072017-04-04 05:51:49 -07002286 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
kthelgason2bc68642017-02-07 07:02:22 -08002287
2288 // Expect to drop this frame, the wait should time out.
sprang4847ae62017-06-27 07:06:52 -07002289 ExpectDroppedFrame();
kthelgason2bc68642017-02-07 07:02:22 -08002290
2291 // Expect the sink_wants to specify a scaled frame.
asapersson0944a802017-04-07 00:57:58 -07002292 EXPECT_LT(video_source_.sink_wants().max_pixel_count, kWidth * kHeight);
kthelgason2bc68642017-02-07 07:02:22 -08002293
sprangc5d62e22017-04-02 23:53:04 -07002294 int last_pixel_count = video_source_.sink_wants().max_pixel_count;
kthelgason2bc68642017-02-07 07:02:22 -08002295
asaperssonfab67072017-04-04 05:51:49 -07002296 // Next frame is scaled.
kthelgason2bc68642017-02-07 07:02:22 -08002297 video_source_.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07002298 CreateFrame(2, kWidth * 3 / 4, kHeight * 3 / 4));
kthelgason2bc68642017-02-07 07:02:22 -08002299
2300 // Expect to drop this frame, the wait should time out.
sprang4847ae62017-06-27 07:06:52 -07002301 ExpectDroppedFrame();
kthelgason2bc68642017-02-07 07:02:22 -08002302
sprangc5d62e22017-04-02 23:53:04 -07002303 EXPECT_LT(video_source_.sink_wants().max_pixel_count, last_pixel_count);
kthelgason2bc68642017-02-07 07:02:22 -08002304
mflodmancc3d4422017-08-03 08:27:51 -07002305 video_stream_encoder_->Stop();
kthelgason2bc68642017-02-07 07:02:22 -08002306}
2307
mflodmancc3d4422017-08-03 08:27:51 -07002308TEST_F(VideoStreamEncoderTest,
2309 NumberOfDroppedFramesLimitedWhenBitrateIsTooLow) {
asaperssonfab67072017-04-04 05:51:49 -07002310 const int kTooLowBitrateForFrameSizeBps = 10000;
mflodmancc3d4422017-08-03 08:27:51 -07002311 video_stream_encoder_->OnBitrateUpdated(kTooLowBitrateForFrameSizeBps, 0, 0);
asaperssonfab67072017-04-04 05:51:49 -07002312 const int kWidth = 640;
2313 const int kHeight = 360;
kthelgason2bc68642017-02-07 07:02:22 -08002314
2315 // We expect the n initial frames to get dropped.
2316 int i;
2317 for (i = 1; i <= kMaxInitialFramedrop; ++i) {
asaperssonfab67072017-04-04 05:51:49 -07002318 video_source_.IncomingCapturedFrame(CreateFrame(i, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002319 ExpectDroppedFrame();
kthelgason2bc68642017-02-07 07:02:22 -08002320 }
2321 // The n+1th frame should not be dropped, even though it's size is too large.
asaperssonfab67072017-04-04 05:51:49 -07002322 video_source_.IncomingCapturedFrame(CreateFrame(i, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002323 WaitForEncodedFrame(i);
kthelgason2bc68642017-02-07 07:02:22 -08002324
2325 // Expect the sink_wants to specify a scaled frame.
asaperssonfab67072017-04-04 05:51:49 -07002326 EXPECT_LT(video_source_.sink_wants().max_pixel_count, kWidth * kHeight);
kthelgason2bc68642017-02-07 07:02:22 -08002327
mflodmancc3d4422017-08-03 08:27:51 -07002328 video_stream_encoder_->Stop();
kthelgason2bc68642017-02-07 07:02:22 -08002329}
2330
mflodmancc3d4422017-08-03 08:27:51 -07002331TEST_F(VideoStreamEncoderTest,
2332 InitialFrameDropOffWithMaintainResolutionPreference) {
asaperssonfab67072017-04-04 05:51:49 -07002333 const int kWidth = 640;
2334 const int kHeight = 360;
mflodmancc3d4422017-08-03 08:27:51 -07002335 video_stream_encoder_->OnBitrateUpdated(kLowTargetBitrateBps, 0, 0);
kthelgason2bc68642017-02-07 07:02:22 -08002336
2337 // Set degradation preference.
mflodmancc3d4422017-08-03 08:27:51 -07002338 video_stream_encoder_->SetSource(
kthelgason2bc68642017-02-07 07:02:22 -08002339 &video_source_,
2340 VideoSendStream::DegradationPreference::kMaintainResolution);
2341
asaperssonfab67072017-04-04 05:51:49 -07002342 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
kthelgason2bc68642017-02-07 07:02:22 -08002343 // Frame should not be dropped, even if it's too large.
sprang4847ae62017-06-27 07:06:52 -07002344 WaitForEncodedFrame(1);
kthelgason2bc68642017-02-07 07:02:22 -08002345
mflodmancc3d4422017-08-03 08:27:51 -07002346 video_stream_encoder_->Stop();
kthelgason2bc68642017-02-07 07:02:22 -08002347}
2348
mflodmancc3d4422017-08-03 08:27:51 -07002349TEST_F(VideoStreamEncoderTest, InitialFrameDropOffWhenEncoderDisabledScaling) {
asaperssonfab67072017-04-04 05:51:49 -07002350 const int kWidth = 640;
2351 const int kHeight = 360;
kthelgasonad9010c2017-02-14 00:46:51 -08002352 fake_encoder_.SetQualityScaling(false);
Niels Möller4db138e2018-04-19 09:04:13 +02002353
2354 VideoEncoderConfig video_encoder_config;
2355 test::FillEncoderConfiguration(kVideoCodecVP8, 1, &video_encoder_config);
2356 // Make format different, to force recreation of encoder.
2357 video_encoder_config.video_format.parameters["foo"] = "foo";
2358 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
Niels Möllerf1338562018-04-26 09:51:47 +02002359 kMaxPayloadLength);
mflodmancc3d4422017-08-03 08:27:51 -07002360 video_stream_encoder_->OnBitrateUpdated(kLowTargetBitrateBps, 0, 0);
asapersson09f05612017-05-15 23:40:18 -07002361
kthelgasonb83797b2017-02-14 11:57:25 -08002362 // Force quality scaler reconfiguration by resetting the source.
mflodmancc3d4422017-08-03 08:27:51 -07002363 video_stream_encoder_->SetSource(
2364 &video_source_,
2365 VideoSendStream::DegradationPreference::kBalanced);
kthelgasonad9010c2017-02-14 00:46:51 -08002366
asaperssonfab67072017-04-04 05:51:49 -07002367 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
kthelgasonad9010c2017-02-14 00:46:51 -08002368 // Frame should not be dropped, even if it's too large.
sprang4847ae62017-06-27 07:06:52 -07002369 WaitForEncodedFrame(1);
kthelgasonad9010c2017-02-14 00:46:51 -08002370
mflodmancc3d4422017-08-03 08:27:51 -07002371 video_stream_encoder_->Stop();
kthelgasonad9010c2017-02-14 00:46:51 -08002372 fake_encoder_.SetQualityScaling(true);
2373}
2374
mflodmancc3d4422017-08-03 08:27:51 -07002375TEST_F(VideoStreamEncoderTest,
asaperssond0de2952017-04-21 01:47:31 -07002376 ResolutionNotAdaptedForTooSmallFrame_MaintainFramerateMode) {
2377 const int kTooSmallWidth = 10;
2378 const int kTooSmallHeight = 10;
mflodmancc3d4422017-08-03 08:27:51 -07002379 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssond0de2952017-04-21 01:47:31 -07002380
2381 // Enable kMaintainFramerate preference, no initial limitation.
2382 test::FrameForwarder source;
mflodmancc3d4422017-08-03 08:27:51 -07002383 video_stream_encoder_->SetSource(
asaperssond0de2952017-04-21 01:47:31 -07002384 &source, VideoSendStream::DegradationPreference::kMaintainFramerate);
2385 VerifyNoLimitation(source.sink_wants());
2386 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2387
2388 // Trigger adapt down, too small frame, expect no change.
2389 source.IncomingCapturedFrame(CreateFrame(1, kTooSmallWidth, kTooSmallHeight));
sprang4847ae62017-06-27 07:06:52 -07002390 WaitForEncodedFrame(1);
mflodmancc3d4422017-08-03 08:27:51 -07002391 video_stream_encoder_->TriggerCpuOveruse();
asaperssond0de2952017-04-21 01:47:31 -07002392 VerifyNoLimitation(source.sink_wants());
2393 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2394 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2395
mflodmancc3d4422017-08-03 08:27:51 -07002396 video_stream_encoder_->Stop();
asaperssond0de2952017-04-21 01:47:31 -07002397}
2398
mflodmancc3d4422017-08-03 08:27:51 -07002399TEST_F(VideoStreamEncoderTest,
2400 ResolutionNotAdaptedForTooSmallFrame_BalancedMode) {
asaperssonf7e294d2017-06-13 23:25:22 -07002401 const int kTooSmallWidth = 10;
2402 const int kTooSmallHeight = 10;
2403 const int kFpsLimit = 7;
mflodmancc3d4422017-08-03 08:27:51 -07002404 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -07002405
2406 // Enable kBalanced preference, no initial limitation.
2407 test::FrameForwarder source;
mflodmancc3d4422017-08-03 08:27:51 -07002408 video_stream_encoder_->SetSource(
2409 &source,
2410 VideoSendStream::DegradationPreference::kBalanced);
asaperssonf7e294d2017-06-13 23:25:22 -07002411 VerifyNoLimitation(source.sink_wants());
2412 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2413 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2414
2415 // Trigger adapt down, expect limited framerate.
2416 source.IncomingCapturedFrame(CreateFrame(1, kTooSmallWidth, kTooSmallHeight));
sprang4847ae62017-06-27 07:06:52 -07002417 WaitForEncodedFrame(1);
mflodmancc3d4422017-08-03 08:27:51 -07002418 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002419 VerifyFpsEqResolutionMax(source.sink_wants(), kFpsLimit);
2420 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2421 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2422 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2423
2424 // Trigger adapt down, too small frame, expect no change.
2425 source.IncomingCapturedFrame(CreateFrame(2, kTooSmallWidth, kTooSmallHeight));
sprang4847ae62017-06-27 07:06:52 -07002426 WaitForEncodedFrame(2);
mflodmancc3d4422017-08-03 08:27:51 -07002427 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002428 VerifyFpsEqResolutionMax(source.sink_wants(), kFpsLimit);
2429 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2430 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2431 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2432
mflodmancc3d4422017-08-03 08:27:51 -07002433 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07002434}
2435
mflodmancc3d4422017-08-03 08:27:51 -07002436TEST_F(VideoStreamEncoderTest, FailingInitEncodeDoesntCauseCrash) {
asapersson02465b82017-04-10 01:12:52 -07002437 fake_encoder_.ForceInitEncodeFailure(true);
mflodmancc3d4422017-08-03 08:27:51 -07002438 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
Niels Möllerf1338562018-04-26 09:51:47 +02002439 ResetEncoder("VP8", 2, 1, 1, false);
asapersson02465b82017-04-10 01:12:52 -07002440 const int kFrameWidth = 1280;
2441 const int kFrameHeight = 720;
2442 video_source_.IncomingCapturedFrame(
2443 CreateFrame(1, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002444 ExpectDroppedFrame();
mflodmancc3d4422017-08-03 08:27:51 -07002445 video_stream_encoder_->Stop();
asapersson02465b82017-04-10 01:12:52 -07002446}
2447
sprangb1ca0732017-02-01 08:38:12 -08002448// TODO(sprang): Extend this with fps throttling and any "balanced" extensions.
mflodmancc3d4422017-08-03 08:27:51 -07002449TEST_F(VideoStreamEncoderTest,
2450 AdaptsResolutionOnOveruse_MaintainFramerateMode) {
2451 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
sprangb1ca0732017-02-01 08:38:12 -08002452
2453 const int kFrameWidth = 1280;
2454 const int kFrameHeight = 720;
2455 // Enabled default VideoAdapter downscaling. First step is 3/4, not 3/5 as
mflodmancc3d4422017-08-03 08:27:51 -07002456 // requested by
2457 // VideoStreamEncoder::VideoSourceProxy::RequestResolutionLowerThan().
sprangb1ca0732017-02-01 08:38:12 -08002458 video_source_.set_adaptation_enabled(true);
2459
2460 video_source_.IncomingCapturedFrame(
2461 CreateFrame(1, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002462 WaitForEncodedFrame(kFrameWidth, kFrameHeight);
sprangb1ca0732017-02-01 08:38:12 -08002463
2464 // Trigger CPU overuse, downscale by 3/4.
mflodmancc3d4422017-08-03 08:27:51 -07002465 video_stream_encoder_->TriggerCpuOveruse();
sprangb1ca0732017-02-01 08:38:12 -08002466 video_source_.IncomingCapturedFrame(
2467 CreateFrame(2, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002468 WaitForEncodedFrame((kFrameWidth * 3) / 4, (kFrameHeight * 3) / 4);
sprangb1ca0732017-02-01 08:38:12 -08002469
asaperssonfab67072017-04-04 05:51:49 -07002470 // Trigger CPU normal use, return to original resolution.
mflodmancc3d4422017-08-03 08:27:51 -07002471 video_stream_encoder_->TriggerCpuNormalUsage();
sprangb1ca0732017-02-01 08:38:12 -08002472 video_source_.IncomingCapturedFrame(
2473 CreateFrame(3, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002474 WaitForEncodedFrame(kFrameWidth, kFrameHeight);
sprangb1ca0732017-02-01 08:38:12 -08002475
mflodmancc3d4422017-08-03 08:27:51 -07002476 video_stream_encoder_->Stop();
sprangb1ca0732017-02-01 08:38:12 -08002477}
sprangfe627f32017-03-29 08:24:59 -07002478
mflodmancc3d4422017-08-03 08:27:51 -07002479TEST_F(VideoStreamEncoderTest,
2480 AdaptsFramerateOnOveruse_MaintainResolutionMode) {
sprangc5d62e22017-04-02 23:53:04 -07002481 const int kFrameWidth = 1280;
2482 const int kFrameHeight = 720;
sprang4847ae62017-06-27 07:06:52 -07002483 int kFrameIntervalMs = rtc::kNumMillisecsPerSec / max_framerate_;
sprangc5d62e22017-04-02 23:53:04 -07002484
mflodmancc3d4422017-08-03 08:27:51 -07002485 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
2486 video_stream_encoder_->SetSource(
sprangc5d62e22017-04-02 23:53:04 -07002487 &video_source_,
2488 VideoSendStream::DegradationPreference::kMaintainResolution);
2489 video_source_.set_adaptation_enabled(true);
2490
sprang4847ae62017-06-27 07:06:52 -07002491 int64_t timestamp_ms = fake_clock_.TimeNanos() / rtc::kNumNanosecsPerMillisec;
sprangc5d62e22017-04-02 23:53:04 -07002492
2493 video_source_.IncomingCapturedFrame(
2494 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002495 WaitForEncodedFrame(timestamp_ms);
sprangc5d62e22017-04-02 23:53:04 -07002496
2497 // Try to trigger overuse. No fps estimate available => no effect.
mflodmancc3d4422017-08-03 08:27:51 -07002498 video_stream_encoder_->TriggerCpuOveruse();
sprangc5d62e22017-04-02 23:53:04 -07002499
2500 // Insert frames for one second to get a stable estimate.
sprang4847ae62017-06-27 07:06:52 -07002501 for (int i = 0; i < max_framerate_; ++i) {
sprangc5d62e22017-04-02 23:53:04 -07002502 timestamp_ms += kFrameIntervalMs;
sprangc5d62e22017-04-02 23:53:04 -07002503 video_source_.IncomingCapturedFrame(
2504 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002505 WaitForEncodedFrame(timestamp_ms);
sprangc5d62e22017-04-02 23:53:04 -07002506 }
2507
2508 // Trigger CPU overuse, reduce framerate by 2/3.
mflodmancc3d4422017-08-03 08:27:51 -07002509 video_stream_encoder_->TriggerCpuOveruse();
sprangc5d62e22017-04-02 23:53:04 -07002510 int num_frames_dropped = 0;
sprang4847ae62017-06-27 07:06:52 -07002511 for (int i = 0; i < max_framerate_; ++i) {
sprangc5d62e22017-04-02 23:53:04 -07002512 timestamp_ms += kFrameIntervalMs;
sprangc5d62e22017-04-02 23:53:04 -07002513 video_source_.IncomingCapturedFrame(
2514 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002515 if (!WaitForFrame(kFrameTimeoutMs)) {
sprangc5d62e22017-04-02 23:53:04 -07002516 ++num_frames_dropped;
2517 } else {
Åsa Perssonc74d8da2017-12-04 14:13:56 +01002518 sink_.CheckLastFrameSizeMatches(kFrameWidth, kFrameHeight);
sprangc5d62e22017-04-02 23:53:04 -07002519 }
2520 }
2521
sprang4847ae62017-06-27 07:06:52 -07002522 // Add some slack to account for frames dropped by the frame dropper.
2523 const int kErrorMargin = 1;
2524 EXPECT_NEAR(num_frames_dropped, max_framerate_ - (max_framerate_ * 2 / 3),
sprangc5d62e22017-04-02 23:53:04 -07002525 kErrorMargin);
2526
2527 // Trigger CPU overuse, reduce framerate by 2/3 again.
mflodmancc3d4422017-08-03 08:27:51 -07002528 video_stream_encoder_->TriggerCpuOveruse();
sprangc5d62e22017-04-02 23:53:04 -07002529 num_frames_dropped = 0;
sprang4847ae62017-06-27 07:06:52 -07002530 for (int i = 0; i < max_framerate_; ++i) {
sprangc5d62e22017-04-02 23:53:04 -07002531 timestamp_ms += kFrameIntervalMs;
sprangc5d62e22017-04-02 23:53:04 -07002532 video_source_.IncomingCapturedFrame(
2533 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002534 if (!WaitForFrame(kFrameTimeoutMs)) {
sprangc5d62e22017-04-02 23:53:04 -07002535 ++num_frames_dropped;
2536 } else {
Åsa Perssonc74d8da2017-12-04 14:13:56 +01002537 sink_.CheckLastFrameSizeMatches(kFrameWidth, kFrameHeight);
sprangc5d62e22017-04-02 23:53:04 -07002538 }
2539 }
sprang4847ae62017-06-27 07:06:52 -07002540 EXPECT_NEAR(num_frames_dropped, max_framerate_ - (max_framerate_ * 4 / 9),
sprangc5d62e22017-04-02 23:53:04 -07002541 kErrorMargin);
2542
2543 // Go back up one step.
mflodmancc3d4422017-08-03 08:27:51 -07002544 video_stream_encoder_->TriggerCpuNormalUsage();
sprangc5d62e22017-04-02 23:53:04 -07002545 num_frames_dropped = 0;
sprang4847ae62017-06-27 07:06:52 -07002546 for (int i = 0; i < max_framerate_; ++i) {
sprangc5d62e22017-04-02 23:53:04 -07002547 timestamp_ms += kFrameIntervalMs;
sprangc5d62e22017-04-02 23:53:04 -07002548 video_source_.IncomingCapturedFrame(
2549 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002550 if (!WaitForFrame(kFrameTimeoutMs)) {
sprangc5d62e22017-04-02 23:53:04 -07002551 ++num_frames_dropped;
2552 } else {
Åsa Perssonc74d8da2017-12-04 14:13:56 +01002553 sink_.CheckLastFrameSizeMatches(kFrameWidth, kFrameHeight);
sprangc5d62e22017-04-02 23:53:04 -07002554 }
2555 }
sprang4847ae62017-06-27 07:06:52 -07002556 EXPECT_NEAR(num_frames_dropped, max_framerate_ - (max_framerate_ * 2 / 3),
sprangc5d62e22017-04-02 23:53:04 -07002557 kErrorMargin);
2558
2559 // Go back up to original mode.
mflodmancc3d4422017-08-03 08:27:51 -07002560 video_stream_encoder_->TriggerCpuNormalUsage();
sprangc5d62e22017-04-02 23:53:04 -07002561 num_frames_dropped = 0;
sprang4847ae62017-06-27 07:06:52 -07002562 for (int i = 0; i < max_framerate_; ++i) {
sprangc5d62e22017-04-02 23:53:04 -07002563 timestamp_ms += kFrameIntervalMs;
sprangc5d62e22017-04-02 23:53:04 -07002564 video_source_.IncomingCapturedFrame(
2565 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002566 if (!WaitForFrame(kFrameTimeoutMs)) {
sprangc5d62e22017-04-02 23:53:04 -07002567 ++num_frames_dropped;
2568 } else {
Åsa Perssonc74d8da2017-12-04 14:13:56 +01002569 sink_.CheckLastFrameSizeMatches(kFrameWidth, kFrameHeight);
sprangc5d62e22017-04-02 23:53:04 -07002570 }
2571 }
2572 EXPECT_NEAR(num_frames_dropped, 0, kErrorMargin);
2573
mflodmancc3d4422017-08-03 08:27:51 -07002574 video_stream_encoder_->Stop();
sprangc5d62e22017-04-02 23:53:04 -07002575}
2576
mflodmancc3d4422017-08-03 08:27:51 -07002577TEST_F(VideoStreamEncoderTest, DoesntAdaptDownPastMinFramerate) {
sprangc5d62e22017-04-02 23:53:04 -07002578 const int kFramerateFps = 5;
2579 const int kFrameIntervalMs = rtc::kNumMillisecsPerSec / kFramerateFps;
sprangc5d62e22017-04-02 23:53:04 -07002580 const int kFrameWidth = 1280;
2581 const int kFrameHeight = 720;
2582
sprang4847ae62017-06-27 07:06:52 -07002583 // Reconfigure encoder with two temporal layers and screensharing, which will
2584 // disable frame dropping and make testing easier.
Niels Möllerf1338562018-04-26 09:51:47 +02002585 ResetEncoder("VP8", 1, 2, 1, true);
sprang4847ae62017-06-27 07:06:52 -07002586
mflodmancc3d4422017-08-03 08:27:51 -07002587 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
2588 video_stream_encoder_->SetSource(
sprangc5d62e22017-04-02 23:53:04 -07002589 &video_source_,
2590 VideoSendStream::DegradationPreference::kMaintainResolution);
2591 video_source_.set_adaptation_enabled(true);
2592
sprang4847ae62017-06-27 07:06:52 -07002593 int64_t timestamp_ms = fake_clock_.TimeNanos() / rtc::kNumNanosecsPerMillisec;
sprangc5d62e22017-04-02 23:53:04 -07002594
2595 // Trigger overuse as much as we can.
Jonathan Yubc771b72017-12-08 17:04:29 -08002596 rtc::VideoSinkWants last_wants;
2597 do {
2598 last_wants = video_source_.sink_wants();
2599
sprangc5d62e22017-04-02 23:53:04 -07002600 // Insert frames to get a new fps estimate...
2601 for (int j = 0; j < kFramerateFps; ++j) {
2602 video_source_.IncomingCapturedFrame(
2603 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
Jonathan Yubc771b72017-12-08 17:04:29 -08002604 if (video_source_.last_sent_width()) {
2605 sink_.WaitForEncodedFrame(timestamp_ms);
2606 }
sprangc5d62e22017-04-02 23:53:04 -07002607 timestamp_ms += kFrameIntervalMs;
Jonathan Yubc771b72017-12-08 17:04:29 -08002608 fake_clock_.AdvanceTimeMicros(
2609 kFrameIntervalMs * rtc::kNumMicrosecsPerMillisec);
sprangc5d62e22017-04-02 23:53:04 -07002610 }
2611 // ...and then try to adapt again.
mflodmancc3d4422017-08-03 08:27:51 -07002612 video_stream_encoder_->TriggerCpuOveruse();
Jonathan Yubc771b72017-12-08 17:04:29 -08002613 } while (video_source_.sink_wants().max_framerate_fps <
2614 last_wants.max_framerate_fps);
sprangc5d62e22017-04-02 23:53:04 -07002615
Jonathan Yubc771b72017-12-08 17:04:29 -08002616 VerifyFpsEqResolutionMax(video_source_.sink_wants(), kMinFramerateFps);
asaperssonf7e294d2017-06-13 23:25:22 -07002617
mflodmancc3d4422017-08-03 08:27:51 -07002618 video_stream_encoder_->Stop();
sprangc5d62e22017-04-02 23:53:04 -07002619}
asaperssonf7e294d2017-06-13 23:25:22 -07002620
mflodmancc3d4422017-08-03 08:27:51 -07002621TEST_F(VideoStreamEncoderTest,
2622 AdaptsResolutionAndFramerateForLowQuality_BalancedMode) {
asaperssonf7e294d2017-06-13 23:25:22 -07002623 const int kWidth = 1280;
2624 const int kHeight = 720;
2625 const int64_t kFrameIntervalMs = 150;
2626 int64_t timestamp_ms = kFrameIntervalMs;
mflodmancc3d4422017-08-03 08:27:51 -07002627 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -07002628
2629 // Enable kBalanced preference, no initial limitation.
2630 AdaptingFrameForwarder source;
2631 source.set_adaptation_enabled(true);
mflodmancc3d4422017-08-03 08:27:51 -07002632 video_stream_encoder_->SetSource(
2633 &source,
2634 VideoSendStream::DegradationPreference::kBalanced);
asaperssonf7e294d2017-06-13 23:25:22 -07002635 timestamp_ms += kFrameIntervalMs;
2636 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002637 WaitForEncodedFrame(kWidth, kHeight);
asaperssonf7e294d2017-06-13 23:25:22 -07002638 VerifyNoLimitation(source.sink_wants());
2639 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2640 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2641 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2642
2643 // Trigger adapt down, expect scaled down resolution (960x540@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002644 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002645 timestamp_ms += kFrameIntervalMs;
2646 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002647 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002648 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
2649 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2650 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2651 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2652
2653 // Trigger adapt down, expect scaled down resolution (640x360@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002654 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002655 timestamp_ms += kFrameIntervalMs;
2656 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002657 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002658 VerifyFpsMaxResolutionLt(source.sink_wants(), source.last_wants());
2659 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2660 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2661 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2662
2663 // Trigger adapt down, expect reduced fps (640x360@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07002664 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002665 timestamp_ms += kFrameIntervalMs;
2666 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002667 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002668 VerifyFpsLtResolutionEq(source.sink_wants(), source.last_wants());
2669 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2670 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2671 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2672
2673 // Trigger adapt down, expect scaled down resolution (480x270@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07002674 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002675 timestamp_ms += kFrameIntervalMs;
2676 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002677 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002678 VerifyFpsEqResolutionLt(source.sink_wants(), source.last_wants());
2679 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2680 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2681 EXPECT_EQ(4, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2682
2683 // Restrict bitrate, trigger adapt down, expect reduced fps (480x270@10fps).
mflodmancc3d4422017-08-03 08:27:51 -07002684 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002685 timestamp_ms += kFrameIntervalMs;
2686 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002687 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002688 VerifyFpsLtResolutionEq(source.sink_wants(), source.last_wants());
2689 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2690 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2691 EXPECT_EQ(5, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2692
2693 // Trigger adapt down, expect scaled down resolution (320x180@10fps).
mflodmancc3d4422017-08-03 08:27:51 -07002694 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002695 timestamp_ms += kFrameIntervalMs;
2696 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002697 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002698 VerifyFpsEqResolutionLt(source.sink_wants(), source.last_wants());
2699 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2700 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2701 EXPECT_EQ(6, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2702
2703 // Trigger adapt down, expect reduced fps (320x180@7fps).
mflodmancc3d4422017-08-03 08:27:51 -07002704 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002705 timestamp_ms += kFrameIntervalMs;
2706 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002707 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002708 VerifyFpsLtResolutionEq(source.sink_wants(), source.last_wants());
2709 rtc::VideoSinkWants last_wants = source.sink_wants();
2710 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2711 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2712 EXPECT_EQ(7, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2713
2714 // Trigger adapt down, min resolution reached, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07002715 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002716 timestamp_ms += kFrameIntervalMs;
2717 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002718 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002719 VerifyFpsEqResolutionEq(source.sink_wants(), last_wants);
2720 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2721 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2722 EXPECT_EQ(7, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2723
2724 // Trigger adapt down, expect expect increased fps (320x180@10fps).
mflodmancc3d4422017-08-03 08:27:51 -07002725 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002726 timestamp_ms += kFrameIntervalMs;
2727 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002728 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002729 VerifyFpsGtResolutionEq(source.sink_wants(), source.last_wants());
2730 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2731 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2732 EXPECT_EQ(8, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2733
2734 // Trigger adapt up, expect upscaled resolution (480x270@10fps).
mflodmancc3d4422017-08-03 08:27:51 -07002735 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002736 timestamp_ms += kFrameIntervalMs;
2737 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002738 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002739 VerifyFpsEqResolutionGt(source.sink_wants(), source.last_wants());
2740 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2741 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2742 EXPECT_EQ(9, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2743
2744 // Increase bitrate, trigger adapt up, expect increased fps (480x270@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07002745 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002746 timestamp_ms += kFrameIntervalMs;
2747 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002748 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002749 VerifyFpsGtResolutionEq(source.sink_wants(), source.last_wants());
2750 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2751 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2752 EXPECT_EQ(10, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2753
2754 // Trigger adapt up, expect upscaled resolution (640x360@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07002755 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002756 timestamp_ms += kFrameIntervalMs;
2757 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002758 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002759 VerifyFpsEqResolutionGt(source.sink_wants(), source.last_wants());
2760 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2761 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2762 EXPECT_EQ(11, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2763
2764 // Trigger adapt up, expect increased fps (640x360@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002765 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002766 timestamp_ms += kFrameIntervalMs;
2767 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002768 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002769 VerifyFpsMaxResolutionEq(source.sink_wants(), source.last_wants());
2770 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2771 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2772 EXPECT_EQ(12, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2773
2774 // Trigger adapt up, expect upscaled resolution (960x540@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002775 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002776 timestamp_ms += kFrameIntervalMs;
2777 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002778 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002779 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
2780 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2781 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2782 EXPECT_EQ(13, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2783
2784 // Trigger adapt up, expect no restriction (1280x720fps@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002785 video_stream_encoder_->TriggerQualityHigh();
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 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
2790 VerifyNoLimitation(source.sink_wants());
2791 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2792 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2793 EXPECT_EQ(14, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2794
2795 // Trigger adapt up, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07002796 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002797 VerifyNoLimitation(source.sink_wants());
2798 EXPECT_EQ(14, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2799
mflodmancc3d4422017-08-03 08:27:51 -07002800 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07002801}
2802
mflodmancc3d4422017-08-03 08:27:51 -07002803TEST_F(VideoStreamEncoderTest, AdaptWithTwoReasonsAndDifferentOrder_Framerate) {
asaperssonf7e294d2017-06-13 23:25:22 -07002804 const int kWidth = 1280;
2805 const int kHeight = 720;
2806 const int64_t kFrameIntervalMs = 150;
2807 int64_t timestamp_ms = kFrameIntervalMs;
mflodmancc3d4422017-08-03 08:27:51 -07002808 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -07002809
2810 // Enable kBalanced preference, no initial limitation.
2811 AdaptingFrameForwarder source;
2812 source.set_adaptation_enabled(true);
mflodmancc3d4422017-08-03 08:27:51 -07002813 video_stream_encoder_->SetSource(
2814 &source,
2815 VideoSendStream::DegradationPreference::kBalanced);
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(kWidth, kHeight);
asaperssonf7e294d2017-06-13 23:25:22 -07002819 VerifyNoLimitation(source.sink_wants());
2820 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2821 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2822 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2823 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
2824 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2825 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2826
2827 // Trigger cpu adapt down, expect scaled down resolution (960x540@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002828 video_stream_encoder_->TriggerCpuOveruse();
asaperssonf7e294d2017-06-13 23:25:22 -07002829 timestamp_ms += kFrameIntervalMs;
2830 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002831 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002832 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
2833 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2834 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2835 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2836 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
2837 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2838 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2839
2840 // Trigger cpu adapt down, expect scaled down resolution (640x360@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002841 video_stream_encoder_->TriggerCpuOveruse();
asaperssonf7e294d2017-06-13 23:25:22 -07002842 timestamp_ms += kFrameIntervalMs;
2843 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002844 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002845 VerifyFpsMaxResolutionLt(source.sink_wants(), source.last_wants());
2846 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2847 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2848 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2849 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
2850 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2851 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2852
2853 // Trigger quality adapt down, expect reduced fps (640x360@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07002854 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002855 timestamp_ms += kFrameIntervalMs;
2856 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002857 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002858 VerifyFpsLtResolutionEq(source.sink_wants(), source.last_wants());
2859 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2860 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2861 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2862 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
2863 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2864 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2865
2866 // Trigger cpu adapt up, expect increased fps (640x360@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002867 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssonf7e294d2017-06-13 23:25:22 -07002868 timestamp_ms += kFrameIntervalMs;
2869 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002870 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002871 VerifyFpsMaxResolutionEq(source.sink_wants(), source.last_wants());
2872 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2873 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2874 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2875 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
2876 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2877 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2878
2879 // Trigger quality adapt up, expect upscaled resolution (960x540@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002880 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002881 timestamp_ms += kFrameIntervalMs;
2882 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002883 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002884 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
2885 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2886 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2887 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2888 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
2889 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2890 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2891
2892 // Trigger cpu adapt up, expect no restriction (1280x720fps@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002893 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssonf7e294d2017-06-13 23:25:22 -07002894 timestamp_ms += kFrameIntervalMs;
2895 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002896 WaitForEncodedFrame(kWidth, kHeight);
asaperssonf7e294d2017-06-13 23:25:22 -07002897 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
2898 VerifyNoLimitation(source.sink_wants());
2899 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2900 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2901 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2902 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
2903 EXPECT_EQ(4, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2904 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2905
2906 // Trigger adapt up, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07002907 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002908 VerifyNoLimitation(source.sink_wants());
2909 EXPECT_EQ(4, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2910 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2911
mflodmancc3d4422017-08-03 08:27:51 -07002912 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07002913}
2914
mflodmancc3d4422017-08-03 08:27:51 -07002915TEST_F(VideoStreamEncoderTest,
2916 AdaptWithTwoReasonsAndDifferentOrder_Resolution) {
asaperssonf7e294d2017-06-13 23:25:22 -07002917 const int kWidth = 640;
2918 const int kHeight = 360;
2919 const int kFpsLimit = 15;
2920 const int64_t kFrameIntervalMs = 150;
2921 int64_t timestamp_ms = kFrameIntervalMs;
mflodmancc3d4422017-08-03 08:27:51 -07002922 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -07002923
2924 // Enable kBalanced preference, no initial limitation.
2925 AdaptingFrameForwarder source;
2926 source.set_adaptation_enabled(true);
mflodmancc3d4422017-08-03 08:27:51 -07002927 video_stream_encoder_->SetSource(
2928 &source,
2929 VideoSendStream::DegradationPreference::kBalanced);
asaperssonf7e294d2017-06-13 23:25:22 -07002930 timestamp_ms += kFrameIntervalMs;
2931 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002932 WaitForEncodedFrame(kWidth, kHeight);
asaperssonf7e294d2017-06-13 23:25:22 -07002933 VerifyNoLimitation(source.sink_wants());
2934 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2935 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2936 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2937 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
2938 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2939 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2940
2941 // Trigger cpu adapt down, expect scaled down framerate (640x360@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07002942 video_stream_encoder_->TriggerCpuOveruse();
asaperssonf7e294d2017-06-13 23:25:22 -07002943 timestamp_ms += kFrameIntervalMs;
2944 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002945 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002946 VerifyFpsEqResolutionMax(source.sink_wants(), kFpsLimit);
2947 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2948 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2949 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2950 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_framerate);
2951 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2952 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2953
2954 // Trigger quality adapt down, expect scaled down resolution (480x270@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07002955 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002956 timestamp_ms += kFrameIntervalMs;
2957 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002958 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002959 VerifyFpsEqResolutionLt(source.sink_wants(), source.last_wants());
2960 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2961 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2962 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2963 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_framerate);
2964 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2965 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2966
2967 // Trigger cpu adapt up, expect upscaled resolution (640x360@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07002968 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssonf7e294d2017-06-13 23:25:22 -07002969 timestamp_ms += kFrameIntervalMs;
2970 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002971 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002972 VerifyFpsEqResolutionGt(source.sink_wants(), source.last_wants());
2973 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2974 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2975 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2976 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
2977 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2978 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2979
2980 // Trigger quality adapt up, expect increased fps (640x360@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002981 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002982 timestamp_ms += kFrameIntervalMs;
2983 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002984 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002985 VerifyNoLimitation(source.sink_wants());
2986 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2987 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2988 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2989 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
2990 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2991 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2992
2993 // Trigger adapt up, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07002994 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002995 VerifyNoLimitation(source.sink_wants());
2996 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2997 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2998
mflodmancc3d4422017-08-03 08:27:51 -07002999 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07003000}
3001
mflodmancc3d4422017-08-03 08:27:51 -07003002TEST_F(VideoStreamEncoderTest, AcceptsFullHdAdaptedDownSimulcastFrames) {
ilnik6b826ef2017-06-16 06:53:48 -07003003 // Simulates simulcast behavior and makes highest stream resolutions divisible
3004 // by 4.
3005 class CroppingVideoStreamFactory
3006 : public VideoEncoderConfig::VideoStreamFactoryInterface {
3007 public:
3008 explicit CroppingVideoStreamFactory(size_t num_temporal_layers,
3009 int framerate)
3010 : num_temporal_layers_(num_temporal_layers), framerate_(framerate) {
3011 EXPECT_GT(num_temporal_layers, 0u);
3012 EXPECT_GT(framerate, 0);
3013 }
3014
3015 private:
3016 std::vector<VideoStream> CreateEncoderStreams(
3017 int width,
3018 int height,
3019 const VideoEncoderConfig& encoder_config) override {
3020 std::vector<VideoStream> streams =
3021 test::CreateVideoStreams(width - width % 4, height - height % 4,
3022 encoder_config);
3023 for (VideoStream& stream : streams) {
Sergey Silkina796a7e2018-03-01 15:11:29 +01003024 stream.num_temporal_layers = num_temporal_layers_;
ilnik6b826ef2017-06-16 06:53:48 -07003025 stream.max_framerate = framerate_;
3026 }
3027 return streams;
3028 }
3029
3030 const size_t num_temporal_layers_;
3031 const int framerate_;
3032 };
3033
3034 const int kFrameWidth = 1920;
3035 const int kFrameHeight = 1080;
3036 // 3/4 of 1920.
3037 const int kAdaptedFrameWidth = 1440;
3038 // 3/4 of 1080 rounded down to multiple of 4.
3039 const int kAdaptedFrameHeight = 808;
3040 const int kFramerate = 24;
3041
mflodmancc3d4422017-08-03 08:27:51 -07003042 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
ilnik6b826ef2017-06-16 06:53:48 -07003043 // Trigger reconfigure encoder (without resetting the entire instance).
3044 VideoEncoderConfig video_encoder_config;
Niels Möller259a4972018-04-05 15:36:51 +02003045 video_encoder_config.codec_type = kVideoCodecVP8;
ilnik6b826ef2017-06-16 06:53:48 -07003046 video_encoder_config.max_bitrate_bps = kTargetBitrateBps;
3047 video_encoder_config.number_of_streams = 1;
3048 video_encoder_config.video_stream_factory =
3049 new rtc::RefCountedObject<CroppingVideoStreamFactory>(1, kFramerate);
mflodmancc3d4422017-08-03 08:27:51 -07003050 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
Niels Möllerf1338562018-04-26 09:51:47 +02003051 kMaxPayloadLength);
mflodmancc3d4422017-08-03 08:27:51 -07003052 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
ilnik6b826ef2017-06-16 06:53:48 -07003053
3054 video_source_.set_adaptation_enabled(true);
3055
3056 video_source_.IncomingCapturedFrame(
3057 CreateFrame(1, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07003058 WaitForEncodedFrame(kFrameWidth, kFrameHeight);
ilnik6b826ef2017-06-16 06:53:48 -07003059
3060 // Trigger CPU overuse, downscale by 3/4.
mflodmancc3d4422017-08-03 08:27:51 -07003061 video_stream_encoder_->TriggerCpuOveruse();
ilnik6b826ef2017-06-16 06:53:48 -07003062 video_source_.IncomingCapturedFrame(
3063 CreateFrame(2, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07003064 WaitForEncodedFrame(kAdaptedFrameWidth, kAdaptedFrameHeight);
ilnik6b826ef2017-06-16 06:53:48 -07003065
mflodmancc3d4422017-08-03 08:27:51 -07003066 video_stream_encoder_->Stop();
ilnik6b826ef2017-06-16 06:53:48 -07003067}
3068
mflodmancc3d4422017-08-03 08:27:51 -07003069TEST_F(VideoStreamEncoderTest, PeriodicallyUpdatesChannelParameters) {
sprang4847ae62017-06-27 07:06:52 -07003070 const int kFrameWidth = 1280;
3071 const int kFrameHeight = 720;
3072 const int kLowFps = 2;
3073 const int kHighFps = 30;
3074
mflodmancc3d4422017-08-03 08:27:51 -07003075 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
sprang4847ae62017-06-27 07:06:52 -07003076
3077 int64_t timestamp_ms = fake_clock_.TimeNanos() / rtc::kNumNanosecsPerMillisec;
3078 max_framerate_ = kLowFps;
3079
3080 // Insert 2 seconds of 2fps video.
3081 for (int i = 0; i < kLowFps * 2; ++i) {
3082 video_source_.IncomingCapturedFrame(
3083 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
3084 WaitForEncodedFrame(timestamp_ms);
3085 timestamp_ms += 1000 / kLowFps;
3086 }
3087
3088 // Make sure encoder is updated with new target.
mflodmancc3d4422017-08-03 08:27:51 -07003089 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
sprang4847ae62017-06-27 07:06:52 -07003090 video_source_.IncomingCapturedFrame(
3091 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
3092 WaitForEncodedFrame(timestamp_ms);
3093 timestamp_ms += 1000 / kLowFps;
3094
3095 EXPECT_EQ(kLowFps, fake_encoder_.GetConfiguredInputFramerate());
3096
3097 // Insert 30fps frames for just a little more than the forced update period.
3098 const int kVcmTimerIntervalFrames =
3099 (vcm::VCMProcessTimer::kDefaultProcessIntervalMs * kHighFps) / 1000;
3100 const int kFrameIntervalMs = 1000 / kHighFps;
3101 max_framerate_ = kHighFps;
3102 for (int i = 0; i < kVcmTimerIntervalFrames + 2; ++i) {
3103 video_source_.IncomingCapturedFrame(
3104 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
3105 // Wait for encoded frame, but skip ahead if it doesn't arrive as it might
3106 // be dropped if the encoder hans't been updated with the new higher target
3107 // framerate yet, causing it to overshoot the target bitrate and then
3108 // suffering the wrath of the media optimizer.
3109 TimedWaitForEncodedFrame(timestamp_ms, 2 * kFrameIntervalMs);
3110 timestamp_ms += kFrameIntervalMs;
3111 }
3112
3113 // Don expect correct measurement just yet, but it should be higher than
3114 // before.
3115 EXPECT_GT(fake_encoder_.GetConfiguredInputFramerate(), kLowFps);
3116
mflodmancc3d4422017-08-03 08:27:51 -07003117 video_stream_encoder_->Stop();
sprang4847ae62017-06-27 07:06:52 -07003118}
3119
mflodmancc3d4422017-08-03 08:27:51 -07003120TEST_F(VideoStreamEncoderTest, DoesNotUpdateBitrateAllocationWhenSuspended) {
sprang4847ae62017-06-27 07:06:52 -07003121 const int kFrameWidth = 1280;
3122 const int kFrameHeight = 720;
3123 const int kTargetBitrateBps = 1000000;
3124
3125 MockBitrateObserver bitrate_observer;
mflodmancc3d4422017-08-03 08:27:51 -07003126 video_stream_encoder_->SetBitrateObserver(&bitrate_observer);
sprang4847ae62017-06-27 07:06:52 -07003127
3128 EXPECT_CALL(bitrate_observer, OnBitrateAllocationUpdated(_)).Times(1);
3129 // Initial bitrate update.
mflodmancc3d4422017-08-03 08:27:51 -07003130 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
3131 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
sprang4847ae62017-06-27 07:06:52 -07003132
3133 // Insert a first video frame, causes another bitrate update.
3134 int64_t timestamp_ms = fake_clock_.TimeNanos() / rtc::kNumNanosecsPerMillisec;
3135 EXPECT_CALL(bitrate_observer, OnBitrateAllocationUpdated(_)).Times(1);
3136 video_source_.IncomingCapturedFrame(
3137 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
3138 WaitForEncodedFrame(timestamp_ms);
3139
3140 // Next, simulate video suspension due to pacer queue overrun.
mflodmancc3d4422017-08-03 08:27:51 -07003141 video_stream_encoder_->OnBitrateUpdated(0, 0, 1);
sprang4847ae62017-06-27 07:06:52 -07003142
3143 // Skip ahead until a new periodic parameter update should have occured.
3144 timestamp_ms += vcm::VCMProcessTimer::kDefaultProcessIntervalMs;
3145 fake_clock_.AdvanceTimeMicros(
3146 vcm::VCMProcessTimer::kDefaultProcessIntervalMs *
3147 rtc::kNumMicrosecsPerMillisec);
3148
3149 // Bitrate observer should not be called.
3150 EXPECT_CALL(bitrate_observer, OnBitrateAllocationUpdated(_)).Times(0);
3151 video_source_.IncomingCapturedFrame(
3152 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
3153 ExpectDroppedFrame();
3154
mflodmancc3d4422017-08-03 08:27:51 -07003155 video_stream_encoder_->Stop();
sprang4847ae62017-06-27 07:06:52 -07003156}
ilnik6b826ef2017-06-16 06:53:48 -07003157
Niels Möller4db138e2018-04-19 09:04:13 +02003158TEST_F(VideoStreamEncoderTest,
3159 DefaultCpuAdaptationThresholdsForSoftwareEncoder) {
3160 const int kFrameWidth = 1280;
3161 const int kFrameHeight = 720;
3162 const CpuOveruseOptions default_options;
3163 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
3164 video_source_.IncomingCapturedFrame(
3165 CreateFrame(1, kFrameWidth, kFrameHeight));
3166 WaitForEncodedFrame(1);
3167 EXPECT_EQ(video_stream_encoder_->overuse_detector_proxy_->GetOptions()
3168 .low_encode_usage_threshold_percent,
3169 default_options.low_encode_usage_threshold_percent);
3170 EXPECT_EQ(video_stream_encoder_->overuse_detector_proxy_->GetOptions()
3171 .high_encode_usage_threshold_percent,
3172 default_options.high_encode_usage_threshold_percent);
3173 video_stream_encoder_->Stop();
3174}
3175
3176TEST_F(VideoStreamEncoderTest,
3177 HigherCpuAdaptationThresholdsForHardwareEncoder) {
3178 const int kFrameWidth = 1280;
3179 const int kFrameHeight = 720;
3180 CpuOveruseOptions hardware_options;
3181 hardware_options.low_encode_usage_threshold_percent = 150;
3182 hardware_options.high_encode_usage_threshold_percent = 200;
3183 encoder_factory_.SetIsHardwareAccelerated(true);
3184
3185 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
3186 video_source_.IncomingCapturedFrame(
3187 CreateFrame(1, kFrameWidth, kFrameHeight));
3188 WaitForEncodedFrame(1);
3189 EXPECT_EQ(video_stream_encoder_->overuse_detector_proxy_->GetOptions()
3190 .low_encode_usage_threshold_percent,
3191 hardware_options.low_encode_usage_threshold_percent);
3192 EXPECT_EQ(video_stream_encoder_->overuse_detector_proxy_->GetOptions()
3193 .high_encode_usage_threshold_percent,
3194 hardware_options.high_encode_usage_threshold_percent);
3195 video_stream_encoder_->Stop();
3196}
3197
perkj26091b12016-09-01 01:17:40 -07003198} // namespace webrtc