blob: 80f8d5a592175f3c22579033de06fcda3ab390d7 [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"
Erik Språng8abd56c2018-10-01 18:47:03 +020017#include "modules/video_coding/codecs/vp8/include/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"
Stefan Holmerdbdb3a02018-07-17 16:03:46 +020022#include "rtc_base/refcountedobject.h"
Mirko Bonadei17f48782018-09-28 08:51:10 +020023#include "system_wrappers/include/metrics.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020024#include "system_wrappers/include/sleep.h"
25#include "test/encoder_settings.h"
26#include "test/fake_encoder.h"
Kári Tristan Helgason639602a2018-08-02 10:51:40 +020027#include "test/field_trial.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020028#include "test/frame_generator.h"
29#include "test/gmock.h"
30#include "test/gtest.h"
Niels Möllercbcbc222018-09-28 09:07:24 +020031#include "test/video_encoder_proxy_factory.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020032#include "video/send_statistics_proxy.h"
33#include "video/video_stream_encoder.h"
perkj26091b12016-09-01 01:17:40 -070034
35namespace webrtc {
36
sprangb1ca0732017-02-01 08:38:12 -080037using ScaleReason = AdaptationObserverInterface::AdaptReason;
sprang57c2fff2017-01-16 06:24:02 -080038using ::testing::_;
39using ::testing::Return;
kthelgason876222f2016-11-29 01:44:11 -080040
perkj803d97f2016-11-01 11:45:46 -070041namespace {
Åsa Persson8c1bf952018-09-13 10:42:19 +020042const int kMinPixelsPerFrame = 320 * 180;
43const int kMinFramerateFps = 2;
44const int kMinBalancedFramerateFps = 7;
45const int64_t kFrameTimeoutMs = 100;
asapersson5f7226f2016-11-25 04:37:00 -080046const size_t kMaxPayloadLength = 1440;
kthelgason2bc68642017-02-07 07:02:22 -080047const int kTargetBitrateBps = 1000000;
48const int kLowTargetBitrateBps = kTargetBitrateBps / 10;
49const int kMaxInitialFramedrop = 4;
sprangfda496a2017-06-15 04:21:07 -070050const int kDefaultFramerate = 30;
Åsa Persson8c1bf952018-09-13 10:42:19 +020051const int64_t kFrameIntervalMs = rtc::kNumMillisecsPerSec / kDefaultFramerate;
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:
Niels Möller213618e2018-07-24 09:29:58 +020094 VideoStreamEncoderUnderTest(SendStatisticsProxy* stats_proxy,
95 const VideoStreamEncoderSettings& settings)
Yves Gerey665174f2018-06-19 15:03:05 +020096 : VideoStreamEncoder(1 /* number_of_cores */,
97 stats_proxy,
98 settings,
99 nullptr /* pre_encode_callback */,
100 std::unique_ptr<OveruseFrameDetector>(
101 overuse_detector_proxy_ =
102 new CpuOveruseDetectorProxy(stats_proxy))) {}
perkj803d97f2016-11-01 11:45:46 -0700103
sprangb1ca0732017-02-01 08:38:12 -0800104 void PostTaskAndWait(bool down, AdaptReason reason) {
perkj803d97f2016-11-01 11:45:46 -0700105 rtc::Event event(false, false);
kthelgason876222f2016-11-29 01:44:11 -0800106 encoder_queue()->PostTask([this, &event, reason, down] {
sprangb1ca0732017-02-01 08:38:12 -0800107 down ? AdaptDown(reason) : AdaptUp(reason);
perkj803d97f2016-11-01 11:45:46 -0700108 event.Set();
109 });
perkj070ba852017-02-16 15:46:27 -0800110 ASSERT_TRUE(event.Wait(5000));
perkj803d97f2016-11-01 11:45:46 -0700111 }
112
kthelgason2fc52542017-03-03 00:24:41 -0800113 // This is used as a synchronisation mechanism, to make sure that the
114 // encoder queue is not blocked before we start sending it frames.
115 void WaitUntilTaskQueueIsIdle() {
116 rtc::Event event(false, false);
Yves Gerey665174f2018-06-19 15:03:05 +0200117 encoder_queue()->PostTask([&event] { event.Set(); });
kthelgason2fc52542017-03-03 00:24:41 -0800118 ASSERT_TRUE(event.Wait(5000));
119 }
120
sprangb1ca0732017-02-01 08:38:12 -0800121 void TriggerCpuOveruse() { PostTaskAndWait(true, AdaptReason::kCpu); }
kthelgason876222f2016-11-29 01:44:11 -0800122
sprangb1ca0732017-02-01 08:38:12 -0800123 void TriggerCpuNormalUsage() { PostTaskAndWait(false, AdaptReason::kCpu); }
kthelgason876222f2016-11-29 01:44:11 -0800124
sprangb1ca0732017-02-01 08:38:12 -0800125 void TriggerQualityLow() { PostTaskAndWait(true, AdaptReason::kQuality); }
kthelgason876222f2016-11-29 01:44:11 -0800126
sprangb1ca0732017-02-01 08:38:12 -0800127 void TriggerQualityHigh() { PostTaskAndWait(false, AdaptReason::kQuality); }
sprangfda496a2017-06-15 04:21:07 -0700128
Niels Möller7dc26b72017-12-06 10:27:48 +0100129 CpuOveruseDetectorProxy* overuse_detector_proxy_;
perkj803d97f2016-11-01 11:45:46 -0700130};
131
asapersson5f7226f2016-11-25 04:37:00 -0800132class VideoStreamFactory
133 : public VideoEncoderConfig::VideoStreamFactoryInterface {
134 public:
sprangfda496a2017-06-15 04:21:07 -0700135 explicit VideoStreamFactory(size_t num_temporal_layers, int framerate)
136 : num_temporal_layers_(num_temporal_layers), framerate_(framerate) {
asapersson5f7226f2016-11-25 04:37:00 -0800137 EXPECT_GT(num_temporal_layers, 0u);
sprangfda496a2017-06-15 04:21:07 -0700138 EXPECT_GT(framerate, 0);
asapersson5f7226f2016-11-25 04:37:00 -0800139 }
140
141 private:
142 std::vector<VideoStream> CreateEncoderStreams(
143 int width,
144 int height,
145 const VideoEncoderConfig& encoder_config) override {
146 std::vector<VideoStream> streams =
147 test::CreateVideoStreams(width, height, encoder_config);
148 for (VideoStream& stream : streams) {
Sergey Silkina796a7e2018-03-01 15:11:29 +0100149 stream.num_temporal_layers = num_temporal_layers_;
sprangfda496a2017-06-15 04:21:07 -0700150 stream.max_framerate = framerate_;
asapersson5f7226f2016-11-25 04:37:00 -0800151 }
152 return streams;
153 }
sprangfda496a2017-06-15 04:21:07 -0700154
asapersson5f7226f2016-11-25 04:37:00 -0800155 const size_t num_temporal_layers_;
sprangfda496a2017-06-15 04:21:07 -0700156 const int framerate_;
asapersson5f7226f2016-11-25 04:37:00 -0800157};
158
sprangb1ca0732017-02-01 08:38:12 -0800159class AdaptingFrameForwarder : public test::FrameForwarder {
160 public:
161 AdaptingFrameForwarder() : adaptation_enabled_(false) {}
asaperssonfab67072017-04-04 05:51:49 -0700162 ~AdaptingFrameForwarder() override {}
sprangb1ca0732017-02-01 08:38:12 -0800163
164 void set_adaptation_enabled(bool enabled) {
165 rtc::CritScope cs(&crit_);
166 adaptation_enabled_ = enabled;
167 }
168
asaperssonfab67072017-04-04 05:51:49 -0700169 bool adaption_enabled() const {
sprangb1ca0732017-02-01 08:38:12 -0800170 rtc::CritScope cs(&crit_);
171 return adaptation_enabled_;
172 }
173
asapersson09f05612017-05-15 23:40:18 -0700174 rtc::VideoSinkWants last_wants() const {
175 rtc::CritScope cs(&crit_);
176 return last_wants_;
177 }
178
Danil Chapovalovb9b146c2018-06-15 12:28:07 +0200179 absl::optional<int> last_sent_width() const { return last_width_; }
180 absl::optional<int> last_sent_height() const { return last_height_; }
Jonathan Yubc771b72017-12-08 17:04:29 -0800181
sprangb1ca0732017-02-01 08:38:12 -0800182 void IncomingCapturedFrame(const VideoFrame& video_frame) override {
183 int cropped_width = 0;
184 int cropped_height = 0;
185 int out_width = 0;
186 int out_height = 0;
sprangc5d62e22017-04-02 23:53:04 -0700187 if (adaption_enabled()) {
188 if (adapter_.AdaptFrameResolution(
189 video_frame.width(), video_frame.height(),
190 video_frame.timestamp_us() * 1000, &cropped_width,
191 &cropped_height, &out_width, &out_height)) {
192 VideoFrame adapted_frame(new rtc::RefCountedObject<TestBuffer>(
193 nullptr, out_width, out_height),
194 99, 99, kVideoRotation_0);
195 adapted_frame.set_ntp_time_ms(video_frame.ntp_time_ms());
196 test::FrameForwarder::IncomingCapturedFrame(adapted_frame);
Jonathan Yubc771b72017-12-08 17:04:29 -0800197 last_width_.emplace(adapted_frame.width());
198 last_height_.emplace(adapted_frame.height());
199 } else {
Danil Chapovalovb9b146c2018-06-15 12:28:07 +0200200 last_width_ = absl::nullopt;
201 last_height_ = absl::nullopt;
sprangc5d62e22017-04-02 23:53:04 -0700202 }
sprangb1ca0732017-02-01 08:38:12 -0800203 } else {
204 test::FrameForwarder::IncomingCapturedFrame(video_frame);
Jonathan Yubc771b72017-12-08 17:04:29 -0800205 last_width_.emplace(video_frame.width());
206 last_height_.emplace(video_frame.height());
sprangb1ca0732017-02-01 08:38:12 -0800207 }
208 }
209
210 void AddOrUpdateSink(rtc::VideoSinkInterface<VideoFrame>* sink,
211 const rtc::VideoSinkWants& wants) override {
212 rtc::CritScope cs(&crit_);
asapersson09f05612017-05-15 23:40:18 -0700213 last_wants_ = sink_wants();
sprangc5d62e22017-04-02 23:53:04 -0700214 adapter_.OnResolutionFramerateRequest(wants.target_pixel_count,
215 wants.max_pixel_count,
216 wants.max_framerate_fps);
sprangb1ca0732017-02-01 08:38:12 -0800217 test::FrameForwarder::AddOrUpdateSink(sink, wants);
218 }
sprangb1ca0732017-02-01 08:38:12 -0800219 cricket::VideoAdapter adapter_;
danilchapa37de392017-09-09 04:17:22 -0700220 bool adaptation_enabled_ RTC_GUARDED_BY(crit_);
221 rtc::VideoSinkWants last_wants_ RTC_GUARDED_BY(crit_);
Danil Chapovalovb9b146c2018-06-15 12:28:07 +0200222 absl::optional<int> last_width_;
223 absl::optional<int> last_height_;
sprangb1ca0732017-02-01 08:38:12 -0800224};
sprangc5d62e22017-04-02 23:53:04 -0700225
Niels Möller213618e2018-07-24 09:29:58 +0200226// TODO(nisse): Mock only VideoStreamEncoderObserver.
sprangc5d62e22017-04-02 23:53:04 -0700227class 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
Niels Möller213618e2018-07-24 09:29:58 +0200241 int GetInputFrameRate() const override {
242 rtc::CritScope cs(&lock_);
243 if (mock_stats_)
244 return mock_stats_->input_frame_rate;
245 return SendStatisticsProxy::GetInputFrameRate();
246 }
sprangc5d62e22017-04-02 23:53:04 -0700247 void SetMockStats(const VideoSendStream::Stats& stats) {
248 rtc::CritScope cs(&lock_);
249 mock_stats_.emplace(stats);
250 }
251
252 void ResetMockStats() {
253 rtc::CritScope cs(&lock_);
254 mock_stats_.reset();
255 }
256
257 private:
258 rtc::CriticalSection lock_;
Danil Chapovalovb9b146c2018-06-15 12:28:07 +0200259 absl::optional<VideoSendStream::Stats> mock_stats_ RTC_GUARDED_BY(lock_);
sprangc5d62e22017-04-02 23:53:04 -0700260};
261
sprang4847ae62017-06-27 07:06:52 -0700262class MockBitrateObserver : public VideoBitrateAllocationObserver {
263 public:
Erik Språng566124a2018-04-23 12:32:22 +0200264 MOCK_METHOD1(OnBitrateAllocationUpdated, void(const VideoBitrateAllocation&));
sprang4847ae62017-06-27 07:06:52 -0700265};
266
perkj803d97f2016-11-01 11:45:46 -0700267} // namespace
268
mflodmancc3d4422017-08-03 08:27:51 -0700269class VideoStreamEncoderTest : public ::testing::Test {
perkj26091b12016-09-01 01:17:40 -0700270 public:
271 static const int kDefaultTimeoutMs = 30 * 1000;
272
mflodmancc3d4422017-08-03 08:27:51 -0700273 VideoStreamEncoderTest()
perkj26091b12016-09-01 01:17:40 -0700274 : video_send_config_(VideoSendStream::Config(nullptr)),
perkjfa10b552016-10-02 23:45:26 -0700275 codec_width_(320),
276 codec_height_(240),
Åsa Persson8c1bf952018-09-13 10:42:19 +0200277 max_framerate_(kDefaultFramerate),
perkj26091b12016-09-01 01:17:40 -0700278 fake_encoder_(),
Niels Möller4db138e2018-04-19 09:04:13 +0200279 encoder_factory_(&fake_encoder_),
sprangc5d62e22017-04-02 23:53:04 -0700280 stats_proxy_(new MockableSendStatisticsProxy(
perkj803d97f2016-11-01 11:45:46 -0700281 Clock::GetRealTimeClock(),
282 video_send_config_,
283 webrtc::VideoEncoderConfig::ContentType::kRealtimeVideo)),
perkj26091b12016-09-01 01:17:40 -0700284 sink_(&fake_encoder_) {}
285
286 void SetUp() override {
perkj803d97f2016-11-01 11:45:46 -0700287 metrics::Reset();
perkj26091b12016-09-01 01:17:40 -0700288 video_send_config_ = VideoSendStream::Config(nullptr);
Niels Möller4db138e2018-04-19 09:04:13 +0200289 video_send_config_.encoder_settings.encoder_factory = &encoder_factory_;
Niels Möller259a4972018-04-05 15:36:51 +0200290 video_send_config_.rtp.payload_name = "FAKE";
291 video_send_config_.rtp.payload_type = 125;
perkj26091b12016-09-01 01:17:40 -0700292
Per512ecb32016-09-23 15:52:06 +0200293 VideoEncoderConfig video_encoder_config;
Niels Möller259a4972018-04-05 15:36:51 +0200294 test::FillEncoderConfiguration(kVideoCodecVP8, 1, &video_encoder_config);
sprang4847ae62017-06-27 07:06:52 -0700295 video_encoder_config.video_stream_factory =
296 new rtc::RefCountedObject<VideoStreamFactory>(1, max_framerate_);
Erik Språng08127a92016-11-16 16:41:30 +0100297 video_encoder_config_ = video_encoder_config.Copy();
sprang4847ae62017-06-27 07:06:52 -0700298
299 // Framerate limit is specified by the VideoStreamFactory.
300 std::vector<VideoStream> streams =
301 video_encoder_config.video_stream_factory->CreateEncoderStreams(
302 codec_width_, codec_height_, video_encoder_config);
303 max_framerate_ = streams[0].max_framerate;
304 fake_clock_.SetTimeMicros(1234);
305
Niels Möllerf1338562018-04-26 09:51:47 +0200306 ConfigureEncoder(std::move(video_encoder_config));
asapersson5f7226f2016-11-25 04:37:00 -0800307 }
308
Niels Möllerf1338562018-04-26 09:51:47 +0200309 void ConfigureEncoder(VideoEncoderConfig video_encoder_config) {
mflodmancc3d4422017-08-03 08:27:51 -0700310 if (video_stream_encoder_)
311 video_stream_encoder_->Stop();
312 video_stream_encoder_.reset(new VideoStreamEncoderUnderTest(
perkj803d97f2016-11-01 11:45:46 -0700313 stats_proxy_.get(), video_send_config_.encoder_settings));
mflodmancc3d4422017-08-03 08:27:51 -0700314 video_stream_encoder_->SetSink(&sink_, false /* rotation_applied */);
315 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -0700316 &video_source_, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
mflodmancc3d4422017-08-03 08:27:51 -0700317 video_stream_encoder_->SetStartBitrate(kTargetBitrateBps);
318 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
Niels Möllerf1338562018-04-26 09:51:47 +0200319 kMaxPayloadLength);
mflodmancc3d4422017-08-03 08:27:51 -0700320 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
asapersson5f7226f2016-11-25 04:37:00 -0800321 }
322
323 void ResetEncoder(const std::string& payload_name,
324 size_t num_streams,
325 size_t num_temporal_layers,
emircanbbcc3562017-08-18 00:28:40 -0700326 unsigned char num_spatial_layers,
sprang4847ae62017-06-27 07:06:52 -0700327 bool screenshare) {
Niels Möller259a4972018-04-05 15:36:51 +0200328 video_send_config_.rtp.payload_name = payload_name;
asapersson5f7226f2016-11-25 04:37:00 -0800329
330 VideoEncoderConfig video_encoder_config;
Niels Möller259a4972018-04-05 15:36:51 +0200331 video_encoder_config.codec_type = PayloadStringToCodecType(payload_name);
asapersson5f7226f2016-11-25 04:37:00 -0800332 video_encoder_config.number_of_streams = num_streams;
kthelgason2bc68642017-02-07 07:02:22 -0800333 video_encoder_config.max_bitrate_bps = kTargetBitrateBps;
asapersson5f7226f2016-11-25 04:37:00 -0800334 video_encoder_config.video_stream_factory =
sprangfda496a2017-06-15 04:21:07 -0700335 new rtc::RefCountedObject<VideoStreamFactory>(num_temporal_layers,
336 kDefaultFramerate);
sprang4847ae62017-06-27 07:06:52 -0700337 video_encoder_config.content_type =
338 screenshare ? VideoEncoderConfig::ContentType::kScreen
339 : VideoEncoderConfig::ContentType::kRealtimeVideo;
emircanbbcc3562017-08-18 00:28:40 -0700340 if (payload_name == "VP9") {
341 VideoCodecVP9 vp9_settings = VideoEncoder::GetDefaultVp9Settings();
342 vp9_settings.numberOfSpatialLayers = num_spatial_layers;
343 video_encoder_config.encoder_specific_settings =
344 new rtc::RefCountedObject<
345 VideoEncoderConfig::Vp9EncoderSpecificSettings>(vp9_settings);
346 }
Niels Möllerf1338562018-04-26 09:51:47 +0200347 ConfigureEncoder(std::move(video_encoder_config));
perkj26091b12016-09-01 01:17:40 -0700348 }
349
sprang57c2fff2017-01-16 06:24:02 -0800350 VideoFrame CreateFrame(int64_t ntp_time_ms,
351 rtc::Event* destruction_event) const {
Per512ecb32016-09-23 15:52:06 +0200352 VideoFrame frame(new rtc::RefCountedObject<TestBuffer>(
353 destruction_event, codec_width_, codec_height_),
354 99, 99, kVideoRotation_0);
sprang57c2fff2017-01-16 06:24:02 -0800355 frame.set_ntp_time_ms(ntp_time_ms);
perkj26091b12016-09-01 01:17:40 -0700356 return frame;
357 }
358
sprang57c2fff2017-01-16 06:24:02 -0800359 VideoFrame CreateFrame(int64_t ntp_time_ms, int width, int height) const {
perkj803d97f2016-11-01 11:45:46 -0700360 VideoFrame frame(
361 new rtc::RefCountedObject<TestBuffer>(nullptr, width, height), 99, 99,
362 kVideoRotation_0);
sprang57c2fff2017-01-16 06:24:02 -0800363 frame.set_ntp_time_ms(ntp_time_ms);
sprangc5d62e22017-04-02 23:53:04 -0700364 frame.set_timestamp_us(ntp_time_ms * 1000);
perkj803d97f2016-11-01 11:45:46 -0700365 return frame;
366 }
367
asapersson02465b82017-04-10 01:12:52 -0700368 void VerifyNoLimitation(const rtc::VideoSinkWants& wants) {
asapersson02465b82017-04-10 01:12:52 -0700369 EXPECT_EQ(std::numeric_limits<int>::max(), wants.max_framerate_fps);
asapersson09f05612017-05-15 23:40:18 -0700370 EXPECT_EQ(std::numeric_limits<int>::max(), wants.max_pixel_count);
371 EXPECT_FALSE(wants.target_pixel_count);
asapersson02465b82017-04-10 01:12:52 -0700372 }
373
asapersson09f05612017-05-15 23:40:18 -0700374 void VerifyFpsEqResolutionEq(const rtc::VideoSinkWants& wants1,
375 const rtc::VideoSinkWants& wants2) {
376 EXPECT_EQ(wants1.max_framerate_fps, wants2.max_framerate_fps);
377 EXPECT_EQ(wants1.max_pixel_count, wants2.max_pixel_count);
378 }
379
Åsa Persson8c1bf952018-09-13 10:42:19 +0200380 void VerifyFpsMaxResolutionMax(const rtc::VideoSinkWants& wants) {
381 EXPECT_EQ(kDefaultFramerate, wants.max_framerate_fps);
382 EXPECT_EQ(std::numeric_limits<int>::max(), wants.max_pixel_count);
383 EXPECT_FALSE(wants.target_pixel_count);
384 }
385
asapersson09f05612017-05-15 23:40:18 -0700386 void VerifyFpsMaxResolutionLt(const rtc::VideoSinkWants& wants1,
387 const rtc::VideoSinkWants& wants2) {
Åsa Persson8c1bf952018-09-13 10:42:19 +0200388 EXPECT_EQ(kDefaultFramerate, wants1.max_framerate_fps);
asapersson09f05612017-05-15 23:40:18 -0700389 EXPECT_LT(wants1.max_pixel_count, wants2.max_pixel_count);
390 EXPECT_GT(wants1.max_pixel_count, 0);
391 }
392
393 void VerifyFpsMaxResolutionGt(const rtc::VideoSinkWants& wants1,
394 const rtc::VideoSinkWants& wants2) {
Åsa Persson8c1bf952018-09-13 10:42:19 +0200395 EXPECT_EQ(kDefaultFramerate, wants1.max_framerate_fps);
asapersson09f05612017-05-15 23:40:18 -0700396 EXPECT_GT(wants1.max_pixel_count, wants2.max_pixel_count);
397 }
398
asaperssonf7e294d2017-06-13 23:25:22 -0700399 void VerifyFpsMaxResolutionEq(const rtc::VideoSinkWants& wants1,
400 const rtc::VideoSinkWants& wants2) {
Åsa Persson8c1bf952018-09-13 10:42:19 +0200401 EXPECT_EQ(kDefaultFramerate, wants1.max_framerate_fps);
asaperssonf7e294d2017-06-13 23:25:22 -0700402 EXPECT_EQ(wants1.max_pixel_count, wants2.max_pixel_count);
403 }
404
405 void VerifyFpsLtResolutionEq(const rtc::VideoSinkWants& wants1,
406 const rtc::VideoSinkWants& wants2) {
407 EXPECT_LT(wants1.max_framerate_fps, wants2.max_framerate_fps);
408 EXPECT_EQ(wants1.max_pixel_count, wants2.max_pixel_count);
409 }
410
411 void VerifyFpsGtResolutionEq(const rtc::VideoSinkWants& wants1,
412 const rtc::VideoSinkWants& wants2) {
413 EXPECT_GT(wants1.max_framerate_fps, wants2.max_framerate_fps);
414 EXPECT_EQ(wants1.max_pixel_count, wants2.max_pixel_count);
415 }
416
417 void VerifyFpsEqResolutionLt(const rtc::VideoSinkWants& wants1,
418 const rtc::VideoSinkWants& wants2) {
419 EXPECT_EQ(wants1.max_framerate_fps, wants2.max_framerate_fps);
420 EXPECT_LT(wants1.max_pixel_count, wants2.max_pixel_count);
421 EXPECT_GT(wants1.max_pixel_count, 0);
422 }
423
424 void VerifyFpsEqResolutionGt(const rtc::VideoSinkWants& wants1,
425 const rtc::VideoSinkWants& wants2) {
426 EXPECT_EQ(wants1.max_framerate_fps, wants2.max_framerate_fps);
427 EXPECT_GT(wants1.max_pixel_count, wants2.max_pixel_count);
428 }
429
asapersson09f05612017-05-15 23:40:18 -0700430 void VerifyFpsMaxResolutionLt(const rtc::VideoSinkWants& wants,
431 int pixel_count) {
Åsa Persson8c1bf952018-09-13 10:42:19 +0200432 EXPECT_EQ(kDefaultFramerate, wants.max_framerate_fps);
asapersson02465b82017-04-10 01:12:52 -0700433 EXPECT_LT(wants.max_pixel_count, pixel_count);
434 EXPECT_GT(wants.max_pixel_count, 0);
asapersson09f05612017-05-15 23:40:18 -0700435 }
436
437 void VerifyFpsLtResolutionMax(const rtc::VideoSinkWants& wants, int fps) {
438 EXPECT_LT(wants.max_framerate_fps, fps);
439 EXPECT_EQ(std::numeric_limits<int>::max(), wants.max_pixel_count);
440 EXPECT_FALSE(wants.target_pixel_count);
asapersson02465b82017-04-10 01:12:52 -0700441 }
442
asaperssonf7e294d2017-06-13 23:25:22 -0700443 void VerifyFpsEqResolutionMax(const rtc::VideoSinkWants& wants,
444 int expected_fps) {
445 EXPECT_EQ(expected_fps, wants.max_framerate_fps);
446 EXPECT_EQ(std::numeric_limits<int>::max(), wants.max_pixel_count);
447 EXPECT_FALSE(wants.target_pixel_count);
448 }
449
Jonathan Yubc771b72017-12-08 17:04:29 -0800450 void VerifyBalancedModeFpsRange(const rtc::VideoSinkWants& wants,
451 int last_frame_pixels) {
452 // Balanced mode should always scale FPS to the desired range before
453 // attempting to scale resolution.
454 int fps_limit = wants.max_framerate_fps;
455 if (last_frame_pixels <= 320 * 240) {
456 EXPECT_TRUE(7 <= fps_limit && fps_limit <= 10);
457 } else if (last_frame_pixels <= 480 * 270) {
458 EXPECT_TRUE(10 <= fps_limit && fps_limit <= 15);
459 } else if (last_frame_pixels <= 640 * 480) {
460 EXPECT_LE(15, fps_limit);
461 } else {
Åsa Persson8c1bf952018-09-13 10:42:19 +0200462 EXPECT_EQ(kDefaultFramerate, fps_limit);
Jonathan Yubc771b72017-12-08 17:04:29 -0800463 }
464 }
465
sprang4847ae62017-06-27 07:06:52 -0700466 void WaitForEncodedFrame(int64_t expected_ntp_time) {
467 sink_.WaitForEncodedFrame(expected_ntp_time);
468 fake_clock_.AdvanceTimeMicros(rtc::kNumMicrosecsPerSec / max_framerate_);
469 }
470
471 bool TimedWaitForEncodedFrame(int64_t expected_ntp_time, int64_t timeout_ms) {
472 bool ok = sink_.TimedWaitForEncodedFrame(expected_ntp_time, timeout_ms);
473 fake_clock_.AdvanceTimeMicros(rtc::kNumMicrosecsPerSec / max_framerate_);
474 return ok;
475 }
476
477 void WaitForEncodedFrame(uint32_t expected_width, uint32_t expected_height) {
478 sink_.WaitForEncodedFrame(expected_width, expected_height);
479 fake_clock_.AdvanceTimeMicros(rtc::kNumMicrosecsPerSec / max_framerate_);
480 }
481
482 void ExpectDroppedFrame() {
483 sink_.ExpectDroppedFrame();
484 fake_clock_.AdvanceTimeMicros(rtc::kNumMicrosecsPerSec / max_framerate_);
485 }
486
487 bool WaitForFrame(int64_t timeout_ms) {
488 bool ok = sink_.WaitForFrame(timeout_ms);
489 fake_clock_.AdvanceTimeMicros(rtc::kNumMicrosecsPerSec / max_framerate_);
490 return ok;
491 }
492
perkj26091b12016-09-01 01:17:40 -0700493 class TestEncoder : public test::FakeEncoder {
494 public:
495 TestEncoder()
496 : FakeEncoder(Clock::GetRealTimeClock()),
497 continue_encode_event_(false, false) {}
498
asaperssonfab67072017-04-04 05:51:49 -0700499 VideoCodec codec_config() const {
brandtre78d2662017-01-16 05:57:16 -0800500 rtc::CritScope lock(&crit_sect_);
perkjfa10b552016-10-02 23:45:26 -0700501 return config_;
502 }
503
504 void BlockNextEncode() {
brandtre78d2662017-01-16 05:57:16 -0800505 rtc::CritScope lock(&local_crit_sect_);
perkjfa10b552016-10-02 23:45:26 -0700506 block_next_encode_ = true;
507 }
508
kthelgason876222f2016-11-29 01:44:11 -0800509 VideoEncoder::ScalingSettings GetScalingSettings() const override {
kthelgason2fc52542017-03-03 00:24:41 -0800510 rtc::CritScope lock(&local_crit_sect_);
kthelgasonad9010c2017-02-14 00:46:51 -0800511 if (quality_scaling_)
Niels Möller225c7872018-02-22 15:03:53 +0100512 return VideoEncoder::ScalingSettings(1, 2, kMinPixelsPerFrame);
513 return VideoEncoder::ScalingSettings::kOff;
kthelgason876222f2016-11-29 01:44:11 -0800514 }
515
perkjfa10b552016-10-02 23:45:26 -0700516 void ContinueEncode() { continue_encode_event_.Set(); }
517
518 void CheckLastTimeStampsMatch(int64_t ntp_time_ms,
519 uint32_t timestamp) const {
brandtre78d2662017-01-16 05:57:16 -0800520 rtc::CritScope lock(&local_crit_sect_);
perkjfa10b552016-10-02 23:45:26 -0700521 EXPECT_EQ(timestamp_, timestamp);
522 EXPECT_EQ(ntp_time_ms_, ntp_time_ms);
523 }
524
kthelgason2fc52542017-03-03 00:24:41 -0800525 void SetQualityScaling(bool b) {
526 rtc::CritScope lock(&local_crit_sect_);
527 quality_scaling_ = b;
528 }
kthelgasonad9010c2017-02-14 00:46:51 -0800529
sprangfe627f32017-03-29 08:24:59 -0700530 void ForceInitEncodeFailure(bool force_failure) {
531 rtc::CritScope lock(&local_crit_sect_);
532 force_init_encode_failed_ = force_failure;
533 }
534
perkjfa10b552016-10-02 23:45:26 -0700535 private:
perkj26091b12016-09-01 01:17:40 -0700536 int32_t Encode(const VideoFrame& input_image,
537 const CodecSpecificInfo* codec_specific_info,
538 const std::vector<FrameType>* frame_types) override {
539 bool block_encode;
540 {
brandtre78d2662017-01-16 05:57:16 -0800541 rtc::CritScope lock(&local_crit_sect_);
perkj26091b12016-09-01 01:17:40 -0700542 EXPECT_GT(input_image.timestamp(), timestamp_);
543 EXPECT_GT(input_image.ntp_time_ms(), ntp_time_ms_);
544 EXPECT_EQ(input_image.timestamp(), input_image.ntp_time_ms() * 90);
545
546 timestamp_ = input_image.timestamp();
547 ntp_time_ms_ = input_image.ntp_time_ms();
perkj803d97f2016-11-01 11:45:46 -0700548 last_input_width_ = input_image.width();
549 last_input_height_ = input_image.height();
perkj26091b12016-09-01 01:17:40 -0700550 block_encode = block_next_encode_;
551 block_next_encode_ = false;
552 }
553 int32_t result =
554 FakeEncoder::Encode(input_image, codec_specific_info, frame_types);
555 if (block_encode)
perkja49cbd32016-09-16 07:53:41 -0700556 EXPECT_TRUE(continue_encode_event_.Wait(kDefaultTimeoutMs));
perkj26091b12016-09-01 01:17:40 -0700557 return result;
558 }
559
sprangfe627f32017-03-29 08:24:59 -0700560 int32_t InitEncode(const VideoCodec* config,
561 int32_t number_of_cores,
562 size_t max_payload_size) override {
563 int res =
564 FakeEncoder::InitEncode(config, number_of_cores, max_payload_size);
565 rtc::CritScope lock(&local_crit_sect_);
Erik Språng82fad3d2018-03-21 09:57:23 +0100566 if (config->codecType == kVideoCodecVP8) {
sprangfe627f32017-03-29 08:24:59 -0700567 // Simulate setting up temporal layers, in order to validate the life
568 // cycle of these objects.
569 int num_streams = std::max<int>(1, config->numberOfSimulcastStreams);
sprangfe627f32017-03-29 08:24:59 -0700570 for (int i = 0; i < num_streams; ++i) {
571 allocated_temporal_layers_.emplace_back(
Erik Språng8abd56c2018-10-01 18:47:03 +0200572 TemporalLayers::CreateTemporalLayers(
573 TemporalLayersType::kFixedPattern,
574 config->VP8().numberOfTemporalLayers));
sprangfe627f32017-03-29 08:24:59 -0700575 }
576 }
577 if (force_init_encode_failed_)
578 return -1;
579 return res;
580 }
581
brandtre78d2662017-01-16 05:57:16 -0800582 rtc::CriticalSection local_crit_sect_;
danilchapa37de392017-09-09 04:17:22 -0700583 bool block_next_encode_ RTC_GUARDED_BY(local_crit_sect_) = false;
perkj26091b12016-09-01 01:17:40 -0700584 rtc::Event continue_encode_event_;
danilchapa37de392017-09-09 04:17:22 -0700585 uint32_t timestamp_ RTC_GUARDED_BY(local_crit_sect_) = 0;
586 int64_t ntp_time_ms_ RTC_GUARDED_BY(local_crit_sect_) = 0;
587 int last_input_width_ RTC_GUARDED_BY(local_crit_sect_) = 0;
588 int last_input_height_ RTC_GUARDED_BY(local_crit_sect_) = 0;
589 bool quality_scaling_ RTC_GUARDED_BY(local_crit_sect_) = true;
sprangfe627f32017-03-29 08:24:59 -0700590 std::vector<std::unique_ptr<TemporalLayers>> allocated_temporal_layers_
danilchapa37de392017-09-09 04:17:22 -0700591 RTC_GUARDED_BY(local_crit_sect_);
592 bool force_init_encode_failed_ RTC_GUARDED_BY(local_crit_sect_) = false;
perkj26091b12016-09-01 01:17:40 -0700593 };
594
mflodmancc3d4422017-08-03 08:27:51 -0700595 class TestSink : public VideoStreamEncoder::EncoderSink {
perkj26091b12016-09-01 01:17:40 -0700596 public:
597 explicit TestSink(TestEncoder* test_encoder)
598 : test_encoder_(test_encoder), encoded_frame_event_(false, false) {}
599
perkj26091b12016-09-01 01:17:40 -0700600 void WaitForEncodedFrame(int64_t expected_ntp_time) {
sprang4847ae62017-06-27 07:06:52 -0700601 EXPECT_TRUE(
602 TimedWaitForEncodedFrame(expected_ntp_time, kDefaultTimeoutMs));
603 }
604
605 bool TimedWaitForEncodedFrame(int64_t expected_ntp_time,
606 int64_t timeout_ms) {
perkj26091b12016-09-01 01:17:40 -0700607 uint32_t timestamp = 0;
sprang4847ae62017-06-27 07:06:52 -0700608 if (!encoded_frame_event_.Wait(timeout_ms))
609 return false;
perkj26091b12016-09-01 01:17:40 -0700610 {
611 rtc::CritScope lock(&crit_);
sprangb1ca0732017-02-01 08:38:12 -0800612 timestamp = last_timestamp_;
perkj26091b12016-09-01 01:17:40 -0700613 }
614 test_encoder_->CheckLastTimeStampsMatch(expected_ntp_time, timestamp);
sprang4847ae62017-06-27 07:06:52 -0700615 return true;
perkj26091b12016-09-01 01:17:40 -0700616 }
617
sprangb1ca0732017-02-01 08:38:12 -0800618 void WaitForEncodedFrame(uint32_t expected_width,
619 uint32_t expected_height) {
sprangc5d62e22017-04-02 23:53:04 -0700620 EXPECT_TRUE(encoded_frame_event_.Wait(kDefaultTimeoutMs));
Åsa Perssonc74d8da2017-12-04 14:13:56 +0100621 CheckLastFrameSizeMatches(expected_width, expected_height);
sprangc5d62e22017-04-02 23:53:04 -0700622 }
623
Åsa Perssonc74d8da2017-12-04 14:13:56 +0100624 void CheckLastFrameSizeMatches(uint32_t expected_width,
sprangc5d62e22017-04-02 23:53:04 -0700625 uint32_t expected_height) {
sprangb1ca0732017-02-01 08:38:12 -0800626 uint32_t width = 0;
627 uint32_t height = 0;
sprangb1ca0732017-02-01 08:38:12 -0800628 {
629 rtc::CritScope lock(&crit_);
630 width = last_width_;
631 height = last_height_;
632 }
633 EXPECT_EQ(expected_height, height);
634 EXPECT_EQ(expected_width, width);
635 }
636
kthelgason2fc52542017-03-03 00:24:41 -0800637 void ExpectDroppedFrame() { EXPECT_FALSE(encoded_frame_event_.Wait(100)); }
kthelgason2bc68642017-02-07 07:02:22 -0800638
sprangc5d62e22017-04-02 23:53:04 -0700639 bool WaitForFrame(int64_t timeout_ms) {
640 return encoded_frame_event_.Wait(timeout_ms);
641 }
642
perkj26091b12016-09-01 01:17:40 -0700643 void SetExpectNoFrames() {
644 rtc::CritScope lock(&crit_);
645 expect_frames_ = false;
646 }
647
asaperssonfab67072017-04-04 05:51:49 -0700648 int number_of_reconfigurations() const {
Per512ecb32016-09-23 15:52:06 +0200649 rtc::CritScope lock(&crit_);
650 return number_of_reconfigurations_;
651 }
652
asaperssonfab67072017-04-04 05:51:49 -0700653 int last_min_transmit_bitrate() const {
Per512ecb32016-09-23 15:52:06 +0200654 rtc::CritScope lock(&crit_);
655 return min_transmit_bitrate_bps_;
656 }
657
perkj26091b12016-09-01 01:17:40 -0700658 private:
sergeyu2cb155a2016-11-04 11:39:29 -0700659 Result OnEncodedImage(
660 const EncodedImage& encoded_image,
661 const CodecSpecificInfo* codec_specific_info,
662 const RTPFragmentationHeader* fragmentation) override {
Per512ecb32016-09-23 15:52:06 +0200663 rtc::CritScope lock(&crit_);
664 EXPECT_TRUE(expect_frames_);
Niels Möller23775882018-08-16 10:24:12 +0200665 last_timestamp_ = encoded_image.Timestamp();
sprangb1ca0732017-02-01 08:38:12 -0800666 last_width_ = encoded_image._encodedWidth;
667 last_height_ = encoded_image._encodedHeight;
Per512ecb32016-09-23 15:52:06 +0200668 encoded_frame_event_.Set();
sprangb1ca0732017-02-01 08:38:12 -0800669 return Result(Result::OK, last_timestamp_);
Per512ecb32016-09-23 15:52:06 +0200670 }
671
672 void OnEncoderConfigurationChanged(std::vector<VideoStream> streams,
673 int min_transmit_bitrate_bps) override {
674 rtc::CriticalSection crit_;
675 ++number_of_reconfigurations_;
676 min_transmit_bitrate_bps_ = min_transmit_bitrate_bps;
677 }
678
perkj26091b12016-09-01 01:17:40 -0700679 rtc::CriticalSection crit_;
680 TestEncoder* test_encoder_;
681 rtc::Event encoded_frame_event_;
sprangb1ca0732017-02-01 08:38:12 -0800682 uint32_t last_timestamp_ = 0;
683 uint32_t last_height_ = 0;
684 uint32_t last_width_ = 0;
perkj26091b12016-09-01 01:17:40 -0700685 bool expect_frames_ = true;
Per512ecb32016-09-23 15:52:06 +0200686 int number_of_reconfigurations_ = 0;
687 int min_transmit_bitrate_bps_ = 0;
perkj26091b12016-09-01 01:17:40 -0700688 };
689
690 VideoSendStream::Config video_send_config_;
Erik Språng08127a92016-11-16 16:41:30 +0100691 VideoEncoderConfig video_encoder_config_;
Per512ecb32016-09-23 15:52:06 +0200692 int codec_width_;
693 int codec_height_;
sprang4847ae62017-06-27 07:06:52 -0700694 int max_framerate_;
perkj26091b12016-09-01 01:17:40 -0700695 TestEncoder fake_encoder_;
Niels Möllercbcbc222018-09-28 09:07:24 +0200696 test::VideoEncoderProxyFactory encoder_factory_;
sprangc5d62e22017-04-02 23:53:04 -0700697 std::unique_ptr<MockableSendStatisticsProxy> stats_proxy_;
perkj26091b12016-09-01 01:17:40 -0700698 TestSink sink_;
sprangb1ca0732017-02-01 08:38:12 -0800699 AdaptingFrameForwarder video_source_;
mflodmancc3d4422017-08-03 08:27:51 -0700700 std::unique_ptr<VideoStreamEncoderUnderTest> video_stream_encoder_;
sprang4847ae62017-06-27 07:06:52 -0700701 rtc::ScopedFakeClock fake_clock_;
perkj26091b12016-09-01 01:17:40 -0700702};
703
mflodmancc3d4422017-08-03 08:27:51 -0700704TEST_F(VideoStreamEncoderTest, EncodeOneFrame) {
705 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkj26091b12016-09-01 01:17:40 -0700706 rtc::Event frame_destroyed_event(false, false);
perkja49cbd32016-09-16 07:53:41 -0700707 video_source_.IncomingCapturedFrame(CreateFrame(1, &frame_destroyed_event));
sprang4847ae62017-06-27 07:06:52 -0700708 WaitForEncodedFrame(1);
perkja49cbd32016-09-16 07:53:41 -0700709 EXPECT_TRUE(frame_destroyed_event.Wait(kDefaultTimeoutMs));
mflodmancc3d4422017-08-03 08:27:51 -0700710 video_stream_encoder_->Stop();
perkj26091b12016-09-01 01:17:40 -0700711}
712
mflodmancc3d4422017-08-03 08:27:51 -0700713TEST_F(VideoStreamEncoderTest, DropsFramesBeforeFirstOnBitrateUpdated) {
perkj26091b12016-09-01 01:17:40 -0700714 // Dropped since no target bitrate has been set.
715 rtc::Event frame_destroyed_event(false, false);
Sebastian Janssona3177052018-04-10 13:05:49 +0200716 // The encoder will cache up to one frame for a short duration. Adding two
717 // frames means that the first frame will be dropped and the second frame will
718 // be sent when the encoder is enabled.
perkja49cbd32016-09-16 07:53:41 -0700719 video_source_.IncomingCapturedFrame(CreateFrame(1, &frame_destroyed_event));
Sebastian Janssona3177052018-04-10 13:05:49 +0200720 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
perkja49cbd32016-09-16 07:53:41 -0700721 EXPECT_TRUE(frame_destroyed_event.Wait(kDefaultTimeoutMs));
perkj26091b12016-09-01 01:17:40 -0700722
mflodmancc3d4422017-08-03 08:27:51 -0700723 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkj26091b12016-09-01 01:17:40 -0700724
Sebastian Janssona3177052018-04-10 13:05:49 +0200725 // The pending frame should be received.
sprang4847ae62017-06-27 07:06:52 -0700726 WaitForEncodedFrame(2);
Sebastian Janssona3177052018-04-10 13:05:49 +0200727 video_source_.IncomingCapturedFrame(CreateFrame(3, nullptr));
728
729 WaitForEncodedFrame(3);
mflodmancc3d4422017-08-03 08:27:51 -0700730 video_stream_encoder_->Stop();
perkj26091b12016-09-01 01:17:40 -0700731}
732
mflodmancc3d4422017-08-03 08:27:51 -0700733TEST_F(VideoStreamEncoderTest, DropsFramesWhenRateSetToZero) {
734 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkja49cbd32016-09-16 07:53:41 -0700735 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700736 WaitForEncodedFrame(1);
perkj26091b12016-09-01 01:17:40 -0700737
mflodmancc3d4422017-08-03 08:27:51 -0700738 video_stream_encoder_->OnBitrateUpdated(0, 0, 0);
Sebastian Janssona3177052018-04-10 13:05:49 +0200739 // The encoder will cache up to one frame for a short duration. Adding two
740 // frames means that the first frame will be dropped and the second frame will
741 // be sent when the encoder is resumed.
perkja49cbd32016-09-16 07:53:41 -0700742 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
Sebastian Janssona3177052018-04-10 13:05:49 +0200743 video_source_.IncomingCapturedFrame(CreateFrame(3, nullptr));
perkj26091b12016-09-01 01:17:40 -0700744
mflodmancc3d4422017-08-03 08:27:51 -0700745 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
sprang4847ae62017-06-27 07:06:52 -0700746 WaitForEncodedFrame(3);
Sebastian Janssona3177052018-04-10 13:05:49 +0200747 video_source_.IncomingCapturedFrame(CreateFrame(4, nullptr));
748 WaitForEncodedFrame(4);
mflodmancc3d4422017-08-03 08:27:51 -0700749 video_stream_encoder_->Stop();
perkj26091b12016-09-01 01:17:40 -0700750}
751
mflodmancc3d4422017-08-03 08:27:51 -0700752TEST_F(VideoStreamEncoderTest, DropsFramesWithSameOrOldNtpTimestamp) {
753 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
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
757 // This frame will be dropped since it has the same ntp timestamp.
perkja49cbd32016-09-16 07:53:41 -0700758 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
perkj26091b12016-09-01 01:17:40 -0700759
perkja49cbd32016-09-16 07:53:41 -0700760 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700761 WaitForEncodedFrame(2);
mflodmancc3d4422017-08-03 08:27:51 -0700762 video_stream_encoder_->Stop();
perkj26091b12016-09-01 01:17:40 -0700763}
764
mflodmancc3d4422017-08-03 08:27:51 -0700765TEST_F(VideoStreamEncoderTest, DropsFrameAfterStop) {
766 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkj26091b12016-09-01 01:17:40 -0700767
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
mflodmancc3d4422017-08-03 08:27:51 -0700771 video_stream_encoder_->Stop();
perkj26091b12016-09-01 01:17:40 -0700772 sink_.SetExpectNoFrames();
773 rtc::Event frame_destroyed_event(false, false);
perkja49cbd32016-09-16 07:53:41 -0700774 video_source_.IncomingCapturedFrame(CreateFrame(2, &frame_destroyed_event));
775 EXPECT_TRUE(frame_destroyed_event.Wait(kDefaultTimeoutMs));
perkj26091b12016-09-01 01:17:40 -0700776}
777
mflodmancc3d4422017-08-03 08:27:51 -0700778TEST_F(VideoStreamEncoderTest, DropsPendingFramesOnSlowEncode) {
779 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkj26091b12016-09-01 01:17:40 -0700780
781 fake_encoder_.BlockNextEncode();
perkja49cbd32016-09-16 07:53:41 -0700782 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700783 WaitForEncodedFrame(1);
perkj26091b12016-09-01 01:17:40 -0700784 // Here, the encoder thread will be blocked in the TestEncoder waiting for a
785 // call to ContinueEncode.
perkja49cbd32016-09-16 07:53:41 -0700786 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
787 video_source_.IncomingCapturedFrame(CreateFrame(3, nullptr));
perkj26091b12016-09-01 01:17:40 -0700788 fake_encoder_.ContinueEncode();
sprang4847ae62017-06-27 07:06:52 -0700789 WaitForEncodedFrame(3);
perkj26091b12016-09-01 01:17:40 -0700790
mflodmancc3d4422017-08-03 08:27:51 -0700791 video_stream_encoder_->Stop();
perkj26091b12016-09-01 01:17:40 -0700792}
793
mflodmancc3d4422017-08-03 08:27:51 -0700794TEST_F(VideoStreamEncoderTest,
795 ConfigureEncoderTriggersOnEncoderConfigurationChanged) {
796 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
Per21d45d22016-10-30 21:37:57 +0100797 EXPECT_EQ(0, sink_.number_of_reconfigurations());
Per512ecb32016-09-23 15:52:06 +0200798
799 // Capture a frame and wait for it to synchronize with the encoder thread.
Perf8c5f2b2016-09-23 16:24:55 +0200800 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700801 WaitForEncodedFrame(1);
Per21d45d22016-10-30 21:37:57 +0100802 // The encoder will have been configured once when the first frame is
803 // received.
804 EXPECT_EQ(1, sink_.number_of_reconfigurations());
Per512ecb32016-09-23 15:52:06 +0200805
806 VideoEncoderConfig video_encoder_config;
Niels Möller259a4972018-04-05 15:36:51 +0200807 test::FillEncoderConfiguration(kVideoCodecVP8, 1, &video_encoder_config);
Per512ecb32016-09-23 15:52:06 +0200808 video_encoder_config.min_transmit_bitrate_bps = 9999;
mflodmancc3d4422017-08-03 08:27:51 -0700809 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
Niels Möllerf1338562018-04-26 09:51:47 +0200810 kMaxPayloadLength);
Per512ecb32016-09-23 15:52:06 +0200811
812 // Capture a frame and wait for it to synchronize with the encoder thread.
Perf8c5f2b2016-09-23 16:24:55 +0200813 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700814 WaitForEncodedFrame(2);
Per21d45d22016-10-30 21:37:57 +0100815 EXPECT_EQ(2, sink_.number_of_reconfigurations());
perkj3b703ed2016-09-29 23:25:40 -0700816 EXPECT_EQ(9999, sink_.last_min_transmit_bitrate());
perkj26105b42016-09-29 22:39:10 -0700817
mflodmancc3d4422017-08-03 08:27:51 -0700818 video_stream_encoder_->Stop();
perkj26105b42016-09-29 22:39:10 -0700819}
820
mflodmancc3d4422017-08-03 08:27:51 -0700821TEST_F(VideoStreamEncoderTest, FrameResolutionChangeReconfigureEncoder) {
822 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkjfa10b552016-10-02 23:45:26 -0700823
824 // Capture a frame and wait for it to synchronize with the encoder thread.
825 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700826 WaitForEncodedFrame(1);
Per21d45d22016-10-30 21:37:57 +0100827 // The encoder will have been configured once.
828 EXPECT_EQ(1, sink_.number_of_reconfigurations());
perkjfa10b552016-10-02 23:45:26 -0700829 EXPECT_EQ(codec_width_, fake_encoder_.codec_config().width);
830 EXPECT_EQ(codec_height_, fake_encoder_.codec_config().height);
831
832 codec_width_ *= 2;
833 codec_height_ *= 2;
834 // Capture a frame with a higher resolution and wait for it to synchronize
835 // with the encoder thread.
836 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700837 WaitForEncodedFrame(2);
perkjfa10b552016-10-02 23:45:26 -0700838 EXPECT_EQ(codec_width_, fake_encoder_.codec_config().width);
839 EXPECT_EQ(codec_height_, fake_encoder_.codec_config().height);
Per21d45d22016-10-30 21:37:57 +0100840 EXPECT_EQ(2, sink_.number_of_reconfigurations());
perkjfa10b552016-10-02 23:45:26 -0700841
mflodmancc3d4422017-08-03 08:27:51 -0700842 video_stream_encoder_->Stop();
perkjfa10b552016-10-02 23:45:26 -0700843}
844
mflodmancc3d4422017-08-03 08:27:51 -0700845TEST_F(VideoStreamEncoderTest, SwitchSourceDeregisterEncoderAsSink) {
perkj803d97f2016-11-01 11:45:46 -0700846 EXPECT_TRUE(video_source_.has_sinks());
847 test::FrameForwarder new_video_source;
mflodmancc3d4422017-08-03 08:27:51 -0700848 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -0700849 &new_video_source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
perkj803d97f2016-11-01 11:45:46 -0700850 EXPECT_FALSE(video_source_.has_sinks());
851 EXPECT_TRUE(new_video_source.has_sinks());
852
mflodmancc3d4422017-08-03 08:27:51 -0700853 video_stream_encoder_->Stop();
perkj803d97f2016-11-01 11:45:46 -0700854}
855
mflodmancc3d4422017-08-03 08:27:51 -0700856TEST_F(VideoStreamEncoderTest, SinkWantsRotationApplied) {
perkj803d97f2016-11-01 11:45:46 -0700857 EXPECT_FALSE(video_source_.sink_wants().rotation_applied);
mflodmancc3d4422017-08-03 08:27:51 -0700858 video_stream_encoder_->SetSink(&sink_, true /*rotation_applied*/);
perkj803d97f2016-11-01 11:45:46 -0700859 EXPECT_TRUE(video_source_.sink_wants().rotation_applied);
mflodmancc3d4422017-08-03 08:27:51 -0700860 video_stream_encoder_->Stop();
perkj803d97f2016-11-01 11:45:46 -0700861}
862
Jonathan Yubc771b72017-12-08 17:04:29 -0800863TEST_F(VideoStreamEncoderTest, TestCpuDowngrades_BalancedMode) {
864 const int kFramerateFps = 30;
asaperssonf7e294d2017-06-13 23:25:22 -0700865 const int kWidth = 1280;
866 const int kHeight = 720;
Jonathan Yubc771b72017-12-08 17:04:29 -0800867
868 // We rely on the automatic resolution adaptation, but we handle framerate
869 // adaptation manually by mocking the stats proxy.
870 video_source_.set_adaptation_enabled(true);
asaperssonf7e294d2017-06-13 23:25:22 -0700871
Taylor Brandstetter49fcc102018-05-16 14:20:41 -0700872 // Enable BALANCED preference, no initial limitation.
Jonathan Yubc771b72017-12-08 17:04:29 -0800873 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
Taylor Brandstetter49fcc102018-05-16 14:20:41 -0700874 video_stream_encoder_->SetSource(&video_source_,
875 webrtc::DegradationPreference::BALANCED);
Jonathan Yubc771b72017-12-08 17:04:29 -0800876 VerifyNoLimitation(video_source_.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -0700877 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
Jonathan Yubc771b72017-12-08 17:04:29 -0800878 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
asaperssonf7e294d2017-06-13 23:25:22 -0700879 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
880
Jonathan Yubc771b72017-12-08 17:04:29 -0800881 // Adapt down as far as possible.
882 rtc::VideoSinkWants last_wants;
883 int64_t t = 1;
884 int loop_count = 0;
885 do {
886 ++loop_count;
887 last_wants = video_source_.sink_wants();
888
889 // Simulate the framerate we've been asked to adapt to.
890 const int fps = std::min(kFramerateFps, last_wants.max_framerate_fps);
891 const int frame_interval_ms = rtc::kNumMillisecsPerSec / fps;
892 VideoSendStream::Stats mock_stats = stats_proxy_->GetStats();
893 mock_stats.input_frame_rate = fps;
894 stats_proxy_->SetMockStats(mock_stats);
895
896 video_source_.IncomingCapturedFrame(CreateFrame(t, kWidth, kHeight));
897 sink_.WaitForEncodedFrame(t);
898 t += frame_interval_ms;
899
mflodmancc3d4422017-08-03 08:27:51 -0700900 video_stream_encoder_->TriggerCpuOveruse();
Jonathan Yubc771b72017-12-08 17:04:29 -0800901 VerifyBalancedModeFpsRange(
902 video_source_.sink_wants(),
903 *video_source_.last_sent_width() * *video_source_.last_sent_height());
904 } while (video_source_.sink_wants().max_pixel_count <
905 last_wants.max_pixel_count ||
906 video_source_.sink_wants().max_framerate_fps <
907 last_wants.max_framerate_fps);
asaperssonf7e294d2017-06-13 23:25:22 -0700908
Jonathan Yubc771b72017-12-08 17:04:29 -0800909 // Verify that we've adapted all the way down.
910 stats_proxy_->ResetMockStats();
asaperssonf7e294d2017-06-13 23:25:22 -0700911 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
Jonathan Yubc771b72017-12-08 17:04:29 -0800912 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_framerate);
913 EXPECT_EQ(loop_count - 1,
asaperssonf7e294d2017-06-13 23:25:22 -0700914 stats_proxy_->GetStats().number_of_cpu_adapt_changes);
Jonathan Yubc771b72017-12-08 17:04:29 -0800915 EXPECT_EQ(kMinPixelsPerFrame, *video_source_.last_sent_width() *
916 *video_source_.last_sent_height());
917 EXPECT_EQ(kMinBalancedFramerateFps,
918 video_source_.sink_wants().max_framerate_fps);
asaperssonf7e294d2017-06-13 23:25:22 -0700919
Jonathan Yubc771b72017-12-08 17:04:29 -0800920 // Adapt back up the same number of times we adapted down.
921 for (int i = 0; i < loop_count - 1; ++i) {
922 last_wants = video_source_.sink_wants();
923
924 // Simulate the framerate we've been asked to adapt to.
925 const int fps = std::min(kFramerateFps, last_wants.max_framerate_fps);
926 const int frame_interval_ms = rtc::kNumMillisecsPerSec / fps;
927 VideoSendStream::Stats mock_stats = stats_proxy_->GetStats();
928 mock_stats.input_frame_rate = fps;
929 stats_proxy_->SetMockStats(mock_stats);
930
931 video_source_.IncomingCapturedFrame(CreateFrame(t, kWidth, kHeight));
932 sink_.WaitForEncodedFrame(t);
933 t += frame_interval_ms;
934
mflodmancc3d4422017-08-03 08:27:51 -0700935 video_stream_encoder_->TriggerCpuNormalUsage();
Jonathan Yubc771b72017-12-08 17:04:29 -0800936 VerifyBalancedModeFpsRange(
937 video_source_.sink_wants(),
938 *video_source_.last_sent_width() * *video_source_.last_sent_height());
939 EXPECT_TRUE(video_source_.sink_wants().max_pixel_count >
940 last_wants.max_pixel_count ||
941 video_source_.sink_wants().max_framerate_fps >
942 last_wants.max_framerate_fps);
asaperssonf7e294d2017-06-13 23:25:22 -0700943 }
944
Åsa Persson8c1bf952018-09-13 10:42:19 +0200945 VerifyFpsMaxResolutionMax(video_source_.sink_wants());
Jonathan Yubc771b72017-12-08 17:04:29 -0800946 stats_proxy_->ResetMockStats();
asaperssonf7e294d2017-06-13 23:25:22 -0700947 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
Jonathan Yubc771b72017-12-08 17:04:29 -0800948 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
949 EXPECT_EQ((loop_count - 1) * 2,
950 stats_proxy_->GetStats().number_of_cpu_adapt_changes);
asaperssonf7e294d2017-06-13 23:25:22 -0700951
mflodmancc3d4422017-08-03 08:27:51 -0700952 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -0700953}
mflodmancc3d4422017-08-03 08:27:51 -0700954TEST_F(VideoStreamEncoderTest, SinkWantsStoredByDegradationPreference) {
955 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson02465b82017-04-10 01:12:52 -0700956 VerifyNoLimitation(video_source_.sink_wants());
perkj803d97f2016-11-01 11:45:46 -0700957
sprangc5d62e22017-04-02 23:53:04 -0700958 const int kFrameWidth = 1280;
959 const int kFrameHeight = 720;
sprangc5d62e22017-04-02 23:53:04 -0700960
Åsa Persson8c1bf952018-09-13 10:42:19 +0200961 int64_t frame_timestamp = 1;
perkj803d97f2016-11-01 11:45:46 -0700962
kthelgason5e13d412016-12-01 03:59:51 -0800963 video_source_.IncomingCapturedFrame(
sprangc5d62e22017-04-02 23:53:04 -0700964 CreateFrame(frame_timestamp, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -0700965 WaitForEncodedFrame(frame_timestamp);
sprangc5d62e22017-04-02 23:53:04 -0700966 frame_timestamp += kFrameIntervalMs;
967
perkj803d97f2016-11-01 11:45:46 -0700968 // Trigger CPU overuse.
mflodmancc3d4422017-08-03 08:27:51 -0700969 video_stream_encoder_->TriggerCpuOveruse();
perkj803d97f2016-11-01 11:45:46 -0700970 video_source_.IncomingCapturedFrame(
sprangc5d62e22017-04-02 23:53:04 -0700971 CreateFrame(frame_timestamp, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -0700972 WaitForEncodedFrame(frame_timestamp);
sprangc5d62e22017-04-02 23:53:04 -0700973 frame_timestamp += kFrameIntervalMs;
sprang3ea3c772017-03-30 07:23:48 -0700974
asapersson0944a802017-04-07 00:57:58 -0700975 // Default degradation preference is maintain-framerate, so will lower max
sprangc5d62e22017-04-02 23:53:04 -0700976 // wanted resolution.
977 EXPECT_FALSE(video_source_.sink_wants().target_pixel_count);
978 EXPECT_LT(video_source_.sink_wants().max_pixel_count,
979 kFrameWidth * kFrameHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +0200980 EXPECT_EQ(kDefaultFramerate, video_source_.sink_wants().max_framerate_fps);
sprangc5d62e22017-04-02 23:53:04 -0700981
982 // Set new source, switch to maintain-resolution.
perkj803d97f2016-11-01 11:45:46 -0700983 test::FrameForwarder new_video_source;
mflodmancc3d4422017-08-03 08:27:51 -0700984 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -0700985 &new_video_source, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
perkj803d97f2016-11-01 11:45:46 -0700986
sprangc5d62e22017-04-02 23:53:04 -0700987 // Initially no degradation registered.
Åsa Persson8c1bf952018-09-13 10:42:19 +0200988 VerifyFpsMaxResolutionMax(new_video_source.sink_wants());
perkj803d97f2016-11-01 11:45:46 -0700989
sprangc5d62e22017-04-02 23:53:04 -0700990 // Force an input frame rate to be available, or the adaptation call won't
991 // know what framerate to adapt form.
asapersson02465b82017-04-10 01:12:52 -0700992 const int kInputFps = 30;
sprangc5d62e22017-04-02 23:53:04 -0700993 VideoSendStream::Stats stats = stats_proxy_->GetStats();
asapersson02465b82017-04-10 01:12:52 -0700994 stats.input_frame_rate = kInputFps;
sprangc5d62e22017-04-02 23:53:04 -0700995 stats_proxy_->SetMockStats(stats);
996
mflodmancc3d4422017-08-03 08:27:51 -0700997 video_stream_encoder_->TriggerCpuOveruse();
perkj803d97f2016-11-01 11:45:46 -0700998 new_video_source.IncomingCapturedFrame(
sprangc5d62e22017-04-02 23:53:04 -0700999 CreateFrame(frame_timestamp, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07001000 WaitForEncodedFrame(frame_timestamp);
sprangc5d62e22017-04-02 23:53:04 -07001001 frame_timestamp += kFrameIntervalMs;
1002
1003 // Some framerate constraint should be set.
sprang84a37592017-02-10 07:04:27 -08001004 EXPECT_FALSE(new_video_source.sink_wants().target_pixel_count);
sprangc5d62e22017-04-02 23:53:04 -07001005 EXPECT_EQ(std::numeric_limits<int>::max(),
1006 new_video_source.sink_wants().max_pixel_count);
asapersson02465b82017-04-10 01:12:52 -07001007 EXPECT_LT(new_video_source.sink_wants().max_framerate_fps, kInputFps);
sprangc5d62e22017-04-02 23:53:04 -07001008
asapersson02465b82017-04-10 01:12:52 -07001009 // Turn off degradation completely.
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001010 video_stream_encoder_->SetSource(&new_video_source,
1011 webrtc::DegradationPreference::DISABLED);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001012 VerifyFpsMaxResolutionMax(new_video_source.sink_wants());
sprangc5d62e22017-04-02 23:53:04 -07001013
mflodmancc3d4422017-08-03 08:27:51 -07001014 video_stream_encoder_->TriggerCpuOveruse();
sprangc5d62e22017-04-02 23:53:04 -07001015 new_video_source.IncomingCapturedFrame(
1016 CreateFrame(frame_timestamp, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07001017 WaitForEncodedFrame(frame_timestamp);
sprangc5d62e22017-04-02 23:53:04 -07001018 frame_timestamp += kFrameIntervalMs;
1019
1020 // Still no degradation.
Åsa Persson8c1bf952018-09-13 10:42:19 +02001021 VerifyFpsMaxResolutionMax(new_video_source.sink_wants());
perkj803d97f2016-11-01 11:45:46 -07001022
1023 // Calling SetSource with resolution scaling enabled apply the old SinkWants.
mflodmancc3d4422017-08-03 08:27:51 -07001024 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001025 &new_video_source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
sprangc5d62e22017-04-02 23:53:04 -07001026 EXPECT_LT(new_video_source.sink_wants().max_pixel_count,
1027 kFrameWidth * kFrameHeight);
sprang84a37592017-02-10 07:04:27 -08001028 EXPECT_FALSE(new_video_source.sink_wants().target_pixel_count);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001029 EXPECT_EQ(kDefaultFramerate, new_video_source.sink_wants().max_framerate_fps);
sprangc5d62e22017-04-02 23:53:04 -07001030
1031 // Calling SetSource with framerate scaling enabled apply the old SinkWants.
mflodmancc3d4422017-08-03 08:27:51 -07001032 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001033 &new_video_source, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
sprangc5d62e22017-04-02 23:53:04 -07001034 EXPECT_FALSE(new_video_source.sink_wants().target_pixel_count);
1035 EXPECT_EQ(std::numeric_limits<int>::max(),
1036 new_video_source.sink_wants().max_pixel_count);
asapersson02465b82017-04-10 01:12:52 -07001037 EXPECT_LT(new_video_source.sink_wants().max_framerate_fps, kInputFps);
perkj803d97f2016-11-01 11:45:46 -07001038
mflodmancc3d4422017-08-03 08:27:51 -07001039 video_stream_encoder_->Stop();
perkj803d97f2016-11-01 11:45:46 -07001040}
1041
mflodmancc3d4422017-08-03 08:27:51 -07001042TEST_F(VideoStreamEncoderTest, StatsTracksQualityAdaptationStats) {
1043 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkj803d97f2016-11-01 11:45:46 -07001044
asaperssonfab67072017-04-04 05:51:49 -07001045 const int kWidth = 1280;
1046 const int kHeight = 720;
asaperssonfab67072017-04-04 05:51:49 -07001047 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001048 WaitForEncodedFrame(1);
asaperssonfab67072017-04-04 05:51:49 -07001049 VideoSendStream::Stats stats = stats_proxy_->GetStats();
1050 EXPECT_FALSE(stats.bw_limited_resolution);
1051 EXPECT_EQ(0, stats.number_of_quality_adapt_changes);
1052
1053 // Trigger adapt down.
mflodmancc3d4422017-08-03 08:27:51 -07001054 video_stream_encoder_->TriggerQualityLow();
asaperssonfab67072017-04-04 05:51:49 -07001055 video_source_.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001056 WaitForEncodedFrame(2);
asaperssonfab67072017-04-04 05:51:49 -07001057
1058 stats = stats_proxy_->GetStats();
1059 EXPECT_TRUE(stats.bw_limited_resolution);
1060 EXPECT_EQ(1, stats.number_of_quality_adapt_changes);
1061
1062 // Trigger adapt up.
mflodmancc3d4422017-08-03 08:27:51 -07001063 video_stream_encoder_->TriggerQualityHigh();
asaperssonfab67072017-04-04 05:51:49 -07001064 video_source_.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001065 WaitForEncodedFrame(3);
asaperssonfab67072017-04-04 05:51:49 -07001066
1067 stats = stats_proxy_->GetStats();
1068 EXPECT_FALSE(stats.bw_limited_resolution);
1069 EXPECT_EQ(2, stats.number_of_quality_adapt_changes);
1070 EXPECT_EQ(0, stats.number_of_cpu_adapt_changes);
1071
mflodmancc3d4422017-08-03 08:27:51 -07001072 video_stream_encoder_->Stop();
asaperssonfab67072017-04-04 05:51:49 -07001073}
1074
mflodmancc3d4422017-08-03 08:27:51 -07001075TEST_F(VideoStreamEncoderTest, StatsTracksCpuAdaptationStats) {
1076 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonfab67072017-04-04 05:51:49 -07001077
1078 const int kWidth = 1280;
1079 const int kHeight = 720;
asaperssonfab67072017-04-04 05:51:49 -07001080 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001081 WaitForEncodedFrame(1);
perkj803d97f2016-11-01 11:45:46 -07001082 VideoSendStream::Stats stats = stats_proxy_->GetStats();
1083 EXPECT_FALSE(stats.cpu_limited_resolution);
1084 EXPECT_EQ(0, stats.number_of_cpu_adapt_changes);
1085
1086 // Trigger CPU overuse.
mflodmancc3d4422017-08-03 08:27:51 -07001087 video_stream_encoder_->TriggerCpuOveruse();
asaperssonfab67072017-04-04 05:51:49 -07001088 video_source_.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001089 WaitForEncodedFrame(2);
perkj803d97f2016-11-01 11:45:46 -07001090
1091 stats = stats_proxy_->GetStats();
1092 EXPECT_TRUE(stats.cpu_limited_resolution);
1093 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1094
1095 // Trigger CPU normal use.
mflodmancc3d4422017-08-03 08:27:51 -07001096 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssonfab67072017-04-04 05:51:49 -07001097 video_source_.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001098 WaitForEncodedFrame(3);
perkj803d97f2016-11-01 11:45:46 -07001099
1100 stats = stats_proxy_->GetStats();
1101 EXPECT_FALSE(stats.cpu_limited_resolution);
1102 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
asaperssonfab67072017-04-04 05:51:49 -07001103 EXPECT_EQ(0, stats.number_of_quality_adapt_changes);
perkj803d97f2016-11-01 11:45:46 -07001104
mflodmancc3d4422017-08-03 08:27:51 -07001105 video_stream_encoder_->Stop();
perkj803d97f2016-11-01 11:45:46 -07001106}
1107
mflodmancc3d4422017-08-03 08:27:51 -07001108TEST_F(VideoStreamEncoderTest, SwitchingSourceKeepsCpuAdaptation) {
1109 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
kthelgason876222f2016-11-29 01:44:11 -08001110
asaperssonfab67072017-04-04 05:51:49 -07001111 const int kWidth = 1280;
1112 const int kHeight = 720;
1113 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001114 WaitForEncodedFrame(1);
kthelgason876222f2016-11-29 01:44:11 -08001115 VideoSendStream::Stats stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001116 EXPECT_FALSE(stats.bw_limited_resolution);
kthelgason876222f2016-11-29 01:44:11 -08001117 EXPECT_FALSE(stats.cpu_limited_resolution);
1118 EXPECT_EQ(0, stats.number_of_cpu_adapt_changes);
1119
asaperssonfab67072017-04-04 05:51:49 -07001120 // Trigger CPU overuse.
mflodmancc3d4422017-08-03 08:27:51 -07001121 video_stream_encoder_->TriggerCpuOveruse();
asaperssonfab67072017-04-04 05:51:49 -07001122 video_source_.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001123 WaitForEncodedFrame(2);
kthelgason876222f2016-11-29 01:44:11 -08001124 stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001125 EXPECT_FALSE(stats.bw_limited_resolution);
kthelgason876222f2016-11-29 01:44:11 -08001126 EXPECT_TRUE(stats.cpu_limited_resolution);
1127 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1128
1129 // Set new source with adaptation still enabled.
1130 test::FrameForwarder new_video_source;
mflodmancc3d4422017-08-03 08:27:51 -07001131 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001132 &new_video_source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
kthelgason876222f2016-11-29 01:44:11 -08001133
asaperssonfab67072017-04-04 05:51:49 -07001134 new_video_source.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001135 WaitForEncodedFrame(3);
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_TRUE(stats.cpu_limited_resolution);
1139 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1140
1141 // Set adaptation disabled.
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001142 video_stream_encoder_->SetSource(&new_video_source,
1143 webrtc::DegradationPreference::DISABLED);
kthelgason876222f2016-11-29 01:44:11 -08001144
asaperssonfab67072017-04-04 05:51:49 -07001145 new_video_source.IncomingCapturedFrame(CreateFrame(4, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001146 WaitForEncodedFrame(4);
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_FALSE(stats.cpu_limited_resolution);
1150 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1151
1152 // Set adaptation back to enabled.
mflodmancc3d4422017-08-03 08:27:51 -07001153 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001154 &new_video_source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
kthelgason876222f2016-11-29 01:44:11 -08001155
asaperssonfab67072017-04-04 05:51:49 -07001156 new_video_source.IncomingCapturedFrame(CreateFrame(5, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001157 WaitForEncodedFrame(5);
kthelgason876222f2016-11-29 01:44:11 -08001158 stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001159 EXPECT_FALSE(stats.bw_limited_resolution);
kthelgason876222f2016-11-29 01:44:11 -08001160 EXPECT_TRUE(stats.cpu_limited_resolution);
1161 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1162
asaperssonfab67072017-04-04 05:51:49 -07001163 // Trigger CPU normal use.
mflodmancc3d4422017-08-03 08:27:51 -07001164 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssonfab67072017-04-04 05:51:49 -07001165 new_video_source.IncomingCapturedFrame(CreateFrame(6, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001166 WaitForEncodedFrame(6);
kthelgason876222f2016-11-29 01:44:11 -08001167 stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001168 EXPECT_FALSE(stats.bw_limited_resolution);
kthelgason876222f2016-11-29 01:44:11 -08001169 EXPECT_FALSE(stats.cpu_limited_resolution);
1170 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
asapersson02465b82017-04-10 01:12:52 -07001171 EXPECT_EQ(0, stats.number_of_quality_adapt_changes);
kthelgason876222f2016-11-29 01:44:11 -08001172
mflodmancc3d4422017-08-03 08:27:51 -07001173 video_stream_encoder_->Stop();
kthelgason876222f2016-11-29 01:44:11 -08001174}
1175
mflodmancc3d4422017-08-03 08:27:51 -07001176TEST_F(VideoStreamEncoderTest, SwitchingSourceKeepsQualityAdaptation) {
1177 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
kthelgason876222f2016-11-29 01:44:11 -08001178
asaperssonfab67072017-04-04 05:51:49 -07001179 const int kWidth = 1280;
1180 const int kHeight = 720;
1181 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001182 WaitForEncodedFrame(1);
kthelgason876222f2016-11-29 01:44:11 -08001183 VideoSendStream::Stats stats = stats_proxy_->GetStats();
kthelgason876222f2016-11-29 01:44:11 -08001184 EXPECT_FALSE(stats.bw_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001185 EXPECT_FALSE(stats.bw_limited_framerate);
asaperssonfab67072017-04-04 05:51:49 -07001186 EXPECT_EQ(0, stats.number_of_quality_adapt_changes);
kthelgason876222f2016-11-29 01:44:11 -08001187
1188 // Set new source with adaptation still enabled.
1189 test::FrameForwarder new_video_source;
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001190 video_stream_encoder_->SetSource(&new_video_source,
1191 webrtc::DegradationPreference::BALANCED);
kthelgason876222f2016-11-29 01:44:11 -08001192
asaperssonfab67072017-04-04 05:51:49 -07001193 new_video_source.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001194 WaitForEncodedFrame(2);
kthelgason876222f2016-11-29 01:44:11 -08001195 stats = stats_proxy_->GetStats();
kthelgason876222f2016-11-29 01:44:11 -08001196 EXPECT_FALSE(stats.bw_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001197 EXPECT_FALSE(stats.bw_limited_framerate);
asaperssonfab67072017-04-04 05:51:49 -07001198 EXPECT_EQ(0, stats.number_of_quality_adapt_changes);
kthelgason876222f2016-11-29 01:44:11 -08001199
asaperssonfab67072017-04-04 05:51:49 -07001200 // Trigger adapt down.
mflodmancc3d4422017-08-03 08:27:51 -07001201 video_stream_encoder_->TriggerQualityLow();
asaperssonfab67072017-04-04 05:51:49 -07001202 new_video_source.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001203 WaitForEncodedFrame(3);
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
asaperssonfab67072017-04-04 05:51:49 -07001209 // Set new source with adaptation still enabled.
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001210 video_stream_encoder_->SetSource(&new_video_source,
1211 webrtc::DegradationPreference::BALANCED);
kthelgason876222f2016-11-29 01:44:11 -08001212
asaperssonfab67072017-04-04 05:51:49 -07001213 new_video_source.IncomingCapturedFrame(CreateFrame(4, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001214 WaitForEncodedFrame(4);
kthelgason876222f2016-11-29 01:44:11 -08001215 stats = stats_proxy_->GetStats();
kthelgason876222f2016-11-29 01:44:11 -08001216 EXPECT_TRUE(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);
kthelgason876222f2016-11-29 01:44:11 -08001219
asapersson02465b82017-04-10 01:12:52 -07001220 // Disable resolution scaling.
mflodmancc3d4422017-08-03 08:27:51 -07001221 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001222 &new_video_source, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
kthelgason876222f2016-11-29 01:44:11 -08001223
asaperssonfab67072017-04-04 05:51:49 -07001224 new_video_source.IncomingCapturedFrame(CreateFrame(5, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001225 WaitForEncodedFrame(5);
kthelgason876222f2016-11-29 01:44:11 -08001226 stats = stats_proxy_->GetStats();
kthelgason876222f2016-11-29 01:44:11 -08001227 EXPECT_FALSE(stats.bw_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001228 EXPECT_FALSE(stats.bw_limited_framerate);
asaperssonfab67072017-04-04 05:51:49 -07001229 EXPECT_EQ(1, stats.number_of_quality_adapt_changes);
1230 EXPECT_EQ(0, stats.number_of_cpu_adapt_changes);
kthelgason876222f2016-11-29 01:44:11 -08001231
mflodmancc3d4422017-08-03 08:27:51 -07001232 video_stream_encoder_->Stop();
kthelgason876222f2016-11-29 01:44:11 -08001233}
1234
mflodmancc3d4422017-08-03 08:27:51 -07001235TEST_F(VideoStreamEncoderTest,
1236 QualityAdaptationStatsAreResetWhenScalerIsDisabled) {
1237 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson36e9eb42017-03-31 05:29:12 -07001238
1239 const int kWidth = 1280;
1240 const int kHeight = 720;
Åsa Persson8c1bf952018-09-13 10:42:19 +02001241 int64_t timestamp_ms = kFrameIntervalMs;
asapersson36e9eb42017-03-31 05:29:12 -07001242 video_source_.set_adaptation_enabled(true);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001243 video_source_.IncomingCapturedFrame(
1244 CreateFrame(timestamp_ms, kWidth, kHeight));
1245 WaitForEncodedFrame(timestamp_ms);
asapersson36e9eb42017-03-31 05:29:12 -07001246 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1247 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1248 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1249
1250 // Trigger adapt down.
mflodmancc3d4422017-08-03 08:27:51 -07001251 video_stream_encoder_->TriggerQualityLow();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001252 timestamp_ms += kFrameIntervalMs;
1253 video_source_.IncomingCapturedFrame(
1254 CreateFrame(timestamp_ms, kWidth, kHeight));
1255 WaitForEncodedFrame(timestamp_ms);
asapersson36e9eb42017-03-31 05:29:12 -07001256 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1257 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1258 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1259
1260 // Trigger overuse.
mflodmancc3d4422017-08-03 08:27:51 -07001261 video_stream_encoder_->TriggerCpuOveruse();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001262 timestamp_ms += kFrameIntervalMs;
1263 video_source_.IncomingCapturedFrame(
1264 CreateFrame(timestamp_ms, kWidth, kHeight));
1265 WaitForEncodedFrame(timestamp_ms);
asapersson36e9eb42017-03-31 05:29:12 -07001266 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1267 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1268 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1269
Niels Möller4db138e2018-04-19 09:04:13 +02001270 // Leave source unchanged, but disable quality scaler.
asapersson36e9eb42017-03-31 05:29:12 -07001271 fake_encoder_.SetQualityScaling(false);
Niels Möller4db138e2018-04-19 09:04:13 +02001272
1273 VideoEncoderConfig video_encoder_config;
1274 test::FillEncoderConfiguration(kVideoCodecVP8, 1, &video_encoder_config);
1275 // Make format different, to force recreation of encoder.
1276 video_encoder_config.video_format.parameters["foo"] = "foo";
1277 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
Niels Möllerf1338562018-04-26 09:51:47 +02001278 kMaxPayloadLength);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001279 timestamp_ms += kFrameIntervalMs;
1280 video_source_.IncomingCapturedFrame(
1281 CreateFrame(timestamp_ms, kWidth, kHeight));
1282 WaitForEncodedFrame(timestamp_ms);
asapersson36e9eb42017-03-31 05:29:12 -07001283 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1284 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1285 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1286
mflodmancc3d4422017-08-03 08:27:51 -07001287 video_stream_encoder_->Stop();
asapersson36e9eb42017-03-31 05:29:12 -07001288}
1289
mflodmancc3d4422017-08-03 08:27:51 -07001290TEST_F(VideoStreamEncoderTest,
1291 StatsTracksCpuAdaptationStatsWhenSwitchingSource) {
1292 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkj803d97f2016-11-01 11:45:46 -07001293
asapersson0944a802017-04-07 00:57:58 -07001294 const int kWidth = 1280;
1295 const int kHeight = 720;
sprang84a37592017-02-10 07:04:27 -08001296 int sequence = 1;
perkj803d97f2016-11-01 11:45:46 -07001297
asaperssonfab67072017-04-04 05:51:49 -07001298 video_source_.IncomingCapturedFrame(CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001299 WaitForEncodedFrame(sequence++);
perkj803d97f2016-11-01 11:45:46 -07001300 VideoSendStream::Stats stats = stats_proxy_->GetStats();
sprang84a37592017-02-10 07:04:27 -08001301 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001302 EXPECT_FALSE(stats.cpu_limited_framerate);
sprang84a37592017-02-10 07:04:27 -08001303 EXPECT_EQ(0, stats.number_of_cpu_adapt_changes);
1304
asapersson02465b82017-04-10 01:12:52 -07001305 // Trigger CPU overuse, should now adapt down.
mflodmancc3d4422017-08-03 08:27:51 -07001306 video_stream_encoder_->TriggerCpuOveruse();
asaperssonfab67072017-04-04 05:51:49 -07001307 video_source_.IncomingCapturedFrame(CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001308 WaitForEncodedFrame(sequence++);
sprang84a37592017-02-10 07:04:27 -08001309 stats = stats_proxy_->GetStats();
perkj803d97f2016-11-01 11:45:46 -07001310 EXPECT_TRUE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001311 EXPECT_FALSE(stats.cpu_limited_framerate);
perkj803d97f2016-11-01 11:45:46 -07001312 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1313
1314 // Set new source with adaptation still enabled.
1315 test::FrameForwarder new_video_source;
mflodmancc3d4422017-08-03 08:27:51 -07001316 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001317 &new_video_source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
perkj803d97f2016-11-01 11:45:46 -07001318
1319 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001320 CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001321 WaitForEncodedFrame(sequence++);
perkj803d97f2016-11-01 11:45:46 -07001322 stats = stats_proxy_->GetStats();
1323 EXPECT_TRUE(stats.cpu_limited_resolution);
asapersson09f05612017-05-15 23:40:18 -07001324 EXPECT_FALSE(stats.cpu_limited_framerate);
perkj803d97f2016-11-01 11:45:46 -07001325 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1326
sprangc5d62e22017-04-02 23:53:04 -07001327 // Set cpu adaptation by frame dropping.
mflodmancc3d4422017-08-03 08:27:51 -07001328 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001329 &new_video_source, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
perkj803d97f2016-11-01 11:45:46 -07001330 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001331 CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001332 WaitForEncodedFrame(sequence++);
perkj803d97f2016-11-01 11:45:46 -07001333 stats = stats_proxy_->GetStats();
sprangc5d62e22017-04-02 23:53:04 -07001334 // Not adapted at first.
perkj803d97f2016-11-01 11:45:46 -07001335 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson09f05612017-05-15 23:40:18 -07001336 EXPECT_FALSE(stats.cpu_limited_framerate);
perkj803d97f2016-11-01 11:45:46 -07001337 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1338
sprangc5d62e22017-04-02 23:53:04 -07001339 // Force an input frame rate to be available, or the adaptation call won't
asapersson09f05612017-05-15 23:40:18 -07001340 // know what framerate to adapt from.
sprangc5d62e22017-04-02 23:53:04 -07001341 VideoSendStream::Stats mock_stats = stats_proxy_->GetStats();
1342 mock_stats.input_frame_rate = 30;
1343 stats_proxy_->SetMockStats(mock_stats);
mflodmancc3d4422017-08-03 08:27:51 -07001344 video_stream_encoder_->TriggerCpuOveruse();
sprangc5d62e22017-04-02 23:53:04 -07001345 stats_proxy_->ResetMockStats();
1346
1347 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001348 CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001349 WaitForEncodedFrame(sequence++);
sprangc5d62e22017-04-02 23:53:04 -07001350
1351 // Framerate now adapted.
1352 stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001353 EXPECT_FALSE(stats.cpu_limited_resolution);
1354 EXPECT_TRUE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001355 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
1356
1357 // Disable CPU adaptation.
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001358 video_stream_encoder_->SetSource(&new_video_source,
1359 webrtc::DegradationPreference::DISABLED);
sprangc5d62e22017-04-02 23:53:04 -07001360 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001361 CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001362 WaitForEncodedFrame(sequence++);
sprangc5d62e22017-04-02 23:53:04 -07001363
1364 stats = stats_proxy_->GetStats();
1365 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001366 EXPECT_FALSE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001367 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
1368
1369 // Try to trigger overuse. Should not succeed.
1370 stats_proxy_->SetMockStats(mock_stats);
mflodmancc3d4422017-08-03 08:27:51 -07001371 video_stream_encoder_->TriggerCpuOveruse();
sprangc5d62e22017-04-02 23:53:04 -07001372 stats_proxy_->ResetMockStats();
1373
1374 stats = stats_proxy_->GetStats();
1375 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001376 EXPECT_FALSE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001377 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
1378
1379 // Switch back the source with resolution adaptation enabled.
mflodmancc3d4422017-08-03 08:27:51 -07001380 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001381 &video_source_, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
asaperssonfab67072017-04-04 05:51:49 -07001382 video_source_.IncomingCapturedFrame(CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001383 WaitForEncodedFrame(sequence++);
perkj803d97f2016-11-01 11:45:46 -07001384 stats = stats_proxy_->GetStats();
1385 EXPECT_TRUE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001386 EXPECT_FALSE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001387 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
perkj803d97f2016-11-01 11:45:46 -07001388
1389 // Trigger CPU normal usage.
mflodmancc3d4422017-08-03 08:27:51 -07001390 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssonfab67072017-04-04 05:51:49 -07001391 video_source_.IncomingCapturedFrame(CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001392 WaitForEncodedFrame(sequence++);
perkj803d97f2016-11-01 11:45:46 -07001393 stats = stats_proxy_->GetStats();
1394 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001395 EXPECT_FALSE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001396 EXPECT_EQ(3, stats.number_of_cpu_adapt_changes);
1397
1398 // Back to the source with adaptation off, set it back to maintain-resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001399 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001400 &new_video_source, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
sprangc5d62e22017-04-02 23:53:04 -07001401 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001402 CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001403 WaitForEncodedFrame(sequence++);
sprangc5d62e22017-04-02 23:53:04 -07001404 stats = stats_proxy_->GetStats();
asapersson13874762017-06-07 00:01:02 -07001405 // Disabled, since we previously switched the source to disabled.
sprangc5d62e22017-04-02 23:53:04 -07001406 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001407 EXPECT_TRUE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001408 EXPECT_EQ(3, stats.number_of_cpu_adapt_changes);
1409
1410 // Trigger CPU normal usage.
mflodmancc3d4422017-08-03 08:27:51 -07001411 video_stream_encoder_->TriggerCpuNormalUsage();
sprangc5d62e22017-04-02 23:53:04 -07001412 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001413 CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001414 WaitForEncodedFrame(sequence++);
sprangc5d62e22017-04-02 23:53:04 -07001415 stats = stats_proxy_->GetStats();
1416 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001417 EXPECT_FALSE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001418 EXPECT_EQ(4, stats.number_of_cpu_adapt_changes);
asapersson02465b82017-04-10 01:12:52 -07001419 EXPECT_EQ(0, stats.number_of_quality_adapt_changes);
perkj803d97f2016-11-01 11:45:46 -07001420
mflodmancc3d4422017-08-03 08:27:51 -07001421 video_stream_encoder_->Stop();
perkj803d97f2016-11-01 11:45:46 -07001422}
1423
mflodmancc3d4422017-08-03 08:27:51 -07001424TEST_F(VideoStreamEncoderTest,
1425 ScalingUpAndDownDoesNothingWithMaintainResolution) {
asaperssonfab67072017-04-04 05:51:49 -07001426 const int kWidth = 1280;
1427 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001428 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
kthelgason876222f2016-11-29 01:44:11 -08001429
asaperssonfab67072017-04-04 05:51:49 -07001430 // Expect no scaling to begin with.
asapersson02465b82017-04-10 01:12:52 -07001431 VerifyNoLimitation(video_source_.sink_wants());
kthelgason876222f2016-11-29 01:44:11 -08001432
asaperssonfab67072017-04-04 05:51:49 -07001433 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001434 WaitForEncodedFrame(1);
kthelgason876222f2016-11-29 01:44:11 -08001435
asaperssonfab67072017-04-04 05:51:49 -07001436 // Trigger scale down.
mflodmancc3d4422017-08-03 08:27:51 -07001437 video_stream_encoder_->TriggerQualityLow();
kthelgason5e13d412016-12-01 03:59:51 -08001438
asaperssonfab67072017-04-04 05:51:49 -07001439 video_source_.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001440 WaitForEncodedFrame(2);
kthelgason5e13d412016-12-01 03:59:51 -08001441
kthelgason876222f2016-11-29 01:44:11 -08001442 // Expect a scale down.
1443 EXPECT_TRUE(video_source_.sink_wants().max_pixel_count);
asaperssonfab67072017-04-04 05:51:49 -07001444 EXPECT_LT(video_source_.sink_wants().max_pixel_count, kWidth * kHeight);
kthelgason876222f2016-11-29 01:44:11 -08001445
asapersson02465b82017-04-10 01:12:52 -07001446 // Set resolution scaling disabled.
kthelgason876222f2016-11-29 01:44:11 -08001447 test::FrameForwarder new_video_source;
mflodmancc3d4422017-08-03 08:27:51 -07001448 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001449 &new_video_source, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
kthelgason876222f2016-11-29 01:44:11 -08001450
asaperssonfab67072017-04-04 05:51:49 -07001451 // Trigger scale down.
mflodmancc3d4422017-08-03 08:27:51 -07001452 video_stream_encoder_->TriggerQualityLow();
asaperssonfab67072017-04-04 05:51:49 -07001453 new_video_source.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001454 WaitForEncodedFrame(3);
kthelgason876222f2016-11-29 01:44:11 -08001455
asaperssonfab67072017-04-04 05:51:49 -07001456 // Expect no scaling.
sprangc5d62e22017-04-02 23:53:04 -07001457 EXPECT_EQ(std::numeric_limits<int>::max(),
1458 new_video_source.sink_wants().max_pixel_count);
kthelgason876222f2016-11-29 01:44:11 -08001459
asaperssonfab67072017-04-04 05:51:49 -07001460 // Trigger scale up.
mflodmancc3d4422017-08-03 08:27:51 -07001461 video_stream_encoder_->TriggerQualityHigh();
asaperssonfab67072017-04-04 05:51:49 -07001462 new_video_source.IncomingCapturedFrame(CreateFrame(4, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001463 WaitForEncodedFrame(4);
kthelgason876222f2016-11-29 01:44:11 -08001464
asapersson02465b82017-04-10 01:12:52 -07001465 // Expect nothing to change, still no scaling.
sprangc5d62e22017-04-02 23:53:04 -07001466 EXPECT_EQ(std::numeric_limits<int>::max(),
1467 new_video_source.sink_wants().max_pixel_count);
kthelgason876222f2016-11-29 01:44:11 -08001468
mflodmancc3d4422017-08-03 08:27:51 -07001469 video_stream_encoder_->Stop();
kthelgason876222f2016-11-29 01:44:11 -08001470}
1471
mflodmancc3d4422017-08-03 08:27:51 -07001472TEST_F(VideoStreamEncoderTest,
1473 SkipsSameAdaptDownRequest_MaintainFramerateMode) {
asapersson02465b82017-04-10 01:12:52 -07001474 const int kWidth = 1280;
1475 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001476 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson02465b82017-04-10 01:12:52 -07001477
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001478 // Enable MAINTAIN_FRAMERATE preference, no initial limitation.
asapersson02465b82017-04-10 01:12:52 -07001479 test::FrameForwarder source;
mflodmancc3d4422017-08-03 08:27:51 -07001480 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001481 &source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
asapersson02465b82017-04-10 01:12:52 -07001482
1483 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001484 WaitForEncodedFrame(1);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001485 VerifyFpsMaxResolutionMax(source.sink_wants());
asapersson02465b82017-04-10 01:12:52 -07001486 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1487 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1488
1489 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001490 video_stream_encoder_->TriggerCpuOveruse();
asapersson09f05612017-05-15 23:40:18 -07001491 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
asapersson02465b82017-04-10 01:12:52 -07001492 const int kLastMaxPixelCount = source.sink_wants().max_pixel_count;
1493 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1494 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1495
1496 // Trigger adapt down for same input resolution, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07001497 video_stream_encoder_->TriggerCpuOveruse();
asapersson02465b82017-04-10 01:12:52 -07001498 EXPECT_EQ(kLastMaxPixelCount, source.sink_wants().max_pixel_count);
1499 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1500 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1501
mflodmancc3d4422017-08-03 08:27:51 -07001502 video_stream_encoder_->Stop();
asapersson02465b82017-04-10 01:12:52 -07001503}
1504
mflodmancc3d4422017-08-03 08:27:51 -07001505TEST_F(VideoStreamEncoderTest, SkipsSameOrLargerAdaptDownRequest_BalancedMode) {
asaperssonf7e294d2017-06-13 23:25:22 -07001506 const int kWidth = 1280;
1507 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001508 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -07001509
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001510 // Enable BALANCED preference, no initial limitation.
asaperssonf7e294d2017-06-13 23:25:22 -07001511 test::FrameForwarder source;
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001512 video_stream_encoder_->SetSource(&source,
1513 webrtc::DegradationPreference::BALANCED);
asaperssonf7e294d2017-06-13 23:25:22 -07001514 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
1515 sink_.WaitForEncodedFrame(1);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001516 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07001517
1518 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001519 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07001520 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
1521 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1522 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1523 const int kLastMaxPixelCount = source.sink_wants().max_pixel_count;
1524
1525 // Trigger adapt down for same input resolution, expect no change.
1526 source.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
1527 sink_.WaitForEncodedFrame(2);
mflodmancc3d4422017-08-03 08:27:51 -07001528 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07001529 EXPECT_EQ(kLastMaxPixelCount, source.sink_wants().max_pixel_count);
1530 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1531 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1532
1533 // Trigger adapt down for larger input resolution, expect no change.
1534 source.IncomingCapturedFrame(CreateFrame(3, kWidth + 1, kHeight + 1));
1535 sink_.WaitForEncodedFrame(3);
mflodmancc3d4422017-08-03 08:27:51 -07001536 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07001537 EXPECT_EQ(kLastMaxPixelCount, source.sink_wants().max_pixel_count);
1538 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1539 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1540
mflodmancc3d4422017-08-03 08:27:51 -07001541 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07001542}
1543
mflodmancc3d4422017-08-03 08:27:51 -07001544TEST_F(VideoStreamEncoderTest,
1545 NoChangeForInitialNormalUsage_MaintainFramerateMode) {
asapersson02465b82017-04-10 01:12:52 -07001546 const int kWidth = 1280;
1547 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001548 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson02465b82017-04-10 01:12:52 -07001549
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001550 // Enable MAINTAIN_FRAMERATE preference, no initial limitation.
asapersson02465b82017-04-10 01:12:52 -07001551 test::FrameForwarder source;
mflodmancc3d4422017-08-03 08:27:51 -07001552 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001553 &source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
asapersson02465b82017-04-10 01:12:52 -07001554
1555 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001556 WaitForEncodedFrame(kWidth, kHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001557 VerifyFpsMaxResolutionMax(source.sink_wants());
asapersson02465b82017-04-10 01:12:52 -07001558 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1559 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1560
1561 // Trigger adapt up, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07001562 video_stream_encoder_->TriggerCpuNormalUsage();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001563 VerifyFpsMaxResolutionMax(source.sink_wants());
asapersson02465b82017-04-10 01:12:52 -07001564 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1565 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1566
mflodmancc3d4422017-08-03 08:27:51 -07001567 video_stream_encoder_->Stop();
asapersson02465b82017-04-10 01:12:52 -07001568}
1569
mflodmancc3d4422017-08-03 08:27:51 -07001570TEST_F(VideoStreamEncoderTest,
1571 NoChangeForInitialNormalUsage_MaintainResolutionMode) {
asapersson02465b82017-04-10 01:12:52 -07001572 const int kWidth = 1280;
1573 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001574 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson02465b82017-04-10 01:12:52 -07001575
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001576 // Enable MAINTAIN_RESOLUTION preference, no initial limitation.
asapersson02465b82017-04-10 01:12:52 -07001577 test::FrameForwarder source;
mflodmancc3d4422017-08-03 08:27:51 -07001578 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001579 &source, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
asapersson02465b82017-04-10 01:12:52 -07001580
1581 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001582 WaitForEncodedFrame(kWidth, kHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001583 VerifyFpsMaxResolutionMax(source.sink_wants());
asapersson09f05612017-05-15 23:40:18 -07001584 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
asapersson02465b82017-04-10 01:12:52 -07001585 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1586
1587 // Trigger adapt up, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07001588 video_stream_encoder_->TriggerCpuNormalUsage();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001589 VerifyFpsMaxResolutionMax(source.sink_wants());
asapersson09f05612017-05-15 23:40:18 -07001590 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
asapersson02465b82017-04-10 01:12:52 -07001591 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1592
mflodmancc3d4422017-08-03 08:27:51 -07001593 video_stream_encoder_->Stop();
asapersson02465b82017-04-10 01:12:52 -07001594}
1595
mflodmancc3d4422017-08-03 08:27:51 -07001596TEST_F(VideoStreamEncoderTest, NoChangeForInitialNormalUsage_BalancedMode) {
asaperssonf7e294d2017-06-13 23:25:22 -07001597 const int kWidth = 1280;
1598 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001599 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -07001600
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001601 // Enable BALANCED preference, no initial limitation.
asaperssonf7e294d2017-06-13 23:25:22 -07001602 test::FrameForwarder source;
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001603 video_stream_encoder_->SetSource(&source,
1604 webrtc::DegradationPreference::BALANCED);
asaperssonf7e294d2017-06-13 23:25:22 -07001605
1606 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
1607 sink_.WaitForEncodedFrame(kWidth, kHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001608 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07001609 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1610 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
1611 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1612
1613 // Trigger adapt up, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07001614 video_stream_encoder_->TriggerQualityHigh();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001615 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07001616 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1617 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
1618 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1619
mflodmancc3d4422017-08-03 08:27:51 -07001620 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07001621}
1622
mflodmancc3d4422017-08-03 08:27:51 -07001623TEST_F(VideoStreamEncoderTest, NoChangeForInitialNormalUsage_DisabledMode) {
asapersson09f05612017-05-15 23:40:18 -07001624 const int kWidth = 1280;
1625 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001626 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson09f05612017-05-15 23:40:18 -07001627
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001628 // Enable DISABLED preference, no initial limitation.
asapersson09f05612017-05-15 23:40:18 -07001629 test::FrameForwarder source;
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001630 video_stream_encoder_->SetSource(&source,
1631 webrtc::DegradationPreference::DISABLED);
asapersson09f05612017-05-15 23:40:18 -07001632
1633 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
1634 sink_.WaitForEncodedFrame(kWidth, kHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001635 VerifyFpsMaxResolutionMax(source.sink_wants());
asapersson09f05612017-05-15 23:40:18 -07001636 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1637 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
1638 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1639
1640 // Trigger adapt up, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07001641 video_stream_encoder_->TriggerQualityHigh();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001642 VerifyFpsMaxResolutionMax(source.sink_wants());
asapersson09f05612017-05-15 23:40:18 -07001643 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1644 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
1645 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1646
mflodmancc3d4422017-08-03 08:27:51 -07001647 video_stream_encoder_->Stop();
asapersson09f05612017-05-15 23:40:18 -07001648}
1649
mflodmancc3d4422017-08-03 08:27:51 -07001650TEST_F(VideoStreamEncoderTest,
1651 AdaptsResolutionForLowQuality_MaintainFramerateMode) {
asapersson02465b82017-04-10 01:12:52 -07001652 const int kWidth = 1280;
1653 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001654 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson02465b82017-04-10 01:12:52 -07001655
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001656 // Enable MAINTAIN_FRAMERATE preference, no initial limitation.
asapersson02465b82017-04-10 01:12:52 -07001657 AdaptingFrameForwarder source;
1658 source.set_adaptation_enabled(true);
mflodmancc3d4422017-08-03 08:27:51 -07001659 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001660 &source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
asapersson02465b82017-04-10 01:12:52 -07001661
1662 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001663 WaitForEncodedFrame(1);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001664 VerifyFpsMaxResolutionMax(source.sink_wants());
asapersson02465b82017-04-10 01:12:52 -07001665 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1666 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1667
1668 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001669 video_stream_encoder_->TriggerQualityLow();
asapersson02465b82017-04-10 01:12:52 -07001670 source.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001671 WaitForEncodedFrame(2);
asapersson09f05612017-05-15 23:40:18 -07001672 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
asapersson02465b82017-04-10 01:12:52 -07001673 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1674 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1675
1676 // Trigger adapt up, expect no restriction.
mflodmancc3d4422017-08-03 08:27:51 -07001677 video_stream_encoder_->TriggerQualityHigh();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001678 VerifyFpsMaxResolutionMax(source.sink_wants());
asapersson02465b82017-04-10 01:12:52 -07001679 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1680 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1681 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1682
mflodmancc3d4422017-08-03 08:27:51 -07001683 video_stream_encoder_->Stop();
asapersson02465b82017-04-10 01:12:52 -07001684}
1685
mflodmancc3d4422017-08-03 08:27:51 -07001686TEST_F(VideoStreamEncoderTest,
1687 AdaptsFramerateForLowQuality_MaintainResolutionMode) {
asapersson09f05612017-05-15 23:40:18 -07001688 const int kWidth = 1280;
1689 const int kHeight = 720;
1690 const int kInputFps = 30;
mflodmancc3d4422017-08-03 08:27:51 -07001691 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson09f05612017-05-15 23:40:18 -07001692
1693 VideoSendStream::Stats stats = stats_proxy_->GetStats();
1694 stats.input_frame_rate = kInputFps;
1695 stats_proxy_->SetMockStats(stats);
1696
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001697 // Expect no scaling to begin with (preference: MAINTAIN_FRAMERATE).
asapersson09f05612017-05-15 23:40:18 -07001698 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
1699 sink_.WaitForEncodedFrame(1);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001700 VerifyFpsMaxResolutionMax(video_source_.sink_wants());
asapersson09f05612017-05-15 23:40:18 -07001701
1702 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001703 video_stream_encoder_->TriggerQualityLow();
asapersson09f05612017-05-15 23:40:18 -07001704 video_source_.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
1705 sink_.WaitForEncodedFrame(2);
1706 VerifyFpsMaxResolutionLt(video_source_.sink_wants(), kWidth * kHeight);
1707
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001708 // Enable MAINTAIN_RESOLUTION preference.
asapersson09f05612017-05-15 23:40:18 -07001709 test::FrameForwarder new_video_source;
mflodmancc3d4422017-08-03 08:27:51 -07001710 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001711 &new_video_source, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001712 VerifyFpsMaxResolutionMax(new_video_source.sink_wants());
asapersson09f05612017-05-15 23:40:18 -07001713
1714 // Trigger adapt down, expect reduced framerate.
mflodmancc3d4422017-08-03 08:27:51 -07001715 video_stream_encoder_->TriggerQualityLow();
asapersson09f05612017-05-15 23:40:18 -07001716 new_video_source.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
1717 sink_.WaitForEncodedFrame(3);
1718 VerifyFpsLtResolutionMax(new_video_source.sink_wants(), kInputFps);
1719
1720 // Trigger adapt up, expect no restriction.
mflodmancc3d4422017-08-03 08:27:51 -07001721 video_stream_encoder_->TriggerQualityHigh();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001722 VerifyFpsMaxResolutionMax(new_video_source.sink_wants());
asapersson09f05612017-05-15 23:40:18 -07001723
mflodmancc3d4422017-08-03 08:27:51 -07001724 video_stream_encoder_->Stop();
asapersson09f05612017-05-15 23:40:18 -07001725}
1726
mflodmancc3d4422017-08-03 08:27:51 -07001727TEST_F(VideoStreamEncoderTest, DoesNotScaleBelowSetResolutionLimit) {
asaperssond0de2952017-04-21 01:47:31 -07001728 const int kWidth = 1280;
1729 const int kHeight = 720;
1730 const size_t kNumFrames = 10;
1731
mflodmancc3d4422017-08-03 08:27:51 -07001732 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
kthelgason5e13d412016-12-01 03:59:51 -08001733
asaperssond0de2952017-04-21 01:47:31 -07001734 // Enable adapter, expected input resolutions when downscaling:
asapersson142fcc92017-08-17 08:58:54 -07001735 // 1280x720 -> 960x540 -> 640x360 -> 480x270 -> 320x180 (kMinPixelsPerFrame)
asaperssond0de2952017-04-21 01:47:31 -07001736 video_source_.set_adaptation_enabled(true);
1737
1738 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1739 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1740
1741 int downscales = 0;
1742 for (size_t i = 1; i <= kNumFrames; i++) {
Åsa Persson8c1bf952018-09-13 10:42:19 +02001743 video_source_.IncomingCapturedFrame(
1744 CreateFrame(i * kFrameIntervalMs, kWidth, kHeight));
1745 WaitForEncodedFrame(i * kFrameIntervalMs);
asaperssond0de2952017-04-21 01:47:31 -07001746
asaperssonfab67072017-04-04 05:51:49 -07001747 // Trigger scale down.
asaperssond0de2952017-04-21 01:47:31 -07001748 rtc::VideoSinkWants last_wants = video_source_.sink_wants();
mflodmancc3d4422017-08-03 08:27:51 -07001749 video_stream_encoder_->TriggerQualityLow();
sprangc5d62e22017-04-02 23:53:04 -07001750 EXPECT_GE(video_source_.sink_wants().max_pixel_count, kMinPixelsPerFrame);
asaperssond0de2952017-04-21 01:47:31 -07001751
1752 if (video_source_.sink_wants().max_pixel_count < last_wants.max_pixel_count)
1753 ++downscales;
1754
1755 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1756 EXPECT_EQ(downscales,
1757 stats_proxy_->GetStats().number_of_quality_adapt_changes);
1758 EXPECT_GT(downscales, 0);
kthelgason5e13d412016-12-01 03:59:51 -08001759 }
mflodmancc3d4422017-08-03 08:27:51 -07001760 video_stream_encoder_->Stop();
asaperssond0de2952017-04-21 01:47:31 -07001761}
1762
mflodmancc3d4422017-08-03 08:27:51 -07001763TEST_F(VideoStreamEncoderTest,
asaperssond0de2952017-04-21 01:47:31 -07001764 AdaptsResolutionUpAndDownTwiceOnOveruse_MaintainFramerateMode) {
1765 const int kWidth = 1280;
1766 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001767 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssond0de2952017-04-21 01:47:31 -07001768
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001769 // Enable MAINTAIN_FRAMERATE preference, no initial limitation.
asaperssond0de2952017-04-21 01:47:31 -07001770 AdaptingFrameForwarder source;
1771 source.set_adaptation_enabled(true);
mflodmancc3d4422017-08-03 08:27:51 -07001772 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001773 &source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
asaperssond0de2952017-04-21 01:47:31 -07001774
Åsa Persson8c1bf952018-09-13 10:42:19 +02001775 int64_t timestamp_ms = kFrameIntervalMs;
1776 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001777 WaitForEncodedFrame(kWidth, kHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001778 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssond0de2952017-04-21 01:47:31 -07001779 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1780 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1781
1782 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001783 video_stream_encoder_->TriggerCpuOveruse();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001784 timestamp_ms += kFrameIntervalMs;
1785 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
1786 WaitForEncodedFrame(timestamp_ms);
asapersson09f05612017-05-15 23:40:18 -07001787 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
asaperssond0de2952017-04-21 01:47:31 -07001788 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1789 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1790
1791 // Trigger adapt up, expect no restriction.
mflodmancc3d4422017-08-03 08:27:51 -07001792 video_stream_encoder_->TriggerCpuNormalUsage();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001793 timestamp_ms += kFrameIntervalMs;
1794 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001795 WaitForEncodedFrame(kWidth, kHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001796 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssond0de2952017-04-21 01:47:31 -07001797 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1798 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1799
1800 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001801 video_stream_encoder_->TriggerCpuOveruse();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001802 timestamp_ms += kFrameIntervalMs;
1803 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
1804 WaitForEncodedFrame(timestamp_ms);
asapersson09f05612017-05-15 23:40:18 -07001805 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
asaperssond0de2952017-04-21 01:47:31 -07001806 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1807 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1808
1809 // Trigger adapt up, expect no restriction.
mflodmancc3d4422017-08-03 08:27:51 -07001810 video_stream_encoder_->TriggerCpuNormalUsage();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001811 timestamp_ms += kFrameIntervalMs;
1812 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
asapersson09f05612017-05-15 23:40:18 -07001813 sink_.WaitForEncodedFrame(kWidth, kHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001814 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssond0de2952017-04-21 01:47:31 -07001815 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1816 EXPECT_EQ(4, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1817
mflodmancc3d4422017-08-03 08:27:51 -07001818 video_stream_encoder_->Stop();
asaperssond0de2952017-04-21 01:47:31 -07001819}
1820
mflodmancc3d4422017-08-03 08:27:51 -07001821TEST_F(VideoStreamEncoderTest,
asaperssonf7e294d2017-06-13 23:25:22 -07001822 AdaptsResolutionUpAndDownTwiceForLowQuality_BalancedMode_NoFpsLimit) {
1823 const int kWidth = 1280;
1824 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001825 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -07001826
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001827 // Enable BALANCED preference, no initial limitation.
asaperssonf7e294d2017-06-13 23:25:22 -07001828 AdaptingFrameForwarder source;
1829 source.set_adaptation_enabled(true);
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001830 video_stream_encoder_->SetSource(&source,
1831 webrtc::DegradationPreference::BALANCED);
asaperssonf7e294d2017-06-13 23:25:22 -07001832
Åsa Persson8c1bf952018-09-13 10:42:19 +02001833 int64_t timestamp_ms = kFrameIntervalMs;
1834 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
asaperssonf7e294d2017-06-13 23:25:22 -07001835 sink_.WaitForEncodedFrame(kWidth, kHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001836 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07001837 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1838 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1839
1840 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001841 video_stream_encoder_->TriggerQualityLow();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001842 timestamp_ms += kFrameIntervalMs;
1843 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
1844 sink_.WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07001845 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
1846 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1847 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1848
1849 // Trigger adapt up, expect no restriction.
mflodmancc3d4422017-08-03 08:27:51 -07001850 video_stream_encoder_->TriggerQualityHigh();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001851 timestamp_ms += kFrameIntervalMs;
1852 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
asaperssonf7e294d2017-06-13 23:25:22 -07001853 sink_.WaitForEncodedFrame(kWidth, kHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001854 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07001855 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1856 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1857
1858 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001859 video_stream_encoder_->TriggerQualityLow();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001860 timestamp_ms += kFrameIntervalMs;
1861 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
1862 sink_.WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07001863 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
1864 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1865 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1866
1867 // Trigger adapt up, expect no restriction.
mflodmancc3d4422017-08-03 08:27:51 -07001868 video_stream_encoder_->TriggerQualityHigh();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001869 timestamp_ms += kFrameIntervalMs;
1870 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
asaperssonf7e294d2017-06-13 23:25:22 -07001871 sink_.WaitForEncodedFrame(kWidth, kHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001872 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07001873 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1874 EXPECT_EQ(4, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1875
mflodmancc3d4422017-08-03 08:27:51 -07001876 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07001877}
1878
mflodmancc3d4422017-08-03 08:27:51 -07001879TEST_F(VideoStreamEncoderTest,
asaperssond0de2952017-04-21 01:47:31 -07001880 AdaptsResolutionOnOveruseAndLowQuality_MaintainFramerateMode) {
1881 const int kWidth = 1280;
1882 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001883 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssond0de2952017-04-21 01:47:31 -07001884
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001885 // Enable MAINTAIN_FRAMERATE preference, no initial limitation.
asaperssond0de2952017-04-21 01:47:31 -07001886 AdaptingFrameForwarder source;
1887 source.set_adaptation_enabled(true);
mflodmancc3d4422017-08-03 08:27:51 -07001888 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001889 &source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
asaperssond0de2952017-04-21 01:47:31 -07001890
Åsa Persson8c1bf952018-09-13 10:42:19 +02001891 int64_t timestamp_ms = kFrameIntervalMs;
1892 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001893 WaitForEncodedFrame(kWidth, kHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001894 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssond0de2952017-04-21 01:47:31 -07001895 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1896 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1897 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1898 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1899
1900 // Trigger cpu adapt down, expect scaled down resolution (960x540).
mflodmancc3d4422017-08-03 08:27:51 -07001901 video_stream_encoder_->TriggerCpuOveruse();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001902 timestamp_ms += kFrameIntervalMs;
1903 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
1904 WaitForEncodedFrame(timestamp_ms);
asapersson09f05612017-05-15 23:40:18 -07001905 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
asaperssond0de2952017-04-21 01:47:31 -07001906 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1907 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1908 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1909 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1910
1911 // Trigger cpu adapt down, expect scaled down resolution (640x360).
mflodmancc3d4422017-08-03 08:27:51 -07001912 video_stream_encoder_->TriggerCpuOveruse();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001913 timestamp_ms += kFrameIntervalMs;
1914 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
1915 WaitForEncodedFrame(timestamp_ms);
asapersson09f05612017-05-15 23:40:18 -07001916 VerifyFpsMaxResolutionLt(source.sink_wants(), source.last_wants());
asaperssond0de2952017-04-21 01:47:31 -07001917 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1918 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1919 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1920 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1921
Jonathan Yubc771b72017-12-08 17:04:29 -08001922 // Trigger cpu adapt down, expect scaled down resolution (480x270).
mflodmancc3d4422017-08-03 08:27:51 -07001923 video_stream_encoder_->TriggerCpuOveruse();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001924 timestamp_ms += kFrameIntervalMs;
1925 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
1926 WaitForEncodedFrame(timestamp_ms);
Jonathan Yubc771b72017-12-08 17:04:29 -08001927 VerifyFpsMaxResolutionLt(source.sink_wants(), source.last_wants());
asaperssond0de2952017-04-21 01:47:31 -07001928 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1929 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
Jonathan Yubc771b72017-12-08 17:04:29 -08001930 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
asaperssond0de2952017-04-21 01:47:31 -07001931 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1932
Jonathan Yubc771b72017-12-08 17:04:29 -08001933 // Trigger quality adapt down, expect scaled down resolution (320x180).
mflodmancc3d4422017-08-03 08:27:51 -07001934 video_stream_encoder_->TriggerQualityLow();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001935 timestamp_ms += kFrameIntervalMs;
1936 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
1937 WaitForEncodedFrame(timestamp_ms);
asapersson09f05612017-05-15 23:40:18 -07001938 VerifyFpsMaxResolutionLt(source.sink_wants(), source.last_wants());
Jonathan Yubc771b72017-12-08 17:04:29 -08001939 rtc::VideoSinkWants last_wants = source.sink_wants();
asaperssond0de2952017-04-21 01:47:31 -07001940 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1941 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1942 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1943 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1944
Jonathan Yubc771b72017-12-08 17:04:29 -08001945 // Trigger quality adapt down, expect no change (min resolution reached).
1946 video_stream_encoder_->TriggerQualityLow();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001947 timestamp_ms += kFrameIntervalMs;
1948 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
1949 WaitForEncodedFrame(timestamp_ms);
Jonathan Yubc771b72017-12-08 17:04:29 -08001950 VerifyFpsMaxResolutionEq(source.sink_wants(), last_wants);
1951 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1952 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1953 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1954 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1955
1956 // Trigger cpu adapt up, expect upscaled resolution (480x270).
mflodmancc3d4422017-08-03 08:27:51 -07001957 video_stream_encoder_->TriggerCpuNormalUsage();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001958 timestamp_ms += kFrameIntervalMs;
1959 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
1960 WaitForEncodedFrame(timestamp_ms);
asapersson09f05612017-05-15 23:40:18 -07001961 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
Jonathan Yubc771b72017-12-08 17:04:29 -08001962 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1963 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1964 EXPECT_EQ(4, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1965 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1966
1967 // Trigger cpu adapt up, expect upscaled resolution (640x360).
1968 video_stream_encoder_->TriggerCpuNormalUsage();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001969 timestamp_ms += kFrameIntervalMs;
1970 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
1971 WaitForEncodedFrame(timestamp_ms);
Jonathan Yubc771b72017-12-08 17:04:29 -08001972 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
1973 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1974 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1975 EXPECT_EQ(5, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1976 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1977
1978 // Trigger cpu adapt up, expect upscaled resolution (960x540).
1979 video_stream_encoder_->TriggerCpuNormalUsage();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001980 timestamp_ms += kFrameIntervalMs;
1981 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
1982 WaitForEncodedFrame(timestamp_ms);
Jonathan Yubc771b72017-12-08 17:04:29 -08001983 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
asaperssond0de2952017-04-21 01:47:31 -07001984 last_wants = source.sink_wants();
1985 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1986 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
Jonathan Yubc771b72017-12-08 17:04:29 -08001987 EXPECT_EQ(6, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
asaperssond0de2952017-04-21 01:47:31 -07001988 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1989
1990 // Trigger cpu adapt up, no cpu downgrades, expect no change (960x540).
mflodmancc3d4422017-08-03 08:27:51 -07001991 video_stream_encoder_->TriggerCpuNormalUsage();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001992 timestamp_ms += kFrameIntervalMs;
1993 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
1994 WaitForEncodedFrame(timestamp_ms);
asapersson09f05612017-05-15 23:40:18 -07001995 VerifyFpsEqResolutionEq(source.sink_wants(), last_wants);
asaperssond0de2952017-04-21 01:47:31 -07001996 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1997 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
Jonathan Yubc771b72017-12-08 17:04:29 -08001998 EXPECT_EQ(6, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
asaperssond0de2952017-04-21 01:47:31 -07001999 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2000
2001 // Trigger quality adapt up, expect no restriction (1280x720).
mflodmancc3d4422017-08-03 08:27:51 -07002002 video_stream_encoder_->TriggerQualityHigh();
Åsa Persson8c1bf952018-09-13 10:42:19 +02002003 timestamp_ms += kFrameIntervalMs;
2004 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002005 WaitForEncodedFrame(kWidth, kHeight);
asapersson09f05612017-05-15 23:40:18 -07002006 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
Åsa Persson8c1bf952018-09-13 10:42:19 +02002007 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssond0de2952017-04-21 01:47:31 -07002008 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2009 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
Jonathan Yubc771b72017-12-08 17:04:29 -08002010 EXPECT_EQ(6, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
asaperssond0de2952017-04-21 01:47:31 -07002011 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
kthelgason5e13d412016-12-01 03:59:51 -08002012
mflodmancc3d4422017-08-03 08:27:51 -07002013 video_stream_encoder_->Stop();
kthelgason5e13d412016-12-01 03:59:51 -08002014}
2015
mflodmancc3d4422017-08-03 08:27:51 -07002016TEST_F(VideoStreamEncoderTest, CpuLimitedHistogramIsReported) {
asaperssonfab67072017-04-04 05:51:49 -07002017 const int kWidth = 640;
2018 const int kHeight = 360;
perkj803d97f2016-11-01 11:45:46 -07002019
mflodmancc3d4422017-08-03 08:27:51 -07002020 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
sprang4847ae62017-06-27 07:06:52 -07002021
perkj803d97f2016-11-01 11:45:46 -07002022 for (int i = 1; i <= SendStatisticsProxy::kMinRequiredMetricsSamples; ++i) {
asaperssonfab67072017-04-04 05:51:49 -07002023 video_source_.IncomingCapturedFrame(CreateFrame(i, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002024 WaitForEncodedFrame(i);
perkj803d97f2016-11-01 11:45:46 -07002025 }
2026
mflodmancc3d4422017-08-03 08:27:51 -07002027 video_stream_encoder_->TriggerCpuOveruse();
perkj803d97f2016-11-01 11:45:46 -07002028 for (int i = 1; i <= SendStatisticsProxy::kMinRequiredMetricsSamples; ++i) {
asaperssonfab67072017-04-04 05:51:49 -07002029 video_source_.IncomingCapturedFrame(CreateFrame(
2030 SendStatisticsProxy::kMinRequiredMetricsSamples + i, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002031 WaitForEncodedFrame(SendStatisticsProxy::kMinRequiredMetricsSamples + i);
perkj803d97f2016-11-01 11:45:46 -07002032 }
2033
mflodmancc3d4422017-08-03 08:27:51 -07002034 video_stream_encoder_->Stop();
2035 video_stream_encoder_.reset();
perkj803d97f2016-11-01 11:45:46 -07002036 stats_proxy_.reset();
sprangf8ee65e2017-02-28 08:49:33 -08002037
perkj803d97f2016-11-01 11:45:46 -07002038 EXPECT_EQ(1,
2039 metrics::NumSamples("WebRTC.Video.CpuLimitedResolutionInPercent"));
2040 EXPECT_EQ(
2041 1, metrics::NumEvents("WebRTC.Video.CpuLimitedResolutionInPercent", 50));
2042}
2043
mflodmancc3d4422017-08-03 08:27:51 -07002044TEST_F(VideoStreamEncoderTest,
2045 CpuLimitedHistogramIsNotReportedForDisabledDegradation) {
2046 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonf4e44af2017-04-19 02:01:06 -07002047 const int kWidth = 640;
2048 const int kHeight = 360;
2049
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002050 video_stream_encoder_->SetSource(&video_source_,
2051 webrtc::DegradationPreference::DISABLED);
asaperssonf4e44af2017-04-19 02:01:06 -07002052
2053 for (int i = 1; i <= SendStatisticsProxy::kMinRequiredMetricsSamples; ++i) {
2054 video_source_.IncomingCapturedFrame(CreateFrame(i, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002055 WaitForEncodedFrame(i);
asaperssonf4e44af2017-04-19 02:01:06 -07002056 }
2057
mflodmancc3d4422017-08-03 08:27:51 -07002058 video_stream_encoder_->Stop();
2059 video_stream_encoder_.reset();
asaperssonf4e44af2017-04-19 02:01:06 -07002060 stats_proxy_.reset();
2061
2062 EXPECT_EQ(0,
2063 metrics::NumSamples("WebRTC.Video.CpuLimitedResolutionInPercent"));
2064}
2065
mflodmancc3d4422017-08-03 08:27:51 -07002066TEST_F(VideoStreamEncoderTest, CallsBitrateObserver) {
sprang4847ae62017-06-27 07:06:52 -07002067 MockBitrateObserver bitrate_observer;
Niels Möller0327c2d2018-05-21 14:09:31 +02002068 video_stream_encoder_->SetBitrateAllocationObserver(&bitrate_observer);
sprang57c2fff2017-01-16 06:24:02 -08002069
2070 const int kDefaultFps = 30;
Erik Språng566124a2018-04-23 12:32:22 +02002071 const VideoBitrateAllocation expected_bitrate =
sprang57c2fff2017-01-16 06:24:02 -08002072 DefaultVideoBitrateAllocator(fake_encoder_.codec_config())
kthelgason2bc68642017-02-07 07:02:22 -08002073 .GetAllocation(kLowTargetBitrateBps, kDefaultFps);
sprang57c2fff2017-01-16 06:24:02 -08002074
2075 // First called on bitrate updated, then again on first frame.
2076 EXPECT_CALL(bitrate_observer, OnBitrateAllocationUpdated(expected_bitrate))
2077 .Times(2);
mflodmancc3d4422017-08-03 08:27:51 -07002078 video_stream_encoder_->OnBitrateUpdated(kLowTargetBitrateBps, 0, 0);
sprang57c2fff2017-01-16 06:24:02 -08002079
2080 const int64_t kStartTimeMs = 1;
2081 video_source_.IncomingCapturedFrame(
2082 CreateFrame(kStartTimeMs, codec_width_, codec_height_));
sprang4847ae62017-06-27 07:06:52 -07002083 WaitForEncodedFrame(kStartTimeMs);
sprang57c2fff2017-01-16 06:24:02 -08002084
2085 // Not called on second frame.
2086 EXPECT_CALL(bitrate_observer, OnBitrateAllocationUpdated(expected_bitrate))
2087 .Times(0);
2088 video_source_.IncomingCapturedFrame(
2089 CreateFrame(kStartTimeMs + 1, codec_width_, codec_height_));
sprang4847ae62017-06-27 07:06:52 -07002090 WaitForEncodedFrame(kStartTimeMs + 1);
sprang57c2fff2017-01-16 06:24:02 -08002091
2092 // Called after a process interval.
2093 const int64_t kProcessIntervalMs =
2094 vcm::VCMProcessTimer::kDefaultProcessIntervalMs;
sprang4847ae62017-06-27 07:06:52 -07002095 fake_clock_.AdvanceTimeMicros(rtc::kNumMicrosecsPerMillisec *
2096 (kProcessIntervalMs + (1000 / kDefaultFps)));
sprang57c2fff2017-01-16 06:24:02 -08002097 EXPECT_CALL(bitrate_observer, OnBitrateAllocationUpdated(expected_bitrate))
2098 .Times(1);
2099 video_source_.IncomingCapturedFrame(CreateFrame(
2100 kStartTimeMs + kProcessIntervalMs, codec_width_, codec_height_));
sprang4847ae62017-06-27 07:06:52 -07002101 WaitForEncodedFrame(kStartTimeMs + kProcessIntervalMs);
sprang57c2fff2017-01-16 06:24:02 -08002102
mflodmancc3d4422017-08-03 08:27:51 -07002103 video_stream_encoder_->Stop();
sprang57c2fff2017-01-16 06:24:02 -08002104}
2105
Niels Möller7dc26b72017-12-06 10:27:48 +01002106TEST_F(VideoStreamEncoderTest, OveruseDetectorUpdatedOnReconfigureAndAdaption) {
2107 const int kFrameWidth = 1280;
2108 const int kFrameHeight = 720;
2109 const int kFramerate = 24;
2110
2111 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
2112 test::FrameForwarder source;
2113 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002114 &source, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
Niels Möller7dc26b72017-12-06 10:27:48 +01002115
2116 // Insert a single frame, triggering initial configuration.
2117 source.IncomingCapturedFrame(CreateFrame(1, kFrameWidth, kFrameHeight));
2118 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2119
2120 EXPECT_EQ(
2121 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2122 kDefaultFramerate);
2123
2124 // Trigger reconfigure encoder (without resetting the entire instance).
2125 VideoEncoderConfig video_encoder_config;
Niels Möller259a4972018-04-05 15:36:51 +02002126 video_encoder_config.codec_type = kVideoCodecVP8;
Niels Möller7dc26b72017-12-06 10:27:48 +01002127 video_encoder_config.max_bitrate_bps = kTargetBitrateBps;
2128 video_encoder_config.number_of_streams = 1;
2129 video_encoder_config.video_stream_factory =
2130 new rtc::RefCountedObject<VideoStreamFactory>(1, kFramerate);
2131 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
Niels Möllerf1338562018-04-26 09:51:47 +02002132 kMaxPayloadLength);
Niels Möller7dc26b72017-12-06 10:27:48 +01002133 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2134
2135 // Detector should be updated with fps limit from codec config.
2136 EXPECT_EQ(
2137 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2138 kFramerate);
2139
2140 // Trigger overuse, max framerate should be reduced.
2141 VideoSendStream::Stats stats = stats_proxy_->GetStats();
2142 stats.input_frame_rate = kFramerate;
2143 stats_proxy_->SetMockStats(stats);
2144 video_stream_encoder_->TriggerCpuOveruse();
2145 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2146 int adapted_framerate =
2147 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate();
2148 EXPECT_LT(adapted_framerate, kFramerate);
2149
2150 // Trigger underuse, max framerate should go back to codec configured fps.
2151 // Set extra low fps, to make sure it's actually reset, not just incremented.
2152 stats = stats_proxy_->GetStats();
2153 stats.input_frame_rate = adapted_framerate / 2;
2154 stats_proxy_->SetMockStats(stats);
2155 video_stream_encoder_->TriggerCpuNormalUsage();
2156 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2157 EXPECT_EQ(
2158 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2159 kFramerate);
2160
2161 video_stream_encoder_->Stop();
2162}
2163
2164TEST_F(VideoStreamEncoderTest,
2165 OveruseDetectorUpdatedRespectsFramerateAfterUnderuse) {
2166 const int kFrameWidth = 1280;
2167 const int kFrameHeight = 720;
2168 const int kLowFramerate = 15;
2169 const int kHighFramerate = 25;
2170
2171 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
2172 test::FrameForwarder source;
2173 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002174 &source, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
Niels Möller7dc26b72017-12-06 10:27:48 +01002175
2176 // Trigger initial configuration.
2177 VideoEncoderConfig video_encoder_config;
Niels Möller259a4972018-04-05 15:36:51 +02002178 video_encoder_config.codec_type = kVideoCodecVP8;
Niels Möller7dc26b72017-12-06 10:27:48 +01002179 video_encoder_config.max_bitrate_bps = kTargetBitrateBps;
2180 video_encoder_config.number_of_streams = 1;
2181 video_encoder_config.video_stream_factory =
2182 new rtc::RefCountedObject<VideoStreamFactory>(1, kLowFramerate);
2183 source.IncomingCapturedFrame(CreateFrame(1, kFrameWidth, kFrameHeight));
2184 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
Niels Möllerf1338562018-04-26 09:51:47 +02002185 kMaxPayloadLength);
Niels Möller7dc26b72017-12-06 10:27:48 +01002186 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2187
2188 EXPECT_EQ(
2189 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2190 kLowFramerate);
2191
2192 // Trigger overuse, max framerate should be reduced.
2193 VideoSendStream::Stats stats = stats_proxy_->GetStats();
2194 stats.input_frame_rate = kLowFramerate;
2195 stats_proxy_->SetMockStats(stats);
2196 video_stream_encoder_->TriggerCpuOveruse();
2197 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2198 int adapted_framerate =
2199 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate();
2200 EXPECT_LT(adapted_framerate, kLowFramerate);
2201
2202 // Reconfigure the encoder with a new (higher max framerate), max fps should
2203 // still respect the adaptation.
2204 video_encoder_config.video_stream_factory =
2205 new rtc::RefCountedObject<VideoStreamFactory>(1, kHighFramerate);
2206 source.IncomingCapturedFrame(CreateFrame(1, kFrameWidth, kFrameHeight));
2207 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
Niels Möllerf1338562018-04-26 09:51:47 +02002208 kMaxPayloadLength);
Niels Möller7dc26b72017-12-06 10:27:48 +01002209 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2210
2211 EXPECT_EQ(
2212 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2213 adapted_framerate);
2214
2215 // Trigger underuse, max framerate should go back to codec configured fps.
2216 stats = stats_proxy_->GetStats();
2217 stats.input_frame_rate = adapted_framerate;
2218 stats_proxy_->SetMockStats(stats);
2219 video_stream_encoder_->TriggerCpuNormalUsage();
2220 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2221 EXPECT_EQ(
2222 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2223 kHighFramerate);
2224
2225 video_stream_encoder_->Stop();
2226}
2227
mflodmancc3d4422017-08-03 08:27:51 -07002228TEST_F(VideoStreamEncoderTest,
2229 OveruseDetectorUpdatedOnDegradationPreferenceChange) {
sprangfda496a2017-06-15 04:21:07 -07002230 const int kFrameWidth = 1280;
2231 const int kFrameHeight = 720;
2232 const int kFramerate = 24;
2233
mflodmancc3d4422017-08-03 08:27:51 -07002234 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
sprangfda496a2017-06-15 04:21:07 -07002235 test::FrameForwarder source;
mflodmancc3d4422017-08-03 08:27:51 -07002236 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002237 &source, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
sprangfda496a2017-06-15 04:21:07 -07002238
2239 // Trigger initial configuration.
2240 VideoEncoderConfig video_encoder_config;
Niels Möller259a4972018-04-05 15:36:51 +02002241 video_encoder_config.codec_type = kVideoCodecVP8;
sprangfda496a2017-06-15 04:21:07 -07002242 video_encoder_config.max_bitrate_bps = kTargetBitrateBps;
2243 video_encoder_config.number_of_streams = 1;
2244 video_encoder_config.video_stream_factory =
2245 new rtc::RefCountedObject<VideoStreamFactory>(1, kFramerate);
2246 source.IncomingCapturedFrame(CreateFrame(1, kFrameWidth, kFrameHeight));
mflodmancc3d4422017-08-03 08:27:51 -07002247 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
Niels Möllerf1338562018-04-26 09:51:47 +02002248 kMaxPayloadLength);
mflodmancc3d4422017-08-03 08:27:51 -07002249 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
sprangfda496a2017-06-15 04:21:07 -07002250
Niels Möller7dc26b72017-12-06 10:27:48 +01002251 EXPECT_EQ(
2252 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2253 kFramerate);
sprangfda496a2017-06-15 04:21:07 -07002254
2255 // Trigger overuse, max framerate should be reduced.
2256 VideoSendStream::Stats stats = stats_proxy_->GetStats();
2257 stats.input_frame_rate = kFramerate;
2258 stats_proxy_->SetMockStats(stats);
mflodmancc3d4422017-08-03 08:27:51 -07002259 video_stream_encoder_->TriggerCpuOveruse();
2260 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
Niels Möller7dc26b72017-12-06 10:27:48 +01002261 int adapted_framerate =
2262 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate();
sprangfda496a2017-06-15 04:21:07 -07002263 EXPECT_LT(adapted_framerate, kFramerate);
2264
2265 // Change degradation preference to not enable framerate scaling. Target
2266 // framerate should be changed to codec defined limit.
mflodmancc3d4422017-08-03 08:27:51 -07002267 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002268 &source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
mflodmancc3d4422017-08-03 08:27:51 -07002269 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
Niels Möller7dc26b72017-12-06 10:27:48 +01002270 EXPECT_EQ(
2271 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2272 kFramerate);
sprangfda496a2017-06-15 04:21:07 -07002273
mflodmancc3d4422017-08-03 08:27:51 -07002274 video_stream_encoder_->Stop();
sprangfda496a2017-06-15 04:21:07 -07002275}
2276
mflodmancc3d4422017-08-03 08:27:51 -07002277TEST_F(VideoStreamEncoderTest, DropsFramesAndScalesWhenBitrateIsTooLow) {
asaperssonfab67072017-04-04 05:51:49 -07002278 const int kTooLowBitrateForFrameSizeBps = 10000;
mflodmancc3d4422017-08-03 08:27:51 -07002279 video_stream_encoder_->OnBitrateUpdated(kTooLowBitrateForFrameSizeBps, 0, 0);
asaperssonfab67072017-04-04 05:51:49 -07002280 const int kWidth = 640;
2281 const int kHeight = 360;
kthelgason2bc68642017-02-07 07:02:22 -08002282
asaperssonfab67072017-04-04 05:51:49 -07002283 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
kthelgason2bc68642017-02-07 07:02:22 -08002284
2285 // Expect to drop this frame, the wait should time out.
sprang4847ae62017-06-27 07:06:52 -07002286 ExpectDroppedFrame();
kthelgason2bc68642017-02-07 07:02:22 -08002287
2288 // Expect the sink_wants to specify a scaled frame.
asapersson0944a802017-04-07 00:57:58 -07002289 EXPECT_LT(video_source_.sink_wants().max_pixel_count, kWidth * kHeight);
kthelgason2bc68642017-02-07 07:02:22 -08002290
sprangc5d62e22017-04-02 23:53:04 -07002291 int last_pixel_count = video_source_.sink_wants().max_pixel_count;
kthelgason2bc68642017-02-07 07:02:22 -08002292
asaperssonfab67072017-04-04 05:51:49 -07002293 // Next frame is scaled.
kthelgason2bc68642017-02-07 07:02:22 -08002294 video_source_.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07002295 CreateFrame(2, kWidth * 3 / 4, kHeight * 3 / 4));
kthelgason2bc68642017-02-07 07:02:22 -08002296
2297 // Expect to drop this frame, the wait should time out.
sprang4847ae62017-06-27 07:06:52 -07002298 ExpectDroppedFrame();
kthelgason2bc68642017-02-07 07:02:22 -08002299
sprangc5d62e22017-04-02 23:53:04 -07002300 EXPECT_LT(video_source_.sink_wants().max_pixel_count, last_pixel_count);
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,
2306 NumberOfDroppedFramesLimitedWhenBitrateIsTooLow) {
asaperssonfab67072017-04-04 05:51:49 -07002307 const int kTooLowBitrateForFrameSizeBps = 10000;
mflodmancc3d4422017-08-03 08:27:51 -07002308 video_stream_encoder_->OnBitrateUpdated(kTooLowBitrateForFrameSizeBps, 0, 0);
asaperssonfab67072017-04-04 05:51:49 -07002309 const int kWidth = 640;
2310 const int kHeight = 360;
kthelgason2bc68642017-02-07 07:02:22 -08002311
2312 // We expect the n initial frames to get dropped.
2313 int i;
2314 for (i = 1; i <= kMaxInitialFramedrop; ++i) {
asaperssonfab67072017-04-04 05:51:49 -07002315 video_source_.IncomingCapturedFrame(CreateFrame(i, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002316 ExpectDroppedFrame();
kthelgason2bc68642017-02-07 07:02:22 -08002317 }
2318 // The n+1th frame should not be dropped, even though it's size is too large.
asaperssonfab67072017-04-04 05:51:49 -07002319 video_source_.IncomingCapturedFrame(CreateFrame(i, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002320 WaitForEncodedFrame(i);
kthelgason2bc68642017-02-07 07:02:22 -08002321
2322 // Expect the sink_wants to specify a scaled frame.
asaperssonfab67072017-04-04 05:51:49 -07002323 EXPECT_LT(video_source_.sink_wants().max_pixel_count, kWidth * kHeight);
kthelgason2bc68642017-02-07 07:02:22 -08002324
mflodmancc3d4422017-08-03 08:27:51 -07002325 video_stream_encoder_->Stop();
kthelgason2bc68642017-02-07 07:02:22 -08002326}
2327
mflodmancc3d4422017-08-03 08:27:51 -07002328TEST_F(VideoStreamEncoderTest,
2329 InitialFrameDropOffWithMaintainResolutionPreference) {
asaperssonfab67072017-04-04 05:51:49 -07002330 const int kWidth = 640;
2331 const int kHeight = 360;
mflodmancc3d4422017-08-03 08:27:51 -07002332 video_stream_encoder_->OnBitrateUpdated(kLowTargetBitrateBps, 0, 0);
kthelgason2bc68642017-02-07 07:02:22 -08002333
2334 // Set degradation preference.
mflodmancc3d4422017-08-03 08:27:51 -07002335 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002336 &video_source_, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
kthelgason2bc68642017-02-07 07:02:22 -08002337
asaperssonfab67072017-04-04 05:51:49 -07002338 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
kthelgason2bc68642017-02-07 07:02:22 -08002339 // Frame should not be dropped, even if it's too large.
sprang4847ae62017-06-27 07:06:52 -07002340 WaitForEncodedFrame(1);
kthelgason2bc68642017-02-07 07:02:22 -08002341
mflodmancc3d4422017-08-03 08:27:51 -07002342 video_stream_encoder_->Stop();
kthelgason2bc68642017-02-07 07:02:22 -08002343}
2344
mflodmancc3d4422017-08-03 08:27:51 -07002345TEST_F(VideoStreamEncoderTest, InitialFrameDropOffWhenEncoderDisabledScaling) {
asaperssonfab67072017-04-04 05:51:49 -07002346 const int kWidth = 640;
2347 const int kHeight = 360;
kthelgasonad9010c2017-02-14 00:46:51 -08002348 fake_encoder_.SetQualityScaling(false);
Niels Möller4db138e2018-04-19 09:04:13 +02002349
2350 VideoEncoderConfig video_encoder_config;
2351 test::FillEncoderConfiguration(kVideoCodecVP8, 1, &video_encoder_config);
2352 // Make format different, to force recreation of encoder.
2353 video_encoder_config.video_format.parameters["foo"] = "foo";
2354 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
Niels Möllerf1338562018-04-26 09:51:47 +02002355 kMaxPayloadLength);
mflodmancc3d4422017-08-03 08:27:51 -07002356 video_stream_encoder_->OnBitrateUpdated(kLowTargetBitrateBps, 0, 0);
asapersson09f05612017-05-15 23:40:18 -07002357
kthelgasonb83797b2017-02-14 11:57:25 -08002358 // Force quality scaler reconfiguration by resetting the source.
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002359 video_stream_encoder_->SetSource(&video_source_,
2360 webrtc::DegradationPreference::BALANCED);
kthelgasonad9010c2017-02-14 00:46:51 -08002361
asaperssonfab67072017-04-04 05:51:49 -07002362 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
kthelgasonad9010c2017-02-14 00:46:51 -08002363 // Frame should not be dropped, even if it's too large.
sprang4847ae62017-06-27 07:06:52 -07002364 WaitForEncodedFrame(1);
kthelgasonad9010c2017-02-14 00:46:51 -08002365
mflodmancc3d4422017-08-03 08:27:51 -07002366 video_stream_encoder_->Stop();
kthelgasonad9010c2017-02-14 00:46:51 -08002367 fake_encoder_.SetQualityScaling(true);
2368}
2369
Kári Tristan Helgason639602a2018-08-02 10:51:40 +02002370TEST_F(VideoStreamEncoderTest, InitialFrameDropActivatesWhenBWEstimateReady) {
2371 webrtc::test::ScopedFieldTrials field_trials(
2372 "WebRTC-InitialFramedrop/Enabled/");
2373 // Reset encoder for field trials to take effect.
2374 ConfigureEncoder(video_encoder_config_.Copy());
2375 const int kTooLowBitrateForFrameSizeBps = 10000;
2376 const int kWidth = 640;
2377 const int kHeight = 360;
2378
2379 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
2380 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
2381 // Frame should not be dropped.
2382 WaitForEncodedFrame(1);
2383
2384 video_stream_encoder_->OnBitrateUpdated(kTooLowBitrateForFrameSizeBps, 0, 0);
2385 video_source_.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
2386 // Expect to drop this frame, the wait should time out.
2387 ExpectDroppedFrame();
2388
2389 // Expect the sink_wants to specify a scaled frame.
2390 EXPECT_LT(video_source_.sink_wants().max_pixel_count, kWidth * kHeight);
2391 video_stream_encoder_->Stop();
2392}
2393
mflodmancc3d4422017-08-03 08:27:51 -07002394TEST_F(VideoStreamEncoderTest,
asaperssond0de2952017-04-21 01:47:31 -07002395 ResolutionNotAdaptedForTooSmallFrame_MaintainFramerateMode) {
2396 const int kTooSmallWidth = 10;
2397 const int kTooSmallHeight = 10;
mflodmancc3d4422017-08-03 08:27:51 -07002398 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssond0de2952017-04-21 01:47:31 -07002399
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002400 // Enable MAINTAIN_FRAMERATE preference, no initial limitation.
asaperssond0de2952017-04-21 01:47:31 -07002401 test::FrameForwarder source;
mflodmancc3d4422017-08-03 08:27:51 -07002402 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002403 &source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
asaperssond0de2952017-04-21 01:47:31 -07002404 VerifyNoLimitation(source.sink_wants());
2405 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2406
2407 // Trigger adapt down, too small frame, expect no change.
2408 source.IncomingCapturedFrame(CreateFrame(1, kTooSmallWidth, kTooSmallHeight));
sprang4847ae62017-06-27 07:06:52 -07002409 WaitForEncodedFrame(1);
mflodmancc3d4422017-08-03 08:27:51 -07002410 video_stream_encoder_->TriggerCpuOveruse();
Åsa Persson8c1bf952018-09-13 10:42:19 +02002411 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssond0de2952017-04-21 01:47:31 -07002412 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2413 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2414
mflodmancc3d4422017-08-03 08:27:51 -07002415 video_stream_encoder_->Stop();
asaperssond0de2952017-04-21 01:47:31 -07002416}
2417
mflodmancc3d4422017-08-03 08:27:51 -07002418TEST_F(VideoStreamEncoderTest,
2419 ResolutionNotAdaptedForTooSmallFrame_BalancedMode) {
asaperssonf7e294d2017-06-13 23:25:22 -07002420 const int kTooSmallWidth = 10;
2421 const int kTooSmallHeight = 10;
2422 const int kFpsLimit = 7;
mflodmancc3d4422017-08-03 08:27:51 -07002423 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -07002424
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002425 // Enable BALANCED preference, no initial limitation.
asaperssonf7e294d2017-06-13 23:25:22 -07002426 test::FrameForwarder source;
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002427 video_stream_encoder_->SetSource(&source,
2428 webrtc::DegradationPreference::BALANCED);
asaperssonf7e294d2017-06-13 23:25:22 -07002429 VerifyNoLimitation(source.sink_wants());
2430 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2431 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2432
2433 // Trigger adapt down, expect limited framerate.
2434 source.IncomingCapturedFrame(CreateFrame(1, kTooSmallWidth, kTooSmallHeight));
sprang4847ae62017-06-27 07:06:52 -07002435 WaitForEncodedFrame(1);
mflodmancc3d4422017-08-03 08:27:51 -07002436 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002437 VerifyFpsEqResolutionMax(source.sink_wants(), kFpsLimit);
2438 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2439 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2440 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2441
2442 // Trigger adapt down, too small frame, expect no change.
2443 source.IncomingCapturedFrame(CreateFrame(2, kTooSmallWidth, kTooSmallHeight));
sprang4847ae62017-06-27 07:06:52 -07002444 WaitForEncodedFrame(2);
mflodmancc3d4422017-08-03 08:27:51 -07002445 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002446 VerifyFpsEqResolutionMax(source.sink_wants(), kFpsLimit);
2447 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2448 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2449 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2450
mflodmancc3d4422017-08-03 08:27:51 -07002451 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07002452}
2453
mflodmancc3d4422017-08-03 08:27:51 -07002454TEST_F(VideoStreamEncoderTest, FailingInitEncodeDoesntCauseCrash) {
asapersson02465b82017-04-10 01:12:52 -07002455 fake_encoder_.ForceInitEncodeFailure(true);
mflodmancc3d4422017-08-03 08:27:51 -07002456 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
Niels Möllerf1338562018-04-26 09:51:47 +02002457 ResetEncoder("VP8", 2, 1, 1, false);
asapersson02465b82017-04-10 01:12:52 -07002458 const int kFrameWidth = 1280;
2459 const int kFrameHeight = 720;
2460 video_source_.IncomingCapturedFrame(
2461 CreateFrame(1, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002462 ExpectDroppedFrame();
mflodmancc3d4422017-08-03 08:27:51 -07002463 video_stream_encoder_->Stop();
asapersson02465b82017-04-10 01:12:52 -07002464}
2465
sprangb1ca0732017-02-01 08:38:12 -08002466// TODO(sprang): Extend this with fps throttling and any "balanced" extensions.
mflodmancc3d4422017-08-03 08:27:51 -07002467TEST_F(VideoStreamEncoderTest,
2468 AdaptsResolutionOnOveruse_MaintainFramerateMode) {
2469 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
sprangb1ca0732017-02-01 08:38:12 -08002470
2471 const int kFrameWidth = 1280;
2472 const int kFrameHeight = 720;
2473 // Enabled default VideoAdapter downscaling. First step is 3/4, not 3/5 as
mflodmancc3d4422017-08-03 08:27:51 -07002474 // requested by
2475 // VideoStreamEncoder::VideoSourceProxy::RequestResolutionLowerThan().
sprangb1ca0732017-02-01 08:38:12 -08002476 video_source_.set_adaptation_enabled(true);
2477
2478 video_source_.IncomingCapturedFrame(
Åsa Persson8c1bf952018-09-13 10:42:19 +02002479 CreateFrame(1 * kFrameIntervalMs, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002480 WaitForEncodedFrame(kFrameWidth, kFrameHeight);
sprangb1ca0732017-02-01 08:38:12 -08002481
2482 // Trigger CPU overuse, downscale by 3/4.
mflodmancc3d4422017-08-03 08:27:51 -07002483 video_stream_encoder_->TriggerCpuOveruse();
sprangb1ca0732017-02-01 08:38:12 -08002484 video_source_.IncomingCapturedFrame(
Åsa Persson8c1bf952018-09-13 10:42:19 +02002485 CreateFrame(2 * kFrameIntervalMs, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002486 WaitForEncodedFrame((kFrameWidth * 3) / 4, (kFrameHeight * 3) / 4);
sprangb1ca0732017-02-01 08:38:12 -08002487
asaperssonfab67072017-04-04 05:51:49 -07002488 // Trigger CPU normal use, return to original resolution.
mflodmancc3d4422017-08-03 08:27:51 -07002489 video_stream_encoder_->TriggerCpuNormalUsage();
sprangb1ca0732017-02-01 08:38:12 -08002490 video_source_.IncomingCapturedFrame(
Åsa Persson8c1bf952018-09-13 10:42:19 +02002491 CreateFrame(3 * kFrameIntervalMs, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002492 WaitForEncodedFrame(kFrameWidth, kFrameHeight);
sprangb1ca0732017-02-01 08:38:12 -08002493
mflodmancc3d4422017-08-03 08:27:51 -07002494 video_stream_encoder_->Stop();
sprangb1ca0732017-02-01 08:38:12 -08002495}
sprangfe627f32017-03-29 08:24:59 -07002496
mflodmancc3d4422017-08-03 08:27:51 -07002497TEST_F(VideoStreamEncoderTest,
2498 AdaptsFramerateOnOveruse_MaintainResolutionMode) {
sprangc5d62e22017-04-02 23:53:04 -07002499 const int kFrameWidth = 1280;
2500 const int kFrameHeight = 720;
sprangc5d62e22017-04-02 23:53:04 -07002501
mflodmancc3d4422017-08-03 08:27:51 -07002502 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
2503 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002504 &video_source_, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
sprangc5d62e22017-04-02 23:53:04 -07002505 video_source_.set_adaptation_enabled(true);
2506
sprang4847ae62017-06-27 07:06:52 -07002507 int64_t timestamp_ms = fake_clock_.TimeNanos() / rtc::kNumNanosecsPerMillisec;
sprangc5d62e22017-04-02 23:53:04 -07002508
2509 video_source_.IncomingCapturedFrame(
2510 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002511 WaitForEncodedFrame(timestamp_ms);
sprangc5d62e22017-04-02 23:53:04 -07002512
2513 // Try to trigger overuse. No fps estimate available => no effect.
mflodmancc3d4422017-08-03 08:27:51 -07002514 video_stream_encoder_->TriggerCpuOveruse();
sprangc5d62e22017-04-02 23:53:04 -07002515
2516 // Insert frames for one second to get a stable estimate.
sprang4847ae62017-06-27 07:06:52 -07002517 for (int i = 0; i < max_framerate_; ++i) {
sprangc5d62e22017-04-02 23:53:04 -07002518 timestamp_ms += kFrameIntervalMs;
sprangc5d62e22017-04-02 23:53:04 -07002519 video_source_.IncomingCapturedFrame(
2520 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002521 WaitForEncodedFrame(timestamp_ms);
sprangc5d62e22017-04-02 23:53:04 -07002522 }
2523
2524 // Trigger CPU overuse, reduce framerate by 2/3.
mflodmancc3d4422017-08-03 08:27:51 -07002525 video_stream_encoder_->TriggerCpuOveruse();
sprangc5d62e22017-04-02 23:53:04 -07002526 int num_frames_dropped = 0;
sprang4847ae62017-06-27 07:06:52 -07002527 for (int i = 0; i < max_framerate_; ++i) {
sprangc5d62e22017-04-02 23:53:04 -07002528 timestamp_ms += kFrameIntervalMs;
sprangc5d62e22017-04-02 23:53:04 -07002529 video_source_.IncomingCapturedFrame(
2530 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002531 if (!WaitForFrame(kFrameTimeoutMs)) {
sprangc5d62e22017-04-02 23:53:04 -07002532 ++num_frames_dropped;
2533 } else {
Åsa Perssonc74d8da2017-12-04 14:13:56 +01002534 sink_.CheckLastFrameSizeMatches(kFrameWidth, kFrameHeight);
sprangc5d62e22017-04-02 23:53:04 -07002535 }
2536 }
2537
sprang4847ae62017-06-27 07:06:52 -07002538 // Add some slack to account for frames dropped by the frame dropper.
2539 const int kErrorMargin = 1;
2540 EXPECT_NEAR(num_frames_dropped, max_framerate_ - (max_framerate_ * 2 / 3),
sprangc5d62e22017-04-02 23:53:04 -07002541 kErrorMargin);
2542
2543 // Trigger CPU overuse, reduce framerate by 2/3 again.
mflodmancc3d4422017-08-03 08:27:51 -07002544 video_stream_encoder_->TriggerCpuOveruse();
sprangc5d62e22017-04-02 23:53:04 -07002545 num_frames_dropped = 0;
Åsa Persson8c1bf952018-09-13 10:42:19 +02002546 for (int i = 0; i <= max_framerate_; ++i) {
sprangc5d62e22017-04-02 23:53:04 -07002547 timestamp_ms += kFrameIntervalMs;
sprangc5d62e22017-04-02 23:53:04 -07002548 video_source_.IncomingCapturedFrame(
2549 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002550 if (!WaitForFrame(kFrameTimeoutMs)) {
sprangc5d62e22017-04-02 23:53:04 -07002551 ++num_frames_dropped;
2552 } else {
Åsa Perssonc74d8da2017-12-04 14:13:56 +01002553 sink_.CheckLastFrameSizeMatches(kFrameWidth, kFrameHeight);
sprangc5d62e22017-04-02 23:53:04 -07002554 }
2555 }
sprang4847ae62017-06-27 07:06:52 -07002556 EXPECT_NEAR(num_frames_dropped, max_framerate_ - (max_framerate_ * 4 / 9),
sprangc5d62e22017-04-02 23:53:04 -07002557 kErrorMargin);
2558
2559 // Go back up one step.
mflodmancc3d4422017-08-03 08:27:51 -07002560 video_stream_encoder_->TriggerCpuNormalUsage();
sprangc5d62e22017-04-02 23:53:04 -07002561 num_frames_dropped = 0;
sprang4847ae62017-06-27 07:06:52 -07002562 for (int i = 0; i < max_framerate_; ++i) {
sprangc5d62e22017-04-02 23:53:04 -07002563 timestamp_ms += kFrameIntervalMs;
sprangc5d62e22017-04-02 23:53:04 -07002564 video_source_.IncomingCapturedFrame(
2565 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002566 if (!WaitForFrame(kFrameTimeoutMs)) {
sprangc5d62e22017-04-02 23:53:04 -07002567 ++num_frames_dropped;
2568 } else {
Åsa Perssonc74d8da2017-12-04 14:13:56 +01002569 sink_.CheckLastFrameSizeMatches(kFrameWidth, kFrameHeight);
sprangc5d62e22017-04-02 23:53:04 -07002570 }
2571 }
sprang4847ae62017-06-27 07:06:52 -07002572 EXPECT_NEAR(num_frames_dropped, max_framerate_ - (max_framerate_ * 2 / 3),
sprangc5d62e22017-04-02 23:53:04 -07002573 kErrorMargin);
2574
2575 // Go back up to original mode.
mflodmancc3d4422017-08-03 08:27:51 -07002576 video_stream_encoder_->TriggerCpuNormalUsage();
sprangc5d62e22017-04-02 23:53:04 -07002577 num_frames_dropped = 0;
sprang4847ae62017-06-27 07:06:52 -07002578 for (int i = 0; i < max_framerate_; ++i) {
sprangc5d62e22017-04-02 23:53:04 -07002579 timestamp_ms += kFrameIntervalMs;
sprangc5d62e22017-04-02 23:53:04 -07002580 video_source_.IncomingCapturedFrame(
2581 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002582 if (!WaitForFrame(kFrameTimeoutMs)) {
sprangc5d62e22017-04-02 23:53:04 -07002583 ++num_frames_dropped;
2584 } else {
Åsa Perssonc74d8da2017-12-04 14:13:56 +01002585 sink_.CheckLastFrameSizeMatches(kFrameWidth, kFrameHeight);
sprangc5d62e22017-04-02 23:53:04 -07002586 }
2587 }
2588 EXPECT_NEAR(num_frames_dropped, 0, kErrorMargin);
2589
mflodmancc3d4422017-08-03 08:27:51 -07002590 video_stream_encoder_->Stop();
sprangc5d62e22017-04-02 23:53:04 -07002591}
2592
mflodmancc3d4422017-08-03 08:27:51 -07002593TEST_F(VideoStreamEncoderTest, DoesntAdaptDownPastMinFramerate) {
sprangc5d62e22017-04-02 23:53:04 -07002594 const int kFramerateFps = 5;
2595 const int kFrameIntervalMs = rtc::kNumMillisecsPerSec / kFramerateFps;
sprangc5d62e22017-04-02 23:53:04 -07002596 const int kFrameWidth = 1280;
2597 const int kFrameHeight = 720;
2598
sprang4847ae62017-06-27 07:06:52 -07002599 // Reconfigure encoder with two temporal layers and screensharing, which will
2600 // disable frame dropping and make testing easier.
Niels Möllerf1338562018-04-26 09:51:47 +02002601 ResetEncoder("VP8", 1, 2, 1, true);
sprang4847ae62017-06-27 07:06:52 -07002602
mflodmancc3d4422017-08-03 08:27:51 -07002603 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
2604 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002605 &video_source_, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
sprangc5d62e22017-04-02 23:53:04 -07002606 video_source_.set_adaptation_enabled(true);
2607
sprang4847ae62017-06-27 07:06:52 -07002608 int64_t timestamp_ms = fake_clock_.TimeNanos() / rtc::kNumNanosecsPerMillisec;
sprangc5d62e22017-04-02 23:53:04 -07002609
2610 // Trigger overuse as much as we can.
Jonathan Yubc771b72017-12-08 17:04:29 -08002611 rtc::VideoSinkWants last_wants;
2612 do {
2613 last_wants = video_source_.sink_wants();
2614
sprangc5d62e22017-04-02 23:53:04 -07002615 // Insert frames to get a new fps estimate...
2616 for (int j = 0; j < kFramerateFps; ++j) {
2617 video_source_.IncomingCapturedFrame(
2618 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
Jonathan Yubc771b72017-12-08 17:04:29 -08002619 if (video_source_.last_sent_width()) {
2620 sink_.WaitForEncodedFrame(timestamp_ms);
2621 }
sprangc5d62e22017-04-02 23:53:04 -07002622 timestamp_ms += kFrameIntervalMs;
Yves Gerey665174f2018-06-19 15:03:05 +02002623 fake_clock_.AdvanceTimeMicros(kFrameIntervalMs *
2624 rtc::kNumMicrosecsPerMillisec);
sprangc5d62e22017-04-02 23:53:04 -07002625 }
2626 // ...and then try to adapt again.
mflodmancc3d4422017-08-03 08:27:51 -07002627 video_stream_encoder_->TriggerCpuOveruse();
Jonathan Yubc771b72017-12-08 17:04:29 -08002628 } while (video_source_.sink_wants().max_framerate_fps <
2629 last_wants.max_framerate_fps);
sprangc5d62e22017-04-02 23:53:04 -07002630
Jonathan Yubc771b72017-12-08 17:04:29 -08002631 VerifyFpsEqResolutionMax(video_source_.sink_wants(), kMinFramerateFps);
asaperssonf7e294d2017-06-13 23:25:22 -07002632
mflodmancc3d4422017-08-03 08:27:51 -07002633 video_stream_encoder_->Stop();
sprangc5d62e22017-04-02 23:53:04 -07002634}
asaperssonf7e294d2017-06-13 23:25:22 -07002635
mflodmancc3d4422017-08-03 08:27:51 -07002636TEST_F(VideoStreamEncoderTest,
2637 AdaptsResolutionAndFramerateForLowQuality_BalancedMode) {
asaperssonf7e294d2017-06-13 23:25:22 -07002638 const int kWidth = 1280;
2639 const int kHeight = 720;
2640 const int64_t kFrameIntervalMs = 150;
2641 int64_t timestamp_ms = kFrameIntervalMs;
mflodmancc3d4422017-08-03 08:27:51 -07002642 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -07002643
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002644 // Enable BALANCED preference, no initial limitation.
asaperssonf7e294d2017-06-13 23:25:22 -07002645 AdaptingFrameForwarder source;
2646 source.set_adaptation_enabled(true);
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002647 video_stream_encoder_->SetSource(&source,
2648 webrtc::DegradationPreference::BALANCED);
asaperssonf7e294d2017-06-13 23:25:22 -07002649 timestamp_ms += kFrameIntervalMs;
2650 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002651 WaitForEncodedFrame(kWidth, kHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +02002652 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07002653 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2654 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2655 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2656
2657 // Trigger adapt down, expect scaled down resolution (960x540@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002658 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002659 timestamp_ms += kFrameIntervalMs;
2660 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002661 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002662 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
2663 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2664 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2665 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2666
2667 // Trigger adapt down, expect scaled down resolution (640x360@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002668 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002669 timestamp_ms += kFrameIntervalMs;
2670 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002671 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002672 VerifyFpsMaxResolutionLt(source.sink_wants(), source.last_wants());
2673 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2674 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2675 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2676
2677 // Trigger adapt down, expect reduced fps (640x360@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07002678 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002679 timestamp_ms += kFrameIntervalMs;
2680 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002681 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002682 VerifyFpsLtResolutionEq(source.sink_wants(), source.last_wants());
2683 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2684 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2685 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2686
2687 // Trigger adapt down, expect scaled down resolution (480x270@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07002688 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002689 timestamp_ms += kFrameIntervalMs;
2690 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002691 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002692 VerifyFpsEqResolutionLt(source.sink_wants(), source.last_wants());
2693 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2694 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2695 EXPECT_EQ(4, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2696
2697 // Restrict bitrate, trigger adapt down, expect reduced fps (480x270@10fps).
mflodmancc3d4422017-08-03 08:27:51 -07002698 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002699 timestamp_ms += kFrameIntervalMs;
2700 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002701 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002702 VerifyFpsLtResolutionEq(source.sink_wants(), source.last_wants());
2703 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2704 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2705 EXPECT_EQ(5, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2706
2707 // Trigger adapt down, expect scaled down resolution (320x180@10fps).
mflodmancc3d4422017-08-03 08:27:51 -07002708 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002709 timestamp_ms += kFrameIntervalMs;
2710 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002711 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002712 VerifyFpsEqResolutionLt(source.sink_wants(), source.last_wants());
2713 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2714 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2715 EXPECT_EQ(6, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2716
2717 // Trigger adapt down, expect reduced fps (320x180@7fps).
mflodmancc3d4422017-08-03 08:27:51 -07002718 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002719 timestamp_ms += kFrameIntervalMs;
2720 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002721 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002722 VerifyFpsLtResolutionEq(source.sink_wants(), source.last_wants());
2723 rtc::VideoSinkWants last_wants = source.sink_wants();
2724 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2725 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2726 EXPECT_EQ(7, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2727
2728 // Trigger adapt down, min resolution reached, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07002729 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002730 timestamp_ms += kFrameIntervalMs;
2731 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002732 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002733 VerifyFpsEqResolutionEq(source.sink_wants(), last_wants);
2734 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2735 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2736 EXPECT_EQ(7, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2737
2738 // Trigger adapt down, expect expect increased fps (320x180@10fps).
mflodmancc3d4422017-08-03 08:27:51 -07002739 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002740 timestamp_ms += kFrameIntervalMs;
2741 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002742 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002743 VerifyFpsGtResolutionEq(source.sink_wants(), source.last_wants());
2744 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2745 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2746 EXPECT_EQ(8, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2747
2748 // Trigger adapt up, expect upscaled resolution (480x270@10fps).
mflodmancc3d4422017-08-03 08:27:51 -07002749 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002750 timestamp_ms += kFrameIntervalMs;
2751 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002752 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002753 VerifyFpsEqResolutionGt(source.sink_wants(), source.last_wants());
2754 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2755 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2756 EXPECT_EQ(9, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2757
2758 // Increase bitrate, trigger adapt up, expect increased fps (480x270@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07002759 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002760 timestamp_ms += kFrameIntervalMs;
2761 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002762 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002763 VerifyFpsGtResolutionEq(source.sink_wants(), source.last_wants());
2764 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2765 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2766 EXPECT_EQ(10, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2767
2768 // Trigger adapt up, expect upscaled resolution (640x360@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07002769 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002770 timestamp_ms += kFrameIntervalMs;
2771 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002772 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002773 VerifyFpsEqResolutionGt(source.sink_wants(), source.last_wants());
2774 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2775 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2776 EXPECT_EQ(11, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2777
2778 // Trigger adapt up, expect increased fps (640x360@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002779 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002780 timestamp_ms += kFrameIntervalMs;
2781 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002782 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002783 VerifyFpsMaxResolutionEq(source.sink_wants(), source.last_wants());
2784 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2785 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2786 EXPECT_EQ(12, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2787
2788 // Trigger adapt up, expect upscaled resolution (960x540@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002789 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002790 timestamp_ms += kFrameIntervalMs;
2791 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002792 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002793 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
2794 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2795 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2796 EXPECT_EQ(13, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2797
2798 // Trigger adapt up, expect no restriction (1280x720fps@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002799 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002800 timestamp_ms += kFrameIntervalMs;
2801 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002802 WaitForEncodedFrame(kWidth, kHeight);
asaperssonf7e294d2017-06-13 23:25:22 -07002803 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
Åsa Persson8c1bf952018-09-13 10:42:19 +02002804 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07002805 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2806 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2807 EXPECT_EQ(14, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2808
2809 // Trigger adapt up, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07002810 video_stream_encoder_->TriggerQualityHigh();
Åsa Persson8c1bf952018-09-13 10:42:19 +02002811 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07002812 EXPECT_EQ(14, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2813
mflodmancc3d4422017-08-03 08:27:51 -07002814 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07002815}
2816
mflodmancc3d4422017-08-03 08:27:51 -07002817TEST_F(VideoStreamEncoderTest, AdaptWithTwoReasonsAndDifferentOrder_Framerate) {
asaperssonf7e294d2017-06-13 23:25:22 -07002818 const int kWidth = 1280;
2819 const int kHeight = 720;
2820 const int64_t kFrameIntervalMs = 150;
2821 int64_t timestamp_ms = kFrameIntervalMs;
mflodmancc3d4422017-08-03 08:27:51 -07002822 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -07002823
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002824 // Enable BALANCED preference, no initial limitation.
asaperssonf7e294d2017-06-13 23:25:22 -07002825 AdaptingFrameForwarder source;
2826 source.set_adaptation_enabled(true);
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002827 video_stream_encoder_->SetSource(&source,
2828 webrtc::DegradationPreference::BALANCED);
asaperssonf7e294d2017-06-13 23:25:22 -07002829 timestamp_ms += kFrameIntervalMs;
2830 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002831 WaitForEncodedFrame(kWidth, kHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +02002832 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07002833 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2834 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2835 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2836 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
2837 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2838 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2839
2840 // Trigger cpu adapt down, expect scaled down resolution (960x540@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002841 video_stream_encoder_->TriggerCpuOveruse();
asaperssonf7e294d2017-06-13 23:25:22 -07002842 timestamp_ms += kFrameIntervalMs;
2843 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002844 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002845 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
2846 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2847 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2848 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2849 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
2850 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2851 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2852
2853 // Trigger cpu adapt down, expect scaled down resolution (640x360@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002854 video_stream_encoder_->TriggerCpuOveruse();
asaperssonf7e294d2017-06-13 23:25:22 -07002855 timestamp_ms += kFrameIntervalMs;
2856 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002857 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002858 VerifyFpsMaxResolutionLt(source.sink_wants(), source.last_wants());
2859 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2860 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2861 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2862 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
2863 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2864 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2865
2866 // Trigger quality adapt down, expect reduced fps (640x360@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07002867 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002868 timestamp_ms += kFrameIntervalMs;
2869 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002870 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002871 VerifyFpsLtResolutionEq(source.sink_wants(), source.last_wants());
2872 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2873 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2874 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2875 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
2876 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2877 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2878
2879 // Trigger cpu adapt up, expect increased fps (640x360@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002880 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssonf7e294d2017-06-13 23:25:22 -07002881 timestamp_ms += kFrameIntervalMs;
2882 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002883 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002884 VerifyFpsMaxResolutionEq(source.sink_wants(), source.last_wants());
2885 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2886 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2887 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2888 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
2889 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2890 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2891
2892 // Trigger quality adapt up, expect upscaled resolution (960x540@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002893 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002894 timestamp_ms += kFrameIntervalMs;
2895 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002896 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002897 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
2898 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2899 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2900 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2901 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
2902 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2903 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2904
2905 // Trigger cpu adapt up, expect no restriction (1280x720fps@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002906 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssonf7e294d2017-06-13 23:25:22 -07002907 timestamp_ms += kFrameIntervalMs;
2908 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002909 WaitForEncodedFrame(kWidth, kHeight);
asaperssonf7e294d2017-06-13 23:25:22 -07002910 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
Åsa Persson8c1bf952018-09-13 10:42:19 +02002911 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07002912 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2913 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2914 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2915 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
2916 EXPECT_EQ(4, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2917 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2918
2919 // Trigger adapt up, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07002920 video_stream_encoder_->TriggerQualityHigh();
Åsa Persson8c1bf952018-09-13 10:42:19 +02002921 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07002922 EXPECT_EQ(4, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2923 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2924
mflodmancc3d4422017-08-03 08:27:51 -07002925 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07002926}
2927
mflodmancc3d4422017-08-03 08:27:51 -07002928TEST_F(VideoStreamEncoderTest,
2929 AdaptWithTwoReasonsAndDifferentOrder_Resolution) {
asaperssonf7e294d2017-06-13 23:25:22 -07002930 const int kWidth = 640;
2931 const int kHeight = 360;
2932 const int kFpsLimit = 15;
2933 const int64_t kFrameIntervalMs = 150;
2934 int64_t timestamp_ms = kFrameIntervalMs;
mflodmancc3d4422017-08-03 08:27:51 -07002935 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -07002936
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002937 // Enable BALANCED preference, no initial limitation.
asaperssonf7e294d2017-06-13 23:25:22 -07002938 AdaptingFrameForwarder source;
2939 source.set_adaptation_enabled(true);
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002940 video_stream_encoder_->SetSource(&source,
2941 webrtc::DegradationPreference::BALANCED);
asaperssonf7e294d2017-06-13 23:25:22 -07002942 timestamp_ms += kFrameIntervalMs;
2943 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002944 WaitForEncodedFrame(kWidth, kHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +02002945 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07002946 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2947 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2948 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2949 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
2950 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2951 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2952
2953 // Trigger cpu adapt down, expect scaled down framerate (640x360@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07002954 video_stream_encoder_->TriggerCpuOveruse();
asaperssonf7e294d2017-06-13 23:25:22 -07002955 timestamp_ms += kFrameIntervalMs;
2956 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002957 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002958 VerifyFpsEqResolutionMax(source.sink_wants(), kFpsLimit);
2959 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2960 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2961 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2962 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_framerate);
2963 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2964 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2965
2966 // Trigger quality adapt down, expect scaled down resolution (480x270@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07002967 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002968 timestamp_ms += kFrameIntervalMs;
2969 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002970 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002971 VerifyFpsEqResolutionLt(source.sink_wants(), source.last_wants());
2972 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2973 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2974 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2975 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_framerate);
2976 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2977 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2978
2979 // Trigger cpu adapt up, expect upscaled resolution (640x360@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07002980 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssonf7e294d2017-06-13 23:25:22 -07002981 timestamp_ms += kFrameIntervalMs;
2982 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002983 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002984 VerifyFpsEqResolutionGt(source.sink_wants(), source.last_wants());
2985 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2986 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2987 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2988 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
2989 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2990 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2991
2992 // Trigger quality adapt up, expect increased fps (640x360@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002993 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002994 timestamp_ms += kFrameIntervalMs;
2995 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002996 WaitForEncodedFrame(timestamp_ms);
Åsa Persson8c1bf952018-09-13 10:42:19 +02002997 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07002998 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2999 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
3000 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
3001 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
3002 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
3003 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3004
3005 // Trigger adapt up, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07003006 video_stream_encoder_->TriggerQualityHigh();
Åsa Persson8c1bf952018-09-13 10:42:19 +02003007 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07003008 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
3009 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3010
mflodmancc3d4422017-08-03 08:27:51 -07003011 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07003012}
3013
mflodmancc3d4422017-08-03 08:27:51 -07003014TEST_F(VideoStreamEncoderTest, AcceptsFullHdAdaptedDownSimulcastFrames) {
ilnik6b826ef2017-06-16 06:53:48 -07003015 // Simulates simulcast behavior and makes highest stream resolutions divisible
3016 // by 4.
3017 class CroppingVideoStreamFactory
3018 : public VideoEncoderConfig::VideoStreamFactoryInterface {
3019 public:
3020 explicit CroppingVideoStreamFactory(size_t num_temporal_layers,
3021 int framerate)
3022 : num_temporal_layers_(num_temporal_layers), framerate_(framerate) {
3023 EXPECT_GT(num_temporal_layers, 0u);
3024 EXPECT_GT(framerate, 0);
3025 }
3026
3027 private:
3028 std::vector<VideoStream> CreateEncoderStreams(
3029 int width,
3030 int height,
3031 const VideoEncoderConfig& encoder_config) override {
Yves Gerey665174f2018-06-19 15:03:05 +02003032 std::vector<VideoStream> streams = test::CreateVideoStreams(
3033 width - width % 4, height - height % 4, encoder_config);
ilnik6b826ef2017-06-16 06:53:48 -07003034 for (VideoStream& stream : streams) {
Sergey Silkina796a7e2018-03-01 15:11:29 +01003035 stream.num_temporal_layers = num_temporal_layers_;
ilnik6b826ef2017-06-16 06:53:48 -07003036 stream.max_framerate = framerate_;
3037 }
3038 return streams;
3039 }
3040
3041 const size_t num_temporal_layers_;
3042 const int framerate_;
3043 };
3044
3045 const int kFrameWidth = 1920;
3046 const int kFrameHeight = 1080;
3047 // 3/4 of 1920.
3048 const int kAdaptedFrameWidth = 1440;
3049 // 3/4 of 1080 rounded down to multiple of 4.
3050 const int kAdaptedFrameHeight = 808;
3051 const int kFramerate = 24;
3052
mflodmancc3d4422017-08-03 08:27:51 -07003053 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
ilnik6b826ef2017-06-16 06:53:48 -07003054 // Trigger reconfigure encoder (without resetting the entire instance).
3055 VideoEncoderConfig video_encoder_config;
Niels Möller259a4972018-04-05 15:36:51 +02003056 video_encoder_config.codec_type = kVideoCodecVP8;
ilnik6b826ef2017-06-16 06:53:48 -07003057 video_encoder_config.max_bitrate_bps = kTargetBitrateBps;
3058 video_encoder_config.number_of_streams = 1;
3059 video_encoder_config.video_stream_factory =
3060 new rtc::RefCountedObject<CroppingVideoStreamFactory>(1, kFramerate);
mflodmancc3d4422017-08-03 08:27:51 -07003061 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
Niels Möllerf1338562018-04-26 09:51:47 +02003062 kMaxPayloadLength);
mflodmancc3d4422017-08-03 08:27:51 -07003063 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
ilnik6b826ef2017-06-16 06:53:48 -07003064
3065 video_source_.set_adaptation_enabled(true);
3066
3067 video_source_.IncomingCapturedFrame(
3068 CreateFrame(1, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07003069 WaitForEncodedFrame(kFrameWidth, kFrameHeight);
ilnik6b826ef2017-06-16 06:53:48 -07003070
3071 // Trigger CPU overuse, downscale by 3/4.
mflodmancc3d4422017-08-03 08:27:51 -07003072 video_stream_encoder_->TriggerCpuOveruse();
ilnik6b826ef2017-06-16 06:53:48 -07003073 video_source_.IncomingCapturedFrame(
3074 CreateFrame(2, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07003075 WaitForEncodedFrame(kAdaptedFrameWidth, kAdaptedFrameHeight);
ilnik6b826ef2017-06-16 06:53:48 -07003076
mflodmancc3d4422017-08-03 08:27:51 -07003077 video_stream_encoder_->Stop();
ilnik6b826ef2017-06-16 06:53:48 -07003078}
3079
mflodmancc3d4422017-08-03 08:27:51 -07003080TEST_F(VideoStreamEncoderTest, PeriodicallyUpdatesChannelParameters) {
sprang4847ae62017-06-27 07:06:52 -07003081 const int kFrameWidth = 1280;
3082 const int kFrameHeight = 720;
3083 const int kLowFps = 2;
3084 const int kHighFps = 30;
3085
mflodmancc3d4422017-08-03 08:27:51 -07003086 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
sprang4847ae62017-06-27 07:06:52 -07003087
3088 int64_t timestamp_ms = fake_clock_.TimeNanos() / rtc::kNumNanosecsPerMillisec;
3089 max_framerate_ = kLowFps;
3090
3091 // Insert 2 seconds of 2fps video.
3092 for (int i = 0; i < kLowFps * 2; ++i) {
3093 video_source_.IncomingCapturedFrame(
3094 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
3095 WaitForEncodedFrame(timestamp_ms);
3096 timestamp_ms += 1000 / kLowFps;
3097 }
3098
3099 // Make sure encoder is updated with new target.
mflodmancc3d4422017-08-03 08:27:51 -07003100 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
sprang4847ae62017-06-27 07:06:52 -07003101 video_source_.IncomingCapturedFrame(
3102 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
3103 WaitForEncodedFrame(timestamp_ms);
3104 timestamp_ms += 1000 / kLowFps;
3105
3106 EXPECT_EQ(kLowFps, fake_encoder_.GetConfiguredInputFramerate());
3107
3108 // Insert 30fps frames for just a little more than the forced update period.
3109 const int kVcmTimerIntervalFrames =
3110 (vcm::VCMProcessTimer::kDefaultProcessIntervalMs * kHighFps) / 1000;
3111 const int kFrameIntervalMs = 1000 / kHighFps;
3112 max_framerate_ = kHighFps;
3113 for (int i = 0; i < kVcmTimerIntervalFrames + 2; ++i) {
3114 video_source_.IncomingCapturedFrame(
3115 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
3116 // Wait for encoded frame, but skip ahead if it doesn't arrive as it might
3117 // be dropped if the encoder hans't been updated with the new higher target
3118 // framerate yet, causing it to overshoot the target bitrate and then
3119 // suffering the wrath of the media optimizer.
3120 TimedWaitForEncodedFrame(timestamp_ms, 2 * kFrameIntervalMs);
3121 timestamp_ms += kFrameIntervalMs;
3122 }
3123
3124 // Don expect correct measurement just yet, but it should be higher than
3125 // before.
3126 EXPECT_GT(fake_encoder_.GetConfiguredInputFramerate(), kLowFps);
3127
mflodmancc3d4422017-08-03 08:27:51 -07003128 video_stream_encoder_->Stop();
sprang4847ae62017-06-27 07:06:52 -07003129}
3130
mflodmancc3d4422017-08-03 08:27:51 -07003131TEST_F(VideoStreamEncoderTest, DoesNotUpdateBitrateAllocationWhenSuspended) {
sprang4847ae62017-06-27 07:06:52 -07003132 const int kFrameWidth = 1280;
3133 const int kFrameHeight = 720;
3134 const int kTargetBitrateBps = 1000000;
3135
3136 MockBitrateObserver bitrate_observer;
Niels Möller0327c2d2018-05-21 14:09:31 +02003137 video_stream_encoder_->SetBitrateAllocationObserver(&bitrate_observer);
sprang4847ae62017-06-27 07:06:52 -07003138
3139 EXPECT_CALL(bitrate_observer, OnBitrateAllocationUpdated(_)).Times(1);
3140 // Initial bitrate update.
mflodmancc3d4422017-08-03 08:27:51 -07003141 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
3142 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
sprang4847ae62017-06-27 07:06:52 -07003143
3144 // Insert a first video frame, causes another bitrate update.
3145 int64_t timestamp_ms = fake_clock_.TimeNanos() / rtc::kNumNanosecsPerMillisec;
3146 EXPECT_CALL(bitrate_observer, OnBitrateAllocationUpdated(_)).Times(1);
3147 video_source_.IncomingCapturedFrame(
3148 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
3149 WaitForEncodedFrame(timestamp_ms);
3150
3151 // Next, simulate video suspension due to pacer queue overrun.
mflodmancc3d4422017-08-03 08:27:51 -07003152 video_stream_encoder_->OnBitrateUpdated(0, 0, 1);
sprang4847ae62017-06-27 07:06:52 -07003153
3154 // Skip ahead until a new periodic parameter update should have occured.
3155 timestamp_ms += vcm::VCMProcessTimer::kDefaultProcessIntervalMs;
3156 fake_clock_.AdvanceTimeMicros(
3157 vcm::VCMProcessTimer::kDefaultProcessIntervalMs *
3158 rtc::kNumMicrosecsPerMillisec);
3159
3160 // Bitrate observer should not be called.
3161 EXPECT_CALL(bitrate_observer, OnBitrateAllocationUpdated(_)).Times(0);
3162 video_source_.IncomingCapturedFrame(
3163 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
3164 ExpectDroppedFrame();
3165
mflodmancc3d4422017-08-03 08:27:51 -07003166 video_stream_encoder_->Stop();
sprang4847ae62017-06-27 07:06:52 -07003167}
ilnik6b826ef2017-06-16 06:53:48 -07003168
Niels Möller4db138e2018-04-19 09:04:13 +02003169TEST_F(VideoStreamEncoderTest,
3170 DefaultCpuAdaptationThresholdsForSoftwareEncoder) {
3171 const int kFrameWidth = 1280;
3172 const int kFrameHeight = 720;
3173 const CpuOveruseOptions default_options;
3174 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
3175 video_source_.IncomingCapturedFrame(
3176 CreateFrame(1, kFrameWidth, kFrameHeight));
3177 WaitForEncodedFrame(1);
3178 EXPECT_EQ(video_stream_encoder_->overuse_detector_proxy_->GetOptions()
3179 .low_encode_usage_threshold_percent,
3180 default_options.low_encode_usage_threshold_percent);
3181 EXPECT_EQ(video_stream_encoder_->overuse_detector_proxy_->GetOptions()
3182 .high_encode_usage_threshold_percent,
3183 default_options.high_encode_usage_threshold_percent);
3184 video_stream_encoder_->Stop();
3185}
3186
3187TEST_F(VideoStreamEncoderTest,
3188 HigherCpuAdaptationThresholdsForHardwareEncoder) {
3189 const int kFrameWidth = 1280;
3190 const int kFrameHeight = 720;
3191 CpuOveruseOptions hardware_options;
3192 hardware_options.low_encode_usage_threshold_percent = 150;
3193 hardware_options.high_encode_usage_threshold_percent = 200;
3194 encoder_factory_.SetIsHardwareAccelerated(true);
3195
3196 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
3197 video_source_.IncomingCapturedFrame(
3198 CreateFrame(1, kFrameWidth, kFrameHeight));
3199 WaitForEncodedFrame(1);
3200 EXPECT_EQ(video_stream_encoder_->overuse_detector_proxy_->GetOptions()
3201 .low_encode_usage_threshold_percent,
3202 hardware_options.low_encode_usage_threshold_percent);
3203 EXPECT_EQ(video_stream_encoder_->overuse_detector_proxy_->GetOptions()
3204 .high_encode_usage_threshold_percent,
3205 hardware_options.high_encode_usage_threshold_percent);
3206 video_stream_encoder_->Stop();
3207}
3208
perkj26091b12016-09-01 01:17:40 -07003209} // namespace webrtc