blob: 7324b800589499e0afa5b13519a1d500caee5fef [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
sprangb1ca0732017-02-01 08:38:12 -080042using ScaleReason = AdaptationObserverInterface::AdaptReason;
sprang57c2fff2017-01-16 06:24:02 -080043using ::testing::_;
44using ::testing::Return;
kthelgason876222f2016-11-29 01:44:11 -080045
perkj803d97f2016-11-01 11:45:46 -070046namespace {
asapersson5f7226f2016-11-25 04:37:00 -080047const size_t kMaxPayloadLength = 1440;
kthelgason2bc68642017-02-07 07:02:22 -080048const int kTargetBitrateBps = 1000000;
49const int kLowTargetBitrateBps = kTargetBitrateBps / 10;
50const int kMaxInitialFramedrop = 4;
sprangfda496a2017-06-15 04:21:07 -070051const int kDefaultFramerate = 30;
asapersson5f7226f2016-11-25 04:37:00 -080052
perkj803d97f2016-11-01 11:45:46 -070053class TestBuffer : public webrtc::I420Buffer {
54 public:
55 TestBuffer(rtc::Event* event, int width, int height)
56 : I420Buffer(width, height), event_(event) {}
57
58 private:
59 friend class rtc::RefCountedObject<TestBuffer>;
60 ~TestBuffer() override {
61 if (event_)
62 event_->Set();
63 }
64 rtc::Event* const event_;
65};
66
Niels Möller7dc26b72017-12-06 10:27:48 +010067class CpuOveruseDetectorProxy : public OveruseFrameDetector {
68 public:
Niels Möllerd1f7eb62018-03-28 16:40:58 +020069 explicit CpuOveruseDetectorProxy(CpuOveruseMetricsObserver* metrics_observer)
70 : OveruseFrameDetector(metrics_observer),
Niels Möller7dc26b72017-12-06 10:27:48 +010071 last_target_framerate_fps_(-1) {}
72 virtual ~CpuOveruseDetectorProxy() {}
73
74 void OnTargetFramerateUpdated(int framerate_fps) override {
75 rtc::CritScope cs(&lock_);
76 last_target_framerate_fps_ = framerate_fps;
77 OveruseFrameDetector::OnTargetFramerateUpdated(framerate_fps);
78 }
79
80 int GetLastTargetFramerate() {
81 rtc::CritScope cs(&lock_);
82 return last_target_framerate_fps_;
83 }
84
Niels Möller4db138e2018-04-19 09:04:13 +020085 CpuOveruseOptions GetOptions() { return options_; }
86
Niels Möller7dc26b72017-12-06 10:27:48 +010087 private:
88 rtc::CriticalSection lock_;
89 int last_target_framerate_fps_ RTC_GUARDED_BY(lock_);
90};
91
mflodmancc3d4422017-08-03 08:27:51 -070092class VideoStreamEncoderUnderTest : public VideoStreamEncoder {
perkj803d97f2016-11-01 11:45:46 -070093 public:
Yves Gerey665174f2018-06-19 15:03:05 +020094 VideoStreamEncoderUnderTest(
95 SendStatisticsProxy* stats_proxy,
96 const VideoSendStream::Config::EncoderSettings& settings)
97 : VideoStreamEncoder(1 /* number_of_cores */,
98 stats_proxy,
99 settings,
100 nullptr /* pre_encode_callback */,
101 std::unique_ptr<OveruseFrameDetector>(
102 overuse_detector_proxy_ =
103 new CpuOveruseDetectorProxy(stats_proxy))) {}
perkj803d97f2016-11-01 11:45:46 -0700104
sprangb1ca0732017-02-01 08:38:12 -0800105 void PostTaskAndWait(bool down, AdaptReason reason) {
perkj803d97f2016-11-01 11:45:46 -0700106 rtc::Event event(false, false);
kthelgason876222f2016-11-29 01:44:11 -0800107 encoder_queue()->PostTask([this, &event, reason, down] {
sprangb1ca0732017-02-01 08:38:12 -0800108 down ? AdaptDown(reason) : AdaptUp(reason);
perkj803d97f2016-11-01 11:45:46 -0700109 event.Set();
110 });
perkj070ba852017-02-16 15:46:27 -0800111 ASSERT_TRUE(event.Wait(5000));
perkj803d97f2016-11-01 11:45:46 -0700112 }
113
kthelgason2fc52542017-03-03 00:24:41 -0800114 // This is used as a synchronisation mechanism, to make sure that the
115 // encoder queue is not blocked before we start sending it frames.
116 void WaitUntilTaskQueueIsIdle() {
117 rtc::Event event(false, false);
Yves Gerey665174f2018-06-19 15:03:05 +0200118 encoder_queue()->PostTask([&event] { event.Set(); });
kthelgason2fc52542017-03-03 00:24:41 -0800119 ASSERT_TRUE(event.Wait(5000));
120 }
121
sprangb1ca0732017-02-01 08:38:12 -0800122 void TriggerCpuOveruse() { PostTaskAndWait(true, AdaptReason::kCpu); }
kthelgason876222f2016-11-29 01:44:11 -0800123
sprangb1ca0732017-02-01 08:38:12 -0800124 void TriggerCpuNormalUsage() { PostTaskAndWait(false, AdaptReason::kCpu); }
kthelgason876222f2016-11-29 01:44:11 -0800125
sprangb1ca0732017-02-01 08:38:12 -0800126 void TriggerQualityLow() { PostTaskAndWait(true, AdaptReason::kQuality); }
kthelgason876222f2016-11-29 01:44:11 -0800127
sprangb1ca0732017-02-01 08:38:12 -0800128 void TriggerQualityHigh() { PostTaskAndWait(false, AdaptReason::kQuality); }
sprangfda496a2017-06-15 04:21:07 -0700129
Niels Möller7dc26b72017-12-06 10:27:48 +0100130 CpuOveruseDetectorProxy* overuse_detector_proxy_;
perkj803d97f2016-11-01 11:45:46 -0700131};
132
asapersson5f7226f2016-11-25 04:37:00 -0800133class VideoStreamFactory
134 : public VideoEncoderConfig::VideoStreamFactoryInterface {
135 public:
sprangfda496a2017-06-15 04:21:07 -0700136 explicit VideoStreamFactory(size_t num_temporal_layers, int framerate)
137 : num_temporal_layers_(num_temporal_layers), framerate_(framerate) {
asapersson5f7226f2016-11-25 04:37:00 -0800138 EXPECT_GT(num_temporal_layers, 0u);
sprangfda496a2017-06-15 04:21:07 -0700139 EXPECT_GT(framerate, 0);
asapersson5f7226f2016-11-25 04:37:00 -0800140 }
141
142 private:
143 std::vector<VideoStream> CreateEncoderStreams(
144 int width,
145 int height,
146 const VideoEncoderConfig& encoder_config) override {
147 std::vector<VideoStream> streams =
148 test::CreateVideoStreams(width, height, encoder_config);
149 for (VideoStream& stream : streams) {
Sergey Silkina796a7e2018-03-01 15:11:29 +0100150 stream.num_temporal_layers = num_temporal_layers_;
sprangfda496a2017-06-15 04:21:07 -0700151 stream.max_framerate = framerate_;
asapersson5f7226f2016-11-25 04:37:00 -0800152 }
153 return streams;
154 }
sprangfda496a2017-06-15 04:21:07 -0700155
asapersson5f7226f2016-11-25 04:37:00 -0800156 const size_t num_temporal_layers_;
sprangfda496a2017-06-15 04:21:07 -0700157 const int framerate_;
asapersson5f7226f2016-11-25 04:37:00 -0800158};
159
sprangb1ca0732017-02-01 08:38:12 -0800160class AdaptingFrameForwarder : public test::FrameForwarder {
161 public:
162 AdaptingFrameForwarder() : adaptation_enabled_(false) {}
asaperssonfab67072017-04-04 05:51:49 -0700163 ~AdaptingFrameForwarder() override {}
sprangb1ca0732017-02-01 08:38:12 -0800164
165 void set_adaptation_enabled(bool enabled) {
166 rtc::CritScope cs(&crit_);
167 adaptation_enabled_ = enabled;
168 }
169
asaperssonfab67072017-04-04 05:51:49 -0700170 bool adaption_enabled() const {
sprangb1ca0732017-02-01 08:38:12 -0800171 rtc::CritScope cs(&crit_);
172 return adaptation_enabled_;
173 }
174
asapersson09f05612017-05-15 23:40:18 -0700175 rtc::VideoSinkWants last_wants() const {
176 rtc::CritScope cs(&crit_);
177 return last_wants_;
178 }
179
Danil Chapovalovb9b146c2018-06-15 12:28:07 +0200180 absl::optional<int> last_sent_width() const { return last_width_; }
181 absl::optional<int> last_sent_height() const { return last_height_; }
Jonathan Yubc771b72017-12-08 17:04:29 -0800182
sprangb1ca0732017-02-01 08:38:12 -0800183 void IncomingCapturedFrame(const VideoFrame& video_frame) override {
184 int cropped_width = 0;
185 int cropped_height = 0;
186 int out_width = 0;
187 int out_height = 0;
sprangc5d62e22017-04-02 23:53:04 -0700188 if (adaption_enabled()) {
189 if (adapter_.AdaptFrameResolution(
190 video_frame.width(), video_frame.height(),
191 video_frame.timestamp_us() * 1000, &cropped_width,
192 &cropped_height, &out_width, &out_height)) {
193 VideoFrame adapted_frame(new rtc::RefCountedObject<TestBuffer>(
194 nullptr, out_width, out_height),
195 99, 99, kVideoRotation_0);
196 adapted_frame.set_ntp_time_ms(video_frame.ntp_time_ms());
197 test::FrameForwarder::IncomingCapturedFrame(adapted_frame);
Jonathan Yubc771b72017-12-08 17:04:29 -0800198 last_width_.emplace(adapted_frame.width());
199 last_height_.emplace(adapted_frame.height());
200 } else {
Danil Chapovalovb9b146c2018-06-15 12:28:07 +0200201 last_width_ = absl::nullopt;
202 last_height_ = absl::nullopt;
sprangc5d62e22017-04-02 23:53:04 -0700203 }
sprangb1ca0732017-02-01 08:38:12 -0800204 } else {
205 test::FrameForwarder::IncomingCapturedFrame(video_frame);
Jonathan Yubc771b72017-12-08 17:04:29 -0800206 last_width_.emplace(video_frame.width());
207 last_height_.emplace(video_frame.height());
sprangb1ca0732017-02-01 08:38:12 -0800208 }
209 }
210
211 void AddOrUpdateSink(rtc::VideoSinkInterface<VideoFrame>* sink,
212 const rtc::VideoSinkWants& wants) override {
213 rtc::CritScope cs(&crit_);
asapersson09f05612017-05-15 23:40:18 -0700214 last_wants_ = sink_wants();
sprangc5d62e22017-04-02 23:53:04 -0700215 adapter_.OnResolutionFramerateRequest(wants.target_pixel_count,
216 wants.max_pixel_count,
217 wants.max_framerate_fps);
sprangb1ca0732017-02-01 08:38:12 -0800218 test::FrameForwarder::AddOrUpdateSink(sink, wants);
219 }
sprangb1ca0732017-02-01 08:38:12 -0800220 cricket::VideoAdapter adapter_;
danilchapa37de392017-09-09 04:17:22 -0700221 bool adaptation_enabled_ RTC_GUARDED_BY(crit_);
222 rtc::VideoSinkWants last_wants_ RTC_GUARDED_BY(crit_);
Danil Chapovalovb9b146c2018-06-15 12:28:07 +0200223 absl::optional<int> last_width_;
224 absl::optional<int> last_height_;
sprangb1ca0732017-02-01 08:38:12 -0800225};
sprangc5d62e22017-04-02 23:53:04 -0700226
227class MockableSendStatisticsProxy : public SendStatisticsProxy {
228 public:
229 MockableSendStatisticsProxy(Clock* clock,
230 const VideoSendStream::Config& config,
231 VideoEncoderConfig::ContentType content_type)
232 : SendStatisticsProxy(clock, config, content_type) {}
233
234 VideoSendStream::Stats GetStats() override {
235 rtc::CritScope cs(&lock_);
236 if (mock_stats_)
237 return *mock_stats_;
238 return SendStatisticsProxy::GetStats();
239 }
240
241 void SetMockStats(const VideoSendStream::Stats& stats) {
242 rtc::CritScope cs(&lock_);
243 mock_stats_.emplace(stats);
244 }
245
246 void ResetMockStats() {
247 rtc::CritScope cs(&lock_);
248 mock_stats_.reset();
249 }
250
251 private:
252 rtc::CriticalSection lock_;
Danil Chapovalovb9b146c2018-06-15 12:28:07 +0200253 absl::optional<VideoSendStream::Stats> mock_stats_ RTC_GUARDED_BY(lock_);
sprangc5d62e22017-04-02 23:53:04 -0700254};
255
sprang4847ae62017-06-27 07:06:52 -0700256class MockBitrateObserver : public VideoBitrateAllocationObserver {
257 public:
Erik Språng566124a2018-04-23 12:32:22 +0200258 MOCK_METHOD1(OnBitrateAllocationUpdated, void(const VideoBitrateAllocation&));
sprang4847ae62017-06-27 07:06:52 -0700259};
260
perkj803d97f2016-11-01 11:45:46 -0700261} // namespace
262
mflodmancc3d4422017-08-03 08:27:51 -0700263class VideoStreamEncoderTest : public ::testing::Test {
perkj26091b12016-09-01 01:17:40 -0700264 public:
265 static const int kDefaultTimeoutMs = 30 * 1000;
266
mflodmancc3d4422017-08-03 08:27:51 -0700267 VideoStreamEncoderTest()
perkj26091b12016-09-01 01:17:40 -0700268 : video_send_config_(VideoSendStream::Config(nullptr)),
perkjfa10b552016-10-02 23:45:26 -0700269 codec_width_(320),
270 codec_height_(240),
sprang4847ae62017-06-27 07:06:52 -0700271 max_framerate_(30),
perkj26091b12016-09-01 01:17:40 -0700272 fake_encoder_(),
Niels Möller4db138e2018-04-19 09:04:13 +0200273 encoder_factory_(&fake_encoder_),
sprangc5d62e22017-04-02 23:53:04 -0700274 stats_proxy_(new MockableSendStatisticsProxy(
perkj803d97f2016-11-01 11:45:46 -0700275 Clock::GetRealTimeClock(),
276 video_send_config_,
277 webrtc::VideoEncoderConfig::ContentType::kRealtimeVideo)),
perkj26091b12016-09-01 01:17:40 -0700278 sink_(&fake_encoder_) {}
279
280 void SetUp() override {
perkj803d97f2016-11-01 11:45:46 -0700281 metrics::Reset();
perkj26091b12016-09-01 01:17:40 -0700282 video_send_config_ = VideoSendStream::Config(nullptr);
Niels Möller4db138e2018-04-19 09:04:13 +0200283 video_send_config_.encoder_settings.encoder_factory = &encoder_factory_;
Niels Möller259a4972018-04-05 15:36:51 +0200284 video_send_config_.rtp.payload_name = "FAKE";
285 video_send_config_.rtp.payload_type = 125;
perkj26091b12016-09-01 01:17:40 -0700286
Per512ecb32016-09-23 15:52:06 +0200287 VideoEncoderConfig video_encoder_config;
Niels Möller259a4972018-04-05 15:36:51 +0200288 test::FillEncoderConfiguration(kVideoCodecVP8, 1, &video_encoder_config);
sprang4847ae62017-06-27 07:06:52 -0700289 video_encoder_config.video_stream_factory =
290 new rtc::RefCountedObject<VideoStreamFactory>(1, max_framerate_);
Erik Språng08127a92016-11-16 16:41:30 +0100291 video_encoder_config_ = video_encoder_config.Copy();
sprang4847ae62017-06-27 07:06:52 -0700292
293 // Framerate limit is specified by the VideoStreamFactory.
294 std::vector<VideoStream> streams =
295 video_encoder_config.video_stream_factory->CreateEncoderStreams(
296 codec_width_, codec_height_, video_encoder_config);
297 max_framerate_ = streams[0].max_framerate;
298 fake_clock_.SetTimeMicros(1234);
299
Niels Möllerf1338562018-04-26 09:51:47 +0200300 ConfigureEncoder(std::move(video_encoder_config));
asapersson5f7226f2016-11-25 04:37:00 -0800301 }
302
Niels Möllerf1338562018-04-26 09:51:47 +0200303 void ConfigureEncoder(VideoEncoderConfig video_encoder_config) {
mflodmancc3d4422017-08-03 08:27:51 -0700304 if (video_stream_encoder_)
305 video_stream_encoder_->Stop();
306 video_stream_encoder_.reset(new VideoStreamEncoderUnderTest(
perkj803d97f2016-11-01 11:45:46 -0700307 stats_proxy_.get(), video_send_config_.encoder_settings));
mflodmancc3d4422017-08-03 08:27:51 -0700308 video_stream_encoder_->SetSink(&sink_, false /* rotation_applied */);
309 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -0700310 &video_source_, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
mflodmancc3d4422017-08-03 08:27:51 -0700311 video_stream_encoder_->SetStartBitrate(kTargetBitrateBps);
312 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
Niels Möllerf1338562018-04-26 09:51:47 +0200313 kMaxPayloadLength);
mflodmancc3d4422017-08-03 08:27:51 -0700314 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
asapersson5f7226f2016-11-25 04:37:00 -0800315 }
316
317 void ResetEncoder(const std::string& payload_name,
318 size_t num_streams,
319 size_t num_temporal_layers,
emircanbbcc3562017-08-18 00:28:40 -0700320 unsigned char num_spatial_layers,
sprang4847ae62017-06-27 07:06:52 -0700321 bool screenshare) {
Niels Möller259a4972018-04-05 15:36:51 +0200322 video_send_config_.rtp.payload_name = payload_name;
asapersson5f7226f2016-11-25 04:37:00 -0800323
324 VideoEncoderConfig video_encoder_config;
Niels Möller259a4972018-04-05 15:36:51 +0200325 video_encoder_config.codec_type = PayloadStringToCodecType(payload_name);
asapersson5f7226f2016-11-25 04:37:00 -0800326 video_encoder_config.number_of_streams = num_streams;
kthelgason2bc68642017-02-07 07:02:22 -0800327 video_encoder_config.max_bitrate_bps = kTargetBitrateBps;
asapersson5f7226f2016-11-25 04:37:00 -0800328 video_encoder_config.video_stream_factory =
sprangfda496a2017-06-15 04:21:07 -0700329 new rtc::RefCountedObject<VideoStreamFactory>(num_temporal_layers,
330 kDefaultFramerate);
sprang4847ae62017-06-27 07:06:52 -0700331 video_encoder_config.content_type =
332 screenshare ? VideoEncoderConfig::ContentType::kScreen
333 : VideoEncoderConfig::ContentType::kRealtimeVideo;
emircanbbcc3562017-08-18 00:28:40 -0700334 if (payload_name == "VP9") {
335 VideoCodecVP9 vp9_settings = VideoEncoder::GetDefaultVp9Settings();
336 vp9_settings.numberOfSpatialLayers = num_spatial_layers;
337 video_encoder_config.encoder_specific_settings =
338 new rtc::RefCountedObject<
339 VideoEncoderConfig::Vp9EncoderSpecificSettings>(vp9_settings);
340 }
Niels Möllerf1338562018-04-26 09:51:47 +0200341 ConfigureEncoder(std::move(video_encoder_config));
perkj26091b12016-09-01 01:17:40 -0700342 }
343
sprang57c2fff2017-01-16 06:24:02 -0800344 VideoFrame CreateFrame(int64_t ntp_time_ms,
345 rtc::Event* destruction_event) const {
Per512ecb32016-09-23 15:52:06 +0200346 VideoFrame frame(new rtc::RefCountedObject<TestBuffer>(
347 destruction_event, codec_width_, codec_height_),
348 99, 99, kVideoRotation_0);
sprang57c2fff2017-01-16 06:24:02 -0800349 frame.set_ntp_time_ms(ntp_time_ms);
perkj26091b12016-09-01 01:17:40 -0700350 return frame;
351 }
352
sprang57c2fff2017-01-16 06:24:02 -0800353 VideoFrame CreateFrame(int64_t ntp_time_ms, int width, int height) const {
perkj803d97f2016-11-01 11:45:46 -0700354 VideoFrame frame(
355 new rtc::RefCountedObject<TestBuffer>(nullptr, width, height), 99, 99,
356 kVideoRotation_0);
sprang57c2fff2017-01-16 06:24:02 -0800357 frame.set_ntp_time_ms(ntp_time_ms);
sprangc5d62e22017-04-02 23:53:04 -0700358 frame.set_timestamp_us(ntp_time_ms * 1000);
perkj803d97f2016-11-01 11:45:46 -0700359 return frame;
360 }
361
asapersson02465b82017-04-10 01:12:52 -0700362 void VerifyNoLimitation(const rtc::VideoSinkWants& wants) {
asapersson02465b82017-04-10 01:12:52 -0700363 EXPECT_EQ(std::numeric_limits<int>::max(), wants.max_framerate_fps);
asapersson09f05612017-05-15 23:40:18 -0700364 EXPECT_EQ(std::numeric_limits<int>::max(), wants.max_pixel_count);
365 EXPECT_FALSE(wants.target_pixel_count);
asapersson02465b82017-04-10 01:12:52 -0700366 }
367
asapersson09f05612017-05-15 23:40:18 -0700368 void VerifyFpsEqResolutionEq(const rtc::VideoSinkWants& wants1,
369 const rtc::VideoSinkWants& wants2) {
370 EXPECT_EQ(wants1.max_framerate_fps, wants2.max_framerate_fps);
371 EXPECT_EQ(wants1.max_pixel_count, wants2.max_pixel_count);
372 }
373
374 void VerifyFpsMaxResolutionLt(const rtc::VideoSinkWants& wants1,
375 const rtc::VideoSinkWants& wants2) {
376 EXPECT_EQ(std::numeric_limits<int>::max(), wants1.max_framerate_fps);
377 EXPECT_LT(wants1.max_pixel_count, wants2.max_pixel_count);
378 EXPECT_GT(wants1.max_pixel_count, 0);
379 }
380
381 void VerifyFpsMaxResolutionGt(const rtc::VideoSinkWants& wants1,
382 const rtc::VideoSinkWants& wants2) {
383 EXPECT_EQ(std::numeric_limits<int>::max(), wants1.max_framerate_fps);
384 EXPECT_GT(wants1.max_pixel_count, wants2.max_pixel_count);
385 }
386
asaperssonf7e294d2017-06-13 23:25:22 -0700387 void VerifyFpsMaxResolutionEq(const rtc::VideoSinkWants& wants1,
388 const rtc::VideoSinkWants& wants2) {
389 EXPECT_EQ(std::numeric_limits<int>::max(), wants1.max_framerate_fps);
390 EXPECT_EQ(wants1.max_pixel_count, wants2.max_pixel_count);
391 }
392
393 void VerifyFpsLtResolutionEq(const rtc::VideoSinkWants& wants1,
394 const rtc::VideoSinkWants& wants2) {
395 EXPECT_LT(wants1.max_framerate_fps, wants2.max_framerate_fps);
396 EXPECT_EQ(wants1.max_pixel_count, wants2.max_pixel_count);
397 }
398
399 void VerifyFpsGtResolutionEq(const rtc::VideoSinkWants& wants1,
400 const rtc::VideoSinkWants& wants2) {
401 EXPECT_GT(wants1.max_framerate_fps, wants2.max_framerate_fps);
402 EXPECT_EQ(wants1.max_pixel_count, wants2.max_pixel_count);
403 }
404
405 void VerifyFpsEqResolutionLt(const rtc::VideoSinkWants& wants1,
406 const rtc::VideoSinkWants& wants2) {
407 EXPECT_EQ(wants1.max_framerate_fps, wants2.max_framerate_fps);
408 EXPECT_LT(wants1.max_pixel_count, wants2.max_pixel_count);
409 EXPECT_GT(wants1.max_pixel_count, 0);
410 }
411
412 void VerifyFpsEqResolutionGt(const rtc::VideoSinkWants& wants1,
413 const rtc::VideoSinkWants& wants2) {
414 EXPECT_EQ(wants1.max_framerate_fps, wants2.max_framerate_fps);
415 EXPECT_GT(wants1.max_pixel_count, wants2.max_pixel_count);
416 }
417
asapersson09f05612017-05-15 23:40:18 -0700418 void VerifyFpsMaxResolutionLt(const rtc::VideoSinkWants& wants,
419 int pixel_count) {
420 EXPECT_EQ(std::numeric_limits<int>::max(), wants.max_framerate_fps);
asapersson02465b82017-04-10 01:12:52 -0700421 EXPECT_LT(wants.max_pixel_count, pixel_count);
422 EXPECT_GT(wants.max_pixel_count, 0);
asapersson09f05612017-05-15 23:40:18 -0700423 }
424
425 void VerifyFpsLtResolutionMax(const rtc::VideoSinkWants& wants, int fps) {
426 EXPECT_LT(wants.max_framerate_fps, fps);
427 EXPECT_EQ(std::numeric_limits<int>::max(), wants.max_pixel_count);
428 EXPECT_FALSE(wants.target_pixel_count);
asapersson02465b82017-04-10 01:12:52 -0700429 }
430
asaperssonf7e294d2017-06-13 23:25:22 -0700431 void VerifyFpsEqResolutionMax(const rtc::VideoSinkWants& wants,
432 int expected_fps) {
433 EXPECT_EQ(expected_fps, wants.max_framerate_fps);
434 EXPECT_EQ(std::numeric_limits<int>::max(), wants.max_pixel_count);
435 EXPECT_FALSE(wants.target_pixel_count);
436 }
437
Jonathan Yubc771b72017-12-08 17:04:29 -0800438 void VerifyBalancedModeFpsRange(const rtc::VideoSinkWants& wants,
439 int last_frame_pixels) {
440 // Balanced mode should always scale FPS to the desired range before
441 // attempting to scale resolution.
442 int fps_limit = wants.max_framerate_fps;
443 if (last_frame_pixels <= 320 * 240) {
444 EXPECT_TRUE(7 <= fps_limit && fps_limit <= 10);
445 } else if (last_frame_pixels <= 480 * 270) {
446 EXPECT_TRUE(10 <= fps_limit && fps_limit <= 15);
447 } else if (last_frame_pixels <= 640 * 480) {
448 EXPECT_LE(15, fps_limit);
449 } else {
450 EXPECT_EQ(std::numeric_limits<int>::max(), fps_limit);
451 }
452 }
453
sprang4847ae62017-06-27 07:06:52 -0700454 void WaitForEncodedFrame(int64_t expected_ntp_time) {
455 sink_.WaitForEncodedFrame(expected_ntp_time);
456 fake_clock_.AdvanceTimeMicros(rtc::kNumMicrosecsPerSec / max_framerate_);
457 }
458
459 bool TimedWaitForEncodedFrame(int64_t expected_ntp_time, int64_t timeout_ms) {
460 bool ok = sink_.TimedWaitForEncodedFrame(expected_ntp_time, timeout_ms);
461 fake_clock_.AdvanceTimeMicros(rtc::kNumMicrosecsPerSec / max_framerate_);
462 return ok;
463 }
464
465 void WaitForEncodedFrame(uint32_t expected_width, uint32_t expected_height) {
466 sink_.WaitForEncodedFrame(expected_width, expected_height);
467 fake_clock_.AdvanceTimeMicros(rtc::kNumMicrosecsPerSec / max_framerate_);
468 }
469
470 void ExpectDroppedFrame() {
471 sink_.ExpectDroppedFrame();
472 fake_clock_.AdvanceTimeMicros(rtc::kNumMicrosecsPerSec / max_framerate_);
473 }
474
475 bool WaitForFrame(int64_t timeout_ms) {
476 bool ok = sink_.WaitForFrame(timeout_ms);
477 fake_clock_.AdvanceTimeMicros(rtc::kNumMicrosecsPerSec / max_framerate_);
478 return ok;
479 }
480
perkj26091b12016-09-01 01:17:40 -0700481 class TestEncoder : public test::FakeEncoder {
482 public:
483 TestEncoder()
484 : FakeEncoder(Clock::GetRealTimeClock()),
485 continue_encode_event_(false, false) {}
486
asaperssonfab67072017-04-04 05:51:49 -0700487 VideoCodec codec_config() const {
brandtre78d2662017-01-16 05:57:16 -0800488 rtc::CritScope lock(&crit_sect_);
perkjfa10b552016-10-02 23:45:26 -0700489 return config_;
490 }
491
492 void BlockNextEncode() {
brandtre78d2662017-01-16 05:57:16 -0800493 rtc::CritScope lock(&local_crit_sect_);
perkjfa10b552016-10-02 23:45:26 -0700494 block_next_encode_ = true;
495 }
496
kthelgason876222f2016-11-29 01:44:11 -0800497 VideoEncoder::ScalingSettings GetScalingSettings() const override {
kthelgason2fc52542017-03-03 00:24:41 -0800498 rtc::CritScope lock(&local_crit_sect_);
kthelgasonad9010c2017-02-14 00:46:51 -0800499 if (quality_scaling_)
Niels Möller225c7872018-02-22 15:03:53 +0100500 return VideoEncoder::ScalingSettings(1, 2, kMinPixelsPerFrame);
501 return VideoEncoder::ScalingSettings::kOff;
kthelgason876222f2016-11-29 01:44:11 -0800502 }
503
perkjfa10b552016-10-02 23:45:26 -0700504 void ContinueEncode() { continue_encode_event_.Set(); }
505
506 void CheckLastTimeStampsMatch(int64_t ntp_time_ms,
507 uint32_t timestamp) const {
brandtre78d2662017-01-16 05:57:16 -0800508 rtc::CritScope lock(&local_crit_sect_);
perkjfa10b552016-10-02 23:45:26 -0700509 EXPECT_EQ(timestamp_, timestamp);
510 EXPECT_EQ(ntp_time_ms_, ntp_time_ms);
511 }
512
kthelgason2fc52542017-03-03 00:24:41 -0800513 void SetQualityScaling(bool b) {
514 rtc::CritScope lock(&local_crit_sect_);
515 quality_scaling_ = b;
516 }
kthelgasonad9010c2017-02-14 00:46:51 -0800517
sprangfe627f32017-03-29 08:24:59 -0700518 void ForceInitEncodeFailure(bool force_failure) {
519 rtc::CritScope lock(&local_crit_sect_);
520 force_init_encode_failed_ = force_failure;
521 }
522
perkjfa10b552016-10-02 23:45:26 -0700523 private:
perkj26091b12016-09-01 01:17:40 -0700524 int32_t Encode(const VideoFrame& input_image,
525 const CodecSpecificInfo* codec_specific_info,
526 const std::vector<FrameType>* frame_types) override {
527 bool block_encode;
528 {
brandtre78d2662017-01-16 05:57:16 -0800529 rtc::CritScope lock(&local_crit_sect_);
perkj26091b12016-09-01 01:17:40 -0700530 EXPECT_GT(input_image.timestamp(), timestamp_);
531 EXPECT_GT(input_image.ntp_time_ms(), ntp_time_ms_);
532 EXPECT_EQ(input_image.timestamp(), input_image.ntp_time_ms() * 90);
533
534 timestamp_ = input_image.timestamp();
535 ntp_time_ms_ = input_image.ntp_time_ms();
perkj803d97f2016-11-01 11:45:46 -0700536 last_input_width_ = input_image.width();
537 last_input_height_ = input_image.height();
perkj26091b12016-09-01 01:17:40 -0700538 block_encode = block_next_encode_;
539 block_next_encode_ = false;
540 }
541 int32_t result =
542 FakeEncoder::Encode(input_image, codec_specific_info, frame_types);
543 if (block_encode)
perkja49cbd32016-09-16 07:53:41 -0700544 EXPECT_TRUE(continue_encode_event_.Wait(kDefaultTimeoutMs));
perkj26091b12016-09-01 01:17:40 -0700545 return result;
546 }
547
sprangfe627f32017-03-29 08:24:59 -0700548 int32_t InitEncode(const VideoCodec* config,
549 int32_t number_of_cores,
550 size_t max_payload_size) override {
551 int res =
552 FakeEncoder::InitEncode(config, number_of_cores, max_payload_size);
553 rtc::CritScope lock(&local_crit_sect_);
Erik Språng82fad3d2018-03-21 09:57:23 +0100554 if (config->codecType == kVideoCodecVP8) {
sprangfe627f32017-03-29 08:24:59 -0700555 // Simulate setting up temporal layers, in order to validate the life
556 // cycle of these objects.
557 int num_streams = std::max<int>(1, config->numberOfSimulcastStreams);
sprangfe627f32017-03-29 08:24:59 -0700558 for (int i = 0; i < num_streams; ++i) {
559 allocated_temporal_layers_.emplace_back(
Niels Möller150dcb02018-03-27 14:16:55 +0200560 TemporalLayers::CreateTemporalLayers(*config, i));
sprangfe627f32017-03-29 08:24:59 -0700561 }
562 }
563 if (force_init_encode_failed_)
564 return -1;
565 return res;
566 }
567
brandtre78d2662017-01-16 05:57:16 -0800568 rtc::CriticalSection local_crit_sect_;
danilchapa37de392017-09-09 04:17:22 -0700569 bool block_next_encode_ RTC_GUARDED_BY(local_crit_sect_) = false;
perkj26091b12016-09-01 01:17:40 -0700570 rtc::Event continue_encode_event_;
danilchapa37de392017-09-09 04:17:22 -0700571 uint32_t timestamp_ RTC_GUARDED_BY(local_crit_sect_) = 0;
572 int64_t ntp_time_ms_ RTC_GUARDED_BY(local_crit_sect_) = 0;
573 int last_input_width_ RTC_GUARDED_BY(local_crit_sect_) = 0;
574 int last_input_height_ RTC_GUARDED_BY(local_crit_sect_) = 0;
575 bool quality_scaling_ RTC_GUARDED_BY(local_crit_sect_) = true;
sprangfe627f32017-03-29 08:24:59 -0700576 std::vector<std::unique_ptr<TemporalLayers>> allocated_temporal_layers_
danilchapa37de392017-09-09 04:17:22 -0700577 RTC_GUARDED_BY(local_crit_sect_);
578 bool force_init_encode_failed_ RTC_GUARDED_BY(local_crit_sect_) = false;
perkj26091b12016-09-01 01:17:40 -0700579 };
580
mflodmancc3d4422017-08-03 08:27:51 -0700581 class TestSink : public VideoStreamEncoder::EncoderSink {
perkj26091b12016-09-01 01:17:40 -0700582 public:
583 explicit TestSink(TestEncoder* test_encoder)
584 : test_encoder_(test_encoder), encoded_frame_event_(false, false) {}
585
perkj26091b12016-09-01 01:17:40 -0700586 void WaitForEncodedFrame(int64_t expected_ntp_time) {
sprang4847ae62017-06-27 07:06:52 -0700587 EXPECT_TRUE(
588 TimedWaitForEncodedFrame(expected_ntp_time, kDefaultTimeoutMs));
589 }
590
591 bool TimedWaitForEncodedFrame(int64_t expected_ntp_time,
592 int64_t timeout_ms) {
perkj26091b12016-09-01 01:17:40 -0700593 uint32_t timestamp = 0;
sprang4847ae62017-06-27 07:06:52 -0700594 if (!encoded_frame_event_.Wait(timeout_ms))
595 return false;
perkj26091b12016-09-01 01:17:40 -0700596 {
597 rtc::CritScope lock(&crit_);
sprangb1ca0732017-02-01 08:38:12 -0800598 timestamp = last_timestamp_;
perkj26091b12016-09-01 01:17:40 -0700599 }
600 test_encoder_->CheckLastTimeStampsMatch(expected_ntp_time, timestamp);
sprang4847ae62017-06-27 07:06:52 -0700601 return true;
perkj26091b12016-09-01 01:17:40 -0700602 }
603
sprangb1ca0732017-02-01 08:38:12 -0800604 void WaitForEncodedFrame(uint32_t expected_width,
605 uint32_t expected_height) {
sprangc5d62e22017-04-02 23:53:04 -0700606 EXPECT_TRUE(encoded_frame_event_.Wait(kDefaultTimeoutMs));
Åsa Perssonc74d8da2017-12-04 14:13:56 +0100607 CheckLastFrameSizeMatches(expected_width, expected_height);
sprangc5d62e22017-04-02 23:53:04 -0700608 }
609
Åsa Perssonc74d8da2017-12-04 14:13:56 +0100610 void CheckLastFrameSizeMatches(uint32_t expected_width,
sprangc5d62e22017-04-02 23:53:04 -0700611 uint32_t expected_height) {
sprangb1ca0732017-02-01 08:38:12 -0800612 uint32_t width = 0;
613 uint32_t height = 0;
sprangb1ca0732017-02-01 08:38:12 -0800614 {
615 rtc::CritScope lock(&crit_);
616 width = last_width_;
617 height = last_height_;
618 }
619 EXPECT_EQ(expected_height, height);
620 EXPECT_EQ(expected_width, width);
621 }
622
kthelgason2fc52542017-03-03 00:24:41 -0800623 void ExpectDroppedFrame() { EXPECT_FALSE(encoded_frame_event_.Wait(100)); }
kthelgason2bc68642017-02-07 07:02:22 -0800624
sprangc5d62e22017-04-02 23:53:04 -0700625 bool WaitForFrame(int64_t timeout_ms) {
626 return encoded_frame_event_.Wait(timeout_ms);
627 }
628
perkj26091b12016-09-01 01:17:40 -0700629 void SetExpectNoFrames() {
630 rtc::CritScope lock(&crit_);
631 expect_frames_ = false;
632 }
633
asaperssonfab67072017-04-04 05:51:49 -0700634 int number_of_reconfigurations() const {
Per512ecb32016-09-23 15:52:06 +0200635 rtc::CritScope lock(&crit_);
636 return number_of_reconfigurations_;
637 }
638
asaperssonfab67072017-04-04 05:51:49 -0700639 int last_min_transmit_bitrate() const {
Per512ecb32016-09-23 15:52:06 +0200640 rtc::CritScope lock(&crit_);
641 return min_transmit_bitrate_bps_;
642 }
643
perkj26091b12016-09-01 01:17:40 -0700644 private:
sergeyu2cb155a2016-11-04 11:39:29 -0700645 Result OnEncodedImage(
646 const EncodedImage& encoded_image,
647 const CodecSpecificInfo* codec_specific_info,
648 const RTPFragmentationHeader* fragmentation) override {
Per512ecb32016-09-23 15:52:06 +0200649 rtc::CritScope lock(&crit_);
650 EXPECT_TRUE(expect_frames_);
sprangb1ca0732017-02-01 08:38:12 -0800651 last_timestamp_ = encoded_image._timeStamp;
652 last_width_ = encoded_image._encodedWidth;
653 last_height_ = encoded_image._encodedHeight;
Per512ecb32016-09-23 15:52:06 +0200654 encoded_frame_event_.Set();
sprangb1ca0732017-02-01 08:38:12 -0800655 return Result(Result::OK, last_timestamp_);
Per512ecb32016-09-23 15:52:06 +0200656 }
657
658 void OnEncoderConfigurationChanged(std::vector<VideoStream> streams,
659 int min_transmit_bitrate_bps) override {
660 rtc::CriticalSection crit_;
661 ++number_of_reconfigurations_;
662 min_transmit_bitrate_bps_ = min_transmit_bitrate_bps;
663 }
664
perkj26091b12016-09-01 01:17:40 -0700665 rtc::CriticalSection crit_;
666 TestEncoder* test_encoder_;
667 rtc::Event encoded_frame_event_;
sprangb1ca0732017-02-01 08:38:12 -0800668 uint32_t last_timestamp_ = 0;
669 uint32_t last_height_ = 0;
670 uint32_t last_width_ = 0;
perkj26091b12016-09-01 01:17:40 -0700671 bool expect_frames_ = true;
Per512ecb32016-09-23 15:52:06 +0200672 int number_of_reconfigurations_ = 0;
673 int min_transmit_bitrate_bps_ = 0;
perkj26091b12016-09-01 01:17:40 -0700674 };
675
676 VideoSendStream::Config video_send_config_;
Erik Språng08127a92016-11-16 16:41:30 +0100677 VideoEncoderConfig video_encoder_config_;
Per512ecb32016-09-23 15:52:06 +0200678 int codec_width_;
679 int codec_height_;
sprang4847ae62017-06-27 07:06:52 -0700680 int max_framerate_;
perkj26091b12016-09-01 01:17:40 -0700681 TestEncoder fake_encoder_;
Niels Möller4db138e2018-04-19 09:04:13 +0200682 test::EncoderProxyFactory encoder_factory_;
sprangc5d62e22017-04-02 23:53:04 -0700683 std::unique_ptr<MockableSendStatisticsProxy> stats_proxy_;
perkj26091b12016-09-01 01:17:40 -0700684 TestSink sink_;
sprangb1ca0732017-02-01 08:38:12 -0800685 AdaptingFrameForwarder video_source_;
mflodmancc3d4422017-08-03 08:27:51 -0700686 std::unique_ptr<VideoStreamEncoderUnderTest> video_stream_encoder_;
sprang4847ae62017-06-27 07:06:52 -0700687 rtc::ScopedFakeClock fake_clock_;
perkj26091b12016-09-01 01:17:40 -0700688};
689
mflodmancc3d4422017-08-03 08:27:51 -0700690TEST_F(VideoStreamEncoderTest, EncodeOneFrame) {
691 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkj26091b12016-09-01 01:17:40 -0700692 rtc::Event frame_destroyed_event(false, false);
perkja49cbd32016-09-16 07:53:41 -0700693 video_source_.IncomingCapturedFrame(CreateFrame(1, &frame_destroyed_event));
sprang4847ae62017-06-27 07:06:52 -0700694 WaitForEncodedFrame(1);
perkja49cbd32016-09-16 07:53:41 -0700695 EXPECT_TRUE(frame_destroyed_event.Wait(kDefaultTimeoutMs));
mflodmancc3d4422017-08-03 08:27:51 -0700696 video_stream_encoder_->Stop();
perkj26091b12016-09-01 01:17:40 -0700697}
698
mflodmancc3d4422017-08-03 08:27:51 -0700699TEST_F(VideoStreamEncoderTest, DropsFramesBeforeFirstOnBitrateUpdated) {
perkj26091b12016-09-01 01:17:40 -0700700 // Dropped since no target bitrate has been set.
701 rtc::Event frame_destroyed_event(false, false);
Sebastian Janssona3177052018-04-10 13:05:49 +0200702 // The encoder will cache up to one frame for a short duration. Adding two
703 // frames means that the first frame will be dropped and the second frame will
704 // be sent when the encoder is enabled.
perkja49cbd32016-09-16 07:53:41 -0700705 video_source_.IncomingCapturedFrame(CreateFrame(1, &frame_destroyed_event));
Sebastian Janssona3177052018-04-10 13:05:49 +0200706 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
perkja49cbd32016-09-16 07:53:41 -0700707 EXPECT_TRUE(frame_destroyed_event.Wait(kDefaultTimeoutMs));
perkj26091b12016-09-01 01:17:40 -0700708
mflodmancc3d4422017-08-03 08:27:51 -0700709 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkj26091b12016-09-01 01:17:40 -0700710
Sebastian Janssona3177052018-04-10 13:05:49 +0200711 // The pending frame should be received.
sprang4847ae62017-06-27 07:06:52 -0700712 WaitForEncodedFrame(2);
Sebastian Janssona3177052018-04-10 13:05:49 +0200713 video_source_.IncomingCapturedFrame(CreateFrame(3, nullptr));
714
715 WaitForEncodedFrame(3);
mflodmancc3d4422017-08-03 08:27:51 -0700716 video_stream_encoder_->Stop();
perkj26091b12016-09-01 01:17:40 -0700717}
718
mflodmancc3d4422017-08-03 08:27:51 -0700719TEST_F(VideoStreamEncoderTest, DropsFramesWhenRateSetToZero) {
720 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkja49cbd32016-09-16 07:53:41 -0700721 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700722 WaitForEncodedFrame(1);
perkj26091b12016-09-01 01:17:40 -0700723
mflodmancc3d4422017-08-03 08:27:51 -0700724 video_stream_encoder_->OnBitrateUpdated(0, 0, 0);
Sebastian Janssona3177052018-04-10 13:05:49 +0200725 // The encoder will cache up to one frame for a short duration. Adding two
726 // frames means that the first frame will be dropped and the second frame will
727 // be sent when the encoder is resumed.
perkja49cbd32016-09-16 07:53:41 -0700728 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
Sebastian Janssona3177052018-04-10 13:05:49 +0200729 video_source_.IncomingCapturedFrame(CreateFrame(3, nullptr));
perkj26091b12016-09-01 01:17:40 -0700730
mflodmancc3d4422017-08-03 08:27:51 -0700731 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
sprang4847ae62017-06-27 07:06:52 -0700732 WaitForEncodedFrame(3);
Sebastian Janssona3177052018-04-10 13:05:49 +0200733 video_source_.IncomingCapturedFrame(CreateFrame(4, nullptr));
734 WaitForEncodedFrame(4);
mflodmancc3d4422017-08-03 08:27:51 -0700735 video_stream_encoder_->Stop();
perkj26091b12016-09-01 01:17:40 -0700736}
737
mflodmancc3d4422017-08-03 08:27:51 -0700738TEST_F(VideoStreamEncoderTest, DropsFramesWithSameOrOldNtpTimestamp) {
739 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkja49cbd32016-09-16 07:53:41 -0700740 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700741 WaitForEncodedFrame(1);
perkj26091b12016-09-01 01:17:40 -0700742
743 // This frame will be dropped since it has the same ntp timestamp.
perkja49cbd32016-09-16 07:53:41 -0700744 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
perkj26091b12016-09-01 01:17:40 -0700745
perkja49cbd32016-09-16 07:53:41 -0700746 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700747 WaitForEncodedFrame(2);
mflodmancc3d4422017-08-03 08:27:51 -0700748 video_stream_encoder_->Stop();
perkj26091b12016-09-01 01:17:40 -0700749}
750
mflodmancc3d4422017-08-03 08:27:51 -0700751TEST_F(VideoStreamEncoderTest, DropsFrameAfterStop) {
752 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkj26091b12016-09-01 01:17:40 -0700753
perkja49cbd32016-09-16 07:53:41 -0700754 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700755 WaitForEncodedFrame(1);
perkj26091b12016-09-01 01:17:40 -0700756
mflodmancc3d4422017-08-03 08:27:51 -0700757 video_stream_encoder_->Stop();
perkj26091b12016-09-01 01:17:40 -0700758 sink_.SetExpectNoFrames();
759 rtc::Event frame_destroyed_event(false, false);
perkja49cbd32016-09-16 07:53:41 -0700760 video_source_.IncomingCapturedFrame(CreateFrame(2, &frame_destroyed_event));
761 EXPECT_TRUE(frame_destroyed_event.Wait(kDefaultTimeoutMs));
perkj26091b12016-09-01 01:17:40 -0700762}
763
mflodmancc3d4422017-08-03 08:27:51 -0700764TEST_F(VideoStreamEncoderTest, DropsPendingFramesOnSlowEncode) {
765 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkj26091b12016-09-01 01:17:40 -0700766
767 fake_encoder_.BlockNextEncode();
perkja49cbd32016-09-16 07:53:41 -0700768 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700769 WaitForEncodedFrame(1);
perkj26091b12016-09-01 01:17:40 -0700770 // Here, the encoder thread will be blocked in the TestEncoder waiting for a
771 // call to ContinueEncode.
perkja49cbd32016-09-16 07:53:41 -0700772 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
773 video_source_.IncomingCapturedFrame(CreateFrame(3, nullptr));
perkj26091b12016-09-01 01:17:40 -0700774 fake_encoder_.ContinueEncode();
sprang4847ae62017-06-27 07:06:52 -0700775 WaitForEncodedFrame(3);
perkj26091b12016-09-01 01:17:40 -0700776
mflodmancc3d4422017-08-03 08:27:51 -0700777 video_stream_encoder_->Stop();
perkj26091b12016-09-01 01:17:40 -0700778}
779
mflodmancc3d4422017-08-03 08:27:51 -0700780TEST_F(VideoStreamEncoderTest,
781 ConfigureEncoderTriggersOnEncoderConfigurationChanged) {
782 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
Per21d45d22016-10-30 21:37:57 +0100783 EXPECT_EQ(0, sink_.number_of_reconfigurations());
Per512ecb32016-09-23 15:52:06 +0200784
785 // Capture a frame and wait for it to synchronize with the encoder thread.
Perf8c5f2b2016-09-23 16:24:55 +0200786 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700787 WaitForEncodedFrame(1);
Per21d45d22016-10-30 21:37:57 +0100788 // The encoder will have been configured once when the first frame is
789 // received.
790 EXPECT_EQ(1, sink_.number_of_reconfigurations());
Per512ecb32016-09-23 15:52:06 +0200791
792 VideoEncoderConfig video_encoder_config;
Niels Möller259a4972018-04-05 15:36:51 +0200793 test::FillEncoderConfiguration(kVideoCodecVP8, 1, &video_encoder_config);
Per512ecb32016-09-23 15:52:06 +0200794 video_encoder_config.min_transmit_bitrate_bps = 9999;
mflodmancc3d4422017-08-03 08:27:51 -0700795 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
Niels Möllerf1338562018-04-26 09:51:47 +0200796 kMaxPayloadLength);
Per512ecb32016-09-23 15:52:06 +0200797
798 // Capture a frame and wait for it to synchronize with the encoder thread.
Perf8c5f2b2016-09-23 16:24:55 +0200799 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700800 WaitForEncodedFrame(2);
Per21d45d22016-10-30 21:37:57 +0100801 EXPECT_EQ(2, sink_.number_of_reconfigurations());
perkj3b703ed2016-09-29 23:25:40 -0700802 EXPECT_EQ(9999, sink_.last_min_transmit_bitrate());
perkj26105b42016-09-29 22:39:10 -0700803
mflodmancc3d4422017-08-03 08:27:51 -0700804 video_stream_encoder_->Stop();
perkj26105b42016-09-29 22:39:10 -0700805}
806
mflodmancc3d4422017-08-03 08:27:51 -0700807TEST_F(VideoStreamEncoderTest, FrameResolutionChangeReconfigureEncoder) {
808 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkjfa10b552016-10-02 23:45:26 -0700809
810 // Capture a frame and wait for it to synchronize with the encoder thread.
811 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700812 WaitForEncodedFrame(1);
Per21d45d22016-10-30 21:37:57 +0100813 // The encoder will have been configured once.
814 EXPECT_EQ(1, sink_.number_of_reconfigurations());
perkjfa10b552016-10-02 23:45:26 -0700815 EXPECT_EQ(codec_width_, fake_encoder_.codec_config().width);
816 EXPECT_EQ(codec_height_, fake_encoder_.codec_config().height);
817
818 codec_width_ *= 2;
819 codec_height_ *= 2;
820 // Capture a frame with a higher resolution and wait for it to synchronize
821 // with the encoder thread.
822 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700823 WaitForEncodedFrame(2);
perkjfa10b552016-10-02 23:45:26 -0700824 EXPECT_EQ(codec_width_, fake_encoder_.codec_config().width);
825 EXPECT_EQ(codec_height_, fake_encoder_.codec_config().height);
Per21d45d22016-10-30 21:37:57 +0100826 EXPECT_EQ(2, sink_.number_of_reconfigurations());
perkjfa10b552016-10-02 23:45:26 -0700827
mflodmancc3d4422017-08-03 08:27:51 -0700828 video_stream_encoder_->Stop();
perkjfa10b552016-10-02 23:45:26 -0700829}
830
mflodmancc3d4422017-08-03 08:27:51 -0700831TEST_F(VideoStreamEncoderTest, SwitchSourceDeregisterEncoderAsSink) {
perkj803d97f2016-11-01 11:45:46 -0700832 EXPECT_TRUE(video_source_.has_sinks());
833 test::FrameForwarder new_video_source;
mflodmancc3d4422017-08-03 08:27:51 -0700834 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -0700835 &new_video_source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
perkj803d97f2016-11-01 11:45:46 -0700836 EXPECT_FALSE(video_source_.has_sinks());
837 EXPECT_TRUE(new_video_source.has_sinks());
838
mflodmancc3d4422017-08-03 08:27:51 -0700839 video_stream_encoder_->Stop();
perkj803d97f2016-11-01 11:45:46 -0700840}
841
mflodmancc3d4422017-08-03 08:27:51 -0700842TEST_F(VideoStreamEncoderTest, SinkWantsRotationApplied) {
perkj803d97f2016-11-01 11:45:46 -0700843 EXPECT_FALSE(video_source_.sink_wants().rotation_applied);
mflodmancc3d4422017-08-03 08:27:51 -0700844 video_stream_encoder_->SetSink(&sink_, true /*rotation_applied*/);
perkj803d97f2016-11-01 11:45:46 -0700845 EXPECT_TRUE(video_source_.sink_wants().rotation_applied);
mflodmancc3d4422017-08-03 08:27:51 -0700846 video_stream_encoder_->Stop();
perkj803d97f2016-11-01 11:45:46 -0700847}
848
Jonathan Yubc771b72017-12-08 17:04:29 -0800849TEST_F(VideoStreamEncoderTest, TestCpuDowngrades_BalancedMode) {
850 const int kFramerateFps = 30;
asaperssonf7e294d2017-06-13 23:25:22 -0700851 const int kWidth = 1280;
852 const int kHeight = 720;
Jonathan Yubc771b72017-12-08 17:04:29 -0800853
854 // We rely on the automatic resolution adaptation, but we handle framerate
855 // adaptation manually by mocking the stats proxy.
856 video_source_.set_adaptation_enabled(true);
asaperssonf7e294d2017-06-13 23:25:22 -0700857
Taylor Brandstetter49fcc102018-05-16 14:20:41 -0700858 // Enable BALANCED preference, no initial limitation.
Jonathan Yubc771b72017-12-08 17:04:29 -0800859 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
Taylor Brandstetter49fcc102018-05-16 14:20:41 -0700860 video_stream_encoder_->SetSource(&video_source_,
861 webrtc::DegradationPreference::BALANCED);
Jonathan Yubc771b72017-12-08 17:04:29 -0800862 VerifyNoLimitation(video_source_.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -0700863 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
Jonathan Yubc771b72017-12-08 17:04:29 -0800864 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
asaperssonf7e294d2017-06-13 23:25:22 -0700865 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
866
Jonathan Yubc771b72017-12-08 17:04:29 -0800867 // Adapt down as far as possible.
868 rtc::VideoSinkWants last_wants;
869 int64_t t = 1;
870 int loop_count = 0;
871 do {
872 ++loop_count;
873 last_wants = video_source_.sink_wants();
874
875 // Simulate the framerate we've been asked to adapt to.
876 const int fps = std::min(kFramerateFps, last_wants.max_framerate_fps);
877 const int frame_interval_ms = rtc::kNumMillisecsPerSec / fps;
878 VideoSendStream::Stats mock_stats = stats_proxy_->GetStats();
879 mock_stats.input_frame_rate = fps;
880 stats_proxy_->SetMockStats(mock_stats);
881
882 video_source_.IncomingCapturedFrame(CreateFrame(t, kWidth, kHeight));
883 sink_.WaitForEncodedFrame(t);
884 t += frame_interval_ms;
885
mflodmancc3d4422017-08-03 08:27:51 -0700886 video_stream_encoder_->TriggerCpuOveruse();
Jonathan Yubc771b72017-12-08 17:04:29 -0800887 VerifyBalancedModeFpsRange(
888 video_source_.sink_wants(),
889 *video_source_.last_sent_width() * *video_source_.last_sent_height());
890 } while (video_source_.sink_wants().max_pixel_count <
891 last_wants.max_pixel_count ||
892 video_source_.sink_wants().max_framerate_fps <
893 last_wants.max_framerate_fps);
asaperssonf7e294d2017-06-13 23:25:22 -0700894
Jonathan Yubc771b72017-12-08 17:04:29 -0800895 // Verify that we've adapted all the way down.
896 stats_proxy_->ResetMockStats();
asaperssonf7e294d2017-06-13 23:25:22 -0700897 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
Jonathan Yubc771b72017-12-08 17:04:29 -0800898 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_framerate);
899 EXPECT_EQ(loop_count - 1,
asaperssonf7e294d2017-06-13 23:25:22 -0700900 stats_proxy_->GetStats().number_of_cpu_adapt_changes);
Jonathan Yubc771b72017-12-08 17:04:29 -0800901 EXPECT_EQ(kMinPixelsPerFrame, *video_source_.last_sent_width() *
902 *video_source_.last_sent_height());
903 EXPECT_EQ(kMinBalancedFramerateFps,
904 video_source_.sink_wants().max_framerate_fps);
asaperssonf7e294d2017-06-13 23:25:22 -0700905
Jonathan Yubc771b72017-12-08 17:04:29 -0800906 // Adapt back up the same number of times we adapted down.
907 for (int i = 0; i < loop_count - 1; ++i) {
908 last_wants = video_source_.sink_wants();
909
910 // Simulate the framerate we've been asked to adapt to.
911 const int fps = std::min(kFramerateFps, last_wants.max_framerate_fps);
912 const int frame_interval_ms = rtc::kNumMillisecsPerSec / fps;
913 VideoSendStream::Stats mock_stats = stats_proxy_->GetStats();
914 mock_stats.input_frame_rate = fps;
915 stats_proxy_->SetMockStats(mock_stats);
916
917 video_source_.IncomingCapturedFrame(CreateFrame(t, kWidth, kHeight));
918 sink_.WaitForEncodedFrame(t);
919 t += frame_interval_ms;
920
mflodmancc3d4422017-08-03 08:27:51 -0700921 video_stream_encoder_->TriggerCpuNormalUsage();
Jonathan Yubc771b72017-12-08 17:04:29 -0800922 VerifyBalancedModeFpsRange(
923 video_source_.sink_wants(),
924 *video_source_.last_sent_width() * *video_source_.last_sent_height());
925 EXPECT_TRUE(video_source_.sink_wants().max_pixel_count >
926 last_wants.max_pixel_count ||
927 video_source_.sink_wants().max_framerate_fps >
928 last_wants.max_framerate_fps);
asaperssonf7e294d2017-06-13 23:25:22 -0700929 }
930
Jonathan Yubc771b72017-12-08 17:04:29 -0800931 VerifyNoLimitation(video_source_.sink_wants());
932 stats_proxy_->ResetMockStats();
asaperssonf7e294d2017-06-13 23:25:22 -0700933 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
Jonathan Yubc771b72017-12-08 17:04:29 -0800934 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
935 EXPECT_EQ((loop_count - 1) * 2,
936 stats_proxy_->GetStats().number_of_cpu_adapt_changes);
asaperssonf7e294d2017-06-13 23:25:22 -0700937
mflodmancc3d4422017-08-03 08:27:51 -0700938 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -0700939}
mflodmancc3d4422017-08-03 08:27:51 -0700940TEST_F(VideoStreamEncoderTest, SinkWantsStoredByDegradationPreference) {
941 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson02465b82017-04-10 01:12:52 -0700942 VerifyNoLimitation(video_source_.sink_wants());
perkj803d97f2016-11-01 11:45:46 -0700943
sprangc5d62e22017-04-02 23:53:04 -0700944 const int kFrameWidth = 1280;
945 const int kFrameHeight = 720;
946 const int kFrameIntervalMs = 1000 / 30;
947
948 int frame_timestamp = 1;
perkj803d97f2016-11-01 11:45:46 -0700949
kthelgason5e13d412016-12-01 03:59:51 -0800950 video_source_.IncomingCapturedFrame(
sprangc5d62e22017-04-02 23:53:04 -0700951 CreateFrame(frame_timestamp, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -0700952 WaitForEncodedFrame(frame_timestamp);
sprangc5d62e22017-04-02 23:53:04 -0700953 frame_timestamp += kFrameIntervalMs;
954
perkj803d97f2016-11-01 11:45:46 -0700955 // Trigger CPU overuse.
mflodmancc3d4422017-08-03 08:27:51 -0700956 video_stream_encoder_->TriggerCpuOveruse();
perkj803d97f2016-11-01 11:45:46 -0700957 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;
sprang3ea3c772017-03-30 07:23:48 -0700961
asapersson0944a802017-04-07 00:57:58 -0700962 // Default degradation preference is maintain-framerate, so will lower max
sprangc5d62e22017-04-02 23:53:04 -0700963 // wanted resolution.
964 EXPECT_FALSE(video_source_.sink_wants().target_pixel_count);
965 EXPECT_LT(video_source_.sink_wants().max_pixel_count,
966 kFrameWidth * kFrameHeight);
967 EXPECT_EQ(std::numeric_limits<int>::max(),
968 video_source_.sink_wants().max_framerate_fps);
969
970 // Set new source, switch to maintain-resolution.
perkj803d97f2016-11-01 11:45:46 -0700971 test::FrameForwarder new_video_source;
mflodmancc3d4422017-08-03 08:27:51 -0700972 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -0700973 &new_video_source, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
perkj803d97f2016-11-01 11:45:46 -0700974
sprangc5d62e22017-04-02 23:53:04 -0700975 // Initially no degradation registered.
asapersson02465b82017-04-10 01:12:52 -0700976 VerifyNoLimitation(new_video_source.sink_wants());
perkj803d97f2016-11-01 11:45:46 -0700977
sprangc5d62e22017-04-02 23:53:04 -0700978 // Force an input frame rate to be available, or the adaptation call won't
979 // know what framerate to adapt form.
asapersson02465b82017-04-10 01:12:52 -0700980 const int kInputFps = 30;
sprangc5d62e22017-04-02 23:53:04 -0700981 VideoSendStream::Stats stats = stats_proxy_->GetStats();
asapersson02465b82017-04-10 01:12:52 -0700982 stats.input_frame_rate = kInputFps;
sprangc5d62e22017-04-02 23:53:04 -0700983 stats_proxy_->SetMockStats(stats);
984
mflodmancc3d4422017-08-03 08:27:51 -0700985 video_stream_encoder_->TriggerCpuOveruse();
perkj803d97f2016-11-01 11:45:46 -0700986 new_video_source.IncomingCapturedFrame(
sprangc5d62e22017-04-02 23:53:04 -0700987 CreateFrame(frame_timestamp, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -0700988 WaitForEncodedFrame(frame_timestamp);
sprangc5d62e22017-04-02 23:53:04 -0700989 frame_timestamp += kFrameIntervalMs;
990
991 // Some framerate constraint should be set.
sprang84a37592017-02-10 07:04:27 -0800992 EXPECT_FALSE(new_video_source.sink_wants().target_pixel_count);
sprangc5d62e22017-04-02 23:53:04 -0700993 EXPECT_EQ(std::numeric_limits<int>::max(),
994 new_video_source.sink_wants().max_pixel_count);
asapersson02465b82017-04-10 01:12:52 -0700995 EXPECT_LT(new_video_source.sink_wants().max_framerate_fps, kInputFps);
sprangc5d62e22017-04-02 23:53:04 -0700996
asapersson02465b82017-04-10 01:12:52 -0700997 // Turn off degradation completely.
Taylor Brandstetter49fcc102018-05-16 14:20:41 -0700998 video_stream_encoder_->SetSource(&new_video_source,
999 webrtc::DegradationPreference::DISABLED);
asapersson02465b82017-04-10 01:12:52 -07001000 VerifyNoLimitation(new_video_source.sink_wants());
sprangc5d62e22017-04-02 23:53:04 -07001001
mflodmancc3d4422017-08-03 08:27:51 -07001002 video_stream_encoder_->TriggerCpuOveruse();
sprangc5d62e22017-04-02 23:53:04 -07001003 new_video_source.IncomingCapturedFrame(
1004 CreateFrame(frame_timestamp, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07001005 WaitForEncodedFrame(frame_timestamp);
sprangc5d62e22017-04-02 23:53:04 -07001006 frame_timestamp += kFrameIntervalMs;
1007
1008 // Still no degradation.
asapersson02465b82017-04-10 01:12:52 -07001009 VerifyNoLimitation(new_video_source.sink_wants());
perkj803d97f2016-11-01 11:45:46 -07001010
1011 // Calling SetSource with resolution scaling enabled apply the old SinkWants.
mflodmancc3d4422017-08-03 08:27:51 -07001012 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001013 &new_video_source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
sprangc5d62e22017-04-02 23:53:04 -07001014 EXPECT_LT(new_video_source.sink_wants().max_pixel_count,
1015 kFrameWidth * kFrameHeight);
sprang84a37592017-02-10 07:04:27 -08001016 EXPECT_FALSE(new_video_source.sink_wants().target_pixel_count);
sprangc5d62e22017-04-02 23:53:04 -07001017 EXPECT_EQ(std::numeric_limits<int>::max(),
1018 new_video_source.sink_wants().max_framerate_fps);
1019
1020 // Calling SetSource with framerate scaling enabled apply the old SinkWants.
mflodmancc3d4422017-08-03 08:27:51 -07001021 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001022 &new_video_source, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
sprangc5d62e22017-04-02 23:53:04 -07001023 EXPECT_FALSE(new_video_source.sink_wants().target_pixel_count);
1024 EXPECT_EQ(std::numeric_limits<int>::max(),
1025 new_video_source.sink_wants().max_pixel_count);
asapersson02465b82017-04-10 01:12:52 -07001026 EXPECT_LT(new_video_source.sink_wants().max_framerate_fps, kInputFps);
perkj803d97f2016-11-01 11:45:46 -07001027
mflodmancc3d4422017-08-03 08:27:51 -07001028 video_stream_encoder_->Stop();
perkj803d97f2016-11-01 11:45:46 -07001029}
1030
mflodmancc3d4422017-08-03 08:27:51 -07001031TEST_F(VideoStreamEncoderTest, StatsTracksQualityAdaptationStats) {
1032 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkj803d97f2016-11-01 11:45:46 -07001033
asaperssonfab67072017-04-04 05:51:49 -07001034 const int kWidth = 1280;
1035 const int kHeight = 720;
asaperssonfab67072017-04-04 05:51:49 -07001036 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001037 WaitForEncodedFrame(1);
asaperssonfab67072017-04-04 05:51:49 -07001038 VideoSendStream::Stats stats = stats_proxy_->GetStats();
1039 EXPECT_FALSE(stats.bw_limited_resolution);
1040 EXPECT_EQ(0, stats.number_of_quality_adapt_changes);
1041
1042 // Trigger adapt down.
mflodmancc3d4422017-08-03 08:27:51 -07001043 video_stream_encoder_->TriggerQualityLow();
asaperssonfab67072017-04-04 05:51:49 -07001044 video_source_.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001045 WaitForEncodedFrame(2);
asaperssonfab67072017-04-04 05:51:49 -07001046
1047 stats = stats_proxy_->GetStats();
1048 EXPECT_TRUE(stats.bw_limited_resolution);
1049 EXPECT_EQ(1, stats.number_of_quality_adapt_changes);
1050
1051 // Trigger adapt up.
mflodmancc3d4422017-08-03 08:27:51 -07001052 video_stream_encoder_->TriggerQualityHigh();
asaperssonfab67072017-04-04 05:51:49 -07001053 video_source_.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001054 WaitForEncodedFrame(3);
asaperssonfab67072017-04-04 05:51:49 -07001055
1056 stats = stats_proxy_->GetStats();
1057 EXPECT_FALSE(stats.bw_limited_resolution);
1058 EXPECT_EQ(2, stats.number_of_quality_adapt_changes);
1059 EXPECT_EQ(0, stats.number_of_cpu_adapt_changes);
1060
mflodmancc3d4422017-08-03 08:27:51 -07001061 video_stream_encoder_->Stop();
asaperssonfab67072017-04-04 05:51:49 -07001062}
1063
mflodmancc3d4422017-08-03 08:27:51 -07001064TEST_F(VideoStreamEncoderTest, StatsTracksCpuAdaptationStats) {
1065 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonfab67072017-04-04 05:51:49 -07001066
1067 const int kWidth = 1280;
1068 const int kHeight = 720;
asaperssonfab67072017-04-04 05:51:49 -07001069 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001070 WaitForEncodedFrame(1);
perkj803d97f2016-11-01 11:45:46 -07001071 VideoSendStream::Stats stats = stats_proxy_->GetStats();
1072 EXPECT_FALSE(stats.cpu_limited_resolution);
1073 EXPECT_EQ(0, stats.number_of_cpu_adapt_changes);
1074
1075 // Trigger CPU overuse.
mflodmancc3d4422017-08-03 08:27:51 -07001076 video_stream_encoder_->TriggerCpuOveruse();
asaperssonfab67072017-04-04 05:51:49 -07001077 video_source_.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001078 WaitForEncodedFrame(2);
perkj803d97f2016-11-01 11:45:46 -07001079
1080 stats = stats_proxy_->GetStats();
1081 EXPECT_TRUE(stats.cpu_limited_resolution);
1082 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1083
1084 // Trigger CPU normal use.
mflodmancc3d4422017-08-03 08:27:51 -07001085 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssonfab67072017-04-04 05:51:49 -07001086 video_source_.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001087 WaitForEncodedFrame(3);
perkj803d97f2016-11-01 11:45:46 -07001088
1089 stats = stats_proxy_->GetStats();
1090 EXPECT_FALSE(stats.cpu_limited_resolution);
1091 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
asaperssonfab67072017-04-04 05:51:49 -07001092 EXPECT_EQ(0, stats.number_of_quality_adapt_changes);
perkj803d97f2016-11-01 11:45:46 -07001093
mflodmancc3d4422017-08-03 08:27:51 -07001094 video_stream_encoder_->Stop();
perkj803d97f2016-11-01 11:45:46 -07001095}
1096
mflodmancc3d4422017-08-03 08:27:51 -07001097TEST_F(VideoStreamEncoderTest, SwitchingSourceKeepsCpuAdaptation) {
1098 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
kthelgason876222f2016-11-29 01:44:11 -08001099
asaperssonfab67072017-04-04 05:51:49 -07001100 const int kWidth = 1280;
1101 const int kHeight = 720;
1102 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001103 WaitForEncodedFrame(1);
kthelgason876222f2016-11-29 01:44:11 -08001104 VideoSendStream::Stats stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001105 EXPECT_FALSE(stats.bw_limited_resolution);
kthelgason876222f2016-11-29 01:44:11 -08001106 EXPECT_FALSE(stats.cpu_limited_resolution);
1107 EXPECT_EQ(0, stats.number_of_cpu_adapt_changes);
1108
asaperssonfab67072017-04-04 05:51:49 -07001109 // Trigger CPU overuse.
mflodmancc3d4422017-08-03 08:27:51 -07001110 video_stream_encoder_->TriggerCpuOveruse();
asaperssonfab67072017-04-04 05:51:49 -07001111 video_source_.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001112 WaitForEncodedFrame(2);
kthelgason876222f2016-11-29 01:44:11 -08001113 stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001114 EXPECT_FALSE(stats.bw_limited_resolution);
kthelgason876222f2016-11-29 01:44:11 -08001115 EXPECT_TRUE(stats.cpu_limited_resolution);
1116 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1117
1118 // Set new source with adaptation still enabled.
1119 test::FrameForwarder new_video_source;
mflodmancc3d4422017-08-03 08:27:51 -07001120 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001121 &new_video_source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
kthelgason876222f2016-11-29 01:44:11 -08001122
asaperssonfab67072017-04-04 05:51:49 -07001123 new_video_source.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001124 WaitForEncodedFrame(3);
kthelgason876222f2016-11-29 01:44:11 -08001125 stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001126 EXPECT_FALSE(stats.bw_limited_resolution);
kthelgason876222f2016-11-29 01:44:11 -08001127 EXPECT_TRUE(stats.cpu_limited_resolution);
1128 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1129
1130 // Set adaptation disabled.
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001131 video_stream_encoder_->SetSource(&new_video_source,
1132 webrtc::DegradationPreference::DISABLED);
kthelgason876222f2016-11-29 01:44:11 -08001133
asaperssonfab67072017-04-04 05:51:49 -07001134 new_video_source.IncomingCapturedFrame(CreateFrame(4, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001135 WaitForEncodedFrame(4);
kthelgason876222f2016-11-29 01:44:11 -08001136 stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001137 EXPECT_FALSE(stats.bw_limited_resolution);
kthelgason876222f2016-11-29 01:44:11 -08001138 EXPECT_FALSE(stats.cpu_limited_resolution);
1139 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1140
1141 // Set adaptation back to enabled.
mflodmancc3d4422017-08-03 08:27:51 -07001142 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001143 &new_video_source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
kthelgason876222f2016-11-29 01:44:11 -08001144
asaperssonfab67072017-04-04 05:51:49 -07001145 new_video_source.IncomingCapturedFrame(CreateFrame(5, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001146 WaitForEncodedFrame(5);
kthelgason876222f2016-11-29 01:44:11 -08001147 stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001148 EXPECT_FALSE(stats.bw_limited_resolution);
kthelgason876222f2016-11-29 01:44:11 -08001149 EXPECT_TRUE(stats.cpu_limited_resolution);
1150 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1151
asaperssonfab67072017-04-04 05:51:49 -07001152 // Trigger CPU normal use.
mflodmancc3d4422017-08-03 08:27:51 -07001153 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssonfab67072017-04-04 05:51:49 -07001154 new_video_source.IncomingCapturedFrame(CreateFrame(6, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001155 WaitForEncodedFrame(6);
kthelgason876222f2016-11-29 01:44:11 -08001156 stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001157 EXPECT_FALSE(stats.bw_limited_resolution);
kthelgason876222f2016-11-29 01:44:11 -08001158 EXPECT_FALSE(stats.cpu_limited_resolution);
1159 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
asapersson02465b82017-04-10 01:12:52 -07001160 EXPECT_EQ(0, stats.number_of_quality_adapt_changes);
kthelgason876222f2016-11-29 01:44:11 -08001161
mflodmancc3d4422017-08-03 08:27:51 -07001162 video_stream_encoder_->Stop();
kthelgason876222f2016-11-29 01:44:11 -08001163}
1164
mflodmancc3d4422017-08-03 08:27:51 -07001165TEST_F(VideoStreamEncoderTest, SwitchingSourceKeepsQualityAdaptation) {
1166 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
kthelgason876222f2016-11-29 01:44:11 -08001167
asaperssonfab67072017-04-04 05:51:49 -07001168 const int kWidth = 1280;
1169 const int kHeight = 720;
1170 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001171 WaitForEncodedFrame(1);
kthelgason876222f2016-11-29 01:44:11 -08001172 VideoSendStream::Stats stats = stats_proxy_->GetStats();
kthelgason876222f2016-11-29 01:44:11 -08001173 EXPECT_FALSE(stats.bw_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001174 EXPECT_FALSE(stats.bw_limited_framerate);
asaperssonfab67072017-04-04 05:51:49 -07001175 EXPECT_EQ(0, stats.number_of_quality_adapt_changes);
kthelgason876222f2016-11-29 01:44:11 -08001176
1177 // Set new source with adaptation still enabled.
1178 test::FrameForwarder new_video_source;
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001179 video_stream_encoder_->SetSource(&new_video_source,
1180 webrtc::DegradationPreference::BALANCED);
kthelgason876222f2016-11-29 01:44:11 -08001181
asaperssonfab67072017-04-04 05:51:49 -07001182 new_video_source.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001183 WaitForEncodedFrame(2);
kthelgason876222f2016-11-29 01:44:11 -08001184 stats = stats_proxy_->GetStats();
kthelgason876222f2016-11-29 01:44:11 -08001185 EXPECT_FALSE(stats.bw_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001186 EXPECT_FALSE(stats.bw_limited_framerate);
asaperssonfab67072017-04-04 05:51:49 -07001187 EXPECT_EQ(0, stats.number_of_quality_adapt_changes);
kthelgason876222f2016-11-29 01:44:11 -08001188
asaperssonfab67072017-04-04 05:51:49 -07001189 // Trigger adapt down.
mflodmancc3d4422017-08-03 08:27:51 -07001190 video_stream_encoder_->TriggerQualityLow();
asaperssonfab67072017-04-04 05:51:49 -07001191 new_video_source.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001192 WaitForEncodedFrame(3);
kthelgason876222f2016-11-29 01:44:11 -08001193 stats = stats_proxy_->GetStats();
kthelgason876222f2016-11-29 01:44:11 -08001194 EXPECT_TRUE(stats.bw_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001195 EXPECT_FALSE(stats.bw_limited_framerate);
asaperssonfab67072017-04-04 05:51:49 -07001196 EXPECT_EQ(1, stats.number_of_quality_adapt_changes);
kthelgason876222f2016-11-29 01:44:11 -08001197
asaperssonfab67072017-04-04 05:51:49 -07001198 // Set new source with adaptation still enabled.
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001199 video_stream_encoder_->SetSource(&new_video_source,
1200 webrtc::DegradationPreference::BALANCED);
kthelgason876222f2016-11-29 01:44:11 -08001201
asaperssonfab67072017-04-04 05:51:49 -07001202 new_video_source.IncomingCapturedFrame(CreateFrame(4, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001203 WaitForEncodedFrame(4);
kthelgason876222f2016-11-29 01:44:11 -08001204 stats = stats_proxy_->GetStats();
kthelgason876222f2016-11-29 01:44:11 -08001205 EXPECT_TRUE(stats.bw_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001206 EXPECT_FALSE(stats.bw_limited_framerate);
asaperssonfab67072017-04-04 05:51:49 -07001207 EXPECT_EQ(1, stats.number_of_quality_adapt_changes);
kthelgason876222f2016-11-29 01:44:11 -08001208
asapersson02465b82017-04-10 01:12:52 -07001209 // Disable resolution scaling.
mflodmancc3d4422017-08-03 08:27:51 -07001210 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001211 &new_video_source, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
kthelgason876222f2016-11-29 01:44:11 -08001212
asaperssonfab67072017-04-04 05:51:49 -07001213 new_video_source.IncomingCapturedFrame(CreateFrame(5, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001214 WaitForEncodedFrame(5);
kthelgason876222f2016-11-29 01:44:11 -08001215 stats = stats_proxy_->GetStats();
kthelgason876222f2016-11-29 01:44:11 -08001216 EXPECT_FALSE(stats.bw_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001217 EXPECT_FALSE(stats.bw_limited_framerate);
asaperssonfab67072017-04-04 05:51:49 -07001218 EXPECT_EQ(1, stats.number_of_quality_adapt_changes);
1219 EXPECT_EQ(0, stats.number_of_cpu_adapt_changes);
kthelgason876222f2016-11-29 01:44:11 -08001220
mflodmancc3d4422017-08-03 08:27:51 -07001221 video_stream_encoder_->Stop();
kthelgason876222f2016-11-29 01:44:11 -08001222}
1223
mflodmancc3d4422017-08-03 08:27:51 -07001224TEST_F(VideoStreamEncoderTest,
1225 QualityAdaptationStatsAreResetWhenScalerIsDisabled) {
1226 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson36e9eb42017-03-31 05:29:12 -07001227
1228 const int kWidth = 1280;
1229 const int kHeight = 720;
1230 video_source_.set_adaptation_enabled(true);
1231 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001232 WaitForEncodedFrame(1);
asapersson36e9eb42017-03-31 05:29:12 -07001233 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1234 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1235 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1236
1237 // Trigger adapt down.
mflodmancc3d4422017-08-03 08:27:51 -07001238 video_stream_encoder_->TriggerQualityLow();
asapersson36e9eb42017-03-31 05:29:12 -07001239 video_source_.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001240 WaitForEncodedFrame(2);
asapersson36e9eb42017-03-31 05:29:12 -07001241 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1242 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1243 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1244
1245 // Trigger overuse.
mflodmancc3d4422017-08-03 08:27:51 -07001246 video_stream_encoder_->TriggerCpuOveruse();
asapersson36e9eb42017-03-31 05:29:12 -07001247 video_source_.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001248 WaitForEncodedFrame(3);
asapersson36e9eb42017-03-31 05:29:12 -07001249 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1250 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1251 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1252
Niels Möller4db138e2018-04-19 09:04:13 +02001253 // Leave source unchanged, but disable quality scaler.
asapersson36e9eb42017-03-31 05:29:12 -07001254 fake_encoder_.SetQualityScaling(false);
Niels Möller4db138e2018-04-19 09:04:13 +02001255
1256 VideoEncoderConfig video_encoder_config;
1257 test::FillEncoderConfiguration(kVideoCodecVP8, 1, &video_encoder_config);
1258 // Make format different, to force recreation of encoder.
1259 video_encoder_config.video_format.parameters["foo"] = "foo";
1260 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
Niels Möllerf1338562018-04-26 09:51:47 +02001261 kMaxPayloadLength);
asapersson36e9eb42017-03-31 05:29:12 -07001262
1263 video_source_.IncomingCapturedFrame(CreateFrame(4, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001264 WaitForEncodedFrame(4);
asapersson36e9eb42017-03-31 05:29:12 -07001265 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1266 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1267 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1268
mflodmancc3d4422017-08-03 08:27:51 -07001269 video_stream_encoder_->Stop();
asapersson36e9eb42017-03-31 05:29:12 -07001270}
1271
mflodmancc3d4422017-08-03 08:27:51 -07001272TEST_F(VideoStreamEncoderTest,
1273 StatsTracksCpuAdaptationStatsWhenSwitchingSource) {
1274 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkj803d97f2016-11-01 11:45:46 -07001275
asapersson0944a802017-04-07 00:57:58 -07001276 const int kWidth = 1280;
1277 const int kHeight = 720;
sprang84a37592017-02-10 07:04:27 -08001278 int sequence = 1;
perkj803d97f2016-11-01 11:45:46 -07001279
asaperssonfab67072017-04-04 05:51:49 -07001280 video_source_.IncomingCapturedFrame(CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001281 WaitForEncodedFrame(sequence++);
perkj803d97f2016-11-01 11:45:46 -07001282 VideoSendStream::Stats stats = stats_proxy_->GetStats();
sprang84a37592017-02-10 07:04:27 -08001283 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001284 EXPECT_FALSE(stats.cpu_limited_framerate);
sprang84a37592017-02-10 07:04:27 -08001285 EXPECT_EQ(0, stats.number_of_cpu_adapt_changes);
1286
asapersson02465b82017-04-10 01:12:52 -07001287 // Trigger CPU overuse, should now adapt down.
mflodmancc3d4422017-08-03 08:27:51 -07001288 video_stream_encoder_->TriggerCpuOveruse();
asaperssonfab67072017-04-04 05:51:49 -07001289 video_source_.IncomingCapturedFrame(CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001290 WaitForEncodedFrame(sequence++);
sprang84a37592017-02-10 07:04:27 -08001291 stats = stats_proxy_->GetStats();
perkj803d97f2016-11-01 11:45:46 -07001292 EXPECT_TRUE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001293 EXPECT_FALSE(stats.cpu_limited_framerate);
perkj803d97f2016-11-01 11:45:46 -07001294 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1295
1296 // Set new source with adaptation still enabled.
1297 test::FrameForwarder new_video_source;
mflodmancc3d4422017-08-03 08:27:51 -07001298 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001299 &new_video_source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
perkj803d97f2016-11-01 11:45:46 -07001300
1301 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001302 CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001303 WaitForEncodedFrame(sequence++);
perkj803d97f2016-11-01 11:45:46 -07001304 stats = stats_proxy_->GetStats();
1305 EXPECT_TRUE(stats.cpu_limited_resolution);
asapersson09f05612017-05-15 23:40:18 -07001306 EXPECT_FALSE(stats.cpu_limited_framerate);
perkj803d97f2016-11-01 11:45:46 -07001307 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1308
sprangc5d62e22017-04-02 23:53:04 -07001309 // Set cpu adaptation by frame dropping.
mflodmancc3d4422017-08-03 08:27:51 -07001310 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001311 &new_video_source, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
perkj803d97f2016-11-01 11:45:46 -07001312 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001313 CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001314 WaitForEncodedFrame(sequence++);
perkj803d97f2016-11-01 11:45:46 -07001315 stats = stats_proxy_->GetStats();
sprangc5d62e22017-04-02 23:53:04 -07001316 // Not adapted at first.
perkj803d97f2016-11-01 11:45:46 -07001317 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson09f05612017-05-15 23:40:18 -07001318 EXPECT_FALSE(stats.cpu_limited_framerate);
perkj803d97f2016-11-01 11:45:46 -07001319 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1320
sprangc5d62e22017-04-02 23:53:04 -07001321 // Force an input frame rate to be available, or the adaptation call won't
asapersson09f05612017-05-15 23:40:18 -07001322 // know what framerate to adapt from.
sprangc5d62e22017-04-02 23:53:04 -07001323 VideoSendStream::Stats mock_stats = stats_proxy_->GetStats();
1324 mock_stats.input_frame_rate = 30;
1325 stats_proxy_->SetMockStats(mock_stats);
mflodmancc3d4422017-08-03 08:27:51 -07001326 video_stream_encoder_->TriggerCpuOveruse();
sprangc5d62e22017-04-02 23:53:04 -07001327 stats_proxy_->ResetMockStats();
1328
1329 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001330 CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001331 WaitForEncodedFrame(sequence++);
sprangc5d62e22017-04-02 23:53:04 -07001332
1333 // Framerate now adapted.
1334 stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001335 EXPECT_FALSE(stats.cpu_limited_resolution);
1336 EXPECT_TRUE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001337 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
1338
1339 // Disable CPU adaptation.
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001340 video_stream_encoder_->SetSource(&new_video_source,
1341 webrtc::DegradationPreference::DISABLED);
sprangc5d62e22017-04-02 23:53:04 -07001342 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001343 CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001344 WaitForEncodedFrame(sequence++);
sprangc5d62e22017-04-02 23:53:04 -07001345
1346 stats = stats_proxy_->GetStats();
1347 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001348 EXPECT_FALSE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001349 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
1350
1351 // Try to trigger overuse. Should not succeed.
1352 stats_proxy_->SetMockStats(mock_stats);
mflodmancc3d4422017-08-03 08:27:51 -07001353 video_stream_encoder_->TriggerCpuOveruse();
sprangc5d62e22017-04-02 23:53:04 -07001354 stats_proxy_->ResetMockStats();
1355
1356 stats = stats_proxy_->GetStats();
1357 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001358 EXPECT_FALSE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001359 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
1360
1361 // Switch back the source with resolution adaptation enabled.
mflodmancc3d4422017-08-03 08:27:51 -07001362 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001363 &video_source_, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
asaperssonfab67072017-04-04 05:51:49 -07001364 video_source_.IncomingCapturedFrame(CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001365 WaitForEncodedFrame(sequence++);
perkj803d97f2016-11-01 11:45:46 -07001366 stats = stats_proxy_->GetStats();
1367 EXPECT_TRUE(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);
perkj803d97f2016-11-01 11:45:46 -07001370
1371 // Trigger CPU normal usage.
mflodmancc3d4422017-08-03 08:27:51 -07001372 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssonfab67072017-04-04 05:51:49 -07001373 video_source_.IncomingCapturedFrame(CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001374 WaitForEncodedFrame(sequence++);
perkj803d97f2016-11-01 11:45:46 -07001375 stats = stats_proxy_->GetStats();
1376 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001377 EXPECT_FALSE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001378 EXPECT_EQ(3, stats.number_of_cpu_adapt_changes);
1379
1380 // Back to the source with adaptation off, set it back to maintain-resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001381 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001382 &new_video_source, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
sprangc5d62e22017-04-02 23:53:04 -07001383 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001384 CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001385 WaitForEncodedFrame(sequence++);
sprangc5d62e22017-04-02 23:53:04 -07001386 stats = stats_proxy_->GetStats();
asapersson13874762017-06-07 00:01:02 -07001387 // Disabled, since we previously switched the source to disabled.
sprangc5d62e22017-04-02 23:53:04 -07001388 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001389 EXPECT_TRUE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001390 EXPECT_EQ(3, stats.number_of_cpu_adapt_changes);
1391
1392 // Trigger CPU normal usage.
mflodmancc3d4422017-08-03 08:27:51 -07001393 video_stream_encoder_->TriggerCpuNormalUsage();
sprangc5d62e22017-04-02 23:53:04 -07001394 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001395 CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001396 WaitForEncodedFrame(sequence++);
sprangc5d62e22017-04-02 23:53:04 -07001397 stats = stats_proxy_->GetStats();
1398 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001399 EXPECT_FALSE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001400 EXPECT_EQ(4, stats.number_of_cpu_adapt_changes);
asapersson02465b82017-04-10 01:12:52 -07001401 EXPECT_EQ(0, stats.number_of_quality_adapt_changes);
perkj803d97f2016-11-01 11:45:46 -07001402
mflodmancc3d4422017-08-03 08:27:51 -07001403 video_stream_encoder_->Stop();
perkj803d97f2016-11-01 11:45:46 -07001404}
1405
mflodmancc3d4422017-08-03 08:27:51 -07001406TEST_F(VideoStreamEncoderTest,
1407 ScalingUpAndDownDoesNothingWithMaintainResolution) {
asaperssonfab67072017-04-04 05:51:49 -07001408 const int kWidth = 1280;
1409 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001410 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
kthelgason876222f2016-11-29 01:44:11 -08001411
asaperssonfab67072017-04-04 05:51:49 -07001412 // Expect no scaling to begin with.
asapersson02465b82017-04-10 01:12:52 -07001413 VerifyNoLimitation(video_source_.sink_wants());
kthelgason876222f2016-11-29 01:44:11 -08001414
asaperssonfab67072017-04-04 05:51:49 -07001415 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001416 WaitForEncodedFrame(1);
kthelgason876222f2016-11-29 01:44:11 -08001417
asaperssonfab67072017-04-04 05:51:49 -07001418 // Trigger scale down.
mflodmancc3d4422017-08-03 08:27:51 -07001419 video_stream_encoder_->TriggerQualityLow();
kthelgason5e13d412016-12-01 03:59:51 -08001420
asaperssonfab67072017-04-04 05:51:49 -07001421 video_source_.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001422 WaitForEncodedFrame(2);
kthelgason5e13d412016-12-01 03:59:51 -08001423
kthelgason876222f2016-11-29 01:44:11 -08001424 // Expect a scale down.
1425 EXPECT_TRUE(video_source_.sink_wants().max_pixel_count);
asaperssonfab67072017-04-04 05:51:49 -07001426 EXPECT_LT(video_source_.sink_wants().max_pixel_count, kWidth * kHeight);
kthelgason876222f2016-11-29 01:44:11 -08001427
asapersson02465b82017-04-10 01:12:52 -07001428 // Set resolution scaling disabled.
kthelgason876222f2016-11-29 01:44:11 -08001429 test::FrameForwarder new_video_source;
mflodmancc3d4422017-08-03 08:27:51 -07001430 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001431 &new_video_source, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
kthelgason876222f2016-11-29 01:44:11 -08001432
asaperssonfab67072017-04-04 05:51:49 -07001433 // Trigger scale down.
mflodmancc3d4422017-08-03 08:27:51 -07001434 video_stream_encoder_->TriggerQualityLow();
asaperssonfab67072017-04-04 05:51:49 -07001435 new_video_source.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001436 WaitForEncodedFrame(3);
kthelgason876222f2016-11-29 01:44:11 -08001437
asaperssonfab67072017-04-04 05:51:49 -07001438 // Expect no scaling.
sprangc5d62e22017-04-02 23:53:04 -07001439 EXPECT_EQ(std::numeric_limits<int>::max(),
1440 new_video_source.sink_wants().max_pixel_count);
kthelgason876222f2016-11-29 01:44:11 -08001441
asaperssonfab67072017-04-04 05:51:49 -07001442 // Trigger scale up.
mflodmancc3d4422017-08-03 08:27:51 -07001443 video_stream_encoder_->TriggerQualityHigh();
asaperssonfab67072017-04-04 05:51:49 -07001444 new_video_source.IncomingCapturedFrame(CreateFrame(4, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001445 WaitForEncodedFrame(4);
kthelgason876222f2016-11-29 01:44:11 -08001446
asapersson02465b82017-04-10 01:12:52 -07001447 // Expect nothing to change, still no scaling.
sprangc5d62e22017-04-02 23:53:04 -07001448 EXPECT_EQ(std::numeric_limits<int>::max(),
1449 new_video_source.sink_wants().max_pixel_count);
kthelgason876222f2016-11-29 01:44:11 -08001450
mflodmancc3d4422017-08-03 08:27:51 -07001451 video_stream_encoder_->Stop();
kthelgason876222f2016-11-29 01:44:11 -08001452}
1453
mflodmancc3d4422017-08-03 08:27:51 -07001454TEST_F(VideoStreamEncoderTest,
1455 SkipsSameAdaptDownRequest_MaintainFramerateMode) {
asapersson02465b82017-04-10 01:12:52 -07001456 const int kWidth = 1280;
1457 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001458 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson02465b82017-04-10 01:12:52 -07001459
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001460 // Enable MAINTAIN_FRAMERATE preference, no initial limitation.
asapersson02465b82017-04-10 01:12:52 -07001461 test::FrameForwarder source;
mflodmancc3d4422017-08-03 08:27:51 -07001462 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001463 &source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
asapersson02465b82017-04-10 01:12:52 -07001464
1465 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001466 WaitForEncodedFrame(1);
asapersson02465b82017-04-10 01:12:52 -07001467 VerifyNoLimitation(source.sink_wants());
1468 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1469 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1470
1471 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001472 video_stream_encoder_->TriggerCpuOveruse();
asapersson09f05612017-05-15 23:40:18 -07001473 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
asapersson02465b82017-04-10 01:12:52 -07001474 const int kLastMaxPixelCount = source.sink_wants().max_pixel_count;
1475 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1476 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1477
1478 // Trigger adapt down for same input resolution, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07001479 video_stream_encoder_->TriggerCpuOveruse();
asapersson02465b82017-04-10 01:12:52 -07001480 EXPECT_EQ(kLastMaxPixelCount, source.sink_wants().max_pixel_count);
1481 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1482 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1483
mflodmancc3d4422017-08-03 08:27:51 -07001484 video_stream_encoder_->Stop();
asapersson02465b82017-04-10 01:12:52 -07001485}
1486
mflodmancc3d4422017-08-03 08:27:51 -07001487TEST_F(VideoStreamEncoderTest, SkipsSameOrLargerAdaptDownRequest_BalancedMode) {
asaperssonf7e294d2017-06-13 23:25:22 -07001488 const int kWidth = 1280;
1489 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001490 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -07001491
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001492 // Enable BALANCED preference, no initial limitation.
asaperssonf7e294d2017-06-13 23:25:22 -07001493 test::FrameForwarder source;
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001494 video_stream_encoder_->SetSource(&source,
1495 webrtc::DegradationPreference::BALANCED);
asaperssonf7e294d2017-06-13 23:25:22 -07001496 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
1497 sink_.WaitForEncodedFrame(1);
1498 VerifyNoLimitation(source.sink_wants());
1499
1500 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001501 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07001502 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
1503 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1504 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1505 const int kLastMaxPixelCount = source.sink_wants().max_pixel_count;
1506
1507 // Trigger adapt down for same input resolution, expect no change.
1508 source.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
1509 sink_.WaitForEncodedFrame(2);
mflodmancc3d4422017-08-03 08:27:51 -07001510 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07001511 EXPECT_EQ(kLastMaxPixelCount, source.sink_wants().max_pixel_count);
1512 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1513 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1514
1515 // Trigger adapt down for larger input resolution, expect no change.
1516 source.IncomingCapturedFrame(CreateFrame(3, kWidth + 1, kHeight + 1));
1517 sink_.WaitForEncodedFrame(3);
mflodmancc3d4422017-08-03 08:27:51 -07001518 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07001519 EXPECT_EQ(kLastMaxPixelCount, source.sink_wants().max_pixel_count);
1520 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1521 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1522
mflodmancc3d4422017-08-03 08:27:51 -07001523 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07001524}
1525
mflodmancc3d4422017-08-03 08:27:51 -07001526TEST_F(VideoStreamEncoderTest,
1527 NoChangeForInitialNormalUsage_MaintainFramerateMode) {
asapersson02465b82017-04-10 01:12:52 -07001528 const int kWidth = 1280;
1529 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001530 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson02465b82017-04-10 01:12:52 -07001531
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001532 // Enable MAINTAIN_FRAMERATE preference, no initial limitation.
asapersson02465b82017-04-10 01:12:52 -07001533 test::FrameForwarder source;
mflodmancc3d4422017-08-03 08:27:51 -07001534 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001535 &source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
asapersson02465b82017-04-10 01:12:52 -07001536
1537 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001538 WaitForEncodedFrame(kWidth, kHeight);
asapersson02465b82017-04-10 01:12:52 -07001539 VerifyNoLimitation(source.sink_wants());
1540 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1541 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1542
1543 // Trigger adapt up, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07001544 video_stream_encoder_->TriggerCpuNormalUsage();
asapersson02465b82017-04-10 01:12:52 -07001545 VerifyNoLimitation(source.sink_wants());
1546 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1547 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1548
mflodmancc3d4422017-08-03 08:27:51 -07001549 video_stream_encoder_->Stop();
asapersson02465b82017-04-10 01:12:52 -07001550}
1551
mflodmancc3d4422017-08-03 08:27:51 -07001552TEST_F(VideoStreamEncoderTest,
1553 NoChangeForInitialNormalUsage_MaintainResolutionMode) {
asapersson02465b82017-04-10 01:12:52 -07001554 const int kWidth = 1280;
1555 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001556 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson02465b82017-04-10 01:12:52 -07001557
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001558 // Enable MAINTAIN_RESOLUTION preference, no initial limitation.
asapersson02465b82017-04-10 01:12:52 -07001559 test::FrameForwarder source;
mflodmancc3d4422017-08-03 08:27:51 -07001560 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001561 &source, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
asapersson02465b82017-04-10 01:12:52 -07001562
1563 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001564 WaitForEncodedFrame(kWidth, kHeight);
asapersson02465b82017-04-10 01:12:52 -07001565 VerifyNoLimitation(source.sink_wants());
asapersson09f05612017-05-15 23:40:18 -07001566 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
asapersson02465b82017-04-10 01:12:52 -07001567 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1568
1569 // Trigger adapt up, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07001570 video_stream_encoder_->TriggerCpuNormalUsage();
asapersson02465b82017-04-10 01:12:52 -07001571 VerifyNoLimitation(source.sink_wants());
asapersson09f05612017-05-15 23:40:18 -07001572 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
asapersson02465b82017-04-10 01:12:52 -07001573 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1574
mflodmancc3d4422017-08-03 08:27:51 -07001575 video_stream_encoder_->Stop();
asapersson02465b82017-04-10 01:12:52 -07001576}
1577
mflodmancc3d4422017-08-03 08:27:51 -07001578TEST_F(VideoStreamEncoderTest, NoChangeForInitialNormalUsage_BalancedMode) {
asaperssonf7e294d2017-06-13 23:25:22 -07001579 const int kWidth = 1280;
1580 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001581 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -07001582
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001583 // Enable BALANCED preference, no initial limitation.
asaperssonf7e294d2017-06-13 23:25:22 -07001584 test::FrameForwarder source;
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001585 video_stream_encoder_->SetSource(&source,
1586 webrtc::DegradationPreference::BALANCED);
asaperssonf7e294d2017-06-13 23:25:22 -07001587
1588 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
1589 sink_.WaitForEncodedFrame(kWidth, kHeight);
1590 VerifyNoLimitation(source.sink_wants());
1591 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1592 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
1593 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1594
1595 // Trigger adapt up, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07001596 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07001597 VerifyNoLimitation(source.sink_wants());
1598 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1599 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
1600 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1601
mflodmancc3d4422017-08-03 08:27:51 -07001602 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07001603}
1604
mflodmancc3d4422017-08-03 08:27:51 -07001605TEST_F(VideoStreamEncoderTest, NoChangeForInitialNormalUsage_DisabledMode) {
asapersson09f05612017-05-15 23:40:18 -07001606 const int kWidth = 1280;
1607 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001608 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson09f05612017-05-15 23:40:18 -07001609
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001610 // Enable DISABLED preference, no initial limitation.
asapersson09f05612017-05-15 23:40:18 -07001611 test::FrameForwarder source;
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001612 video_stream_encoder_->SetSource(&source,
1613 webrtc::DegradationPreference::DISABLED);
asapersson09f05612017-05-15 23:40:18 -07001614
1615 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
1616 sink_.WaitForEncodedFrame(kWidth, kHeight);
1617 VerifyNoLimitation(source.sink_wants());
1618 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1619 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
1620 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1621
1622 // Trigger adapt up, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07001623 video_stream_encoder_->TriggerQualityHigh();
asapersson09f05612017-05-15 23:40:18 -07001624 VerifyNoLimitation(source.sink_wants());
1625 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1626 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
1627 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1628
mflodmancc3d4422017-08-03 08:27:51 -07001629 video_stream_encoder_->Stop();
asapersson09f05612017-05-15 23:40:18 -07001630}
1631
mflodmancc3d4422017-08-03 08:27:51 -07001632TEST_F(VideoStreamEncoderTest,
1633 AdaptsResolutionForLowQuality_MaintainFramerateMode) {
asapersson02465b82017-04-10 01:12:52 -07001634 const int kWidth = 1280;
1635 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001636 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson02465b82017-04-10 01:12:52 -07001637
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001638 // Enable MAINTAIN_FRAMERATE preference, no initial limitation.
asapersson02465b82017-04-10 01:12:52 -07001639 AdaptingFrameForwarder source;
1640 source.set_adaptation_enabled(true);
mflodmancc3d4422017-08-03 08:27:51 -07001641 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001642 &source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
asapersson02465b82017-04-10 01:12:52 -07001643
1644 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001645 WaitForEncodedFrame(1);
asapersson02465b82017-04-10 01:12:52 -07001646 VerifyNoLimitation(source.sink_wants());
1647 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1648 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1649
1650 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001651 video_stream_encoder_->TriggerQualityLow();
asapersson02465b82017-04-10 01:12:52 -07001652 source.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001653 WaitForEncodedFrame(2);
asapersson09f05612017-05-15 23:40:18 -07001654 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
asapersson02465b82017-04-10 01:12:52 -07001655 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1656 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1657
1658 // Trigger adapt up, expect no restriction.
mflodmancc3d4422017-08-03 08:27:51 -07001659 video_stream_encoder_->TriggerQualityHigh();
asapersson02465b82017-04-10 01:12:52 -07001660 VerifyNoLimitation(source.sink_wants());
1661 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1662 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1663 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1664
mflodmancc3d4422017-08-03 08:27:51 -07001665 video_stream_encoder_->Stop();
asapersson02465b82017-04-10 01:12:52 -07001666}
1667
mflodmancc3d4422017-08-03 08:27:51 -07001668TEST_F(VideoStreamEncoderTest,
1669 AdaptsFramerateForLowQuality_MaintainResolutionMode) {
asapersson09f05612017-05-15 23:40:18 -07001670 const int kWidth = 1280;
1671 const int kHeight = 720;
1672 const int kInputFps = 30;
mflodmancc3d4422017-08-03 08:27:51 -07001673 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson09f05612017-05-15 23:40:18 -07001674
1675 VideoSendStream::Stats stats = stats_proxy_->GetStats();
1676 stats.input_frame_rate = kInputFps;
1677 stats_proxy_->SetMockStats(stats);
1678
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001679 // Expect no scaling to begin with (preference: MAINTAIN_FRAMERATE).
asapersson09f05612017-05-15 23:40:18 -07001680 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
1681 sink_.WaitForEncodedFrame(1);
1682 VerifyNoLimitation(video_source_.sink_wants());
1683
1684 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001685 video_stream_encoder_->TriggerQualityLow();
asapersson09f05612017-05-15 23:40:18 -07001686 video_source_.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
1687 sink_.WaitForEncodedFrame(2);
1688 VerifyFpsMaxResolutionLt(video_source_.sink_wants(), kWidth * kHeight);
1689
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001690 // Enable MAINTAIN_RESOLUTION preference.
asapersson09f05612017-05-15 23:40:18 -07001691 test::FrameForwarder new_video_source;
mflodmancc3d4422017-08-03 08:27:51 -07001692 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001693 &new_video_source, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
asapersson09f05612017-05-15 23:40:18 -07001694 VerifyNoLimitation(new_video_source.sink_wants());
1695
1696 // Trigger adapt down, expect reduced framerate.
mflodmancc3d4422017-08-03 08:27:51 -07001697 video_stream_encoder_->TriggerQualityLow();
asapersson09f05612017-05-15 23:40:18 -07001698 new_video_source.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
1699 sink_.WaitForEncodedFrame(3);
1700 VerifyFpsLtResolutionMax(new_video_source.sink_wants(), kInputFps);
1701
1702 // Trigger adapt up, expect no restriction.
mflodmancc3d4422017-08-03 08:27:51 -07001703 video_stream_encoder_->TriggerQualityHigh();
asapersson09f05612017-05-15 23:40:18 -07001704 VerifyNoLimitation(new_video_source.sink_wants());
1705
mflodmancc3d4422017-08-03 08:27:51 -07001706 video_stream_encoder_->Stop();
asapersson09f05612017-05-15 23:40:18 -07001707}
1708
mflodmancc3d4422017-08-03 08:27:51 -07001709TEST_F(VideoStreamEncoderTest, DoesNotScaleBelowSetResolutionLimit) {
asaperssond0de2952017-04-21 01:47:31 -07001710 const int kWidth = 1280;
1711 const int kHeight = 720;
1712 const size_t kNumFrames = 10;
1713
mflodmancc3d4422017-08-03 08:27:51 -07001714 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
kthelgason5e13d412016-12-01 03:59:51 -08001715
asaperssond0de2952017-04-21 01:47:31 -07001716 // Enable adapter, expected input resolutions when downscaling:
asapersson142fcc92017-08-17 08:58:54 -07001717 // 1280x720 -> 960x540 -> 640x360 -> 480x270 -> 320x180 (kMinPixelsPerFrame)
asaperssond0de2952017-04-21 01:47:31 -07001718 video_source_.set_adaptation_enabled(true);
1719
1720 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1721 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1722
1723 int downscales = 0;
1724 for (size_t i = 1; i <= kNumFrames; i++) {
1725 video_source_.IncomingCapturedFrame(CreateFrame(i, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001726 WaitForEncodedFrame(i);
asaperssond0de2952017-04-21 01:47:31 -07001727
asaperssonfab67072017-04-04 05:51:49 -07001728 // Trigger scale down.
asaperssond0de2952017-04-21 01:47:31 -07001729 rtc::VideoSinkWants last_wants = video_source_.sink_wants();
mflodmancc3d4422017-08-03 08:27:51 -07001730 video_stream_encoder_->TriggerQualityLow();
sprangc5d62e22017-04-02 23:53:04 -07001731 EXPECT_GE(video_source_.sink_wants().max_pixel_count, kMinPixelsPerFrame);
asaperssond0de2952017-04-21 01:47:31 -07001732
1733 if (video_source_.sink_wants().max_pixel_count < last_wants.max_pixel_count)
1734 ++downscales;
1735
1736 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1737 EXPECT_EQ(downscales,
1738 stats_proxy_->GetStats().number_of_quality_adapt_changes);
1739 EXPECT_GT(downscales, 0);
kthelgason5e13d412016-12-01 03:59:51 -08001740 }
mflodmancc3d4422017-08-03 08:27:51 -07001741 video_stream_encoder_->Stop();
asaperssond0de2952017-04-21 01:47:31 -07001742}
1743
mflodmancc3d4422017-08-03 08:27:51 -07001744TEST_F(VideoStreamEncoderTest,
asaperssond0de2952017-04-21 01:47:31 -07001745 AdaptsResolutionUpAndDownTwiceOnOveruse_MaintainFramerateMode) {
1746 const int kWidth = 1280;
1747 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001748 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssond0de2952017-04-21 01:47:31 -07001749
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001750 // Enable MAINTAIN_FRAMERATE preference, no initial limitation.
asaperssond0de2952017-04-21 01:47:31 -07001751 AdaptingFrameForwarder source;
1752 source.set_adaptation_enabled(true);
mflodmancc3d4422017-08-03 08:27:51 -07001753 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001754 &source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
asaperssond0de2952017-04-21 01:47:31 -07001755
1756 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001757 WaitForEncodedFrame(kWidth, kHeight);
asaperssond0de2952017-04-21 01:47:31 -07001758 VerifyNoLimitation(source.sink_wants());
1759 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1760 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1761
1762 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001763 video_stream_encoder_->TriggerCpuOveruse();
asaperssond0de2952017-04-21 01:47:31 -07001764 source.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001765 WaitForEncodedFrame(2);
asapersson09f05612017-05-15 23:40:18 -07001766 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
asaperssond0de2952017-04-21 01:47:31 -07001767 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1768 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1769
1770 // Trigger adapt up, expect no restriction.
mflodmancc3d4422017-08-03 08:27:51 -07001771 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssond0de2952017-04-21 01:47:31 -07001772 source.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001773 WaitForEncodedFrame(kWidth, kHeight);
asaperssond0de2952017-04-21 01:47:31 -07001774 VerifyNoLimitation(source.sink_wants());
1775 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1776 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1777
1778 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001779 video_stream_encoder_->TriggerCpuOveruse();
asaperssond0de2952017-04-21 01:47:31 -07001780 source.IncomingCapturedFrame(CreateFrame(4, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001781 WaitForEncodedFrame(4);
asapersson09f05612017-05-15 23:40:18 -07001782 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
asaperssond0de2952017-04-21 01:47:31 -07001783 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1784 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1785
1786 // Trigger adapt up, expect no restriction.
mflodmancc3d4422017-08-03 08:27:51 -07001787 video_stream_encoder_->TriggerCpuNormalUsage();
asapersson09f05612017-05-15 23:40:18 -07001788 source.IncomingCapturedFrame(CreateFrame(5, kWidth, kHeight));
1789 sink_.WaitForEncodedFrame(kWidth, kHeight);
asaperssond0de2952017-04-21 01:47:31 -07001790 VerifyNoLimitation(source.sink_wants());
1791 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1792 EXPECT_EQ(4, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1793
mflodmancc3d4422017-08-03 08:27:51 -07001794 video_stream_encoder_->Stop();
asaperssond0de2952017-04-21 01:47:31 -07001795}
1796
mflodmancc3d4422017-08-03 08:27:51 -07001797TEST_F(VideoStreamEncoderTest,
asaperssonf7e294d2017-06-13 23:25:22 -07001798 AdaptsResolutionUpAndDownTwiceForLowQuality_BalancedMode_NoFpsLimit) {
1799 const int kWidth = 1280;
1800 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001801 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -07001802
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001803 // Enable BALANCED preference, no initial limitation.
asaperssonf7e294d2017-06-13 23:25:22 -07001804 AdaptingFrameForwarder source;
1805 source.set_adaptation_enabled(true);
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001806 video_stream_encoder_->SetSource(&source,
1807 webrtc::DegradationPreference::BALANCED);
asaperssonf7e294d2017-06-13 23:25:22 -07001808
1809 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
1810 sink_.WaitForEncodedFrame(kWidth, kHeight);
1811 VerifyNoLimitation(source.sink_wants());
1812 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1813 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1814
1815 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001816 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07001817 source.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
1818 sink_.WaitForEncodedFrame(2);
1819 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
1820 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1821 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1822
1823 // Trigger adapt up, expect no restriction.
mflodmancc3d4422017-08-03 08:27:51 -07001824 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07001825 source.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
1826 sink_.WaitForEncodedFrame(kWidth, kHeight);
1827 VerifyNoLimitation(source.sink_wants());
1828 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1829 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1830
1831 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001832 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07001833 source.IncomingCapturedFrame(CreateFrame(4, kWidth, kHeight));
1834 sink_.WaitForEncodedFrame(4);
1835 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
1836 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1837 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1838
1839 // Trigger adapt up, expect no restriction.
mflodmancc3d4422017-08-03 08:27:51 -07001840 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07001841 source.IncomingCapturedFrame(CreateFrame(5, kWidth, kHeight));
1842 sink_.WaitForEncodedFrame(kWidth, kHeight);
1843 VerifyNoLimitation(source.sink_wants());
1844 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1845 EXPECT_EQ(4, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1846
mflodmancc3d4422017-08-03 08:27:51 -07001847 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07001848}
1849
mflodmancc3d4422017-08-03 08:27:51 -07001850TEST_F(VideoStreamEncoderTest,
asaperssond0de2952017-04-21 01:47:31 -07001851 AdaptsResolutionOnOveruseAndLowQuality_MaintainFramerateMode) {
1852 const int kWidth = 1280;
1853 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001854 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssond0de2952017-04-21 01:47:31 -07001855
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001856 // Enable MAINTAIN_FRAMERATE preference, no initial limitation.
asaperssond0de2952017-04-21 01:47:31 -07001857 AdaptingFrameForwarder source;
1858 source.set_adaptation_enabled(true);
mflodmancc3d4422017-08-03 08:27:51 -07001859 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001860 &source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
asaperssond0de2952017-04-21 01:47:31 -07001861
1862 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001863 WaitForEncodedFrame(kWidth, kHeight);
asaperssond0de2952017-04-21 01:47:31 -07001864 VerifyNoLimitation(source.sink_wants());
1865 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1866 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1867 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1868 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1869
1870 // Trigger cpu adapt down, expect scaled down resolution (960x540).
mflodmancc3d4422017-08-03 08:27:51 -07001871 video_stream_encoder_->TriggerCpuOveruse();
asaperssond0de2952017-04-21 01:47:31 -07001872 source.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001873 WaitForEncodedFrame(2);
asapersson09f05612017-05-15 23:40:18 -07001874 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
asaperssond0de2952017-04-21 01:47:31 -07001875 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1876 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1877 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1878 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1879
1880 // Trigger cpu adapt down, expect scaled down resolution (640x360).
mflodmancc3d4422017-08-03 08:27:51 -07001881 video_stream_encoder_->TriggerCpuOveruse();
asaperssond0de2952017-04-21 01:47:31 -07001882 source.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001883 WaitForEncodedFrame(3);
asapersson09f05612017-05-15 23:40:18 -07001884 VerifyFpsMaxResolutionLt(source.sink_wants(), source.last_wants());
asaperssond0de2952017-04-21 01:47:31 -07001885 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1886 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1887 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1888 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1889
Jonathan Yubc771b72017-12-08 17:04:29 -08001890 // Trigger cpu adapt down, expect scaled down resolution (480x270).
mflodmancc3d4422017-08-03 08:27:51 -07001891 video_stream_encoder_->TriggerCpuOveruse();
asaperssond0de2952017-04-21 01:47:31 -07001892 source.IncomingCapturedFrame(CreateFrame(4, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001893 WaitForEncodedFrame(4);
Jonathan Yubc771b72017-12-08 17:04:29 -08001894 VerifyFpsMaxResolutionLt(source.sink_wants(), source.last_wants());
asaperssond0de2952017-04-21 01:47:31 -07001895 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1896 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
Jonathan Yubc771b72017-12-08 17:04:29 -08001897 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
asaperssond0de2952017-04-21 01:47:31 -07001898 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1899
Jonathan Yubc771b72017-12-08 17:04:29 -08001900 // Trigger quality adapt down, expect scaled down resolution (320x180).
mflodmancc3d4422017-08-03 08:27:51 -07001901 video_stream_encoder_->TriggerQualityLow();
asaperssond0de2952017-04-21 01:47:31 -07001902 source.IncomingCapturedFrame(CreateFrame(5, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001903 WaitForEncodedFrame(5);
asapersson09f05612017-05-15 23:40:18 -07001904 VerifyFpsMaxResolutionLt(source.sink_wants(), source.last_wants());
Jonathan Yubc771b72017-12-08 17:04:29 -08001905 rtc::VideoSinkWants last_wants = source.sink_wants();
asaperssond0de2952017-04-21 01:47:31 -07001906 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1907 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1908 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1909 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1910
Jonathan Yubc771b72017-12-08 17:04:29 -08001911 // Trigger quality adapt down, expect no change (min resolution reached).
1912 video_stream_encoder_->TriggerQualityLow();
1913 source.IncomingCapturedFrame(CreateFrame(6, kWidth, kHeight));
1914 WaitForEncodedFrame(6);
1915 VerifyFpsMaxResolutionEq(source.sink_wants(), last_wants);
1916 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1917 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1918 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1919 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1920
1921 // Trigger cpu adapt up, expect upscaled resolution (480x270).
mflodmancc3d4422017-08-03 08:27:51 -07001922 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssond0de2952017-04-21 01:47:31 -07001923 source.IncomingCapturedFrame(CreateFrame(7, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001924 WaitForEncodedFrame(7);
asapersson09f05612017-05-15 23:40:18 -07001925 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
Jonathan Yubc771b72017-12-08 17:04:29 -08001926 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1927 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1928 EXPECT_EQ(4, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1929 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1930
1931 // Trigger cpu adapt up, expect upscaled resolution (640x360).
1932 video_stream_encoder_->TriggerCpuNormalUsage();
1933 source.IncomingCapturedFrame(CreateFrame(8, kWidth, kHeight));
1934 WaitForEncodedFrame(8);
1935 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
1936 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1937 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1938 EXPECT_EQ(5, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1939 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1940
1941 // Trigger cpu adapt up, expect upscaled resolution (960x540).
1942 video_stream_encoder_->TriggerCpuNormalUsage();
1943 source.IncomingCapturedFrame(CreateFrame(9, kWidth, kHeight));
1944 WaitForEncodedFrame(9);
1945 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
asaperssond0de2952017-04-21 01:47:31 -07001946 last_wants = source.sink_wants();
1947 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1948 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
Jonathan Yubc771b72017-12-08 17:04:29 -08001949 EXPECT_EQ(6, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
asaperssond0de2952017-04-21 01:47:31 -07001950 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1951
1952 // Trigger cpu adapt up, no cpu downgrades, expect no change (960x540).
mflodmancc3d4422017-08-03 08:27:51 -07001953 video_stream_encoder_->TriggerCpuNormalUsage();
Jonathan Yubc771b72017-12-08 17:04:29 -08001954 source.IncomingCapturedFrame(CreateFrame(10, kWidth, kHeight));
1955 WaitForEncodedFrame(10);
asapersson09f05612017-05-15 23:40:18 -07001956 VerifyFpsEqResolutionEq(source.sink_wants(), last_wants);
asaperssond0de2952017-04-21 01:47:31 -07001957 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1958 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
Jonathan Yubc771b72017-12-08 17:04:29 -08001959 EXPECT_EQ(6, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
asaperssond0de2952017-04-21 01:47:31 -07001960 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1961
1962 // Trigger quality adapt up, expect no restriction (1280x720).
mflodmancc3d4422017-08-03 08:27:51 -07001963 video_stream_encoder_->TriggerQualityHigh();
Jonathan Yubc771b72017-12-08 17:04:29 -08001964 source.IncomingCapturedFrame(CreateFrame(11, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001965 WaitForEncodedFrame(kWidth, kHeight);
asapersson09f05612017-05-15 23:40:18 -07001966 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
asaperssond0de2952017-04-21 01:47:31 -07001967 VerifyNoLimitation(source.sink_wants());
1968 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1969 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
Jonathan Yubc771b72017-12-08 17:04:29 -08001970 EXPECT_EQ(6, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
asaperssond0de2952017-04-21 01:47:31 -07001971 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
kthelgason5e13d412016-12-01 03:59:51 -08001972
mflodmancc3d4422017-08-03 08:27:51 -07001973 video_stream_encoder_->Stop();
kthelgason5e13d412016-12-01 03:59:51 -08001974}
1975
mflodmancc3d4422017-08-03 08:27:51 -07001976TEST_F(VideoStreamEncoderTest, CpuLimitedHistogramIsReported) {
asaperssonfab67072017-04-04 05:51:49 -07001977 const int kWidth = 640;
1978 const int kHeight = 360;
perkj803d97f2016-11-01 11:45:46 -07001979
mflodmancc3d4422017-08-03 08:27:51 -07001980 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
sprang4847ae62017-06-27 07:06:52 -07001981
perkj803d97f2016-11-01 11:45:46 -07001982 for (int i = 1; i <= SendStatisticsProxy::kMinRequiredMetricsSamples; ++i) {
asaperssonfab67072017-04-04 05:51:49 -07001983 video_source_.IncomingCapturedFrame(CreateFrame(i, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001984 WaitForEncodedFrame(i);
perkj803d97f2016-11-01 11:45:46 -07001985 }
1986
mflodmancc3d4422017-08-03 08:27:51 -07001987 video_stream_encoder_->TriggerCpuOveruse();
perkj803d97f2016-11-01 11:45:46 -07001988 for (int i = 1; i <= SendStatisticsProxy::kMinRequiredMetricsSamples; ++i) {
asaperssonfab67072017-04-04 05:51:49 -07001989 video_source_.IncomingCapturedFrame(CreateFrame(
1990 SendStatisticsProxy::kMinRequiredMetricsSamples + i, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001991 WaitForEncodedFrame(SendStatisticsProxy::kMinRequiredMetricsSamples + i);
perkj803d97f2016-11-01 11:45:46 -07001992 }
1993
mflodmancc3d4422017-08-03 08:27:51 -07001994 video_stream_encoder_->Stop();
1995 video_stream_encoder_.reset();
perkj803d97f2016-11-01 11:45:46 -07001996 stats_proxy_.reset();
sprangf8ee65e2017-02-28 08:49:33 -08001997
perkj803d97f2016-11-01 11:45:46 -07001998 EXPECT_EQ(1,
1999 metrics::NumSamples("WebRTC.Video.CpuLimitedResolutionInPercent"));
2000 EXPECT_EQ(
2001 1, metrics::NumEvents("WebRTC.Video.CpuLimitedResolutionInPercent", 50));
2002}
2003
mflodmancc3d4422017-08-03 08:27:51 -07002004TEST_F(VideoStreamEncoderTest,
2005 CpuLimitedHistogramIsNotReportedForDisabledDegradation) {
2006 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonf4e44af2017-04-19 02:01:06 -07002007 const int kWidth = 640;
2008 const int kHeight = 360;
2009
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002010 video_stream_encoder_->SetSource(&video_source_,
2011 webrtc::DegradationPreference::DISABLED);
asaperssonf4e44af2017-04-19 02:01:06 -07002012
2013 for (int i = 1; i <= SendStatisticsProxy::kMinRequiredMetricsSamples; ++i) {
2014 video_source_.IncomingCapturedFrame(CreateFrame(i, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002015 WaitForEncodedFrame(i);
asaperssonf4e44af2017-04-19 02:01:06 -07002016 }
2017
mflodmancc3d4422017-08-03 08:27:51 -07002018 video_stream_encoder_->Stop();
2019 video_stream_encoder_.reset();
asaperssonf4e44af2017-04-19 02:01:06 -07002020 stats_proxy_.reset();
2021
2022 EXPECT_EQ(0,
2023 metrics::NumSamples("WebRTC.Video.CpuLimitedResolutionInPercent"));
2024}
2025
mflodmancc3d4422017-08-03 08:27:51 -07002026TEST_F(VideoStreamEncoderTest, CallsBitrateObserver) {
sprang4847ae62017-06-27 07:06:52 -07002027 MockBitrateObserver bitrate_observer;
Niels Möller0327c2d2018-05-21 14:09:31 +02002028 video_stream_encoder_->SetBitrateAllocationObserver(&bitrate_observer);
sprang57c2fff2017-01-16 06:24:02 -08002029
2030 const int kDefaultFps = 30;
Erik Språng566124a2018-04-23 12:32:22 +02002031 const VideoBitrateAllocation expected_bitrate =
sprang57c2fff2017-01-16 06:24:02 -08002032 DefaultVideoBitrateAllocator(fake_encoder_.codec_config())
kthelgason2bc68642017-02-07 07:02:22 -08002033 .GetAllocation(kLowTargetBitrateBps, kDefaultFps);
sprang57c2fff2017-01-16 06:24:02 -08002034
2035 // First called on bitrate updated, then again on first frame.
2036 EXPECT_CALL(bitrate_observer, OnBitrateAllocationUpdated(expected_bitrate))
2037 .Times(2);
mflodmancc3d4422017-08-03 08:27:51 -07002038 video_stream_encoder_->OnBitrateUpdated(kLowTargetBitrateBps, 0, 0);
sprang57c2fff2017-01-16 06:24:02 -08002039
2040 const int64_t kStartTimeMs = 1;
2041 video_source_.IncomingCapturedFrame(
2042 CreateFrame(kStartTimeMs, codec_width_, codec_height_));
sprang4847ae62017-06-27 07:06:52 -07002043 WaitForEncodedFrame(kStartTimeMs);
sprang57c2fff2017-01-16 06:24:02 -08002044
2045 // Not called on second frame.
2046 EXPECT_CALL(bitrate_observer, OnBitrateAllocationUpdated(expected_bitrate))
2047 .Times(0);
2048 video_source_.IncomingCapturedFrame(
2049 CreateFrame(kStartTimeMs + 1, codec_width_, codec_height_));
sprang4847ae62017-06-27 07:06:52 -07002050 WaitForEncodedFrame(kStartTimeMs + 1);
sprang57c2fff2017-01-16 06:24:02 -08002051
2052 // Called after a process interval.
2053 const int64_t kProcessIntervalMs =
2054 vcm::VCMProcessTimer::kDefaultProcessIntervalMs;
sprang4847ae62017-06-27 07:06:52 -07002055 fake_clock_.AdvanceTimeMicros(rtc::kNumMicrosecsPerMillisec *
2056 (kProcessIntervalMs + (1000 / kDefaultFps)));
sprang57c2fff2017-01-16 06:24:02 -08002057 EXPECT_CALL(bitrate_observer, OnBitrateAllocationUpdated(expected_bitrate))
2058 .Times(1);
2059 video_source_.IncomingCapturedFrame(CreateFrame(
2060 kStartTimeMs + kProcessIntervalMs, codec_width_, codec_height_));
sprang4847ae62017-06-27 07:06:52 -07002061 WaitForEncodedFrame(kStartTimeMs + kProcessIntervalMs);
sprang57c2fff2017-01-16 06:24:02 -08002062
mflodmancc3d4422017-08-03 08:27:51 -07002063 video_stream_encoder_->Stop();
sprang57c2fff2017-01-16 06:24:02 -08002064}
2065
Niels Möller7dc26b72017-12-06 10:27:48 +01002066TEST_F(VideoStreamEncoderTest, OveruseDetectorUpdatedOnReconfigureAndAdaption) {
2067 const int kFrameWidth = 1280;
2068 const int kFrameHeight = 720;
2069 const int kFramerate = 24;
2070
2071 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
2072 test::FrameForwarder source;
2073 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002074 &source, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
Niels Möller7dc26b72017-12-06 10:27:48 +01002075
2076 // Insert a single frame, triggering initial configuration.
2077 source.IncomingCapturedFrame(CreateFrame(1, kFrameWidth, kFrameHeight));
2078 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2079
2080 EXPECT_EQ(
2081 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2082 kDefaultFramerate);
2083
2084 // Trigger reconfigure encoder (without resetting the entire instance).
2085 VideoEncoderConfig video_encoder_config;
Niels Möller259a4972018-04-05 15:36:51 +02002086 video_encoder_config.codec_type = kVideoCodecVP8;
Niels Möller7dc26b72017-12-06 10:27:48 +01002087 video_encoder_config.max_bitrate_bps = kTargetBitrateBps;
2088 video_encoder_config.number_of_streams = 1;
2089 video_encoder_config.video_stream_factory =
2090 new rtc::RefCountedObject<VideoStreamFactory>(1, kFramerate);
2091 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
Niels Möllerf1338562018-04-26 09:51:47 +02002092 kMaxPayloadLength);
Niels Möller7dc26b72017-12-06 10:27:48 +01002093 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2094
2095 // Detector should be updated with fps limit from codec config.
2096 EXPECT_EQ(
2097 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2098 kFramerate);
2099
2100 // Trigger overuse, max framerate should be reduced.
2101 VideoSendStream::Stats stats = stats_proxy_->GetStats();
2102 stats.input_frame_rate = kFramerate;
2103 stats_proxy_->SetMockStats(stats);
2104 video_stream_encoder_->TriggerCpuOveruse();
2105 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2106 int adapted_framerate =
2107 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate();
2108 EXPECT_LT(adapted_framerate, kFramerate);
2109
2110 // Trigger underuse, max framerate should go back to codec configured fps.
2111 // Set extra low fps, to make sure it's actually reset, not just incremented.
2112 stats = stats_proxy_->GetStats();
2113 stats.input_frame_rate = adapted_framerate / 2;
2114 stats_proxy_->SetMockStats(stats);
2115 video_stream_encoder_->TriggerCpuNormalUsage();
2116 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2117 EXPECT_EQ(
2118 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2119 kFramerate);
2120
2121 video_stream_encoder_->Stop();
2122}
2123
2124TEST_F(VideoStreamEncoderTest,
2125 OveruseDetectorUpdatedRespectsFramerateAfterUnderuse) {
2126 const int kFrameWidth = 1280;
2127 const int kFrameHeight = 720;
2128 const int kLowFramerate = 15;
2129 const int kHighFramerate = 25;
2130
2131 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
2132 test::FrameForwarder source;
2133 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002134 &source, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
Niels Möller7dc26b72017-12-06 10:27:48 +01002135
2136 // Trigger initial configuration.
2137 VideoEncoderConfig video_encoder_config;
Niels Möller259a4972018-04-05 15:36:51 +02002138 video_encoder_config.codec_type = kVideoCodecVP8;
Niels Möller7dc26b72017-12-06 10:27:48 +01002139 video_encoder_config.max_bitrate_bps = kTargetBitrateBps;
2140 video_encoder_config.number_of_streams = 1;
2141 video_encoder_config.video_stream_factory =
2142 new rtc::RefCountedObject<VideoStreamFactory>(1, kLowFramerate);
2143 source.IncomingCapturedFrame(CreateFrame(1, kFrameWidth, kFrameHeight));
2144 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
Niels Möllerf1338562018-04-26 09:51:47 +02002145 kMaxPayloadLength);
Niels Möller7dc26b72017-12-06 10:27:48 +01002146 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2147
2148 EXPECT_EQ(
2149 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2150 kLowFramerate);
2151
2152 // Trigger overuse, max framerate should be reduced.
2153 VideoSendStream::Stats stats = stats_proxy_->GetStats();
2154 stats.input_frame_rate = kLowFramerate;
2155 stats_proxy_->SetMockStats(stats);
2156 video_stream_encoder_->TriggerCpuOveruse();
2157 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2158 int adapted_framerate =
2159 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate();
2160 EXPECT_LT(adapted_framerate, kLowFramerate);
2161
2162 // Reconfigure the encoder with a new (higher max framerate), max fps should
2163 // still respect the adaptation.
2164 video_encoder_config.video_stream_factory =
2165 new rtc::RefCountedObject<VideoStreamFactory>(1, kHighFramerate);
2166 source.IncomingCapturedFrame(CreateFrame(1, kFrameWidth, kFrameHeight));
2167 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
Niels Möllerf1338562018-04-26 09:51:47 +02002168 kMaxPayloadLength);
Niels Möller7dc26b72017-12-06 10:27:48 +01002169 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2170
2171 EXPECT_EQ(
2172 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2173 adapted_framerate);
2174
2175 // Trigger underuse, max framerate should go back to codec configured fps.
2176 stats = stats_proxy_->GetStats();
2177 stats.input_frame_rate = adapted_framerate;
2178 stats_proxy_->SetMockStats(stats);
2179 video_stream_encoder_->TriggerCpuNormalUsage();
2180 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2181 EXPECT_EQ(
2182 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2183 kHighFramerate);
2184
2185 video_stream_encoder_->Stop();
2186}
2187
mflodmancc3d4422017-08-03 08:27:51 -07002188TEST_F(VideoStreamEncoderTest,
2189 OveruseDetectorUpdatedOnDegradationPreferenceChange) {
sprangfda496a2017-06-15 04:21:07 -07002190 const int kFrameWidth = 1280;
2191 const int kFrameHeight = 720;
2192 const int kFramerate = 24;
2193
mflodmancc3d4422017-08-03 08:27:51 -07002194 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
sprangfda496a2017-06-15 04:21:07 -07002195 test::FrameForwarder source;
mflodmancc3d4422017-08-03 08:27:51 -07002196 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002197 &source, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
sprangfda496a2017-06-15 04:21:07 -07002198
2199 // Trigger initial configuration.
2200 VideoEncoderConfig video_encoder_config;
Niels Möller259a4972018-04-05 15:36:51 +02002201 video_encoder_config.codec_type = kVideoCodecVP8;
sprangfda496a2017-06-15 04:21:07 -07002202 video_encoder_config.max_bitrate_bps = kTargetBitrateBps;
2203 video_encoder_config.number_of_streams = 1;
2204 video_encoder_config.video_stream_factory =
2205 new rtc::RefCountedObject<VideoStreamFactory>(1, kFramerate);
2206 source.IncomingCapturedFrame(CreateFrame(1, kFrameWidth, kFrameHeight));
mflodmancc3d4422017-08-03 08:27:51 -07002207 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
Niels Möllerf1338562018-04-26 09:51:47 +02002208 kMaxPayloadLength);
mflodmancc3d4422017-08-03 08:27:51 -07002209 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
sprangfda496a2017-06-15 04:21:07 -07002210
Niels Möller7dc26b72017-12-06 10:27:48 +01002211 EXPECT_EQ(
2212 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2213 kFramerate);
sprangfda496a2017-06-15 04:21:07 -07002214
2215 // Trigger overuse, max framerate should be reduced.
2216 VideoSendStream::Stats stats = stats_proxy_->GetStats();
2217 stats.input_frame_rate = kFramerate;
2218 stats_proxy_->SetMockStats(stats);
mflodmancc3d4422017-08-03 08:27:51 -07002219 video_stream_encoder_->TriggerCpuOveruse();
2220 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
Niels Möller7dc26b72017-12-06 10:27:48 +01002221 int adapted_framerate =
2222 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate();
sprangfda496a2017-06-15 04:21:07 -07002223 EXPECT_LT(adapted_framerate, kFramerate);
2224
2225 // Change degradation preference to not enable framerate scaling. Target
2226 // framerate should be changed to codec defined limit.
mflodmancc3d4422017-08-03 08:27:51 -07002227 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002228 &source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
mflodmancc3d4422017-08-03 08:27:51 -07002229 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
Niels Möller7dc26b72017-12-06 10:27:48 +01002230 EXPECT_EQ(
2231 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2232 kFramerate);
sprangfda496a2017-06-15 04:21:07 -07002233
mflodmancc3d4422017-08-03 08:27:51 -07002234 video_stream_encoder_->Stop();
sprangfda496a2017-06-15 04:21:07 -07002235}
2236
mflodmancc3d4422017-08-03 08:27:51 -07002237TEST_F(VideoStreamEncoderTest, DropsFramesAndScalesWhenBitrateIsTooLow) {
asaperssonfab67072017-04-04 05:51:49 -07002238 const int kTooLowBitrateForFrameSizeBps = 10000;
mflodmancc3d4422017-08-03 08:27:51 -07002239 video_stream_encoder_->OnBitrateUpdated(kTooLowBitrateForFrameSizeBps, 0, 0);
asaperssonfab67072017-04-04 05:51:49 -07002240 const int kWidth = 640;
2241 const int kHeight = 360;
kthelgason2bc68642017-02-07 07:02:22 -08002242
asaperssonfab67072017-04-04 05:51:49 -07002243 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
kthelgason2bc68642017-02-07 07:02:22 -08002244
2245 // Expect to drop this frame, the wait should time out.
sprang4847ae62017-06-27 07:06:52 -07002246 ExpectDroppedFrame();
kthelgason2bc68642017-02-07 07:02:22 -08002247
2248 // Expect the sink_wants to specify a scaled frame.
asapersson0944a802017-04-07 00:57:58 -07002249 EXPECT_LT(video_source_.sink_wants().max_pixel_count, kWidth * kHeight);
kthelgason2bc68642017-02-07 07:02:22 -08002250
sprangc5d62e22017-04-02 23:53:04 -07002251 int last_pixel_count = video_source_.sink_wants().max_pixel_count;
kthelgason2bc68642017-02-07 07:02:22 -08002252
asaperssonfab67072017-04-04 05:51:49 -07002253 // Next frame is scaled.
kthelgason2bc68642017-02-07 07:02:22 -08002254 video_source_.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07002255 CreateFrame(2, kWidth * 3 / 4, kHeight * 3 / 4));
kthelgason2bc68642017-02-07 07:02:22 -08002256
2257 // Expect to drop this frame, the wait should time out.
sprang4847ae62017-06-27 07:06:52 -07002258 ExpectDroppedFrame();
kthelgason2bc68642017-02-07 07:02:22 -08002259
sprangc5d62e22017-04-02 23:53:04 -07002260 EXPECT_LT(video_source_.sink_wants().max_pixel_count, last_pixel_count);
kthelgason2bc68642017-02-07 07:02:22 -08002261
mflodmancc3d4422017-08-03 08:27:51 -07002262 video_stream_encoder_->Stop();
kthelgason2bc68642017-02-07 07:02:22 -08002263}
2264
mflodmancc3d4422017-08-03 08:27:51 -07002265TEST_F(VideoStreamEncoderTest,
2266 NumberOfDroppedFramesLimitedWhenBitrateIsTooLow) {
asaperssonfab67072017-04-04 05:51:49 -07002267 const int kTooLowBitrateForFrameSizeBps = 10000;
mflodmancc3d4422017-08-03 08:27:51 -07002268 video_stream_encoder_->OnBitrateUpdated(kTooLowBitrateForFrameSizeBps, 0, 0);
asaperssonfab67072017-04-04 05:51:49 -07002269 const int kWidth = 640;
2270 const int kHeight = 360;
kthelgason2bc68642017-02-07 07:02:22 -08002271
2272 // We expect the n initial frames to get dropped.
2273 int i;
2274 for (i = 1; i <= kMaxInitialFramedrop; ++i) {
asaperssonfab67072017-04-04 05:51:49 -07002275 video_source_.IncomingCapturedFrame(CreateFrame(i, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002276 ExpectDroppedFrame();
kthelgason2bc68642017-02-07 07:02:22 -08002277 }
2278 // The n+1th frame should not be dropped, even though it's size is too large.
asaperssonfab67072017-04-04 05:51:49 -07002279 video_source_.IncomingCapturedFrame(CreateFrame(i, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002280 WaitForEncodedFrame(i);
kthelgason2bc68642017-02-07 07:02:22 -08002281
2282 // Expect the sink_wants to specify a scaled frame.
asaperssonfab67072017-04-04 05:51:49 -07002283 EXPECT_LT(video_source_.sink_wants().max_pixel_count, kWidth * kHeight);
kthelgason2bc68642017-02-07 07:02:22 -08002284
mflodmancc3d4422017-08-03 08:27:51 -07002285 video_stream_encoder_->Stop();
kthelgason2bc68642017-02-07 07:02:22 -08002286}
2287
mflodmancc3d4422017-08-03 08:27:51 -07002288TEST_F(VideoStreamEncoderTest,
2289 InitialFrameDropOffWithMaintainResolutionPreference) {
asaperssonfab67072017-04-04 05:51:49 -07002290 const int kWidth = 640;
2291 const int kHeight = 360;
mflodmancc3d4422017-08-03 08:27:51 -07002292 video_stream_encoder_->OnBitrateUpdated(kLowTargetBitrateBps, 0, 0);
kthelgason2bc68642017-02-07 07:02:22 -08002293
2294 // Set degradation preference.
mflodmancc3d4422017-08-03 08:27:51 -07002295 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002296 &video_source_, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
kthelgason2bc68642017-02-07 07:02:22 -08002297
asaperssonfab67072017-04-04 05:51:49 -07002298 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
kthelgason2bc68642017-02-07 07:02:22 -08002299 // Frame should not be dropped, even if it's too large.
sprang4847ae62017-06-27 07:06:52 -07002300 WaitForEncodedFrame(1);
kthelgason2bc68642017-02-07 07:02:22 -08002301
mflodmancc3d4422017-08-03 08:27:51 -07002302 video_stream_encoder_->Stop();
kthelgason2bc68642017-02-07 07:02:22 -08002303}
2304
mflodmancc3d4422017-08-03 08:27:51 -07002305TEST_F(VideoStreamEncoderTest, InitialFrameDropOffWhenEncoderDisabledScaling) {
asaperssonfab67072017-04-04 05:51:49 -07002306 const int kWidth = 640;
2307 const int kHeight = 360;
kthelgasonad9010c2017-02-14 00:46:51 -08002308 fake_encoder_.SetQualityScaling(false);
Niels Möller4db138e2018-04-19 09:04:13 +02002309
2310 VideoEncoderConfig video_encoder_config;
2311 test::FillEncoderConfiguration(kVideoCodecVP8, 1, &video_encoder_config);
2312 // Make format different, to force recreation of encoder.
2313 video_encoder_config.video_format.parameters["foo"] = "foo";
2314 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
Niels Möllerf1338562018-04-26 09:51:47 +02002315 kMaxPayloadLength);
mflodmancc3d4422017-08-03 08:27:51 -07002316 video_stream_encoder_->OnBitrateUpdated(kLowTargetBitrateBps, 0, 0);
asapersson09f05612017-05-15 23:40:18 -07002317
kthelgasonb83797b2017-02-14 11:57:25 -08002318 // Force quality scaler reconfiguration by resetting the source.
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002319 video_stream_encoder_->SetSource(&video_source_,
2320 webrtc::DegradationPreference::BALANCED);
kthelgasonad9010c2017-02-14 00:46:51 -08002321
asaperssonfab67072017-04-04 05:51:49 -07002322 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
kthelgasonad9010c2017-02-14 00:46:51 -08002323 // Frame should not be dropped, even if it's too large.
sprang4847ae62017-06-27 07:06:52 -07002324 WaitForEncodedFrame(1);
kthelgasonad9010c2017-02-14 00:46:51 -08002325
mflodmancc3d4422017-08-03 08:27:51 -07002326 video_stream_encoder_->Stop();
kthelgasonad9010c2017-02-14 00:46:51 -08002327 fake_encoder_.SetQualityScaling(true);
2328}
2329
mflodmancc3d4422017-08-03 08:27:51 -07002330TEST_F(VideoStreamEncoderTest,
asaperssond0de2952017-04-21 01:47:31 -07002331 ResolutionNotAdaptedForTooSmallFrame_MaintainFramerateMode) {
2332 const int kTooSmallWidth = 10;
2333 const int kTooSmallHeight = 10;
mflodmancc3d4422017-08-03 08:27:51 -07002334 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssond0de2952017-04-21 01:47:31 -07002335
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002336 // Enable MAINTAIN_FRAMERATE preference, no initial limitation.
asaperssond0de2952017-04-21 01:47:31 -07002337 test::FrameForwarder source;
mflodmancc3d4422017-08-03 08:27:51 -07002338 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002339 &source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
asaperssond0de2952017-04-21 01:47:31 -07002340 VerifyNoLimitation(source.sink_wants());
2341 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2342
2343 // Trigger adapt down, too small frame, expect no change.
2344 source.IncomingCapturedFrame(CreateFrame(1, kTooSmallWidth, kTooSmallHeight));
sprang4847ae62017-06-27 07:06:52 -07002345 WaitForEncodedFrame(1);
mflodmancc3d4422017-08-03 08:27:51 -07002346 video_stream_encoder_->TriggerCpuOveruse();
asaperssond0de2952017-04-21 01:47:31 -07002347 VerifyNoLimitation(source.sink_wants());
2348 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2349 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2350
mflodmancc3d4422017-08-03 08:27:51 -07002351 video_stream_encoder_->Stop();
asaperssond0de2952017-04-21 01:47:31 -07002352}
2353
mflodmancc3d4422017-08-03 08:27:51 -07002354TEST_F(VideoStreamEncoderTest,
2355 ResolutionNotAdaptedForTooSmallFrame_BalancedMode) {
asaperssonf7e294d2017-06-13 23:25:22 -07002356 const int kTooSmallWidth = 10;
2357 const int kTooSmallHeight = 10;
2358 const int kFpsLimit = 7;
mflodmancc3d4422017-08-03 08:27:51 -07002359 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -07002360
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002361 // Enable BALANCED preference, no initial limitation.
asaperssonf7e294d2017-06-13 23:25:22 -07002362 test::FrameForwarder source;
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002363 video_stream_encoder_->SetSource(&source,
2364 webrtc::DegradationPreference::BALANCED);
asaperssonf7e294d2017-06-13 23:25:22 -07002365 VerifyNoLimitation(source.sink_wants());
2366 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2367 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2368
2369 // Trigger adapt down, expect limited framerate.
2370 source.IncomingCapturedFrame(CreateFrame(1, kTooSmallWidth, kTooSmallHeight));
sprang4847ae62017-06-27 07:06:52 -07002371 WaitForEncodedFrame(1);
mflodmancc3d4422017-08-03 08:27:51 -07002372 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002373 VerifyFpsEqResolutionMax(source.sink_wants(), kFpsLimit);
2374 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2375 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2376 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2377
2378 // Trigger adapt down, too small frame, expect no change.
2379 source.IncomingCapturedFrame(CreateFrame(2, kTooSmallWidth, kTooSmallHeight));
sprang4847ae62017-06-27 07:06:52 -07002380 WaitForEncodedFrame(2);
mflodmancc3d4422017-08-03 08:27:51 -07002381 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002382 VerifyFpsEqResolutionMax(source.sink_wants(), kFpsLimit);
2383 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2384 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2385 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2386
mflodmancc3d4422017-08-03 08:27:51 -07002387 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07002388}
2389
mflodmancc3d4422017-08-03 08:27:51 -07002390TEST_F(VideoStreamEncoderTest, FailingInitEncodeDoesntCauseCrash) {
asapersson02465b82017-04-10 01:12:52 -07002391 fake_encoder_.ForceInitEncodeFailure(true);
mflodmancc3d4422017-08-03 08:27:51 -07002392 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
Niels Möllerf1338562018-04-26 09:51:47 +02002393 ResetEncoder("VP8", 2, 1, 1, false);
asapersson02465b82017-04-10 01:12:52 -07002394 const int kFrameWidth = 1280;
2395 const int kFrameHeight = 720;
2396 video_source_.IncomingCapturedFrame(
2397 CreateFrame(1, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002398 ExpectDroppedFrame();
mflodmancc3d4422017-08-03 08:27:51 -07002399 video_stream_encoder_->Stop();
asapersson02465b82017-04-10 01:12:52 -07002400}
2401
sprangb1ca0732017-02-01 08:38:12 -08002402// TODO(sprang): Extend this with fps throttling and any "balanced" extensions.
mflodmancc3d4422017-08-03 08:27:51 -07002403TEST_F(VideoStreamEncoderTest,
2404 AdaptsResolutionOnOveruse_MaintainFramerateMode) {
2405 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
sprangb1ca0732017-02-01 08:38:12 -08002406
2407 const int kFrameWidth = 1280;
2408 const int kFrameHeight = 720;
2409 // Enabled default VideoAdapter downscaling. First step is 3/4, not 3/5 as
mflodmancc3d4422017-08-03 08:27:51 -07002410 // requested by
2411 // VideoStreamEncoder::VideoSourceProxy::RequestResolutionLowerThan().
sprangb1ca0732017-02-01 08:38:12 -08002412 video_source_.set_adaptation_enabled(true);
2413
2414 video_source_.IncomingCapturedFrame(
2415 CreateFrame(1, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002416 WaitForEncodedFrame(kFrameWidth, kFrameHeight);
sprangb1ca0732017-02-01 08:38:12 -08002417
2418 // Trigger CPU overuse, downscale by 3/4.
mflodmancc3d4422017-08-03 08:27:51 -07002419 video_stream_encoder_->TriggerCpuOveruse();
sprangb1ca0732017-02-01 08:38:12 -08002420 video_source_.IncomingCapturedFrame(
2421 CreateFrame(2, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002422 WaitForEncodedFrame((kFrameWidth * 3) / 4, (kFrameHeight * 3) / 4);
sprangb1ca0732017-02-01 08:38:12 -08002423
asaperssonfab67072017-04-04 05:51:49 -07002424 // Trigger CPU normal use, return to original resolution.
mflodmancc3d4422017-08-03 08:27:51 -07002425 video_stream_encoder_->TriggerCpuNormalUsage();
sprangb1ca0732017-02-01 08:38:12 -08002426 video_source_.IncomingCapturedFrame(
2427 CreateFrame(3, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002428 WaitForEncodedFrame(kFrameWidth, kFrameHeight);
sprangb1ca0732017-02-01 08:38:12 -08002429
mflodmancc3d4422017-08-03 08:27:51 -07002430 video_stream_encoder_->Stop();
sprangb1ca0732017-02-01 08:38:12 -08002431}
sprangfe627f32017-03-29 08:24:59 -07002432
mflodmancc3d4422017-08-03 08:27:51 -07002433TEST_F(VideoStreamEncoderTest,
2434 AdaptsFramerateOnOveruse_MaintainResolutionMode) {
sprangc5d62e22017-04-02 23:53:04 -07002435 const int kFrameWidth = 1280;
2436 const int kFrameHeight = 720;
sprang4847ae62017-06-27 07:06:52 -07002437 int kFrameIntervalMs = rtc::kNumMillisecsPerSec / max_framerate_;
sprangc5d62e22017-04-02 23:53:04 -07002438
mflodmancc3d4422017-08-03 08:27:51 -07002439 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
2440 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002441 &video_source_, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
sprangc5d62e22017-04-02 23:53:04 -07002442 video_source_.set_adaptation_enabled(true);
2443
sprang4847ae62017-06-27 07:06:52 -07002444 int64_t timestamp_ms = fake_clock_.TimeNanos() / rtc::kNumNanosecsPerMillisec;
sprangc5d62e22017-04-02 23:53:04 -07002445
2446 video_source_.IncomingCapturedFrame(
2447 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002448 WaitForEncodedFrame(timestamp_ms);
sprangc5d62e22017-04-02 23:53:04 -07002449
2450 // Try to trigger overuse. No fps estimate available => no effect.
mflodmancc3d4422017-08-03 08:27:51 -07002451 video_stream_encoder_->TriggerCpuOveruse();
sprangc5d62e22017-04-02 23:53:04 -07002452
2453 // Insert frames for one second to get a stable estimate.
sprang4847ae62017-06-27 07:06:52 -07002454 for (int i = 0; i < max_framerate_; ++i) {
sprangc5d62e22017-04-02 23:53:04 -07002455 timestamp_ms += kFrameIntervalMs;
sprangc5d62e22017-04-02 23:53:04 -07002456 video_source_.IncomingCapturedFrame(
2457 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002458 WaitForEncodedFrame(timestamp_ms);
sprangc5d62e22017-04-02 23:53:04 -07002459 }
2460
2461 // Trigger CPU overuse, reduce framerate by 2/3.
mflodmancc3d4422017-08-03 08:27:51 -07002462 video_stream_encoder_->TriggerCpuOveruse();
sprangc5d62e22017-04-02 23:53:04 -07002463 int num_frames_dropped = 0;
sprang4847ae62017-06-27 07:06:52 -07002464 for (int i = 0; i < max_framerate_; ++i) {
sprangc5d62e22017-04-02 23:53:04 -07002465 timestamp_ms += kFrameIntervalMs;
sprangc5d62e22017-04-02 23:53:04 -07002466 video_source_.IncomingCapturedFrame(
2467 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002468 if (!WaitForFrame(kFrameTimeoutMs)) {
sprangc5d62e22017-04-02 23:53:04 -07002469 ++num_frames_dropped;
2470 } else {
Åsa Perssonc74d8da2017-12-04 14:13:56 +01002471 sink_.CheckLastFrameSizeMatches(kFrameWidth, kFrameHeight);
sprangc5d62e22017-04-02 23:53:04 -07002472 }
2473 }
2474
sprang4847ae62017-06-27 07:06:52 -07002475 // Add some slack to account for frames dropped by the frame dropper.
2476 const int kErrorMargin = 1;
2477 EXPECT_NEAR(num_frames_dropped, max_framerate_ - (max_framerate_ * 2 / 3),
sprangc5d62e22017-04-02 23:53:04 -07002478 kErrorMargin);
2479
2480 // Trigger CPU overuse, reduce framerate by 2/3 again.
mflodmancc3d4422017-08-03 08:27:51 -07002481 video_stream_encoder_->TriggerCpuOveruse();
sprangc5d62e22017-04-02 23:53:04 -07002482 num_frames_dropped = 0;
sprang4847ae62017-06-27 07:06:52 -07002483 for (int i = 0; i < max_framerate_; ++i) {
sprangc5d62e22017-04-02 23:53:04 -07002484 timestamp_ms += kFrameIntervalMs;
sprangc5d62e22017-04-02 23:53:04 -07002485 video_source_.IncomingCapturedFrame(
2486 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002487 if (!WaitForFrame(kFrameTimeoutMs)) {
sprangc5d62e22017-04-02 23:53:04 -07002488 ++num_frames_dropped;
2489 } else {
Åsa Perssonc74d8da2017-12-04 14:13:56 +01002490 sink_.CheckLastFrameSizeMatches(kFrameWidth, kFrameHeight);
sprangc5d62e22017-04-02 23:53:04 -07002491 }
2492 }
sprang4847ae62017-06-27 07:06:52 -07002493 EXPECT_NEAR(num_frames_dropped, max_framerate_ - (max_framerate_ * 4 / 9),
sprangc5d62e22017-04-02 23:53:04 -07002494 kErrorMargin);
2495
2496 // Go back up one step.
mflodmancc3d4422017-08-03 08:27:51 -07002497 video_stream_encoder_->TriggerCpuNormalUsage();
sprangc5d62e22017-04-02 23:53:04 -07002498 num_frames_dropped = 0;
sprang4847ae62017-06-27 07:06:52 -07002499 for (int i = 0; i < max_framerate_; ++i) {
sprangc5d62e22017-04-02 23:53:04 -07002500 timestamp_ms += kFrameIntervalMs;
sprangc5d62e22017-04-02 23:53:04 -07002501 video_source_.IncomingCapturedFrame(
2502 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002503 if (!WaitForFrame(kFrameTimeoutMs)) {
sprangc5d62e22017-04-02 23:53:04 -07002504 ++num_frames_dropped;
2505 } else {
Åsa Perssonc74d8da2017-12-04 14:13:56 +01002506 sink_.CheckLastFrameSizeMatches(kFrameWidth, kFrameHeight);
sprangc5d62e22017-04-02 23:53:04 -07002507 }
2508 }
sprang4847ae62017-06-27 07:06:52 -07002509 EXPECT_NEAR(num_frames_dropped, max_framerate_ - (max_framerate_ * 2 / 3),
sprangc5d62e22017-04-02 23:53:04 -07002510 kErrorMargin);
2511
2512 // Go back up to original mode.
mflodmancc3d4422017-08-03 08:27:51 -07002513 video_stream_encoder_->TriggerCpuNormalUsage();
sprangc5d62e22017-04-02 23:53:04 -07002514 num_frames_dropped = 0;
sprang4847ae62017-06-27 07:06:52 -07002515 for (int i = 0; i < max_framerate_; ++i) {
sprangc5d62e22017-04-02 23:53:04 -07002516 timestamp_ms += kFrameIntervalMs;
sprangc5d62e22017-04-02 23:53:04 -07002517 video_source_.IncomingCapturedFrame(
2518 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002519 if (!WaitForFrame(kFrameTimeoutMs)) {
sprangc5d62e22017-04-02 23:53:04 -07002520 ++num_frames_dropped;
2521 } else {
Åsa Perssonc74d8da2017-12-04 14:13:56 +01002522 sink_.CheckLastFrameSizeMatches(kFrameWidth, kFrameHeight);
sprangc5d62e22017-04-02 23:53:04 -07002523 }
2524 }
2525 EXPECT_NEAR(num_frames_dropped, 0, kErrorMargin);
2526
mflodmancc3d4422017-08-03 08:27:51 -07002527 video_stream_encoder_->Stop();
sprangc5d62e22017-04-02 23:53:04 -07002528}
2529
mflodmancc3d4422017-08-03 08:27:51 -07002530TEST_F(VideoStreamEncoderTest, DoesntAdaptDownPastMinFramerate) {
sprangc5d62e22017-04-02 23:53:04 -07002531 const int kFramerateFps = 5;
2532 const int kFrameIntervalMs = rtc::kNumMillisecsPerSec / kFramerateFps;
sprangc5d62e22017-04-02 23:53:04 -07002533 const int kFrameWidth = 1280;
2534 const int kFrameHeight = 720;
2535
sprang4847ae62017-06-27 07:06:52 -07002536 // Reconfigure encoder with two temporal layers and screensharing, which will
2537 // disable frame dropping and make testing easier.
Niels Möllerf1338562018-04-26 09:51:47 +02002538 ResetEncoder("VP8", 1, 2, 1, true);
sprang4847ae62017-06-27 07:06:52 -07002539
mflodmancc3d4422017-08-03 08:27:51 -07002540 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
2541 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002542 &video_source_, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
sprangc5d62e22017-04-02 23:53:04 -07002543 video_source_.set_adaptation_enabled(true);
2544
sprang4847ae62017-06-27 07:06:52 -07002545 int64_t timestamp_ms = fake_clock_.TimeNanos() / rtc::kNumNanosecsPerMillisec;
sprangc5d62e22017-04-02 23:53:04 -07002546
2547 // Trigger overuse as much as we can.
Jonathan Yubc771b72017-12-08 17:04:29 -08002548 rtc::VideoSinkWants last_wants;
2549 do {
2550 last_wants = video_source_.sink_wants();
2551
sprangc5d62e22017-04-02 23:53:04 -07002552 // Insert frames to get a new fps estimate...
2553 for (int j = 0; j < kFramerateFps; ++j) {
2554 video_source_.IncomingCapturedFrame(
2555 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
Jonathan Yubc771b72017-12-08 17:04:29 -08002556 if (video_source_.last_sent_width()) {
2557 sink_.WaitForEncodedFrame(timestamp_ms);
2558 }
sprangc5d62e22017-04-02 23:53:04 -07002559 timestamp_ms += kFrameIntervalMs;
Yves Gerey665174f2018-06-19 15:03:05 +02002560 fake_clock_.AdvanceTimeMicros(kFrameIntervalMs *
2561 rtc::kNumMicrosecsPerMillisec);
sprangc5d62e22017-04-02 23:53:04 -07002562 }
2563 // ...and then try to adapt again.
mflodmancc3d4422017-08-03 08:27:51 -07002564 video_stream_encoder_->TriggerCpuOveruse();
Jonathan Yubc771b72017-12-08 17:04:29 -08002565 } while (video_source_.sink_wants().max_framerate_fps <
2566 last_wants.max_framerate_fps);
sprangc5d62e22017-04-02 23:53:04 -07002567
Jonathan Yubc771b72017-12-08 17:04:29 -08002568 VerifyFpsEqResolutionMax(video_source_.sink_wants(), kMinFramerateFps);
asaperssonf7e294d2017-06-13 23:25:22 -07002569
mflodmancc3d4422017-08-03 08:27:51 -07002570 video_stream_encoder_->Stop();
sprangc5d62e22017-04-02 23:53:04 -07002571}
asaperssonf7e294d2017-06-13 23:25:22 -07002572
mflodmancc3d4422017-08-03 08:27:51 -07002573TEST_F(VideoStreamEncoderTest,
2574 AdaptsResolutionAndFramerateForLowQuality_BalancedMode) {
asaperssonf7e294d2017-06-13 23:25:22 -07002575 const int kWidth = 1280;
2576 const int kHeight = 720;
2577 const int64_t kFrameIntervalMs = 150;
2578 int64_t timestamp_ms = kFrameIntervalMs;
mflodmancc3d4422017-08-03 08:27:51 -07002579 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -07002580
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002581 // Enable BALANCED preference, no initial limitation.
asaperssonf7e294d2017-06-13 23:25:22 -07002582 AdaptingFrameForwarder source;
2583 source.set_adaptation_enabled(true);
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002584 video_stream_encoder_->SetSource(&source,
2585 webrtc::DegradationPreference::BALANCED);
asaperssonf7e294d2017-06-13 23:25:22 -07002586 timestamp_ms += kFrameIntervalMs;
2587 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002588 WaitForEncodedFrame(kWidth, kHeight);
asaperssonf7e294d2017-06-13 23:25:22 -07002589 VerifyNoLimitation(source.sink_wants());
2590 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2591 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2592 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2593
2594 // Trigger adapt down, expect scaled down resolution (960x540@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002595 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002596 timestamp_ms += kFrameIntervalMs;
2597 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002598 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002599 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
2600 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2601 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2602 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2603
2604 // Trigger adapt down, expect scaled down resolution (640x360@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002605 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002606 timestamp_ms += kFrameIntervalMs;
2607 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002608 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002609 VerifyFpsMaxResolutionLt(source.sink_wants(), source.last_wants());
2610 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2611 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2612 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2613
2614 // Trigger adapt down, expect reduced fps (640x360@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07002615 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002616 timestamp_ms += kFrameIntervalMs;
2617 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002618 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002619 VerifyFpsLtResolutionEq(source.sink_wants(), source.last_wants());
2620 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2621 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2622 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2623
2624 // Trigger adapt down, expect scaled down resolution (480x270@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07002625 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002626 timestamp_ms += kFrameIntervalMs;
2627 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002628 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002629 VerifyFpsEqResolutionLt(source.sink_wants(), source.last_wants());
2630 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2631 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2632 EXPECT_EQ(4, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2633
2634 // Restrict bitrate, trigger adapt down, expect reduced fps (480x270@10fps).
mflodmancc3d4422017-08-03 08:27:51 -07002635 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002636 timestamp_ms += kFrameIntervalMs;
2637 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002638 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002639 VerifyFpsLtResolutionEq(source.sink_wants(), source.last_wants());
2640 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2641 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2642 EXPECT_EQ(5, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2643
2644 // Trigger adapt down, expect scaled down resolution (320x180@10fps).
mflodmancc3d4422017-08-03 08:27:51 -07002645 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002646 timestamp_ms += kFrameIntervalMs;
2647 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002648 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002649 VerifyFpsEqResolutionLt(source.sink_wants(), source.last_wants());
2650 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2651 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2652 EXPECT_EQ(6, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2653
2654 // Trigger adapt down, expect reduced fps (320x180@7fps).
mflodmancc3d4422017-08-03 08:27:51 -07002655 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002656 timestamp_ms += kFrameIntervalMs;
2657 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002658 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002659 VerifyFpsLtResolutionEq(source.sink_wants(), source.last_wants());
2660 rtc::VideoSinkWants last_wants = source.sink_wants();
2661 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2662 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2663 EXPECT_EQ(7, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2664
2665 // Trigger adapt down, min resolution reached, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07002666 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002667 timestamp_ms += kFrameIntervalMs;
2668 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002669 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002670 VerifyFpsEqResolutionEq(source.sink_wants(), last_wants);
2671 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2672 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2673 EXPECT_EQ(7, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2674
2675 // Trigger adapt down, expect expect increased fps (320x180@10fps).
mflodmancc3d4422017-08-03 08:27:51 -07002676 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002677 timestamp_ms += kFrameIntervalMs;
2678 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002679 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002680 VerifyFpsGtResolutionEq(source.sink_wants(), source.last_wants());
2681 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2682 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2683 EXPECT_EQ(8, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2684
2685 // Trigger adapt up, expect upscaled resolution (480x270@10fps).
mflodmancc3d4422017-08-03 08:27:51 -07002686 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002687 timestamp_ms += kFrameIntervalMs;
2688 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002689 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002690 VerifyFpsEqResolutionGt(source.sink_wants(), source.last_wants());
2691 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2692 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2693 EXPECT_EQ(9, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2694
2695 // Increase bitrate, trigger adapt up, expect increased fps (480x270@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07002696 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002697 timestamp_ms += kFrameIntervalMs;
2698 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002699 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002700 VerifyFpsGtResolutionEq(source.sink_wants(), source.last_wants());
2701 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2702 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2703 EXPECT_EQ(10, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2704
2705 // Trigger adapt up, expect upscaled resolution (640x360@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07002706 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002707 timestamp_ms += kFrameIntervalMs;
2708 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002709 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002710 VerifyFpsEqResolutionGt(source.sink_wants(), source.last_wants());
2711 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2712 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2713 EXPECT_EQ(11, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2714
2715 // Trigger adapt up, expect increased fps (640x360@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002716 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002717 timestamp_ms += kFrameIntervalMs;
2718 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002719 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002720 VerifyFpsMaxResolutionEq(source.sink_wants(), source.last_wants());
2721 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2722 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2723 EXPECT_EQ(12, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2724
2725 // Trigger adapt up, expect upscaled resolution (960x540@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002726 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002727 timestamp_ms += kFrameIntervalMs;
2728 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002729 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002730 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
2731 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2732 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2733 EXPECT_EQ(13, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2734
2735 // Trigger adapt up, expect no restriction (1280x720fps@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002736 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002737 timestamp_ms += kFrameIntervalMs;
2738 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002739 WaitForEncodedFrame(kWidth, kHeight);
asaperssonf7e294d2017-06-13 23:25:22 -07002740 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
2741 VerifyNoLimitation(source.sink_wants());
2742 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2743 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2744 EXPECT_EQ(14, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2745
2746 // Trigger adapt up, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07002747 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002748 VerifyNoLimitation(source.sink_wants());
2749 EXPECT_EQ(14, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2750
mflodmancc3d4422017-08-03 08:27:51 -07002751 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07002752}
2753
mflodmancc3d4422017-08-03 08:27:51 -07002754TEST_F(VideoStreamEncoderTest, AdaptWithTwoReasonsAndDifferentOrder_Framerate) {
asaperssonf7e294d2017-06-13 23:25:22 -07002755 const int kWidth = 1280;
2756 const int kHeight = 720;
2757 const int64_t kFrameIntervalMs = 150;
2758 int64_t timestamp_ms = kFrameIntervalMs;
mflodmancc3d4422017-08-03 08:27:51 -07002759 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -07002760
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002761 // Enable BALANCED preference, no initial limitation.
asaperssonf7e294d2017-06-13 23:25:22 -07002762 AdaptingFrameForwarder source;
2763 source.set_adaptation_enabled(true);
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002764 video_stream_encoder_->SetSource(&source,
2765 webrtc::DegradationPreference::BALANCED);
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(kWidth, kHeight);
asaperssonf7e294d2017-06-13 23:25:22 -07002769 VerifyNoLimitation(source.sink_wants());
2770 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2771 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2772 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2773 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
2774 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2775 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2776
2777 // Trigger cpu adapt down, expect scaled down resolution (960x540@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002778 video_stream_encoder_->TriggerCpuOveruse();
asaperssonf7e294d2017-06-13 23:25:22 -07002779 timestamp_ms += kFrameIntervalMs;
2780 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002781 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002782 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
2783 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2784 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2785 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2786 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
2787 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2788 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2789
2790 // Trigger cpu adapt down, expect scaled down resolution (640x360@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002791 video_stream_encoder_->TriggerCpuOveruse();
asaperssonf7e294d2017-06-13 23:25:22 -07002792 timestamp_ms += kFrameIntervalMs;
2793 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002794 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002795 VerifyFpsMaxResolutionLt(source.sink_wants(), source.last_wants());
2796 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2797 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2798 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2799 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
2800 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2801 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2802
2803 // Trigger quality adapt down, expect reduced fps (640x360@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07002804 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002805 timestamp_ms += kFrameIntervalMs;
2806 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002807 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002808 VerifyFpsLtResolutionEq(source.sink_wants(), source.last_wants());
2809 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2810 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2811 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2812 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
2813 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2814 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2815
2816 // Trigger cpu adapt up, expect increased fps (640x360@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002817 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssonf7e294d2017-06-13 23:25:22 -07002818 timestamp_ms += kFrameIntervalMs;
2819 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002820 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002821 VerifyFpsMaxResolutionEq(source.sink_wants(), source.last_wants());
2822 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2823 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2824 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2825 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
2826 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2827 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2828
2829 // Trigger quality adapt up, expect upscaled resolution (960x540@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002830 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002831 timestamp_ms += kFrameIntervalMs;
2832 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002833 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002834 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
2835 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2836 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2837 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2838 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
2839 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2840 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2841
2842 // Trigger cpu adapt up, expect no restriction (1280x720fps@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002843 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssonf7e294d2017-06-13 23:25:22 -07002844 timestamp_ms += kFrameIntervalMs;
2845 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002846 WaitForEncodedFrame(kWidth, kHeight);
asaperssonf7e294d2017-06-13 23:25:22 -07002847 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
2848 VerifyNoLimitation(source.sink_wants());
2849 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2850 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2851 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2852 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
2853 EXPECT_EQ(4, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2854 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2855
2856 // Trigger adapt up, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07002857 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002858 VerifyNoLimitation(source.sink_wants());
2859 EXPECT_EQ(4, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2860 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2861
mflodmancc3d4422017-08-03 08:27:51 -07002862 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07002863}
2864
mflodmancc3d4422017-08-03 08:27:51 -07002865TEST_F(VideoStreamEncoderTest,
2866 AdaptWithTwoReasonsAndDifferentOrder_Resolution) {
asaperssonf7e294d2017-06-13 23:25:22 -07002867 const int kWidth = 640;
2868 const int kHeight = 360;
2869 const int kFpsLimit = 15;
2870 const int64_t kFrameIntervalMs = 150;
2871 int64_t timestamp_ms = kFrameIntervalMs;
mflodmancc3d4422017-08-03 08:27:51 -07002872 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -07002873
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002874 // Enable BALANCED preference, no initial limitation.
asaperssonf7e294d2017-06-13 23:25:22 -07002875 AdaptingFrameForwarder source;
2876 source.set_adaptation_enabled(true);
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002877 video_stream_encoder_->SetSource(&source,
2878 webrtc::DegradationPreference::BALANCED);
asaperssonf7e294d2017-06-13 23:25:22 -07002879 timestamp_ms += kFrameIntervalMs;
2880 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002881 WaitForEncodedFrame(kWidth, kHeight);
asaperssonf7e294d2017-06-13 23:25:22 -07002882 VerifyNoLimitation(source.sink_wants());
2883 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2884 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2885 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2886 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
2887 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2888 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2889
2890 // Trigger cpu adapt down, expect scaled down framerate (640x360@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07002891 video_stream_encoder_->TriggerCpuOveruse();
asaperssonf7e294d2017-06-13 23:25:22 -07002892 timestamp_ms += kFrameIntervalMs;
2893 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002894 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002895 VerifyFpsEqResolutionMax(source.sink_wants(), kFpsLimit);
2896 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2897 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2898 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2899 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_framerate);
2900 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2901 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2902
2903 // Trigger quality adapt down, expect scaled down resolution (480x270@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07002904 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002905 timestamp_ms += kFrameIntervalMs;
2906 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002907 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002908 VerifyFpsEqResolutionLt(source.sink_wants(), source.last_wants());
2909 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2910 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2911 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2912 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_framerate);
2913 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2914 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2915
2916 // Trigger cpu adapt up, expect upscaled resolution (640x360@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07002917 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssonf7e294d2017-06-13 23:25:22 -07002918 timestamp_ms += kFrameIntervalMs;
2919 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002920 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002921 VerifyFpsEqResolutionGt(source.sink_wants(), source.last_wants());
2922 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2923 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2924 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2925 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
2926 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2927 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2928
2929 // Trigger quality adapt up, expect increased fps (640x360@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002930 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002931 timestamp_ms += kFrameIntervalMs;
2932 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002933 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002934 VerifyNoLimitation(source.sink_wants());
2935 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2936 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2937 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2938 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
2939 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2940 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2941
2942 // Trigger adapt up, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07002943 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002944 VerifyNoLimitation(source.sink_wants());
2945 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2946 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2947
mflodmancc3d4422017-08-03 08:27:51 -07002948 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07002949}
2950
mflodmancc3d4422017-08-03 08:27:51 -07002951TEST_F(VideoStreamEncoderTest, AcceptsFullHdAdaptedDownSimulcastFrames) {
ilnik6b826ef2017-06-16 06:53:48 -07002952 // Simulates simulcast behavior and makes highest stream resolutions divisible
2953 // by 4.
2954 class CroppingVideoStreamFactory
2955 : public VideoEncoderConfig::VideoStreamFactoryInterface {
2956 public:
2957 explicit CroppingVideoStreamFactory(size_t num_temporal_layers,
2958 int framerate)
2959 : num_temporal_layers_(num_temporal_layers), framerate_(framerate) {
2960 EXPECT_GT(num_temporal_layers, 0u);
2961 EXPECT_GT(framerate, 0);
2962 }
2963
2964 private:
2965 std::vector<VideoStream> CreateEncoderStreams(
2966 int width,
2967 int height,
2968 const VideoEncoderConfig& encoder_config) override {
Yves Gerey665174f2018-06-19 15:03:05 +02002969 std::vector<VideoStream> streams = test::CreateVideoStreams(
2970 width - width % 4, height - height % 4, encoder_config);
ilnik6b826ef2017-06-16 06:53:48 -07002971 for (VideoStream& stream : streams) {
Sergey Silkina796a7e2018-03-01 15:11:29 +01002972 stream.num_temporal_layers = num_temporal_layers_;
ilnik6b826ef2017-06-16 06:53:48 -07002973 stream.max_framerate = framerate_;
2974 }
2975 return streams;
2976 }
2977
2978 const size_t num_temporal_layers_;
2979 const int framerate_;
2980 };
2981
2982 const int kFrameWidth = 1920;
2983 const int kFrameHeight = 1080;
2984 // 3/4 of 1920.
2985 const int kAdaptedFrameWidth = 1440;
2986 // 3/4 of 1080 rounded down to multiple of 4.
2987 const int kAdaptedFrameHeight = 808;
2988 const int kFramerate = 24;
2989
mflodmancc3d4422017-08-03 08:27:51 -07002990 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
ilnik6b826ef2017-06-16 06:53:48 -07002991 // Trigger reconfigure encoder (without resetting the entire instance).
2992 VideoEncoderConfig video_encoder_config;
Niels Möller259a4972018-04-05 15:36:51 +02002993 video_encoder_config.codec_type = kVideoCodecVP8;
ilnik6b826ef2017-06-16 06:53:48 -07002994 video_encoder_config.max_bitrate_bps = kTargetBitrateBps;
2995 video_encoder_config.number_of_streams = 1;
2996 video_encoder_config.video_stream_factory =
2997 new rtc::RefCountedObject<CroppingVideoStreamFactory>(1, kFramerate);
mflodmancc3d4422017-08-03 08:27:51 -07002998 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
Niels Möllerf1338562018-04-26 09:51:47 +02002999 kMaxPayloadLength);
mflodmancc3d4422017-08-03 08:27:51 -07003000 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
ilnik6b826ef2017-06-16 06:53:48 -07003001
3002 video_source_.set_adaptation_enabled(true);
3003
3004 video_source_.IncomingCapturedFrame(
3005 CreateFrame(1, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07003006 WaitForEncodedFrame(kFrameWidth, kFrameHeight);
ilnik6b826ef2017-06-16 06:53:48 -07003007
3008 // Trigger CPU overuse, downscale by 3/4.
mflodmancc3d4422017-08-03 08:27:51 -07003009 video_stream_encoder_->TriggerCpuOveruse();
ilnik6b826ef2017-06-16 06:53:48 -07003010 video_source_.IncomingCapturedFrame(
3011 CreateFrame(2, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07003012 WaitForEncodedFrame(kAdaptedFrameWidth, kAdaptedFrameHeight);
ilnik6b826ef2017-06-16 06:53:48 -07003013
mflodmancc3d4422017-08-03 08:27:51 -07003014 video_stream_encoder_->Stop();
ilnik6b826ef2017-06-16 06:53:48 -07003015}
3016
mflodmancc3d4422017-08-03 08:27:51 -07003017TEST_F(VideoStreamEncoderTest, PeriodicallyUpdatesChannelParameters) {
sprang4847ae62017-06-27 07:06:52 -07003018 const int kFrameWidth = 1280;
3019 const int kFrameHeight = 720;
3020 const int kLowFps = 2;
3021 const int kHighFps = 30;
3022
mflodmancc3d4422017-08-03 08:27:51 -07003023 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
sprang4847ae62017-06-27 07:06:52 -07003024
3025 int64_t timestamp_ms = fake_clock_.TimeNanos() / rtc::kNumNanosecsPerMillisec;
3026 max_framerate_ = kLowFps;
3027
3028 // Insert 2 seconds of 2fps video.
3029 for (int i = 0; i < kLowFps * 2; ++i) {
3030 video_source_.IncomingCapturedFrame(
3031 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
3032 WaitForEncodedFrame(timestamp_ms);
3033 timestamp_ms += 1000 / kLowFps;
3034 }
3035
3036 // Make sure encoder is updated with new target.
mflodmancc3d4422017-08-03 08:27:51 -07003037 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
sprang4847ae62017-06-27 07:06:52 -07003038 video_source_.IncomingCapturedFrame(
3039 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
3040 WaitForEncodedFrame(timestamp_ms);
3041 timestamp_ms += 1000 / kLowFps;
3042
3043 EXPECT_EQ(kLowFps, fake_encoder_.GetConfiguredInputFramerate());
3044
3045 // Insert 30fps frames for just a little more than the forced update period.
3046 const int kVcmTimerIntervalFrames =
3047 (vcm::VCMProcessTimer::kDefaultProcessIntervalMs * kHighFps) / 1000;
3048 const int kFrameIntervalMs = 1000 / kHighFps;
3049 max_framerate_ = kHighFps;
3050 for (int i = 0; i < kVcmTimerIntervalFrames + 2; ++i) {
3051 video_source_.IncomingCapturedFrame(
3052 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
3053 // Wait for encoded frame, but skip ahead if it doesn't arrive as it might
3054 // be dropped if the encoder hans't been updated with the new higher target
3055 // framerate yet, causing it to overshoot the target bitrate and then
3056 // suffering the wrath of the media optimizer.
3057 TimedWaitForEncodedFrame(timestamp_ms, 2 * kFrameIntervalMs);
3058 timestamp_ms += kFrameIntervalMs;
3059 }
3060
3061 // Don expect correct measurement just yet, but it should be higher than
3062 // before.
3063 EXPECT_GT(fake_encoder_.GetConfiguredInputFramerate(), kLowFps);
3064
mflodmancc3d4422017-08-03 08:27:51 -07003065 video_stream_encoder_->Stop();
sprang4847ae62017-06-27 07:06:52 -07003066}
3067
mflodmancc3d4422017-08-03 08:27:51 -07003068TEST_F(VideoStreamEncoderTest, DoesNotUpdateBitrateAllocationWhenSuspended) {
sprang4847ae62017-06-27 07:06:52 -07003069 const int kFrameWidth = 1280;
3070 const int kFrameHeight = 720;
3071 const int kTargetBitrateBps = 1000000;
3072
3073 MockBitrateObserver bitrate_observer;
Niels Möller0327c2d2018-05-21 14:09:31 +02003074 video_stream_encoder_->SetBitrateAllocationObserver(&bitrate_observer);
sprang4847ae62017-06-27 07:06:52 -07003075
3076 EXPECT_CALL(bitrate_observer, OnBitrateAllocationUpdated(_)).Times(1);
3077 // Initial bitrate update.
mflodmancc3d4422017-08-03 08:27:51 -07003078 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
3079 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
sprang4847ae62017-06-27 07:06:52 -07003080
3081 // Insert a first video frame, causes another bitrate update.
3082 int64_t timestamp_ms = fake_clock_.TimeNanos() / rtc::kNumNanosecsPerMillisec;
3083 EXPECT_CALL(bitrate_observer, OnBitrateAllocationUpdated(_)).Times(1);
3084 video_source_.IncomingCapturedFrame(
3085 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
3086 WaitForEncodedFrame(timestamp_ms);
3087
3088 // Next, simulate video suspension due to pacer queue overrun.
mflodmancc3d4422017-08-03 08:27:51 -07003089 video_stream_encoder_->OnBitrateUpdated(0, 0, 1);
sprang4847ae62017-06-27 07:06:52 -07003090
3091 // Skip ahead until a new periodic parameter update should have occured.
3092 timestamp_ms += vcm::VCMProcessTimer::kDefaultProcessIntervalMs;
3093 fake_clock_.AdvanceTimeMicros(
3094 vcm::VCMProcessTimer::kDefaultProcessIntervalMs *
3095 rtc::kNumMicrosecsPerMillisec);
3096
3097 // Bitrate observer should not be called.
3098 EXPECT_CALL(bitrate_observer, OnBitrateAllocationUpdated(_)).Times(0);
3099 video_source_.IncomingCapturedFrame(
3100 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
3101 ExpectDroppedFrame();
3102
mflodmancc3d4422017-08-03 08:27:51 -07003103 video_stream_encoder_->Stop();
sprang4847ae62017-06-27 07:06:52 -07003104}
ilnik6b826ef2017-06-16 06:53:48 -07003105
Niels Möller4db138e2018-04-19 09:04:13 +02003106TEST_F(VideoStreamEncoderTest,
3107 DefaultCpuAdaptationThresholdsForSoftwareEncoder) {
3108 const int kFrameWidth = 1280;
3109 const int kFrameHeight = 720;
3110 const CpuOveruseOptions default_options;
3111 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
3112 video_source_.IncomingCapturedFrame(
3113 CreateFrame(1, kFrameWidth, kFrameHeight));
3114 WaitForEncodedFrame(1);
3115 EXPECT_EQ(video_stream_encoder_->overuse_detector_proxy_->GetOptions()
3116 .low_encode_usage_threshold_percent,
3117 default_options.low_encode_usage_threshold_percent);
3118 EXPECT_EQ(video_stream_encoder_->overuse_detector_proxy_->GetOptions()
3119 .high_encode_usage_threshold_percent,
3120 default_options.high_encode_usage_threshold_percent);
3121 video_stream_encoder_->Stop();
3122}
3123
3124TEST_F(VideoStreamEncoderTest,
3125 HigherCpuAdaptationThresholdsForHardwareEncoder) {
3126 const int kFrameWidth = 1280;
3127 const int kFrameHeight = 720;
3128 CpuOveruseOptions hardware_options;
3129 hardware_options.low_encode_usage_threshold_percent = 150;
3130 hardware_options.high_encode_usage_threshold_percent = 200;
3131 encoder_factory_.SetIsHardwareAccelerated(true);
3132
3133 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
3134 video_source_.IncomingCapturedFrame(
3135 CreateFrame(1, kFrameWidth, kFrameHeight));
3136 WaitForEncodedFrame(1);
3137 EXPECT_EQ(video_stream_encoder_->overuse_detector_proxy_->GetOptions()
3138 .low_encode_usage_threshold_percent,
3139 hardware_options.low_encode_usage_threshold_percent);
3140 EXPECT_EQ(video_stream_encoder_->overuse_detector_proxy_->GetOptions()
3141 .high_encode_usage_threshold_percent,
3142 hardware_options.high_encode_usage_threshold_percent);
3143 video_stream_encoder_->Stop();
3144}
3145
perkj26091b12016-09-01 01:17:40 -07003146} // namespace webrtc