blob: 84521fb0c7b6ca697b7de5137de64d15bbfd1f42 [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
Erik Språng4529fbc2018-10-12 10:30:31 +020011#include "video/video_stream_encoder.h"
12
sprangfe627f32017-03-29 08:24:59 -070013#include <algorithm>
perkj803d97f2016-11-01 11:45:46 -070014#include <limits>
Per512ecb32016-09-23 15:52:06 +020015#include <utility>
16
Jiawei Ouc2ebe212018-11-08 10:02:56 -080017#include "api/video/builtin_video_bitrate_allocator_factory.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020018#include "api/video/i420_buffer.h"
Erik Språng4529fbc2018-10-12 10:30:31 +020019#include "api/video_codecs/create_vp8_temporal_layers.h"
20#include "api/video_codecs/vp8_temporal_layers.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020021#include "media/base/videoadapter.h"
Sergey Silkin86684962018-03-28 19:32:37 +020022#include "modules/video_coding/codecs/vp9/include/vp9_globals.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020023#include "modules/video_coding/utility/default_video_bitrate_allocator.h"
24#include "rtc_base/fakeclock.h"
25#include "rtc_base/logging.h"
Stefan Holmerdbdb3a02018-07-17 16:03:46 +020026#include "rtc_base/refcountedobject.h"
Mirko Bonadei17f48782018-09-28 08:51:10 +020027#include "system_wrappers/include/metrics.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020028#include "system_wrappers/include/sleep.h"
29#include "test/encoder_settings.h"
30#include "test/fake_encoder.h"
Kári Tristan Helgason639602a2018-08-02 10:51:40 +020031#include "test/field_trial.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020032#include "test/frame_generator.h"
33#include "test/gmock.h"
34#include "test/gtest.h"
Niels Möllercbcbc222018-09-28 09:07:24 +020035#include "test/video_encoder_proxy_factory.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020036#include "video/send_statistics_proxy.h"
perkj26091b12016-09-01 01:17:40 -070037
38namespace webrtc {
39
sprangb1ca0732017-02-01 08:38:12 -080040using ScaleReason = AdaptationObserverInterface::AdaptReason;
sprang57c2fff2017-01-16 06:24:02 -080041using ::testing::_;
42using ::testing::Return;
kthelgason876222f2016-11-29 01:44:11 -080043
perkj803d97f2016-11-01 11:45:46 -070044namespace {
Åsa Persson8c1bf952018-09-13 10:42:19 +020045const int kMinPixelsPerFrame = 320 * 180;
46const int kMinFramerateFps = 2;
47const int kMinBalancedFramerateFps = 7;
48const int64_t kFrameTimeoutMs = 100;
asapersson5f7226f2016-11-25 04:37:00 -080049const size_t kMaxPayloadLength = 1440;
kthelgason2bc68642017-02-07 07:02:22 -080050const int kTargetBitrateBps = 1000000;
51const int kLowTargetBitrateBps = kTargetBitrateBps / 10;
52const int kMaxInitialFramedrop = 4;
sprangfda496a2017-06-15 04:21:07 -070053const int kDefaultFramerate = 30;
Åsa Persson8c1bf952018-09-13 10:42:19 +020054const int64_t kFrameIntervalMs = rtc::kNumMillisecsPerSec / kDefaultFramerate;
asapersson5f7226f2016-11-25 04:37:00 -080055
perkj803d97f2016-11-01 11:45:46 -070056class TestBuffer : public webrtc::I420Buffer {
57 public:
58 TestBuffer(rtc::Event* event, int width, int height)
59 : I420Buffer(width, height), event_(event) {}
60
61 private:
62 friend class rtc::RefCountedObject<TestBuffer>;
63 ~TestBuffer() override {
64 if (event_)
65 event_->Set();
66 }
67 rtc::Event* const event_;
68};
69
Niels Möller7dc26b72017-12-06 10:27:48 +010070class CpuOveruseDetectorProxy : public OveruseFrameDetector {
71 public:
Niels Möllerd1f7eb62018-03-28 16:40:58 +020072 explicit CpuOveruseDetectorProxy(CpuOveruseMetricsObserver* metrics_observer)
73 : OveruseFrameDetector(metrics_observer),
Niels Möller7dc26b72017-12-06 10:27:48 +010074 last_target_framerate_fps_(-1) {}
75 virtual ~CpuOveruseDetectorProxy() {}
76
77 void OnTargetFramerateUpdated(int framerate_fps) override {
78 rtc::CritScope cs(&lock_);
79 last_target_framerate_fps_ = framerate_fps;
80 OveruseFrameDetector::OnTargetFramerateUpdated(framerate_fps);
81 }
82
83 int GetLastTargetFramerate() {
84 rtc::CritScope cs(&lock_);
85 return last_target_framerate_fps_;
86 }
87
Niels Möller4db138e2018-04-19 09:04:13 +020088 CpuOveruseOptions GetOptions() { return options_; }
89
Niels Möller7dc26b72017-12-06 10:27:48 +010090 private:
91 rtc::CriticalSection lock_;
92 int last_target_framerate_fps_ RTC_GUARDED_BY(lock_);
93};
94
mflodmancc3d4422017-08-03 08:27:51 -070095class VideoStreamEncoderUnderTest : public VideoStreamEncoder {
perkj803d97f2016-11-01 11:45:46 -070096 public:
Niels Möller213618e2018-07-24 09:29:58 +020097 VideoStreamEncoderUnderTest(SendStatisticsProxy* stats_proxy,
98 const VideoStreamEncoderSettings& settings)
Yves Gerey665174f2018-06-19 15:03:05 +020099 : VideoStreamEncoder(1 /* number_of_cores */,
100 stats_proxy,
101 settings,
Yves Gerey665174f2018-06-19 15:03:05 +0200102 std::unique_ptr<OveruseFrameDetector>(
103 overuse_detector_proxy_ =
104 new CpuOveruseDetectorProxy(stats_proxy))) {}
perkj803d97f2016-11-01 11:45:46 -0700105
sprangb1ca0732017-02-01 08:38:12 -0800106 void PostTaskAndWait(bool down, AdaptReason reason) {
Niels Möllerc572ff32018-11-07 08:43:50 +0100107 rtc::Event event;
kthelgason876222f2016-11-29 01:44:11 -0800108 encoder_queue()->PostTask([this, &event, reason, down] {
sprangb1ca0732017-02-01 08:38:12 -0800109 down ? AdaptDown(reason) : AdaptUp(reason);
perkj803d97f2016-11-01 11:45:46 -0700110 event.Set();
111 });
perkj070ba852017-02-16 15:46:27 -0800112 ASSERT_TRUE(event.Wait(5000));
perkj803d97f2016-11-01 11:45:46 -0700113 }
114
kthelgason2fc52542017-03-03 00:24:41 -0800115 // This is used as a synchronisation mechanism, to make sure that the
116 // encoder queue is not blocked before we start sending it frames.
117 void WaitUntilTaskQueueIsIdle() {
Niels Möllerc572ff32018-11-07 08:43:50 +0100118 rtc::Event event;
Yves Gerey665174f2018-06-19 15:03:05 +0200119 encoder_queue()->PostTask([&event] { event.Set(); });
kthelgason2fc52542017-03-03 00:24:41 -0800120 ASSERT_TRUE(event.Wait(5000));
121 }
122
sprangb1ca0732017-02-01 08:38:12 -0800123 void TriggerCpuOveruse() { PostTaskAndWait(true, AdaptReason::kCpu); }
kthelgason876222f2016-11-29 01:44:11 -0800124
sprangb1ca0732017-02-01 08:38:12 -0800125 void TriggerCpuNormalUsage() { PostTaskAndWait(false, AdaptReason::kCpu); }
kthelgason876222f2016-11-29 01:44:11 -0800126
sprangb1ca0732017-02-01 08:38:12 -0800127 void TriggerQualityLow() { PostTaskAndWait(true, AdaptReason::kQuality); }
kthelgason876222f2016-11-29 01:44:11 -0800128
sprangb1ca0732017-02-01 08:38:12 -0800129 void TriggerQualityHigh() { PostTaskAndWait(false, AdaptReason::kQuality); }
sprangfda496a2017-06-15 04:21:07 -0700130
Niels Möller7dc26b72017-12-06 10:27:48 +0100131 CpuOveruseDetectorProxy* overuse_detector_proxy_;
perkj803d97f2016-11-01 11:45:46 -0700132};
133
asapersson5f7226f2016-11-25 04:37:00 -0800134class VideoStreamFactory
135 : public VideoEncoderConfig::VideoStreamFactoryInterface {
136 public:
sprangfda496a2017-06-15 04:21:07 -0700137 explicit VideoStreamFactory(size_t num_temporal_layers, int framerate)
138 : num_temporal_layers_(num_temporal_layers), framerate_(framerate) {
asapersson5f7226f2016-11-25 04:37:00 -0800139 EXPECT_GT(num_temporal_layers, 0u);
sprangfda496a2017-06-15 04:21:07 -0700140 EXPECT_GT(framerate, 0);
asapersson5f7226f2016-11-25 04:37:00 -0800141 }
142
143 private:
144 std::vector<VideoStream> CreateEncoderStreams(
145 int width,
146 int height,
147 const VideoEncoderConfig& encoder_config) override {
148 std::vector<VideoStream> streams =
149 test::CreateVideoStreams(width, height, encoder_config);
150 for (VideoStream& stream : streams) {
Sergey Silkina796a7e2018-03-01 15:11:29 +0100151 stream.num_temporal_layers = num_temporal_layers_;
sprangfda496a2017-06-15 04:21:07 -0700152 stream.max_framerate = framerate_;
asapersson5f7226f2016-11-25 04:37:00 -0800153 }
154 return streams;
155 }
sprangfda496a2017-06-15 04:21:07 -0700156
asapersson5f7226f2016-11-25 04:37:00 -0800157 const size_t num_temporal_layers_;
sprangfda496a2017-06-15 04:21:07 -0700158 const int framerate_;
asapersson5f7226f2016-11-25 04:37:00 -0800159};
160
sprangb1ca0732017-02-01 08:38:12 -0800161class AdaptingFrameForwarder : public test::FrameForwarder {
162 public:
163 AdaptingFrameForwarder() : adaptation_enabled_(false) {}
asaperssonfab67072017-04-04 05:51:49 -0700164 ~AdaptingFrameForwarder() override {}
sprangb1ca0732017-02-01 08:38:12 -0800165
166 void set_adaptation_enabled(bool enabled) {
167 rtc::CritScope cs(&crit_);
168 adaptation_enabled_ = enabled;
169 }
170
asaperssonfab67072017-04-04 05:51:49 -0700171 bool adaption_enabled() const {
sprangb1ca0732017-02-01 08:38:12 -0800172 rtc::CritScope cs(&crit_);
173 return adaptation_enabled_;
174 }
175
asapersson09f05612017-05-15 23:40:18 -0700176 rtc::VideoSinkWants last_wants() const {
177 rtc::CritScope cs(&crit_);
178 return last_wants_;
179 }
180
Danil Chapovalovb9b146c2018-06-15 12:28:07 +0200181 absl::optional<int> last_sent_width() const { return last_width_; }
182 absl::optional<int> last_sent_height() const { return last_height_; }
Jonathan Yubc771b72017-12-08 17:04:29 -0800183
sprangb1ca0732017-02-01 08:38:12 -0800184 void IncomingCapturedFrame(const VideoFrame& video_frame) override {
185 int cropped_width = 0;
186 int cropped_height = 0;
187 int out_width = 0;
188 int out_height = 0;
sprangc5d62e22017-04-02 23:53:04 -0700189 if (adaption_enabled()) {
190 if (adapter_.AdaptFrameResolution(
191 video_frame.width(), video_frame.height(),
192 video_frame.timestamp_us() * 1000, &cropped_width,
193 &cropped_height, &out_width, &out_height)) {
Artem Titov1ebfb6a2019-01-03 23:49:37 +0100194 VideoFrame adapted_frame =
195 VideoFrame::Builder()
196 .set_video_frame_buffer(new rtc::RefCountedObject<TestBuffer>(
197 nullptr, out_width, out_height))
198 .set_timestamp_rtp(99)
199 .set_timestamp_ms(99)
200 .set_rotation(kVideoRotation_0)
201 .build();
sprangc5d62e22017-04-02 23:53:04 -0700202 adapted_frame.set_ntp_time_ms(video_frame.ntp_time_ms());
203 test::FrameForwarder::IncomingCapturedFrame(adapted_frame);
Jonathan Yubc771b72017-12-08 17:04:29 -0800204 last_width_.emplace(adapted_frame.width());
205 last_height_.emplace(adapted_frame.height());
206 } else {
Danil Chapovalovb9b146c2018-06-15 12:28:07 +0200207 last_width_ = absl::nullopt;
208 last_height_ = absl::nullopt;
sprangc5d62e22017-04-02 23:53:04 -0700209 }
sprangb1ca0732017-02-01 08:38:12 -0800210 } else {
211 test::FrameForwarder::IncomingCapturedFrame(video_frame);
Jonathan Yubc771b72017-12-08 17:04:29 -0800212 last_width_.emplace(video_frame.width());
213 last_height_.emplace(video_frame.height());
sprangb1ca0732017-02-01 08:38:12 -0800214 }
215 }
216
217 void AddOrUpdateSink(rtc::VideoSinkInterface<VideoFrame>* sink,
218 const rtc::VideoSinkWants& wants) override {
219 rtc::CritScope cs(&crit_);
asapersson09f05612017-05-15 23:40:18 -0700220 last_wants_ = sink_wants();
sprangc5d62e22017-04-02 23:53:04 -0700221 adapter_.OnResolutionFramerateRequest(wants.target_pixel_count,
222 wants.max_pixel_count,
223 wants.max_framerate_fps);
sprangb1ca0732017-02-01 08:38:12 -0800224 test::FrameForwarder::AddOrUpdateSink(sink, wants);
225 }
sprangb1ca0732017-02-01 08:38:12 -0800226 cricket::VideoAdapter adapter_;
danilchapa37de392017-09-09 04:17:22 -0700227 bool adaptation_enabled_ RTC_GUARDED_BY(crit_);
228 rtc::VideoSinkWants last_wants_ RTC_GUARDED_BY(crit_);
Danil Chapovalovb9b146c2018-06-15 12:28:07 +0200229 absl::optional<int> last_width_;
230 absl::optional<int> last_height_;
sprangb1ca0732017-02-01 08:38:12 -0800231};
sprangc5d62e22017-04-02 23:53:04 -0700232
Niels Möller213618e2018-07-24 09:29:58 +0200233// TODO(nisse): Mock only VideoStreamEncoderObserver.
sprangc5d62e22017-04-02 23:53:04 -0700234class MockableSendStatisticsProxy : public SendStatisticsProxy {
235 public:
236 MockableSendStatisticsProxy(Clock* clock,
237 const VideoSendStream::Config& config,
238 VideoEncoderConfig::ContentType content_type)
239 : SendStatisticsProxy(clock, config, content_type) {}
240
241 VideoSendStream::Stats GetStats() override {
242 rtc::CritScope cs(&lock_);
243 if (mock_stats_)
244 return *mock_stats_;
245 return SendStatisticsProxy::GetStats();
246 }
247
Niels Möller213618e2018-07-24 09:29:58 +0200248 int GetInputFrameRate() const override {
249 rtc::CritScope cs(&lock_);
250 if (mock_stats_)
251 return mock_stats_->input_frame_rate;
252 return SendStatisticsProxy::GetInputFrameRate();
253 }
sprangc5d62e22017-04-02 23:53:04 -0700254 void SetMockStats(const VideoSendStream::Stats& stats) {
255 rtc::CritScope cs(&lock_);
256 mock_stats_.emplace(stats);
257 }
258
259 void ResetMockStats() {
260 rtc::CritScope cs(&lock_);
261 mock_stats_.reset();
262 }
263
264 private:
265 rtc::CriticalSection lock_;
Danil Chapovalovb9b146c2018-06-15 12:28:07 +0200266 absl::optional<VideoSendStream::Stats> mock_stats_ RTC_GUARDED_BY(lock_);
sprangc5d62e22017-04-02 23:53:04 -0700267};
268
sprang4847ae62017-06-27 07:06:52 -0700269class MockBitrateObserver : public VideoBitrateAllocationObserver {
270 public:
Erik Språng566124a2018-04-23 12:32:22 +0200271 MOCK_METHOD1(OnBitrateAllocationUpdated, void(const VideoBitrateAllocation&));
sprang4847ae62017-06-27 07:06:52 -0700272};
273
perkj803d97f2016-11-01 11:45:46 -0700274} // namespace
275
mflodmancc3d4422017-08-03 08:27:51 -0700276class VideoStreamEncoderTest : public ::testing::Test {
perkj26091b12016-09-01 01:17:40 -0700277 public:
278 static const int kDefaultTimeoutMs = 30 * 1000;
279
mflodmancc3d4422017-08-03 08:27:51 -0700280 VideoStreamEncoderTest()
perkj26091b12016-09-01 01:17:40 -0700281 : video_send_config_(VideoSendStream::Config(nullptr)),
perkjfa10b552016-10-02 23:45:26 -0700282 codec_width_(320),
283 codec_height_(240),
Åsa Persson8c1bf952018-09-13 10:42:19 +0200284 max_framerate_(kDefaultFramerate),
perkj26091b12016-09-01 01:17:40 -0700285 fake_encoder_(),
Niels Möller4db138e2018-04-19 09:04:13 +0200286 encoder_factory_(&fake_encoder_),
Jiawei Ouc2ebe212018-11-08 10:02:56 -0800287 bitrate_allocator_factory_(CreateBuiltinVideoBitrateAllocatorFactory()),
sprangc5d62e22017-04-02 23:53:04 -0700288 stats_proxy_(new MockableSendStatisticsProxy(
perkj803d97f2016-11-01 11:45:46 -0700289 Clock::GetRealTimeClock(),
290 video_send_config_,
291 webrtc::VideoEncoderConfig::ContentType::kRealtimeVideo)),
perkj26091b12016-09-01 01:17:40 -0700292 sink_(&fake_encoder_) {}
293
294 void SetUp() override {
perkj803d97f2016-11-01 11:45:46 -0700295 metrics::Reset();
perkj26091b12016-09-01 01:17:40 -0700296 video_send_config_ = VideoSendStream::Config(nullptr);
Niels Möller4db138e2018-04-19 09:04:13 +0200297 video_send_config_.encoder_settings.encoder_factory = &encoder_factory_;
Jiawei Ouc2ebe212018-11-08 10:02:56 -0800298 video_send_config_.encoder_settings.bitrate_allocator_factory =
299 bitrate_allocator_factory_.get();
Niels Möller259a4972018-04-05 15:36:51 +0200300 video_send_config_.rtp.payload_name = "FAKE";
301 video_send_config_.rtp.payload_type = 125;
perkj26091b12016-09-01 01:17:40 -0700302
Per512ecb32016-09-23 15:52:06 +0200303 VideoEncoderConfig video_encoder_config;
Niels Möller259a4972018-04-05 15:36:51 +0200304 test::FillEncoderConfiguration(kVideoCodecVP8, 1, &video_encoder_config);
sprang4847ae62017-06-27 07:06:52 -0700305 video_encoder_config.video_stream_factory =
306 new rtc::RefCountedObject<VideoStreamFactory>(1, max_framerate_);
Erik Språng08127a92016-11-16 16:41:30 +0100307 video_encoder_config_ = video_encoder_config.Copy();
sprang4847ae62017-06-27 07:06:52 -0700308
309 // Framerate limit is specified by the VideoStreamFactory.
310 std::vector<VideoStream> streams =
311 video_encoder_config.video_stream_factory->CreateEncoderStreams(
312 codec_width_, codec_height_, video_encoder_config);
313 max_framerate_ = streams[0].max_framerate;
314 fake_clock_.SetTimeMicros(1234);
315
Niels Möllerf1338562018-04-26 09:51:47 +0200316 ConfigureEncoder(std::move(video_encoder_config));
asapersson5f7226f2016-11-25 04:37:00 -0800317 }
318
Niels Möllerf1338562018-04-26 09:51:47 +0200319 void ConfigureEncoder(VideoEncoderConfig video_encoder_config) {
mflodmancc3d4422017-08-03 08:27:51 -0700320 if (video_stream_encoder_)
321 video_stream_encoder_->Stop();
322 video_stream_encoder_.reset(new VideoStreamEncoderUnderTest(
perkj803d97f2016-11-01 11:45:46 -0700323 stats_proxy_.get(), video_send_config_.encoder_settings));
mflodmancc3d4422017-08-03 08:27:51 -0700324 video_stream_encoder_->SetSink(&sink_, false /* rotation_applied */);
325 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -0700326 &video_source_, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
mflodmancc3d4422017-08-03 08:27:51 -0700327 video_stream_encoder_->SetStartBitrate(kTargetBitrateBps);
328 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
Niels Möllerf1338562018-04-26 09:51:47 +0200329 kMaxPayloadLength);
mflodmancc3d4422017-08-03 08:27:51 -0700330 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
asapersson5f7226f2016-11-25 04:37:00 -0800331 }
332
333 void ResetEncoder(const std::string& payload_name,
334 size_t num_streams,
335 size_t num_temporal_layers,
emircanbbcc3562017-08-18 00:28:40 -0700336 unsigned char num_spatial_layers,
sprang4847ae62017-06-27 07:06:52 -0700337 bool screenshare) {
Niels Möller259a4972018-04-05 15:36:51 +0200338 video_send_config_.rtp.payload_name = payload_name;
asapersson5f7226f2016-11-25 04:37:00 -0800339
340 VideoEncoderConfig video_encoder_config;
Niels Möller259a4972018-04-05 15:36:51 +0200341 video_encoder_config.codec_type = PayloadStringToCodecType(payload_name);
asapersson5f7226f2016-11-25 04:37:00 -0800342 video_encoder_config.number_of_streams = num_streams;
kthelgason2bc68642017-02-07 07:02:22 -0800343 video_encoder_config.max_bitrate_bps = kTargetBitrateBps;
asapersson5f7226f2016-11-25 04:37:00 -0800344 video_encoder_config.video_stream_factory =
sprangfda496a2017-06-15 04:21:07 -0700345 new rtc::RefCountedObject<VideoStreamFactory>(num_temporal_layers,
346 kDefaultFramerate);
sprang4847ae62017-06-27 07:06:52 -0700347 video_encoder_config.content_type =
348 screenshare ? VideoEncoderConfig::ContentType::kScreen
349 : VideoEncoderConfig::ContentType::kRealtimeVideo;
emircanbbcc3562017-08-18 00:28:40 -0700350 if (payload_name == "VP9") {
351 VideoCodecVP9 vp9_settings = VideoEncoder::GetDefaultVp9Settings();
352 vp9_settings.numberOfSpatialLayers = num_spatial_layers;
353 video_encoder_config.encoder_specific_settings =
354 new rtc::RefCountedObject<
355 VideoEncoderConfig::Vp9EncoderSpecificSettings>(vp9_settings);
356 }
Niels Möllerf1338562018-04-26 09:51:47 +0200357 ConfigureEncoder(std::move(video_encoder_config));
perkj26091b12016-09-01 01:17:40 -0700358 }
359
sprang57c2fff2017-01-16 06:24:02 -0800360 VideoFrame CreateFrame(int64_t ntp_time_ms,
361 rtc::Event* destruction_event) const {
Artem Titov1ebfb6a2019-01-03 23:49:37 +0100362 VideoFrame frame =
363 VideoFrame::Builder()
364 .set_video_frame_buffer(new rtc::RefCountedObject<TestBuffer>(
365 destruction_event, codec_width_, codec_height_))
366 .set_timestamp_rtp(99)
367 .set_timestamp_ms(99)
368 .set_rotation(kVideoRotation_0)
369 .build();
sprang57c2fff2017-01-16 06:24:02 -0800370 frame.set_ntp_time_ms(ntp_time_ms);
perkj26091b12016-09-01 01:17:40 -0700371 return frame;
372 }
373
sprang57c2fff2017-01-16 06:24:02 -0800374 VideoFrame CreateFrame(int64_t ntp_time_ms, int width, int height) const {
Artem Titov1ebfb6a2019-01-03 23:49:37 +0100375 VideoFrame frame =
376 VideoFrame::Builder()
377 .set_video_frame_buffer(
378 new rtc::RefCountedObject<TestBuffer>(nullptr, width, height))
379 .set_timestamp_rtp(99)
380 .set_timestamp_ms(99)
381 .set_rotation(kVideoRotation_0)
382 .build();
sprang57c2fff2017-01-16 06:24:02 -0800383 frame.set_ntp_time_ms(ntp_time_ms);
sprangc5d62e22017-04-02 23:53:04 -0700384 frame.set_timestamp_us(ntp_time_ms * 1000);
perkj803d97f2016-11-01 11:45:46 -0700385 return frame;
386 }
387
asapersson02465b82017-04-10 01:12:52 -0700388 void VerifyNoLimitation(const rtc::VideoSinkWants& wants) {
asapersson02465b82017-04-10 01:12:52 -0700389 EXPECT_EQ(std::numeric_limits<int>::max(), wants.max_framerate_fps);
asapersson09f05612017-05-15 23:40:18 -0700390 EXPECT_EQ(std::numeric_limits<int>::max(), wants.max_pixel_count);
391 EXPECT_FALSE(wants.target_pixel_count);
asapersson02465b82017-04-10 01:12:52 -0700392 }
393
asapersson09f05612017-05-15 23:40:18 -0700394 void VerifyFpsEqResolutionEq(const rtc::VideoSinkWants& wants1,
395 const rtc::VideoSinkWants& wants2) {
396 EXPECT_EQ(wants1.max_framerate_fps, wants2.max_framerate_fps);
397 EXPECT_EQ(wants1.max_pixel_count, wants2.max_pixel_count);
398 }
399
Åsa Persson8c1bf952018-09-13 10:42:19 +0200400 void VerifyFpsMaxResolutionMax(const rtc::VideoSinkWants& wants) {
401 EXPECT_EQ(kDefaultFramerate, wants.max_framerate_fps);
402 EXPECT_EQ(std::numeric_limits<int>::max(), wants.max_pixel_count);
403 EXPECT_FALSE(wants.target_pixel_count);
404 }
405
asapersson09f05612017-05-15 23:40:18 -0700406 void VerifyFpsMaxResolutionLt(const rtc::VideoSinkWants& wants1,
407 const rtc::VideoSinkWants& wants2) {
Åsa Persson8c1bf952018-09-13 10:42:19 +0200408 EXPECT_EQ(kDefaultFramerate, wants1.max_framerate_fps);
asapersson09f05612017-05-15 23:40:18 -0700409 EXPECT_LT(wants1.max_pixel_count, wants2.max_pixel_count);
410 EXPECT_GT(wants1.max_pixel_count, 0);
411 }
412
413 void VerifyFpsMaxResolutionGt(const rtc::VideoSinkWants& wants1,
414 const rtc::VideoSinkWants& wants2) {
Åsa Persson8c1bf952018-09-13 10:42:19 +0200415 EXPECT_EQ(kDefaultFramerate, wants1.max_framerate_fps);
asapersson09f05612017-05-15 23:40:18 -0700416 EXPECT_GT(wants1.max_pixel_count, wants2.max_pixel_count);
417 }
418
asaperssonf7e294d2017-06-13 23:25:22 -0700419 void VerifyFpsMaxResolutionEq(const rtc::VideoSinkWants& wants1,
420 const rtc::VideoSinkWants& wants2) {
Åsa Persson8c1bf952018-09-13 10:42:19 +0200421 EXPECT_EQ(kDefaultFramerate, wants1.max_framerate_fps);
asaperssonf7e294d2017-06-13 23:25:22 -0700422 EXPECT_EQ(wants1.max_pixel_count, wants2.max_pixel_count);
423 }
424
425 void VerifyFpsLtResolutionEq(const rtc::VideoSinkWants& wants1,
426 const rtc::VideoSinkWants& wants2) {
427 EXPECT_LT(wants1.max_framerate_fps, wants2.max_framerate_fps);
428 EXPECT_EQ(wants1.max_pixel_count, wants2.max_pixel_count);
429 }
430
431 void VerifyFpsGtResolutionEq(const rtc::VideoSinkWants& wants1,
432 const rtc::VideoSinkWants& wants2) {
433 EXPECT_GT(wants1.max_framerate_fps, wants2.max_framerate_fps);
434 EXPECT_EQ(wants1.max_pixel_count, wants2.max_pixel_count);
435 }
436
437 void VerifyFpsEqResolutionLt(const rtc::VideoSinkWants& wants1,
438 const rtc::VideoSinkWants& wants2) {
439 EXPECT_EQ(wants1.max_framerate_fps, wants2.max_framerate_fps);
440 EXPECT_LT(wants1.max_pixel_count, wants2.max_pixel_count);
441 EXPECT_GT(wants1.max_pixel_count, 0);
442 }
443
444 void VerifyFpsEqResolutionGt(const rtc::VideoSinkWants& wants1,
445 const rtc::VideoSinkWants& wants2) {
446 EXPECT_EQ(wants1.max_framerate_fps, wants2.max_framerate_fps);
447 EXPECT_GT(wants1.max_pixel_count, wants2.max_pixel_count);
448 }
449
asapersson09f05612017-05-15 23:40:18 -0700450 void VerifyFpsMaxResolutionLt(const rtc::VideoSinkWants& wants,
451 int pixel_count) {
Åsa Persson8c1bf952018-09-13 10:42:19 +0200452 EXPECT_EQ(kDefaultFramerate, wants.max_framerate_fps);
asapersson02465b82017-04-10 01:12:52 -0700453 EXPECT_LT(wants.max_pixel_count, pixel_count);
454 EXPECT_GT(wants.max_pixel_count, 0);
asapersson09f05612017-05-15 23:40:18 -0700455 }
456
457 void VerifyFpsLtResolutionMax(const rtc::VideoSinkWants& wants, int fps) {
458 EXPECT_LT(wants.max_framerate_fps, fps);
459 EXPECT_EQ(std::numeric_limits<int>::max(), wants.max_pixel_count);
460 EXPECT_FALSE(wants.target_pixel_count);
asapersson02465b82017-04-10 01:12:52 -0700461 }
462
asaperssonf7e294d2017-06-13 23:25:22 -0700463 void VerifyFpsEqResolutionMax(const rtc::VideoSinkWants& wants,
464 int expected_fps) {
465 EXPECT_EQ(expected_fps, wants.max_framerate_fps);
466 EXPECT_EQ(std::numeric_limits<int>::max(), wants.max_pixel_count);
467 EXPECT_FALSE(wants.target_pixel_count);
468 }
469
Jonathan Yubc771b72017-12-08 17:04:29 -0800470 void VerifyBalancedModeFpsRange(const rtc::VideoSinkWants& wants,
471 int last_frame_pixels) {
472 // Balanced mode should always scale FPS to the desired range before
473 // attempting to scale resolution.
474 int fps_limit = wants.max_framerate_fps;
475 if (last_frame_pixels <= 320 * 240) {
476 EXPECT_TRUE(7 <= fps_limit && fps_limit <= 10);
477 } else if (last_frame_pixels <= 480 * 270) {
478 EXPECT_TRUE(10 <= fps_limit && fps_limit <= 15);
479 } else if (last_frame_pixels <= 640 * 480) {
480 EXPECT_LE(15, fps_limit);
481 } else {
Åsa Persson8c1bf952018-09-13 10:42:19 +0200482 EXPECT_EQ(kDefaultFramerate, fps_limit);
Jonathan Yubc771b72017-12-08 17:04:29 -0800483 }
484 }
485
sprang4847ae62017-06-27 07:06:52 -0700486 void WaitForEncodedFrame(int64_t expected_ntp_time) {
487 sink_.WaitForEncodedFrame(expected_ntp_time);
488 fake_clock_.AdvanceTimeMicros(rtc::kNumMicrosecsPerSec / max_framerate_);
489 }
490
491 bool TimedWaitForEncodedFrame(int64_t expected_ntp_time, int64_t timeout_ms) {
492 bool ok = sink_.TimedWaitForEncodedFrame(expected_ntp_time, timeout_ms);
493 fake_clock_.AdvanceTimeMicros(rtc::kNumMicrosecsPerSec / max_framerate_);
494 return ok;
495 }
496
497 void WaitForEncodedFrame(uint32_t expected_width, uint32_t expected_height) {
498 sink_.WaitForEncodedFrame(expected_width, expected_height);
499 fake_clock_.AdvanceTimeMicros(rtc::kNumMicrosecsPerSec / max_framerate_);
500 }
501
502 void ExpectDroppedFrame() {
503 sink_.ExpectDroppedFrame();
504 fake_clock_.AdvanceTimeMicros(rtc::kNumMicrosecsPerSec / max_framerate_);
505 }
506
507 bool WaitForFrame(int64_t timeout_ms) {
508 bool ok = sink_.WaitForFrame(timeout_ms);
509 fake_clock_.AdvanceTimeMicros(rtc::kNumMicrosecsPerSec / max_framerate_);
510 return ok;
511 }
512
perkj26091b12016-09-01 01:17:40 -0700513 class TestEncoder : public test::FakeEncoder {
514 public:
Niels Möllerc572ff32018-11-07 08:43:50 +0100515 TestEncoder() : FakeEncoder(Clock::GetRealTimeClock()) {}
perkj26091b12016-09-01 01:17:40 -0700516
asaperssonfab67072017-04-04 05:51:49 -0700517 VideoCodec codec_config() const {
brandtre78d2662017-01-16 05:57:16 -0800518 rtc::CritScope lock(&crit_sect_);
perkjfa10b552016-10-02 23:45:26 -0700519 return config_;
520 }
521
522 void BlockNextEncode() {
brandtre78d2662017-01-16 05:57:16 -0800523 rtc::CritScope lock(&local_crit_sect_);
perkjfa10b552016-10-02 23:45:26 -0700524 block_next_encode_ = true;
525 }
526
Erik Språngaed30702018-11-05 12:57:17 +0100527 VideoEncoder::EncoderInfo GetEncoderInfo() const override {
Mirta Dvornicic1ec2a162018-12-10 09:47:34 +0000528 EncoderInfo info;
kthelgason2fc52542017-03-03 00:24:41 -0800529 rtc::CritScope lock(&local_crit_sect_);
Erik Språngaed30702018-11-05 12:57:17 +0100530 if (quality_scaling_) {
531 info.scaling_settings =
532 VideoEncoder::ScalingSettings(1, 2, kMinPixelsPerFrame);
533 }
534 return info;
kthelgason876222f2016-11-29 01:44:11 -0800535 }
536
perkjfa10b552016-10-02 23:45:26 -0700537 void ContinueEncode() { continue_encode_event_.Set(); }
538
539 void CheckLastTimeStampsMatch(int64_t ntp_time_ms,
540 uint32_t timestamp) const {
brandtre78d2662017-01-16 05:57:16 -0800541 rtc::CritScope lock(&local_crit_sect_);
perkjfa10b552016-10-02 23:45:26 -0700542 EXPECT_EQ(timestamp_, timestamp);
543 EXPECT_EQ(ntp_time_ms_, ntp_time_ms);
544 }
545
kthelgason2fc52542017-03-03 00:24:41 -0800546 void SetQualityScaling(bool b) {
547 rtc::CritScope lock(&local_crit_sect_);
548 quality_scaling_ = b;
549 }
kthelgasonad9010c2017-02-14 00:46:51 -0800550
sprangfe627f32017-03-29 08:24:59 -0700551 void ForceInitEncodeFailure(bool force_failure) {
552 rtc::CritScope lock(&local_crit_sect_);
553 force_init_encode_failed_ = force_failure;
554 }
555
perkjfa10b552016-10-02 23:45:26 -0700556 private:
perkj26091b12016-09-01 01:17:40 -0700557 int32_t Encode(const VideoFrame& input_image,
558 const CodecSpecificInfo* codec_specific_info,
559 const std::vector<FrameType>* frame_types) override {
560 bool block_encode;
561 {
brandtre78d2662017-01-16 05:57:16 -0800562 rtc::CritScope lock(&local_crit_sect_);
perkj26091b12016-09-01 01:17:40 -0700563 EXPECT_GT(input_image.timestamp(), timestamp_);
564 EXPECT_GT(input_image.ntp_time_ms(), ntp_time_ms_);
565 EXPECT_EQ(input_image.timestamp(), input_image.ntp_time_ms() * 90);
566
567 timestamp_ = input_image.timestamp();
568 ntp_time_ms_ = input_image.ntp_time_ms();
perkj803d97f2016-11-01 11:45:46 -0700569 last_input_width_ = input_image.width();
570 last_input_height_ = input_image.height();
perkj26091b12016-09-01 01:17:40 -0700571 block_encode = block_next_encode_;
572 block_next_encode_ = false;
573 }
574 int32_t result =
575 FakeEncoder::Encode(input_image, codec_specific_info, frame_types);
576 if (block_encode)
perkja49cbd32016-09-16 07:53:41 -0700577 EXPECT_TRUE(continue_encode_event_.Wait(kDefaultTimeoutMs));
perkj26091b12016-09-01 01:17:40 -0700578 return result;
579 }
580
sprangfe627f32017-03-29 08:24:59 -0700581 int32_t InitEncode(const VideoCodec* config,
582 int32_t number_of_cores,
583 size_t max_payload_size) override {
584 int res =
585 FakeEncoder::InitEncode(config, number_of_cores, max_payload_size);
586 rtc::CritScope lock(&local_crit_sect_);
Erik Språng82fad3d2018-03-21 09:57:23 +0100587 if (config->codecType == kVideoCodecVP8) {
sprangfe627f32017-03-29 08:24:59 -0700588 // Simulate setting up temporal layers, in order to validate the life
589 // cycle of these objects.
590 int num_streams = std::max<int>(1, config->numberOfSimulcastStreams);
sprangfe627f32017-03-29 08:24:59 -0700591 for (int i = 0; i < num_streams; ++i) {
592 allocated_temporal_layers_.emplace_back(
Erik Språng4529fbc2018-10-12 10:30:31 +0200593 CreateVp8TemporalLayers(Vp8TemporalLayersType::kFixedPattern,
594 config->VP8().numberOfTemporalLayers));
sprangfe627f32017-03-29 08:24:59 -0700595 }
596 }
597 if (force_init_encode_failed_)
598 return -1;
599 return res;
600 }
601
brandtre78d2662017-01-16 05:57:16 -0800602 rtc::CriticalSection local_crit_sect_;
danilchapa37de392017-09-09 04:17:22 -0700603 bool block_next_encode_ RTC_GUARDED_BY(local_crit_sect_) = false;
perkj26091b12016-09-01 01:17:40 -0700604 rtc::Event continue_encode_event_;
danilchapa37de392017-09-09 04:17:22 -0700605 uint32_t timestamp_ RTC_GUARDED_BY(local_crit_sect_) = 0;
606 int64_t ntp_time_ms_ RTC_GUARDED_BY(local_crit_sect_) = 0;
607 int last_input_width_ RTC_GUARDED_BY(local_crit_sect_) = 0;
608 int last_input_height_ RTC_GUARDED_BY(local_crit_sect_) = 0;
609 bool quality_scaling_ RTC_GUARDED_BY(local_crit_sect_) = true;
Erik Språng4529fbc2018-10-12 10:30:31 +0200610 std::vector<std::unique_ptr<Vp8TemporalLayers>> allocated_temporal_layers_
danilchapa37de392017-09-09 04:17:22 -0700611 RTC_GUARDED_BY(local_crit_sect_);
612 bool force_init_encode_failed_ RTC_GUARDED_BY(local_crit_sect_) = false;
perkj26091b12016-09-01 01:17:40 -0700613 };
614
mflodmancc3d4422017-08-03 08:27:51 -0700615 class TestSink : public VideoStreamEncoder::EncoderSink {
perkj26091b12016-09-01 01:17:40 -0700616 public:
617 explicit TestSink(TestEncoder* test_encoder)
Niels Möllerc572ff32018-11-07 08:43:50 +0100618 : test_encoder_(test_encoder) {}
perkj26091b12016-09-01 01:17:40 -0700619
perkj26091b12016-09-01 01:17:40 -0700620 void WaitForEncodedFrame(int64_t expected_ntp_time) {
sprang4847ae62017-06-27 07:06:52 -0700621 EXPECT_TRUE(
622 TimedWaitForEncodedFrame(expected_ntp_time, kDefaultTimeoutMs));
623 }
624
625 bool TimedWaitForEncodedFrame(int64_t expected_ntp_time,
626 int64_t timeout_ms) {
perkj26091b12016-09-01 01:17:40 -0700627 uint32_t timestamp = 0;
sprang4847ae62017-06-27 07:06:52 -0700628 if (!encoded_frame_event_.Wait(timeout_ms))
629 return false;
perkj26091b12016-09-01 01:17:40 -0700630 {
631 rtc::CritScope lock(&crit_);
sprangb1ca0732017-02-01 08:38:12 -0800632 timestamp = last_timestamp_;
perkj26091b12016-09-01 01:17:40 -0700633 }
634 test_encoder_->CheckLastTimeStampsMatch(expected_ntp_time, timestamp);
sprang4847ae62017-06-27 07:06:52 -0700635 return true;
perkj26091b12016-09-01 01:17:40 -0700636 }
637
sprangb1ca0732017-02-01 08:38:12 -0800638 void WaitForEncodedFrame(uint32_t expected_width,
639 uint32_t expected_height) {
sprangc5d62e22017-04-02 23:53:04 -0700640 EXPECT_TRUE(encoded_frame_event_.Wait(kDefaultTimeoutMs));
Åsa Perssonc74d8da2017-12-04 14:13:56 +0100641 CheckLastFrameSizeMatches(expected_width, expected_height);
sprangc5d62e22017-04-02 23:53:04 -0700642 }
643
Åsa Perssonc74d8da2017-12-04 14:13:56 +0100644 void CheckLastFrameSizeMatches(uint32_t expected_width,
sprangc5d62e22017-04-02 23:53:04 -0700645 uint32_t expected_height) {
sprangb1ca0732017-02-01 08:38:12 -0800646 uint32_t width = 0;
647 uint32_t height = 0;
sprangb1ca0732017-02-01 08:38:12 -0800648 {
649 rtc::CritScope lock(&crit_);
650 width = last_width_;
651 height = last_height_;
652 }
653 EXPECT_EQ(expected_height, height);
654 EXPECT_EQ(expected_width, width);
655 }
656
kthelgason2fc52542017-03-03 00:24:41 -0800657 void ExpectDroppedFrame() { EXPECT_FALSE(encoded_frame_event_.Wait(100)); }
kthelgason2bc68642017-02-07 07:02:22 -0800658
sprangc5d62e22017-04-02 23:53:04 -0700659 bool WaitForFrame(int64_t timeout_ms) {
660 return encoded_frame_event_.Wait(timeout_ms);
661 }
662
perkj26091b12016-09-01 01:17:40 -0700663 void SetExpectNoFrames() {
664 rtc::CritScope lock(&crit_);
665 expect_frames_ = false;
666 }
667
asaperssonfab67072017-04-04 05:51:49 -0700668 int number_of_reconfigurations() const {
Per512ecb32016-09-23 15:52:06 +0200669 rtc::CritScope lock(&crit_);
670 return number_of_reconfigurations_;
671 }
672
asaperssonfab67072017-04-04 05:51:49 -0700673 int last_min_transmit_bitrate() const {
Per512ecb32016-09-23 15:52:06 +0200674 rtc::CritScope lock(&crit_);
675 return min_transmit_bitrate_bps_;
676 }
677
perkj26091b12016-09-01 01:17:40 -0700678 private:
sergeyu2cb155a2016-11-04 11:39:29 -0700679 Result OnEncodedImage(
680 const EncodedImage& encoded_image,
681 const CodecSpecificInfo* codec_specific_info,
682 const RTPFragmentationHeader* fragmentation) override {
Per512ecb32016-09-23 15:52:06 +0200683 rtc::CritScope lock(&crit_);
684 EXPECT_TRUE(expect_frames_);
Niels Möller23775882018-08-16 10:24:12 +0200685 last_timestamp_ = encoded_image.Timestamp();
sprangb1ca0732017-02-01 08:38:12 -0800686 last_width_ = encoded_image._encodedWidth;
687 last_height_ = encoded_image._encodedHeight;
Per512ecb32016-09-23 15:52:06 +0200688 encoded_frame_event_.Set();
sprangb1ca0732017-02-01 08:38:12 -0800689 return Result(Result::OK, last_timestamp_);
Per512ecb32016-09-23 15:52:06 +0200690 }
691
692 void OnEncoderConfigurationChanged(std::vector<VideoStream> streams,
693 int min_transmit_bitrate_bps) override {
694 rtc::CriticalSection crit_;
695 ++number_of_reconfigurations_;
696 min_transmit_bitrate_bps_ = min_transmit_bitrate_bps;
697 }
698
perkj26091b12016-09-01 01:17:40 -0700699 rtc::CriticalSection crit_;
700 TestEncoder* test_encoder_;
701 rtc::Event encoded_frame_event_;
sprangb1ca0732017-02-01 08:38:12 -0800702 uint32_t last_timestamp_ = 0;
703 uint32_t last_height_ = 0;
704 uint32_t last_width_ = 0;
perkj26091b12016-09-01 01:17:40 -0700705 bool expect_frames_ = true;
Per512ecb32016-09-23 15:52:06 +0200706 int number_of_reconfigurations_ = 0;
707 int min_transmit_bitrate_bps_ = 0;
perkj26091b12016-09-01 01:17:40 -0700708 };
709
710 VideoSendStream::Config video_send_config_;
Erik Språng08127a92016-11-16 16:41:30 +0100711 VideoEncoderConfig video_encoder_config_;
Per512ecb32016-09-23 15:52:06 +0200712 int codec_width_;
713 int codec_height_;
sprang4847ae62017-06-27 07:06:52 -0700714 int max_framerate_;
perkj26091b12016-09-01 01:17:40 -0700715 TestEncoder fake_encoder_;
Niels Möllercbcbc222018-09-28 09:07:24 +0200716 test::VideoEncoderProxyFactory encoder_factory_;
Jiawei Ouc2ebe212018-11-08 10:02:56 -0800717 std::unique_ptr<VideoBitrateAllocatorFactory> bitrate_allocator_factory_;
sprangc5d62e22017-04-02 23:53:04 -0700718 std::unique_ptr<MockableSendStatisticsProxy> stats_proxy_;
perkj26091b12016-09-01 01:17:40 -0700719 TestSink sink_;
sprangb1ca0732017-02-01 08:38:12 -0800720 AdaptingFrameForwarder video_source_;
mflodmancc3d4422017-08-03 08:27:51 -0700721 std::unique_ptr<VideoStreamEncoderUnderTest> video_stream_encoder_;
sprang4847ae62017-06-27 07:06:52 -0700722 rtc::ScopedFakeClock fake_clock_;
perkj26091b12016-09-01 01:17:40 -0700723};
724
mflodmancc3d4422017-08-03 08:27:51 -0700725TEST_F(VideoStreamEncoderTest, EncodeOneFrame) {
726 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
Niels Möllerc572ff32018-11-07 08:43:50 +0100727 rtc::Event frame_destroyed_event;
perkja49cbd32016-09-16 07:53:41 -0700728 video_source_.IncomingCapturedFrame(CreateFrame(1, &frame_destroyed_event));
sprang4847ae62017-06-27 07:06:52 -0700729 WaitForEncodedFrame(1);
perkja49cbd32016-09-16 07:53:41 -0700730 EXPECT_TRUE(frame_destroyed_event.Wait(kDefaultTimeoutMs));
mflodmancc3d4422017-08-03 08:27:51 -0700731 video_stream_encoder_->Stop();
perkj26091b12016-09-01 01:17:40 -0700732}
733
mflodmancc3d4422017-08-03 08:27:51 -0700734TEST_F(VideoStreamEncoderTest, DropsFramesBeforeFirstOnBitrateUpdated) {
perkj26091b12016-09-01 01:17:40 -0700735 // Dropped since no target bitrate has been set.
Niels Möllerc572ff32018-11-07 08:43:50 +0100736 rtc::Event frame_destroyed_event;
Sebastian Janssona3177052018-04-10 13:05:49 +0200737 // The encoder will cache up to one frame for a short duration. Adding two
738 // frames means that the first frame will be dropped and the second frame will
739 // be sent when the encoder is enabled.
perkja49cbd32016-09-16 07:53:41 -0700740 video_source_.IncomingCapturedFrame(CreateFrame(1, &frame_destroyed_event));
Sebastian Janssona3177052018-04-10 13:05:49 +0200741 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
perkja49cbd32016-09-16 07:53:41 -0700742 EXPECT_TRUE(frame_destroyed_event.Wait(kDefaultTimeoutMs));
perkj26091b12016-09-01 01:17:40 -0700743
mflodmancc3d4422017-08-03 08:27:51 -0700744 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkj26091b12016-09-01 01:17:40 -0700745
Sebastian Janssona3177052018-04-10 13:05:49 +0200746 // The pending frame should be received.
sprang4847ae62017-06-27 07:06:52 -0700747 WaitForEncodedFrame(2);
Sebastian Janssona3177052018-04-10 13:05:49 +0200748 video_source_.IncomingCapturedFrame(CreateFrame(3, nullptr));
749
750 WaitForEncodedFrame(3);
mflodmancc3d4422017-08-03 08:27:51 -0700751 video_stream_encoder_->Stop();
perkj26091b12016-09-01 01:17:40 -0700752}
753
mflodmancc3d4422017-08-03 08:27:51 -0700754TEST_F(VideoStreamEncoderTest, DropsFramesWhenRateSetToZero) {
755 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkja49cbd32016-09-16 07:53:41 -0700756 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700757 WaitForEncodedFrame(1);
perkj26091b12016-09-01 01:17:40 -0700758
mflodmancc3d4422017-08-03 08:27:51 -0700759 video_stream_encoder_->OnBitrateUpdated(0, 0, 0);
Sebastian Janssona3177052018-04-10 13:05:49 +0200760 // The encoder will cache up to one frame for a short duration. Adding two
761 // frames means that the first frame will be dropped and the second frame will
762 // be sent when the encoder is resumed.
perkja49cbd32016-09-16 07:53:41 -0700763 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
Sebastian Janssona3177052018-04-10 13:05:49 +0200764 video_source_.IncomingCapturedFrame(CreateFrame(3, nullptr));
perkj26091b12016-09-01 01:17:40 -0700765
mflodmancc3d4422017-08-03 08:27:51 -0700766 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
sprang4847ae62017-06-27 07:06:52 -0700767 WaitForEncodedFrame(3);
Sebastian Janssona3177052018-04-10 13:05:49 +0200768 video_source_.IncomingCapturedFrame(CreateFrame(4, nullptr));
769 WaitForEncodedFrame(4);
mflodmancc3d4422017-08-03 08:27:51 -0700770 video_stream_encoder_->Stop();
perkj26091b12016-09-01 01:17:40 -0700771}
772
mflodmancc3d4422017-08-03 08:27:51 -0700773TEST_F(VideoStreamEncoderTest, DropsFramesWithSameOrOldNtpTimestamp) {
774 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkja49cbd32016-09-16 07:53:41 -0700775 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700776 WaitForEncodedFrame(1);
perkj26091b12016-09-01 01:17:40 -0700777
778 // This frame will be dropped since it has the same ntp timestamp.
perkja49cbd32016-09-16 07:53:41 -0700779 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
perkj26091b12016-09-01 01:17:40 -0700780
perkja49cbd32016-09-16 07:53:41 -0700781 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700782 WaitForEncodedFrame(2);
mflodmancc3d4422017-08-03 08:27:51 -0700783 video_stream_encoder_->Stop();
perkj26091b12016-09-01 01:17:40 -0700784}
785
mflodmancc3d4422017-08-03 08:27:51 -0700786TEST_F(VideoStreamEncoderTest, DropsFrameAfterStop) {
787 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkj26091b12016-09-01 01:17:40 -0700788
perkja49cbd32016-09-16 07:53:41 -0700789 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700790 WaitForEncodedFrame(1);
perkj26091b12016-09-01 01:17:40 -0700791
mflodmancc3d4422017-08-03 08:27:51 -0700792 video_stream_encoder_->Stop();
perkj26091b12016-09-01 01:17:40 -0700793 sink_.SetExpectNoFrames();
Niels Möllerc572ff32018-11-07 08:43:50 +0100794 rtc::Event frame_destroyed_event;
perkja49cbd32016-09-16 07:53:41 -0700795 video_source_.IncomingCapturedFrame(CreateFrame(2, &frame_destroyed_event));
796 EXPECT_TRUE(frame_destroyed_event.Wait(kDefaultTimeoutMs));
perkj26091b12016-09-01 01:17:40 -0700797}
798
mflodmancc3d4422017-08-03 08:27:51 -0700799TEST_F(VideoStreamEncoderTest, DropsPendingFramesOnSlowEncode) {
800 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkj26091b12016-09-01 01:17:40 -0700801
802 fake_encoder_.BlockNextEncode();
perkja49cbd32016-09-16 07:53:41 -0700803 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700804 WaitForEncodedFrame(1);
perkj26091b12016-09-01 01:17:40 -0700805 // Here, the encoder thread will be blocked in the TestEncoder waiting for a
806 // call to ContinueEncode.
perkja49cbd32016-09-16 07:53:41 -0700807 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
808 video_source_.IncomingCapturedFrame(CreateFrame(3, nullptr));
perkj26091b12016-09-01 01:17:40 -0700809 fake_encoder_.ContinueEncode();
sprang4847ae62017-06-27 07:06:52 -0700810 WaitForEncodedFrame(3);
perkj26091b12016-09-01 01:17:40 -0700811
mflodmancc3d4422017-08-03 08:27:51 -0700812 video_stream_encoder_->Stop();
perkj26091b12016-09-01 01:17:40 -0700813}
814
mflodmancc3d4422017-08-03 08:27:51 -0700815TEST_F(VideoStreamEncoderTest,
816 ConfigureEncoderTriggersOnEncoderConfigurationChanged) {
817 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
Per21d45d22016-10-30 21:37:57 +0100818 EXPECT_EQ(0, sink_.number_of_reconfigurations());
Per512ecb32016-09-23 15:52:06 +0200819
820 // Capture a frame and wait for it to synchronize with the encoder thread.
Perf8c5f2b2016-09-23 16:24:55 +0200821 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700822 WaitForEncodedFrame(1);
Per21d45d22016-10-30 21:37:57 +0100823 // The encoder will have been configured once when the first frame is
824 // received.
825 EXPECT_EQ(1, sink_.number_of_reconfigurations());
Per512ecb32016-09-23 15:52:06 +0200826
827 VideoEncoderConfig video_encoder_config;
Niels Möller259a4972018-04-05 15:36:51 +0200828 test::FillEncoderConfiguration(kVideoCodecVP8, 1, &video_encoder_config);
Per512ecb32016-09-23 15:52:06 +0200829 video_encoder_config.min_transmit_bitrate_bps = 9999;
mflodmancc3d4422017-08-03 08:27:51 -0700830 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
Niels Möllerf1338562018-04-26 09:51:47 +0200831 kMaxPayloadLength);
Per512ecb32016-09-23 15:52:06 +0200832
833 // Capture a frame and wait for it to synchronize with the encoder thread.
Perf8c5f2b2016-09-23 16:24:55 +0200834 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700835 WaitForEncodedFrame(2);
Per21d45d22016-10-30 21:37:57 +0100836 EXPECT_EQ(2, sink_.number_of_reconfigurations());
perkj3b703ed2016-09-29 23:25:40 -0700837 EXPECT_EQ(9999, sink_.last_min_transmit_bitrate());
perkj26105b42016-09-29 22:39:10 -0700838
mflodmancc3d4422017-08-03 08:27:51 -0700839 video_stream_encoder_->Stop();
perkj26105b42016-09-29 22:39:10 -0700840}
841
mflodmancc3d4422017-08-03 08:27:51 -0700842TEST_F(VideoStreamEncoderTest, FrameResolutionChangeReconfigureEncoder) {
843 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkjfa10b552016-10-02 23:45:26 -0700844
845 // Capture a frame and wait for it to synchronize with the encoder thread.
846 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700847 WaitForEncodedFrame(1);
Per21d45d22016-10-30 21:37:57 +0100848 // The encoder will have been configured once.
849 EXPECT_EQ(1, sink_.number_of_reconfigurations());
perkjfa10b552016-10-02 23:45:26 -0700850 EXPECT_EQ(codec_width_, fake_encoder_.codec_config().width);
851 EXPECT_EQ(codec_height_, fake_encoder_.codec_config().height);
852
853 codec_width_ *= 2;
854 codec_height_ *= 2;
855 // Capture a frame with a higher resolution and wait for it to synchronize
856 // with the encoder thread.
857 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700858 WaitForEncodedFrame(2);
perkjfa10b552016-10-02 23:45:26 -0700859 EXPECT_EQ(codec_width_, fake_encoder_.codec_config().width);
860 EXPECT_EQ(codec_height_, fake_encoder_.codec_config().height);
Per21d45d22016-10-30 21:37:57 +0100861 EXPECT_EQ(2, sink_.number_of_reconfigurations());
perkjfa10b552016-10-02 23:45:26 -0700862
mflodmancc3d4422017-08-03 08:27:51 -0700863 video_stream_encoder_->Stop();
perkjfa10b552016-10-02 23:45:26 -0700864}
865
mflodmancc3d4422017-08-03 08:27:51 -0700866TEST_F(VideoStreamEncoderTest, SwitchSourceDeregisterEncoderAsSink) {
perkj803d97f2016-11-01 11:45:46 -0700867 EXPECT_TRUE(video_source_.has_sinks());
868 test::FrameForwarder new_video_source;
mflodmancc3d4422017-08-03 08:27:51 -0700869 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -0700870 &new_video_source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
perkj803d97f2016-11-01 11:45:46 -0700871 EXPECT_FALSE(video_source_.has_sinks());
872 EXPECT_TRUE(new_video_source.has_sinks());
873
mflodmancc3d4422017-08-03 08:27:51 -0700874 video_stream_encoder_->Stop();
perkj803d97f2016-11-01 11:45:46 -0700875}
876
mflodmancc3d4422017-08-03 08:27:51 -0700877TEST_F(VideoStreamEncoderTest, SinkWantsRotationApplied) {
perkj803d97f2016-11-01 11:45:46 -0700878 EXPECT_FALSE(video_source_.sink_wants().rotation_applied);
mflodmancc3d4422017-08-03 08:27:51 -0700879 video_stream_encoder_->SetSink(&sink_, true /*rotation_applied*/);
perkj803d97f2016-11-01 11:45:46 -0700880 EXPECT_TRUE(video_source_.sink_wants().rotation_applied);
mflodmancc3d4422017-08-03 08:27:51 -0700881 video_stream_encoder_->Stop();
perkj803d97f2016-11-01 11:45:46 -0700882}
883
Jonathan Yubc771b72017-12-08 17:04:29 -0800884TEST_F(VideoStreamEncoderTest, TestCpuDowngrades_BalancedMode) {
885 const int kFramerateFps = 30;
asaperssonf7e294d2017-06-13 23:25:22 -0700886 const int kWidth = 1280;
887 const int kHeight = 720;
Jonathan Yubc771b72017-12-08 17:04:29 -0800888
889 // We rely on the automatic resolution adaptation, but we handle framerate
890 // adaptation manually by mocking the stats proxy.
891 video_source_.set_adaptation_enabled(true);
asaperssonf7e294d2017-06-13 23:25:22 -0700892
Taylor Brandstetter49fcc102018-05-16 14:20:41 -0700893 // Enable BALANCED preference, no initial limitation.
Jonathan Yubc771b72017-12-08 17:04:29 -0800894 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
Taylor Brandstetter49fcc102018-05-16 14:20:41 -0700895 video_stream_encoder_->SetSource(&video_source_,
896 webrtc::DegradationPreference::BALANCED);
Jonathan Yubc771b72017-12-08 17:04:29 -0800897 VerifyNoLimitation(video_source_.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -0700898 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
Jonathan Yubc771b72017-12-08 17:04:29 -0800899 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
asaperssonf7e294d2017-06-13 23:25:22 -0700900 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
901
Jonathan Yubc771b72017-12-08 17:04:29 -0800902 // Adapt down as far as possible.
903 rtc::VideoSinkWants last_wants;
904 int64_t t = 1;
905 int loop_count = 0;
906 do {
907 ++loop_count;
908 last_wants = video_source_.sink_wants();
909
910 // Simulate the framerate we've been asked to adapt to.
911 const int fps = std::min(kFramerateFps, last_wants.max_framerate_fps);
912 const int frame_interval_ms = rtc::kNumMillisecsPerSec / fps;
913 VideoSendStream::Stats mock_stats = stats_proxy_->GetStats();
914 mock_stats.input_frame_rate = fps;
915 stats_proxy_->SetMockStats(mock_stats);
916
917 video_source_.IncomingCapturedFrame(CreateFrame(t, kWidth, kHeight));
918 sink_.WaitForEncodedFrame(t);
919 t += frame_interval_ms;
920
mflodmancc3d4422017-08-03 08:27:51 -0700921 video_stream_encoder_->TriggerCpuOveruse();
Jonathan Yubc771b72017-12-08 17:04:29 -0800922 VerifyBalancedModeFpsRange(
923 video_source_.sink_wants(),
924 *video_source_.last_sent_width() * *video_source_.last_sent_height());
925 } while (video_source_.sink_wants().max_pixel_count <
926 last_wants.max_pixel_count ||
927 video_source_.sink_wants().max_framerate_fps <
928 last_wants.max_framerate_fps);
asaperssonf7e294d2017-06-13 23:25:22 -0700929
Jonathan Yubc771b72017-12-08 17:04:29 -0800930 // Verify that we've adapted all the way down.
931 stats_proxy_->ResetMockStats();
asaperssonf7e294d2017-06-13 23:25:22 -0700932 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
Jonathan Yubc771b72017-12-08 17:04:29 -0800933 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_framerate);
934 EXPECT_EQ(loop_count - 1,
asaperssonf7e294d2017-06-13 23:25:22 -0700935 stats_proxy_->GetStats().number_of_cpu_adapt_changes);
Jonathan Yubc771b72017-12-08 17:04:29 -0800936 EXPECT_EQ(kMinPixelsPerFrame, *video_source_.last_sent_width() *
937 *video_source_.last_sent_height());
938 EXPECT_EQ(kMinBalancedFramerateFps,
939 video_source_.sink_wants().max_framerate_fps);
asaperssonf7e294d2017-06-13 23:25:22 -0700940
Jonathan Yubc771b72017-12-08 17:04:29 -0800941 // Adapt back up the same number of times we adapted down.
942 for (int i = 0; i < loop_count - 1; ++i) {
943 last_wants = video_source_.sink_wants();
944
945 // Simulate the framerate we've been asked to adapt to.
946 const int fps = std::min(kFramerateFps, last_wants.max_framerate_fps);
947 const int frame_interval_ms = rtc::kNumMillisecsPerSec / fps;
948 VideoSendStream::Stats mock_stats = stats_proxy_->GetStats();
949 mock_stats.input_frame_rate = fps;
950 stats_proxy_->SetMockStats(mock_stats);
951
952 video_source_.IncomingCapturedFrame(CreateFrame(t, kWidth, kHeight));
953 sink_.WaitForEncodedFrame(t);
954 t += frame_interval_ms;
955
mflodmancc3d4422017-08-03 08:27:51 -0700956 video_stream_encoder_->TriggerCpuNormalUsage();
Jonathan Yubc771b72017-12-08 17:04:29 -0800957 VerifyBalancedModeFpsRange(
958 video_source_.sink_wants(),
959 *video_source_.last_sent_width() * *video_source_.last_sent_height());
960 EXPECT_TRUE(video_source_.sink_wants().max_pixel_count >
961 last_wants.max_pixel_count ||
962 video_source_.sink_wants().max_framerate_fps >
963 last_wants.max_framerate_fps);
asaperssonf7e294d2017-06-13 23:25:22 -0700964 }
965
Åsa Persson8c1bf952018-09-13 10:42:19 +0200966 VerifyFpsMaxResolutionMax(video_source_.sink_wants());
Jonathan Yubc771b72017-12-08 17:04:29 -0800967 stats_proxy_->ResetMockStats();
asaperssonf7e294d2017-06-13 23:25:22 -0700968 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
Jonathan Yubc771b72017-12-08 17:04:29 -0800969 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
970 EXPECT_EQ((loop_count - 1) * 2,
971 stats_proxy_->GetStats().number_of_cpu_adapt_changes);
asaperssonf7e294d2017-06-13 23:25:22 -0700972
mflodmancc3d4422017-08-03 08:27:51 -0700973 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -0700974}
mflodmancc3d4422017-08-03 08:27:51 -0700975TEST_F(VideoStreamEncoderTest, SinkWantsStoredByDegradationPreference) {
976 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson02465b82017-04-10 01:12:52 -0700977 VerifyNoLimitation(video_source_.sink_wants());
perkj803d97f2016-11-01 11:45:46 -0700978
sprangc5d62e22017-04-02 23:53:04 -0700979 const int kFrameWidth = 1280;
980 const int kFrameHeight = 720;
sprangc5d62e22017-04-02 23:53:04 -0700981
Åsa Persson8c1bf952018-09-13 10:42:19 +0200982 int64_t frame_timestamp = 1;
perkj803d97f2016-11-01 11:45:46 -0700983
kthelgason5e13d412016-12-01 03:59:51 -0800984 video_source_.IncomingCapturedFrame(
sprangc5d62e22017-04-02 23:53:04 -0700985 CreateFrame(frame_timestamp, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -0700986 WaitForEncodedFrame(frame_timestamp);
sprangc5d62e22017-04-02 23:53:04 -0700987 frame_timestamp += kFrameIntervalMs;
988
perkj803d97f2016-11-01 11:45:46 -0700989 // Trigger CPU overuse.
mflodmancc3d4422017-08-03 08:27:51 -0700990 video_stream_encoder_->TriggerCpuOveruse();
perkj803d97f2016-11-01 11:45:46 -0700991 video_source_.IncomingCapturedFrame(
sprangc5d62e22017-04-02 23:53:04 -0700992 CreateFrame(frame_timestamp, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -0700993 WaitForEncodedFrame(frame_timestamp);
sprangc5d62e22017-04-02 23:53:04 -0700994 frame_timestamp += kFrameIntervalMs;
sprang3ea3c772017-03-30 07:23:48 -0700995
asapersson0944a802017-04-07 00:57:58 -0700996 // Default degradation preference is maintain-framerate, so will lower max
sprangc5d62e22017-04-02 23:53:04 -0700997 // wanted resolution.
998 EXPECT_FALSE(video_source_.sink_wants().target_pixel_count);
999 EXPECT_LT(video_source_.sink_wants().max_pixel_count,
1000 kFrameWidth * kFrameHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001001 EXPECT_EQ(kDefaultFramerate, video_source_.sink_wants().max_framerate_fps);
sprangc5d62e22017-04-02 23:53:04 -07001002
1003 // Set new source, switch to maintain-resolution.
perkj803d97f2016-11-01 11:45:46 -07001004 test::FrameForwarder new_video_source;
mflodmancc3d4422017-08-03 08:27:51 -07001005 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001006 &new_video_source, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
perkj803d97f2016-11-01 11:45:46 -07001007
sprangc5d62e22017-04-02 23:53:04 -07001008 // Initially no degradation registered.
Åsa Persson8c1bf952018-09-13 10:42:19 +02001009 VerifyFpsMaxResolutionMax(new_video_source.sink_wants());
perkj803d97f2016-11-01 11:45:46 -07001010
sprangc5d62e22017-04-02 23:53:04 -07001011 // Force an input frame rate to be available, or the adaptation call won't
1012 // know what framerate to adapt form.
asapersson02465b82017-04-10 01:12:52 -07001013 const int kInputFps = 30;
sprangc5d62e22017-04-02 23:53:04 -07001014 VideoSendStream::Stats stats = stats_proxy_->GetStats();
asapersson02465b82017-04-10 01:12:52 -07001015 stats.input_frame_rate = kInputFps;
sprangc5d62e22017-04-02 23:53:04 -07001016 stats_proxy_->SetMockStats(stats);
1017
mflodmancc3d4422017-08-03 08:27:51 -07001018 video_stream_encoder_->TriggerCpuOveruse();
perkj803d97f2016-11-01 11:45:46 -07001019 new_video_source.IncomingCapturedFrame(
sprangc5d62e22017-04-02 23:53:04 -07001020 CreateFrame(frame_timestamp, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07001021 WaitForEncodedFrame(frame_timestamp);
sprangc5d62e22017-04-02 23:53:04 -07001022 frame_timestamp += kFrameIntervalMs;
1023
1024 // Some framerate constraint should be set.
sprang84a37592017-02-10 07:04:27 -08001025 EXPECT_FALSE(new_video_source.sink_wants().target_pixel_count);
sprangc5d62e22017-04-02 23:53:04 -07001026 EXPECT_EQ(std::numeric_limits<int>::max(),
1027 new_video_source.sink_wants().max_pixel_count);
asapersson02465b82017-04-10 01:12:52 -07001028 EXPECT_LT(new_video_source.sink_wants().max_framerate_fps, kInputFps);
sprangc5d62e22017-04-02 23:53:04 -07001029
asapersson02465b82017-04-10 01:12:52 -07001030 // Turn off degradation completely.
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001031 video_stream_encoder_->SetSource(&new_video_source,
1032 webrtc::DegradationPreference::DISABLED);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001033 VerifyFpsMaxResolutionMax(new_video_source.sink_wants());
sprangc5d62e22017-04-02 23:53:04 -07001034
mflodmancc3d4422017-08-03 08:27:51 -07001035 video_stream_encoder_->TriggerCpuOveruse();
sprangc5d62e22017-04-02 23:53:04 -07001036 new_video_source.IncomingCapturedFrame(
1037 CreateFrame(frame_timestamp, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07001038 WaitForEncodedFrame(frame_timestamp);
sprangc5d62e22017-04-02 23:53:04 -07001039 frame_timestamp += kFrameIntervalMs;
1040
1041 // Still no degradation.
Åsa Persson8c1bf952018-09-13 10:42:19 +02001042 VerifyFpsMaxResolutionMax(new_video_source.sink_wants());
perkj803d97f2016-11-01 11:45:46 -07001043
1044 // Calling SetSource with resolution scaling enabled apply the old SinkWants.
mflodmancc3d4422017-08-03 08:27:51 -07001045 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001046 &new_video_source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
sprangc5d62e22017-04-02 23:53:04 -07001047 EXPECT_LT(new_video_source.sink_wants().max_pixel_count,
1048 kFrameWidth * kFrameHeight);
sprang84a37592017-02-10 07:04:27 -08001049 EXPECT_FALSE(new_video_source.sink_wants().target_pixel_count);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001050 EXPECT_EQ(kDefaultFramerate, new_video_source.sink_wants().max_framerate_fps);
sprangc5d62e22017-04-02 23:53:04 -07001051
1052 // Calling SetSource with framerate scaling enabled apply the old SinkWants.
mflodmancc3d4422017-08-03 08:27:51 -07001053 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001054 &new_video_source, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
sprangc5d62e22017-04-02 23:53:04 -07001055 EXPECT_FALSE(new_video_source.sink_wants().target_pixel_count);
1056 EXPECT_EQ(std::numeric_limits<int>::max(),
1057 new_video_source.sink_wants().max_pixel_count);
asapersson02465b82017-04-10 01:12:52 -07001058 EXPECT_LT(new_video_source.sink_wants().max_framerate_fps, kInputFps);
perkj803d97f2016-11-01 11:45:46 -07001059
mflodmancc3d4422017-08-03 08:27:51 -07001060 video_stream_encoder_->Stop();
perkj803d97f2016-11-01 11:45:46 -07001061}
1062
mflodmancc3d4422017-08-03 08:27:51 -07001063TEST_F(VideoStreamEncoderTest, StatsTracksQualityAdaptationStats) {
1064 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkj803d97f2016-11-01 11:45:46 -07001065
asaperssonfab67072017-04-04 05:51:49 -07001066 const int kWidth = 1280;
1067 const int kHeight = 720;
asaperssonfab67072017-04-04 05:51:49 -07001068 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001069 WaitForEncodedFrame(1);
asaperssonfab67072017-04-04 05:51:49 -07001070 VideoSendStream::Stats stats = stats_proxy_->GetStats();
1071 EXPECT_FALSE(stats.bw_limited_resolution);
1072 EXPECT_EQ(0, stats.number_of_quality_adapt_changes);
1073
1074 // Trigger adapt down.
mflodmancc3d4422017-08-03 08:27:51 -07001075 video_stream_encoder_->TriggerQualityLow();
asaperssonfab67072017-04-04 05:51:49 -07001076 video_source_.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001077 WaitForEncodedFrame(2);
asaperssonfab67072017-04-04 05:51:49 -07001078
1079 stats = stats_proxy_->GetStats();
1080 EXPECT_TRUE(stats.bw_limited_resolution);
1081 EXPECT_EQ(1, stats.number_of_quality_adapt_changes);
1082
1083 // Trigger adapt up.
mflodmancc3d4422017-08-03 08:27:51 -07001084 video_stream_encoder_->TriggerQualityHigh();
asaperssonfab67072017-04-04 05:51:49 -07001085 video_source_.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001086 WaitForEncodedFrame(3);
asaperssonfab67072017-04-04 05:51:49 -07001087
1088 stats = stats_proxy_->GetStats();
1089 EXPECT_FALSE(stats.bw_limited_resolution);
1090 EXPECT_EQ(2, stats.number_of_quality_adapt_changes);
1091 EXPECT_EQ(0, stats.number_of_cpu_adapt_changes);
1092
mflodmancc3d4422017-08-03 08:27:51 -07001093 video_stream_encoder_->Stop();
asaperssonfab67072017-04-04 05:51:49 -07001094}
1095
mflodmancc3d4422017-08-03 08:27:51 -07001096TEST_F(VideoStreamEncoderTest, StatsTracksCpuAdaptationStats) {
1097 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonfab67072017-04-04 05:51:49 -07001098
1099 const int kWidth = 1280;
1100 const int kHeight = 720;
asaperssonfab67072017-04-04 05:51:49 -07001101 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001102 WaitForEncodedFrame(1);
perkj803d97f2016-11-01 11:45:46 -07001103 VideoSendStream::Stats stats = stats_proxy_->GetStats();
1104 EXPECT_FALSE(stats.cpu_limited_resolution);
1105 EXPECT_EQ(0, stats.number_of_cpu_adapt_changes);
1106
1107 // Trigger CPU overuse.
mflodmancc3d4422017-08-03 08:27:51 -07001108 video_stream_encoder_->TriggerCpuOveruse();
asaperssonfab67072017-04-04 05:51:49 -07001109 video_source_.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001110 WaitForEncodedFrame(2);
perkj803d97f2016-11-01 11:45:46 -07001111
1112 stats = stats_proxy_->GetStats();
1113 EXPECT_TRUE(stats.cpu_limited_resolution);
1114 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1115
1116 // Trigger CPU normal use.
mflodmancc3d4422017-08-03 08:27:51 -07001117 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssonfab67072017-04-04 05:51:49 -07001118 video_source_.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001119 WaitForEncodedFrame(3);
perkj803d97f2016-11-01 11:45:46 -07001120
1121 stats = stats_proxy_->GetStats();
1122 EXPECT_FALSE(stats.cpu_limited_resolution);
1123 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
asaperssonfab67072017-04-04 05:51:49 -07001124 EXPECT_EQ(0, stats.number_of_quality_adapt_changes);
perkj803d97f2016-11-01 11:45:46 -07001125
mflodmancc3d4422017-08-03 08:27:51 -07001126 video_stream_encoder_->Stop();
perkj803d97f2016-11-01 11:45:46 -07001127}
1128
mflodmancc3d4422017-08-03 08:27:51 -07001129TEST_F(VideoStreamEncoderTest, SwitchingSourceKeepsCpuAdaptation) {
1130 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
kthelgason876222f2016-11-29 01:44:11 -08001131
asaperssonfab67072017-04-04 05:51:49 -07001132 const int kWidth = 1280;
1133 const int kHeight = 720;
1134 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001135 WaitForEncodedFrame(1);
kthelgason876222f2016-11-29 01:44:11 -08001136 VideoSendStream::Stats stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001137 EXPECT_FALSE(stats.bw_limited_resolution);
kthelgason876222f2016-11-29 01:44:11 -08001138 EXPECT_FALSE(stats.cpu_limited_resolution);
1139 EXPECT_EQ(0, stats.number_of_cpu_adapt_changes);
1140
asaperssonfab67072017-04-04 05:51:49 -07001141 // Trigger CPU overuse.
mflodmancc3d4422017-08-03 08:27:51 -07001142 video_stream_encoder_->TriggerCpuOveruse();
asaperssonfab67072017-04-04 05:51:49 -07001143 video_source_.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001144 WaitForEncodedFrame(2);
kthelgason876222f2016-11-29 01:44:11 -08001145 stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001146 EXPECT_FALSE(stats.bw_limited_resolution);
kthelgason876222f2016-11-29 01:44:11 -08001147 EXPECT_TRUE(stats.cpu_limited_resolution);
1148 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1149
1150 // Set new source with adaptation still enabled.
1151 test::FrameForwarder new_video_source;
mflodmancc3d4422017-08-03 08:27:51 -07001152 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001153 &new_video_source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
kthelgason876222f2016-11-29 01:44:11 -08001154
asaperssonfab67072017-04-04 05:51:49 -07001155 new_video_source.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001156 WaitForEncodedFrame(3);
kthelgason876222f2016-11-29 01:44:11 -08001157 stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001158 EXPECT_FALSE(stats.bw_limited_resolution);
kthelgason876222f2016-11-29 01:44:11 -08001159 EXPECT_TRUE(stats.cpu_limited_resolution);
1160 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1161
1162 // Set adaptation disabled.
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001163 video_stream_encoder_->SetSource(&new_video_source,
1164 webrtc::DegradationPreference::DISABLED);
kthelgason876222f2016-11-29 01:44:11 -08001165
asaperssonfab67072017-04-04 05:51:49 -07001166 new_video_source.IncomingCapturedFrame(CreateFrame(4, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001167 WaitForEncodedFrame(4);
kthelgason876222f2016-11-29 01:44:11 -08001168 stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001169 EXPECT_FALSE(stats.bw_limited_resolution);
kthelgason876222f2016-11-29 01:44:11 -08001170 EXPECT_FALSE(stats.cpu_limited_resolution);
1171 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1172
1173 // Set adaptation back to enabled.
mflodmancc3d4422017-08-03 08:27:51 -07001174 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001175 &new_video_source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
kthelgason876222f2016-11-29 01:44:11 -08001176
asaperssonfab67072017-04-04 05:51:49 -07001177 new_video_source.IncomingCapturedFrame(CreateFrame(5, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001178 WaitForEncodedFrame(5);
kthelgason876222f2016-11-29 01:44:11 -08001179 stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001180 EXPECT_FALSE(stats.bw_limited_resolution);
kthelgason876222f2016-11-29 01:44:11 -08001181 EXPECT_TRUE(stats.cpu_limited_resolution);
1182 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1183
asaperssonfab67072017-04-04 05:51:49 -07001184 // Trigger CPU normal use.
mflodmancc3d4422017-08-03 08:27:51 -07001185 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssonfab67072017-04-04 05:51:49 -07001186 new_video_source.IncomingCapturedFrame(CreateFrame(6, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001187 WaitForEncodedFrame(6);
kthelgason876222f2016-11-29 01:44:11 -08001188 stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001189 EXPECT_FALSE(stats.bw_limited_resolution);
kthelgason876222f2016-11-29 01:44:11 -08001190 EXPECT_FALSE(stats.cpu_limited_resolution);
1191 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
asapersson02465b82017-04-10 01:12:52 -07001192 EXPECT_EQ(0, stats.number_of_quality_adapt_changes);
kthelgason876222f2016-11-29 01:44:11 -08001193
mflodmancc3d4422017-08-03 08:27:51 -07001194 video_stream_encoder_->Stop();
kthelgason876222f2016-11-29 01:44:11 -08001195}
1196
mflodmancc3d4422017-08-03 08:27:51 -07001197TEST_F(VideoStreamEncoderTest, SwitchingSourceKeepsQualityAdaptation) {
1198 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
kthelgason876222f2016-11-29 01:44:11 -08001199
asaperssonfab67072017-04-04 05:51:49 -07001200 const int kWidth = 1280;
1201 const int kHeight = 720;
1202 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001203 WaitForEncodedFrame(1);
kthelgason876222f2016-11-29 01:44:11 -08001204 VideoSendStream::Stats stats = stats_proxy_->GetStats();
kthelgason876222f2016-11-29 01:44:11 -08001205 EXPECT_FALSE(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(0, stats.number_of_quality_adapt_changes);
kthelgason876222f2016-11-29 01:44:11 -08001208
1209 // Set new source with adaptation still enabled.
1210 test::FrameForwarder new_video_source;
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001211 video_stream_encoder_->SetSource(&new_video_source,
1212 webrtc::DegradationPreference::BALANCED);
kthelgason876222f2016-11-29 01:44:11 -08001213
asaperssonfab67072017-04-04 05:51:49 -07001214 new_video_source.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001215 WaitForEncodedFrame(2);
kthelgason876222f2016-11-29 01:44:11 -08001216 stats = stats_proxy_->GetStats();
kthelgason876222f2016-11-29 01:44:11 -08001217 EXPECT_FALSE(stats.bw_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001218 EXPECT_FALSE(stats.bw_limited_framerate);
asaperssonfab67072017-04-04 05:51:49 -07001219 EXPECT_EQ(0, stats.number_of_quality_adapt_changes);
kthelgason876222f2016-11-29 01:44:11 -08001220
asaperssonfab67072017-04-04 05:51:49 -07001221 // Trigger adapt down.
mflodmancc3d4422017-08-03 08:27:51 -07001222 video_stream_encoder_->TriggerQualityLow();
asaperssonfab67072017-04-04 05:51:49 -07001223 new_video_source.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001224 WaitForEncodedFrame(3);
kthelgason876222f2016-11-29 01:44:11 -08001225 stats = stats_proxy_->GetStats();
kthelgason876222f2016-11-29 01:44:11 -08001226 EXPECT_TRUE(stats.bw_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001227 EXPECT_FALSE(stats.bw_limited_framerate);
asaperssonfab67072017-04-04 05:51:49 -07001228 EXPECT_EQ(1, stats.number_of_quality_adapt_changes);
kthelgason876222f2016-11-29 01:44:11 -08001229
asaperssonfab67072017-04-04 05:51:49 -07001230 // Set new source with adaptation still enabled.
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001231 video_stream_encoder_->SetSource(&new_video_source,
1232 webrtc::DegradationPreference::BALANCED);
kthelgason876222f2016-11-29 01:44:11 -08001233
asaperssonfab67072017-04-04 05:51:49 -07001234 new_video_source.IncomingCapturedFrame(CreateFrame(4, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001235 WaitForEncodedFrame(4);
kthelgason876222f2016-11-29 01:44:11 -08001236 stats = stats_proxy_->GetStats();
kthelgason876222f2016-11-29 01:44:11 -08001237 EXPECT_TRUE(stats.bw_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001238 EXPECT_FALSE(stats.bw_limited_framerate);
asaperssonfab67072017-04-04 05:51:49 -07001239 EXPECT_EQ(1, stats.number_of_quality_adapt_changes);
kthelgason876222f2016-11-29 01:44:11 -08001240
asapersson02465b82017-04-10 01:12:52 -07001241 // Disable resolution scaling.
mflodmancc3d4422017-08-03 08:27:51 -07001242 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001243 &new_video_source, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
kthelgason876222f2016-11-29 01:44:11 -08001244
asaperssonfab67072017-04-04 05:51:49 -07001245 new_video_source.IncomingCapturedFrame(CreateFrame(5, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001246 WaitForEncodedFrame(5);
kthelgason876222f2016-11-29 01:44:11 -08001247 stats = stats_proxy_->GetStats();
kthelgason876222f2016-11-29 01:44:11 -08001248 EXPECT_FALSE(stats.bw_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001249 EXPECT_FALSE(stats.bw_limited_framerate);
asaperssonfab67072017-04-04 05:51:49 -07001250 EXPECT_EQ(1, stats.number_of_quality_adapt_changes);
1251 EXPECT_EQ(0, stats.number_of_cpu_adapt_changes);
kthelgason876222f2016-11-29 01:44:11 -08001252
mflodmancc3d4422017-08-03 08:27:51 -07001253 video_stream_encoder_->Stop();
kthelgason876222f2016-11-29 01:44:11 -08001254}
1255
mflodmancc3d4422017-08-03 08:27:51 -07001256TEST_F(VideoStreamEncoderTest,
1257 QualityAdaptationStatsAreResetWhenScalerIsDisabled) {
1258 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson36e9eb42017-03-31 05:29:12 -07001259
1260 const int kWidth = 1280;
1261 const int kHeight = 720;
Åsa Persson8c1bf952018-09-13 10:42:19 +02001262 int64_t timestamp_ms = kFrameIntervalMs;
asapersson36e9eb42017-03-31 05:29:12 -07001263 video_source_.set_adaptation_enabled(true);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001264 video_source_.IncomingCapturedFrame(
1265 CreateFrame(timestamp_ms, kWidth, kHeight));
1266 WaitForEncodedFrame(timestamp_ms);
asapersson36e9eb42017-03-31 05:29:12 -07001267 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1268 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1269 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1270
1271 // Trigger adapt down.
mflodmancc3d4422017-08-03 08:27:51 -07001272 video_stream_encoder_->TriggerQualityLow();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001273 timestamp_ms += kFrameIntervalMs;
1274 video_source_.IncomingCapturedFrame(
1275 CreateFrame(timestamp_ms, kWidth, kHeight));
1276 WaitForEncodedFrame(timestamp_ms);
asapersson36e9eb42017-03-31 05:29:12 -07001277 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1278 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1279 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1280
1281 // Trigger overuse.
mflodmancc3d4422017-08-03 08:27:51 -07001282 video_stream_encoder_->TriggerCpuOveruse();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001283 timestamp_ms += kFrameIntervalMs;
1284 video_source_.IncomingCapturedFrame(
1285 CreateFrame(timestamp_ms, kWidth, kHeight));
1286 WaitForEncodedFrame(timestamp_ms);
asapersson36e9eb42017-03-31 05:29:12 -07001287 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1288 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1289 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1290
Niels Möller4db138e2018-04-19 09:04:13 +02001291 // Leave source unchanged, but disable quality scaler.
asapersson36e9eb42017-03-31 05:29:12 -07001292 fake_encoder_.SetQualityScaling(false);
Niels Möller4db138e2018-04-19 09:04:13 +02001293
1294 VideoEncoderConfig video_encoder_config;
1295 test::FillEncoderConfiguration(kVideoCodecVP8, 1, &video_encoder_config);
1296 // Make format different, to force recreation of encoder.
1297 video_encoder_config.video_format.parameters["foo"] = "foo";
1298 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
Niels Möllerf1338562018-04-26 09:51:47 +02001299 kMaxPayloadLength);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001300 timestamp_ms += kFrameIntervalMs;
1301 video_source_.IncomingCapturedFrame(
1302 CreateFrame(timestamp_ms, kWidth, kHeight));
1303 WaitForEncodedFrame(timestamp_ms);
asapersson36e9eb42017-03-31 05:29:12 -07001304 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1305 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1306 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1307
mflodmancc3d4422017-08-03 08:27:51 -07001308 video_stream_encoder_->Stop();
asapersson36e9eb42017-03-31 05:29:12 -07001309}
1310
mflodmancc3d4422017-08-03 08:27:51 -07001311TEST_F(VideoStreamEncoderTest,
1312 StatsTracksCpuAdaptationStatsWhenSwitchingSource) {
1313 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkj803d97f2016-11-01 11:45:46 -07001314
asapersson0944a802017-04-07 00:57:58 -07001315 const int kWidth = 1280;
1316 const int kHeight = 720;
sprang84a37592017-02-10 07:04:27 -08001317 int sequence = 1;
perkj803d97f2016-11-01 11:45:46 -07001318
asaperssonfab67072017-04-04 05:51:49 -07001319 video_source_.IncomingCapturedFrame(CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001320 WaitForEncodedFrame(sequence++);
perkj803d97f2016-11-01 11:45:46 -07001321 VideoSendStream::Stats stats = stats_proxy_->GetStats();
sprang84a37592017-02-10 07:04:27 -08001322 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001323 EXPECT_FALSE(stats.cpu_limited_framerate);
sprang84a37592017-02-10 07:04:27 -08001324 EXPECT_EQ(0, stats.number_of_cpu_adapt_changes);
1325
asapersson02465b82017-04-10 01:12:52 -07001326 // Trigger CPU overuse, should now adapt down.
mflodmancc3d4422017-08-03 08:27:51 -07001327 video_stream_encoder_->TriggerCpuOveruse();
asaperssonfab67072017-04-04 05:51:49 -07001328 video_source_.IncomingCapturedFrame(CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001329 WaitForEncodedFrame(sequence++);
sprang84a37592017-02-10 07:04:27 -08001330 stats = stats_proxy_->GetStats();
perkj803d97f2016-11-01 11:45:46 -07001331 EXPECT_TRUE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001332 EXPECT_FALSE(stats.cpu_limited_framerate);
perkj803d97f2016-11-01 11:45:46 -07001333 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1334
1335 // Set new source with adaptation still enabled.
1336 test::FrameForwarder new_video_source;
mflodmancc3d4422017-08-03 08:27:51 -07001337 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001338 &new_video_source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
perkj803d97f2016-11-01 11:45:46 -07001339
1340 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001341 CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001342 WaitForEncodedFrame(sequence++);
perkj803d97f2016-11-01 11:45:46 -07001343 stats = stats_proxy_->GetStats();
1344 EXPECT_TRUE(stats.cpu_limited_resolution);
asapersson09f05612017-05-15 23:40:18 -07001345 EXPECT_FALSE(stats.cpu_limited_framerate);
perkj803d97f2016-11-01 11:45:46 -07001346 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1347
sprangc5d62e22017-04-02 23:53:04 -07001348 // Set cpu adaptation by frame dropping.
mflodmancc3d4422017-08-03 08:27:51 -07001349 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001350 &new_video_source, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
perkj803d97f2016-11-01 11:45:46 -07001351 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001352 CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001353 WaitForEncodedFrame(sequence++);
perkj803d97f2016-11-01 11:45:46 -07001354 stats = stats_proxy_->GetStats();
sprangc5d62e22017-04-02 23:53:04 -07001355 // Not adapted at first.
perkj803d97f2016-11-01 11:45:46 -07001356 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson09f05612017-05-15 23:40:18 -07001357 EXPECT_FALSE(stats.cpu_limited_framerate);
perkj803d97f2016-11-01 11:45:46 -07001358 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1359
sprangc5d62e22017-04-02 23:53:04 -07001360 // Force an input frame rate to be available, or the adaptation call won't
asapersson09f05612017-05-15 23:40:18 -07001361 // know what framerate to adapt from.
sprangc5d62e22017-04-02 23:53:04 -07001362 VideoSendStream::Stats mock_stats = stats_proxy_->GetStats();
1363 mock_stats.input_frame_rate = 30;
1364 stats_proxy_->SetMockStats(mock_stats);
mflodmancc3d4422017-08-03 08:27:51 -07001365 video_stream_encoder_->TriggerCpuOveruse();
sprangc5d62e22017-04-02 23:53:04 -07001366 stats_proxy_->ResetMockStats();
1367
1368 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001369 CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001370 WaitForEncodedFrame(sequence++);
sprangc5d62e22017-04-02 23:53:04 -07001371
1372 // Framerate now adapted.
1373 stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001374 EXPECT_FALSE(stats.cpu_limited_resolution);
1375 EXPECT_TRUE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001376 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
1377
1378 // Disable CPU adaptation.
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001379 video_stream_encoder_->SetSource(&new_video_source,
1380 webrtc::DegradationPreference::DISABLED);
sprangc5d62e22017-04-02 23:53:04 -07001381 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001382 CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001383 WaitForEncodedFrame(sequence++);
sprangc5d62e22017-04-02 23:53:04 -07001384
1385 stats = stats_proxy_->GetStats();
1386 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001387 EXPECT_FALSE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001388 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
1389
1390 // Try to trigger overuse. Should not succeed.
1391 stats_proxy_->SetMockStats(mock_stats);
mflodmancc3d4422017-08-03 08:27:51 -07001392 video_stream_encoder_->TriggerCpuOveruse();
sprangc5d62e22017-04-02 23:53:04 -07001393 stats_proxy_->ResetMockStats();
1394
1395 stats = stats_proxy_->GetStats();
1396 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001397 EXPECT_FALSE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001398 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
1399
1400 // Switch back the source with resolution adaptation enabled.
mflodmancc3d4422017-08-03 08:27:51 -07001401 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001402 &video_source_, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
asaperssonfab67072017-04-04 05:51:49 -07001403 video_source_.IncomingCapturedFrame(CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001404 WaitForEncodedFrame(sequence++);
perkj803d97f2016-11-01 11:45:46 -07001405 stats = stats_proxy_->GetStats();
1406 EXPECT_TRUE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001407 EXPECT_FALSE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001408 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
perkj803d97f2016-11-01 11:45:46 -07001409
1410 // Trigger CPU normal usage.
mflodmancc3d4422017-08-03 08:27:51 -07001411 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssonfab67072017-04-04 05:51:49 -07001412 video_source_.IncomingCapturedFrame(CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001413 WaitForEncodedFrame(sequence++);
perkj803d97f2016-11-01 11:45:46 -07001414 stats = stats_proxy_->GetStats();
1415 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001416 EXPECT_FALSE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001417 EXPECT_EQ(3, stats.number_of_cpu_adapt_changes);
1418
1419 // Back to the source with adaptation off, set it back to maintain-resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001420 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001421 &new_video_source, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
sprangc5d62e22017-04-02 23:53:04 -07001422 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001423 CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001424 WaitForEncodedFrame(sequence++);
sprangc5d62e22017-04-02 23:53:04 -07001425 stats = stats_proxy_->GetStats();
asapersson13874762017-06-07 00:01:02 -07001426 // Disabled, since we previously switched the source to disabled.
sprangc5d62e22017-04-02 23:53:04 -07001427 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001428 EXPECT_TRUE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001429 EXPECT_EQ(3, stats.number_of_cpu_adapt_changes);
1430
1431 // Trigger CPU normal usage.
mflodmancc3d4422017-08-03 08:27:51 -07001432 video_stream_encoder_->TriggerCpuNormalUsage();
sprangc5d62e22017-04-02 23:53:04 -07001433 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001434 CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001435 WaitForEncodedFrame(sequence++);
sprangc5d62e22017-04-02 23:53:04 -07001436 stats = stats_proxy_->GetStats();
1437 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001438 EXPECT_FALSE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001439 EXPECT_EQ(4, stats.number_of_cpu_adapt_changes);
asapersson02465b82017-04-10 01:12:52 -07001440 EXPECT_EQ(0, stats.number_of_quality_adapt_changes);
perkj803d97f2016-11-01 11:45:46 -07001441
mflodmancc3d4422017-08-03 08:27:51 -07001442 video_stream_encoder_->Stop();
perkj803d97f2016-11-01 11:45:46 -07001443}
1444
mflodmancc3d4422017-08-03 08:27:51 -07001445TEST_F(VideoStreamEncoderTest,
1446 ScalingUpAndDownDoesNothingWithMaintainResolution) {
asaperssonfab67072017-04-04 05:51:49 -07001447 const int kWidth = 1280;
1448 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001449 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
kthelgason876222f2016-11-29 01:44:11 -08001450
asaperssonfab67072017-04-04 05:51:49 -07001451 // Expect no scaling to begin with.
asapersson02465b82017-04-10 01:12:52 -07001452 VerifyNoLimitation(video_source_.sink_wants());
kthelgason876222f2016-11-29 01:44:11 -08001453
asaperssonfab67072017-04-04 05:51:49 -07001454 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001455 WaitForEncodedFrame(1);
kthelgason876222f2016-11-29 01:44:11 -08001456
asaperssonfab67072017-04-04 05:51:49 -07001457 // Trigger scale down.
mflodmancc3d4422017-08-03 08:27:51 -07001458 video_stream_encoder_->TriggerQualityLow();
kthelgason5e13d412016-12-01 03:59:51 -08001459
asaperssonfab67072017-04-04 05:51:49 -07001460 video_source_.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001461 WaitForEncodedFrame(2);
kthelgason5e13d412016-12-01 03:59:51 -08001462
kthelgason876222f2016-11-29 01:44:11 -08001463 // Expect a scale down.
1464 EXPECT_TRUE(video_source_.sink_wants().max_pixel_count);
asaperssonfab67072017-04-04 05:51:49 -07001465 EXPECT_LT(video_source_.sink_wants().max_pixel_count, kWidth * kHeight);
kthelgason876222f2016-11-29 01:44:11 -08001466
asapersson02465b82017-04-10 01:12:52 -07001467 // Set resolution scaling disabled.
kthelgason876222f2016-11-29 01:44:11 -08001468 test::FrameForwarder new_video_source;
mflodmancc3d4422017-08-03 08:27:51 -07001469 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001470 &new_video_source, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
kthelgason876222f2016-11-29 01:44:11 -08001471
asaperssonfab67072017-04-04 05:51:49 -07001472 // Trigger scale down.
mflodmancc3d4422017-08-03 08:27:51 -07001473 video_stream_encoder_->TriggerQualityLow();
asaperssonfab67072017-04-04 05:51:49 -07001474 new_video_source.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001475 WaitForEncodedFrame(3);
kthelgason876222f2016-11-29 01:44:11 -08001476
asaperssonfab67072017-04-04 05:51:49 -07001477 // Expect no scaling.
sprangc5d62e22017-04-02 23:53:04 -07001478 EXPECT_EQ(std::numeric_limits<int>::max(),
1479 new_video_source.sink_wants().max_pixel_count);
kthelgason876222f2016-11-29 01:44:11 -08001480
asaperssonfab67072017-04-04 05:51:49 -07001481 // Trigger scale up.
mflodmancc3d4422017-08-03 08:27:51 -07001482 video_stream_encoder_->TriggerQualityHigh();
asaperssonfab67072017-04-04 05:51:49 -07001483 new_video_source.IncomingCapturedFrame(CreateFrame(4, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001484 WaitForEncodedFrame(4);
kthelgason876222f2016-11-29 01:44:11 -08001485
asapersson02465b82017-04-10 01:12:52 -07001486 // Expect nothing to change, still no scaling.
sprangc5d62e22017-04-02 23:53:04 -07001487 EXPECT_EQ(std::numeric_limits<int>::max(),
1488 new_video_source.sink_wants().max_pixel_count);
kthelgason876222f2016-11-29 01:44:11 -08001489
mflodmancc3d4422017-08-03 08:27:51 -07001490 video_stream_encoder_->Stop();
kthelgason876222f2016-11-29 01:44:11 -08001491}
1492
mflodmancc3d4422017-08-03 08:27:51 -07001493TEST_F(VideoStreamEncoderTest,
1494 SkipsSameAdaptDownRequest_MaintainFramerateMode) {
asapersson02465b82017-04-10 01:12:52 -07001495 const int kWidth = 1280;
1496 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001497 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson02465b82017-04-10 01:12:52 -07001498
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001499 // Enable MAINTAIN_FRAMERATE preference, no initial limitation.
asapersson02465b82017-04-10 01:12:52 -07001500 test::FrameForwarder source;
mflodmancc3d4422017-08-03 08:27:51 -07001501 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001502 &source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
asapersson02465b82017-04-10 01:12:52 -07001503
1504 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001505 WaitForEncodedFrame(1);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001506 VerifyFpsMaxResolutionMax(source.sink_wants());
asapersson02465b82017-04-10 01:12:52 -07001507 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1508 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1509
1510 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001511 video_stream_encoder_->TriggerCpuOveruse();
asapersson09f05612017-05-15 23:40:18 -07001512 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
asapersson02465b82017-04-10 01:12:52 -07001513 const int kLastMaxPixelCount = source.sink_wants().max_pixel_count;
1514 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1515 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1516
1517 // Trigger adapt down for same input resolution, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07001518 video_stream_encoder_->TriggerCpuOveruse();
asapersson02465b82017-04-10 01:12:52 -07001519 EXPECT_EQ(kLastMaxPixelCount, source.sink_wants().max_pixel_count);
1520 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1521 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1522
mflodmancc3d4422017-08-03 08:27:51 -07001523 video_stream_encoder_->Stop();
asapersson02465b82017-04-10 01:12:52 -07001524}
1525
mflodmancc3d4422017-08-03 08:27:51 -07001526TEST_F(VideoStreamEncoderTest, SkipsSameOrLargerAdaptDownRequest_BalancedMode) {
asaperssonf7e294d2017-06-13 23:25:22 -07001527 const int kWidth = 1280;
1528 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001529 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -07001530
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001531 // Enable BALANCED preference, no initial limitation.
asaperssonf7e294d2017-06-13 23:25:22 -07001532 test::FrameForwarder source;
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001533 video_stream_encoder_->SetSource(&source,
1534 webrtc::DegradationPreference::BALANCED);
asaperssonf7e294d2017-06-13 23:25:22 -07001535 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
1536 sink_.WaitForEncodedFrame(1);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001537 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07001538
1539 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001540 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07001541 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
1542 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1543 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1544 const int kLastMaxPixelCount = source.sink_wants().max_pixel_count;
1545
1546 // Trigger adapt down for same input resolution, expect no change.
1547 source.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
1548 sink_.WaitForEncodedFrame(2);
mflodmancc3d4422017-08-03 08:27:51 -07001549 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07001550 EXPECT_EQ(kLastMaxPixelCount, source.sink_wants().max_pixel_count);
1551 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1552 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1553
1554 // Trigger adapt down for larger input resolution, expect no change.
1555 source.IncomingCapturedFrame(CreateFrame(3, kWidth + 1, kHeight + 1));
1556 sink_.WaitForEncodedFrame(3);
mflodmancc3d4422017-08-03 08:27:51 -07001557 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07001558 EXPECT_EQ(kLastMaxPixelCount, source.sink_wants().max_pixel_count);
1559 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1560 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1561
mflodmancc3d4422017-08-03 08:27:51 -07001562 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07001563}
1564
mflodmancc3d4422017-08-03 08:27:51 -07001565TEST_F(VideoStreamEncoderTest,
1566 NoChangeForInitialNormalUsage_MaintainFramerateMode) {
asapersson02465b82017-04-10 01:12:52 -07001567 const int kWidth = 1280;
1568 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001569 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson02465b82017-04-10 01:12:52 -07001570
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001571 // Enable MAINTAIN_FRAMERATE preference, no initial limitation.
asapersson02465b82017-04-10 01:12:52 -07001572 test::FrameForwarder source;
mflodmancc3d4422017-08-03 08:27:51 -07001573 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001574 &source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
asapersson02465b82017-04-10 01:12:52 -07001575
1576 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001577 WaitForEncodedFrame(kWidth, kHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001578 VerifyFpsMaxResolutionMax(source.sink_wants());
asapersson02465b82017-04-10 01:12:52 -07001579 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1580 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1581
1582 // Trigger adapt up, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07001583 video_stream_encoder_->TriggerCpuNormalUsage();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001584 VerifyFpsMaxResolutionMax(source.sink_wants());
asapersson02465b82017-04-10 01:12:52 -07001585 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1586 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1587
mflodmancc3d4422017-08-03 08:27:51 -07001588 video_stream_encoder_->Stop();
asapersson02465b82017-04-10 01:12:52 -07001589}
1590
mflodmancc3d4422017-08-03 08:27:51 -07001591TEST_F(VideoStreamEncoderTest,
1592 NoChangeForInitialNormalUsage_MaintainResolutionMode) {
asapersson02465b82017-04-10 01:12:52 -07001593 const int kWidth = 1280;
1594 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001595 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson02465b82017-04-10 01:12:52 -07001596
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001597 // Enable MAINTAIN_RESOLUTION preference, no initial limitation.
asapersson02465b82017-04-10 01:12:52 -07001598 test::FrameForwarder source;
mflodmancc3d4422017-08-03 08:27:51 -07001599 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001600 &source, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
asapersson02465b82017-04-10 01:12:52 -07001601
1602 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001603 WaitForEncodedFrame(kWidth, kHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001604 VerifyFpsMaxResolutionMax(source.sink_wants());
asapersson09f05612017-05-15 23:40:18 -07001605 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
asapersson02465b82017-04-10 01:12:52 -07001606 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1607
1608 // Trigger adapt up, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07001609 video_stream_encoder_->TriggerCpuNormalUsage();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001610 VerifyFpsMaxResolutionMax(source.sink_wants());
asapersson09f05612017-05-15 23:40:18 -07001611 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
asapersson02465b82017-04-10 01:12:52 -07001612 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1613
mflodmancc3d4422017-08-03 08:27:51 -07001614 video_stream_encoder_->Stop();
asapersson02465b82017-04-10 01:12:52 -07001615}
1616
mflodmancc3d4422017-08-03 08:27:51 -07001617TEST_F(VideoStreamEncoderTest, NoChangeForInitialNormalUsage_BalancedMode) {
asaperssonf7e294d2017-06-13 23:25:22 -07001618 const int kWidth = 1280;
1619 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001620 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -07001621
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001622 // Enable BALANCED preference, no initial limitation.
asaperssonf7e294d2017-06-13 23:25:22 -07001623 test::FrameForwarder source;
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001624 video_stream_encoder_->SetSource(&source,
1625 webrtc::DegradationPreference::BALANCED);
asaperssonf7e294d2017-06-13 23:25:22 -07001626
1627 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
1628 sink_.WaitForEncodedFrame(kWidth, kHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001629 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07001630 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1631 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
1632 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1633
1634 // Trigger adapt up, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07001635 video_stream_encoder_->TriggerQualityHigh();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001636 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07001637 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1638 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
1639 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1640
mflodmancc3d4422017-08-03 08:27:51 -07001641 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07001642}
1643
mflodmancc3d4422017-08-03 08:27:51 -07001644TEST_F(VideoStreamEncoderTest, NoChangeForInitialNormalUsage_DisabledMode) {
asapersson09f05612017-05-15 23:40:18 -07001645 const int kWidth = 1280;
1646 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001647 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson09f05612017-05-15 23:40:18 -07001648
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001649 // Enable DISABLED preference, no initial limitation.
asapersson09f05612017-05-15 23:40:18 -07001650 test::FrameForwarder source;
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001651 video_stream_encoder_->SetSource(&source,
1652 webrtc::DegradationPreference::DISABLED);
asapersson09f05612017-05-15 23:40:18 -07001653
1654 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
1655 sink_.WaitForEncodedFrame(kWidth, kHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001656 VerifyFpsMaxResolutionMax(source.sink_wants());
asapersson09f05612017-05-15 23:40:18 -07001657 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1658 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
1659 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1660
1661 // Trigger adapt up, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07001662 video_stream_encoder_->TriggerQualityHigh();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001663 VerifyFpsMaxResolutionMax(source.sink_wants());
asapersson09f05612017-05-15 23:40:18 -07001664 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1665 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
1666 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1667
mflodmancc3d4422017-08-03 08:27:51 -07001668 video_stream_encoder_->Stop();
asapersson09f05612017-05-15 23:40:18 -07001669}
1670
mflodmancc3d4422017-08-03 08:27:51 -07001671TEST_F(VideoStreamEncoderTest,
1672 AdaptsResolutionForLowQuality_MaintainFramerateMode) {
asapersson02465b82017-04-10 01:12:52 -07001673 const int kWidth = 1280;
1674 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001675 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson02465b82017-04-10 01:12:52 -07001676
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001677 // Enable MAINTAIN_FRAMERATE preference, no initial limitation.
asapersson02465b82017-04-10 01:12:52 -07001678 AdaptingFrameForwarder source;
1679 source.set_adaptation_enabled(true);
mflodmancc3d4422017-08-03 08:27:51 -07001680 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001681 &source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
asapersson02465b82017-04-10 01:12:52 -07001682
1683 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001684 WaitForEncodedFrame(1);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001685 VerifyFpsMaxResolutionMax(source.sink_wants());
asapersson02465b82017-04-10 01:12:52 -07001686 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1687 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1688
1689 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001690 video_stream_encoder_->TriggerQualityLow();
asapersson02465b82017-04-10 01:12:52 -07001691 source.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001692 WaitForEncodedFrame(2);
asapersson09f05612017-05-15 23:40:18 -07001693 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
asapersson02465b82017-04-10 01:12:52 -07001694 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1695 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1696
1697 // Trigger adapt up, expect no restriction.
mflodmancc3d4422017-08-03 08:27:51 -07001698 video_stream_encoder_->TriggerQualityHigh();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001699 VerifyFpsMaxResolutionMax(source.sink_wants());
asapersson02465b82017-04-10 01:12:52 -07001700 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1701 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1702 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1703
mflodmancc3d4422017-08-03 08:27:51 -07001704 video_stream_encoder_->Stop();
asapersson02465b82017-04-10 01:12:52 -07001705}
1706
mflodmancc3d4422017-08-03 08:27:51 -07001707TEST_F(VideoStreamEncoderTest,
1708 AdaptsFramerateForLowQuality_MaintainResolutionMode) {
asapersson09f05612017-05-15 23:40:18 -07001709 const int kWidth = 1280;
1710 const int kHeight = 720;
1711 const int kInputFps = 30;
mflodmancc3d4422017-08-03 08:27:51 -07001712 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson09f05612017-05-15 23:40:18 -07001713
1714 VideoSendStream::Stats stats = stats_proxy_->GetStats();
1715 stats.input_frame_rate = kInputFps;
1716 stats_proxy_->SetMockStats(stats);
1717
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001718 // Expect no scaling to begin with (preference: MAINTAIN_FRAMERATE).
asapersson09f05612017-05-15 23:40:18 -07001719 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
1720 sink_.WaitForEncodedFrame(1);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001721 VerifyFpsMaxResolutionMax(video_source_.sink_wants());
asapersson09f05612017-05-15 23:40:18 -07001722
1723 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001724 video_stream_encoder_->TriggerQualityLow();
asapersson09f05612017-05-15 23:40:18 -07001725 video_source_.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
1726 sink_.WaitForEncodedFrame(2);
1727 VerifyFpsMaxResolutionLt(video_source_.sink_wants(), kWidth * kHeight);
1728
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001729 // Enable MAINTAIN_RESOLUTION preference.
asapersson09f05612017-05-15 23:40:18 -07001730 test::FrameForwarder new_video_source;
mflodmancc3d4422017-08-03 08:27:51 -07001731 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001732 &new_video_source, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001733 VerifyFpsMaxResolutionMax(new_video_source.sink_wants());
asapersson09f05612017-05-15 23:40:18 -07001734
1735 // Trigger adapt down, expect reduced framerate.
mflodmancc3d4422017-08-03 08:27:51 -07001736 video_stream_encoder_->TriggerQualityLow();
asapersson09f05612017-05-15 23:40:18 -07001737 new_video_source.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
1738 sink_.WaitForEncodedFrame(3);
1739 VerifyFpsLtResolutionMax(new_video_source.sink_wants(), kInputFps);
1740
1741 // Trigger adapt up, expect no restriction.
mflodmancc3d4422017-08-03 08:27:51 -07001742 video_stream_encoder_->TriggerQualityHigh();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001743 VerifyFpsMaxResolutionMax(new_video_source.sink_wants());
asapersson09f05612017-05-15 23:40:18 -07001744
mflodmancc3d4422017-08-03 08:27:51 -07001745 video_stream_encoder_->Stop();
asapersson09f05612017-05-15 23:40:18 -07001746}
1747
mflodmancc3d4422017-08-03 08:27:51 -07001748TEST_F(VideoStreamEncoderTest, DoesNotScaleBelowSetResolutionLimit) {
asaperssond0de2952017-04-21 01:47:31 -07001749 const int kWidth = 1280;
1750 const int kHeight = 720;
1751 const size_t kNumFrames = 10;
1752
mflodmancc3d4422017-08-03 08:27:51 -07001753 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
kthelgason5e13d412016-12-01 03:59:51 -08001754
asaperssond0de2952017-04-21 01:47:31 -07001755 // Enable adapter, expected input resolutions when downscaling:
asapersson142fcc92017-08-17 08:58:54 -07001756 // 1280x720 -> 960x540 -> 640x360 -> 480x270 -> 320x180 (kMinPixelsPerFrame)
asaperssond0de2952017-04-21 01:47:31 -07001757 video_source_.set_adaptation_enabled(true);
1758
1759 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1760 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1761
1762 int downscales = 0;
1763 for (size_t i = 1; i <= kNumFrames; i++) {
Åsa Persson8c1bf952018-09-13 10:42:19 +02001764 video_source_.IncomingCapturedFrame(
1765 CreateFrame(i * kFrameIntervalMs, kWidth, kHeight));
1766 WaitForEncodedFrame(i * kFrameIntervalMs);
asaperssond0de2952017-04-21 01:47:31 -07001767
asaperssonfab67072017-04-04 05:51:49 -07001768 // Trigger scale down.
asaperssond0de2952017-04-21 01:47:31 -07001769 rtc::VideoSinkWants last_wants = video_source_.sink_wants();
mflodmancc3d4422017-08-03 08:27:51 -07001770 video_stream_encoder_->TriggerQualityLow();
sprangc5d62e22017-04-02 23:53:04 -07001771 EXPECT_GE(video_source_.sink_wants().max_pixel_count, kMinPixelsPerFrame);
asaperssond0de2952017-04-21 01:47:31 -07001772
1773 if (video_source_.sink_wants().max_pixel_count < last_wants.max_pixel_count)
1774 ++downscales;
1775
1776 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1777 EXPECT_EQ(downscales,
1778 stats_proxy_->GetStats().number_of_quality_adapt_changes);
1779 EXPECT_GT(downscales, 0);
kthelgason5e13d412016-12-01 03:59:51 -08001780 }
mflodmancc3d4422017-08-03 08:27:51 -07001781 video_stream_encoder_->Stop();
asaperssond0de2952017-04-21 01:47:31 -07001782}
1783
mflodmancc3d4422017-08-03 08:27:51 -07001784TEST_F(VideoStreamEncoderTest,
asaperssond0de2952017-04-21 01:47:31 -07001785 AdaptsResolutionUpAndDownTwiceOnOveruse_MaintainFramerateMode) {
1786 const int kWidth = 1280;
1787 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001788 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssond0de2952017-04-21 01:47:31 -07001789
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001790 // Enable MAINTAIN_FRAMERATE preference, no initial limitation.
asaperssond0de2952017-04-21 01:47:31 -07001791 AdaptingFrameForwarder source;
1792 source.set_adaptation_enabled(true);
mflodmancc3d4422017-08-03 08:27:51 -07001793 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001794 &source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
asaperssond0de2952017-04-21 01:47:31 -07001795
Åsa Persson8c1bf952018-09-13 10:42:19 +02001796 int64_t timestamp_ms = kFrameIntervalMs;
1797 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001798 WaitForEncodedFrame(kWidth, kHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001799 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssond0de2952017-04-21 01:47:31 -07001800 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1801 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1802
1803 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001804 video_stream_encoder_->TriggerCpuOveruse();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001805 timestamp_ms += kFrameIntervalMs;
1806 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
1807 WaitForEncodedFrame(timestamp_ms);
asapersson09f05612017-05-15 23:40:18 -07001808 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
asaperssond0de2952017-04-21 01:47:31 -07001809 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1810 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1811
1812 // Trigger adapt up, expect no restriction.
mflodmancc3d4422017-08-03 08:27:51 -07001813 video_stream_encoder_->TriggerCpuNormalUsage();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001814 timestamp_ms += kFrameIntervalMs;
1815 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001816 WaitForEncodedFrame(kWidth, kHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001817 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssond0de2952017-04-21 01:47:31 -07001818 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1819 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1820
1821 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001822 video_stream_encoder_->TriggerCpuOveruse();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001823 timestamp_ms += kFrameIntervalMs;
1824 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
1825 WaitForEncodedFrame(timestamp_ms);
asapersson09f05612017-05-15 23:40:18 -07001826 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
asaperssond0de2952017-04-21 01:47:31 -07001827 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1828 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1829
1830 // Trigger adapt up, expect no restriction.
mflodmancc3d4422017-08-03 08:27:51 -07001831 video_stream_encoder_->TriggerCpuNormalUsage();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001832 timestamp_ms += kFrameIntervalMs;
1833 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
asapersson09f05612017-05-15 23:40:18 -07001834 sink_.WaitForEncodedFrame(kWidth, kHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001835 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssond0de2952017-04-21 01:47:31 -07001836 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1837 EXPECT_EQ(4, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1838
mflodmancc3d4422017-08-03 08:27:51 -07001839 video_stream_encoder_->Stop();
asaperssond0de2952017-04-21 01:47:31 -07001840}
1841
mflodmancc3d4422017-08-03 08:27:51 -07001842TEST_F(VideoStreamEncoderTest,
asaperssonf7e294d2017-06-13 23:25:22 -07001843 AdaptsResolutionUpAndDownTwiceForLowQuality_BalancedMode_NoFpsLimit) {
1844 const int kWidth = 1280;
1845 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001846 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -07001847
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001848 // Enable BALANCED preference, no initial limitation.
asaperssonf7e294d2017-06-13 23:25:22 -07001849 AdaptingFrameForwarder source;
1850 source.set_adaptation_enabled(true);
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001851 video_stream_encoder_->SetSource(&source,
1852 webrtc::DegradationPreference::BALANCED);
asaperssonf7e294d2017-06-13 23:25:22 -07001853
Åsa Persson8c1bf952018-09-13 10:42:19 +02001854 int64_t timestamp_ms = kFrameIntervalMs;
1855 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
asaperssonf7e294d2017-06-13 23:25:22 -07001856 sink_.WaitForEncodedFrame(kWidth, kHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001857 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07001858 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1859 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1860
1861 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001862 video_stream_encoder_->TriggerQualityLow();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001863 timestamp_ms += kFrameIntervalMs;
1864 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
1865 sink_.WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07001866 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
1867 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1868 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1869
1870 // Trigger adapt up, expect no restriction.
mflodmancc3d4422017-08-03 08:27:51 -07001871 video_stream_encoder_->TriggerQualityHigh();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001872 timestamp_ms += kFrameIntervalMs;
1873 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
asaperssonf7e294d2017-06-13 23:25:22 -07001874 sink_.WaitForEncodedFrame(kWidth, kHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001875 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07001876 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1877 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1878
1879 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001880 video_stream_encoder_->TriggerQualityLow();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001881 timestamp_ms += kFrameIntervalMs;
1882 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
1883 sink_.WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07001884 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
1885 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1886 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1887
1888 // Trigger adapt up, expect no restriction.
mflodmancc3d4422017-08-03 08:27:51 -07001889 video_stream_encoder_->TriggerQualityHigh();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001890 timestamp_ms += kFrameIntervalMs;
1891 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
asaperssonf7e294d2017-06-13 23:25:22 -07001892 sink_.WaitForEncodedFrame(kWidth, kHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001893 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07001894 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1895 EXPECT_EQ(4, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1896
mflodmancc3d4422017-08-03 08:27:51 -07001897 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07001898}
1899
mflodmancc3d4422017-08-03 08:27:51 -07001900TEST_F(VideoStreamEncoderTest,
asaperssond0de2952017-04-21 01:47:31 -07001901 AdaptsResolutionOnOveruseAndLowQuality_MaintainFramerateMode) {
1902 const int kWidth = 1280;
1903 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001904 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssond0de2952017-04-21 01:47:31 -07001905
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001906 // Enable MAINTAIN_FRAMERATE preference, no initial limitation.
asaperssond0de2952017-04-21 01:47:31 -07001907 AdaptingFrameForwarder source;
1908 source.set_adaptation_enabled(true);
mflodmancc3d4422017-08-03 08:27:51 -07001909 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001910 &source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
asaperssond0de2952017-04-21 01:47:31 -07001911
Åsa Persson8c1bf952018-09-13 10:42:19 +02001912 int64_t timestamp_ms = kFrameIntervalMs;
1913 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001914 WaitForEncodedFrame(kWidth, kHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001915 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssond0de2952017-04-21 01:47:31 -07001916 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1917 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1918 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1919 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1920
1921 // Trigger cpu adapt down, expect scaled down resolution (960x540).
mflodmancc3d4422017-08-03 08:27:51 -07001922 video_stream_encoder_->TriggerCpuOveruse();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001923 timestamp_ms += kFrameIntervalMs;
1924 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
1925 WaitForEncodedFrame(timestamp_ms);
asapersson09f05612017-05-15 23:40:18 -07001926 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
asaperssond0de2952017-04-21 01:47:31 -07001927 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1928 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1929 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1930 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1931
1932 // Trigger cpu adapt down, expect scaled down resolution (640x360).
mflodmancc3d4422017-08-03 08:27:51 -07001933 video_stream_encoder_->TriggerCpuOveruse();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001934 timestamp_ms += kFrameIntervalMs;
1935 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
1936 WaitForEncodedFrame(timestamp_ms);
asapersson09f05612017-05-15 23:40:18 -07001937 VerifyFpsMaxResolutionLt(source.sink_wants(), source.last_wants());
asaperssond0de2952017-04-21 01:47:31 -07001938 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1939 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1940 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1941 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1942
Jonathan Yubc771b72017-12-08 17:04:29 -08001943 // Trigger cpu adapt down, expect scaled down resolution (480x270).
mflodmancc3d4422017-08-03 08:27:51 -07001944 video_stream_encoder_->TriggerCpuOveruse();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001945 timestamp_ms += kFrameIntervalMs;
1946 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
1947 WaitForEncodedFrame(timestamp_ms);
Jonathan Yubc771b72017-12-08 17:04:29 -08001948 VerifyFpsMaxResolutionLt(source.sink_wants(), source.last_wants());
asaperssond0de2952017-04-21 01:47:31 -07001949 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1950 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
Jonathan Yubc771b72017-12-08 17:04:29 -08001951 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
asaperssond0de2952017-04-21 01:47:31 -07001952 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1953
Jonathan Yubc771b72017-12-08 17:04:29 -08001954 // Trigger quality adapt down, expect scaled down resolution (320x180).
mflodmancc3d4422017-08-03 08:27:51 -07001955 video_stream_encoder_->TriggerQualityLow();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001956 timestamp_ms += kFrameIntervalMs;
1957 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
1958 WaitForEncodedFrame(timestamp_ms);
asapersson09f05612017-05-15 23:40:18 -07001959 VerifyFpsMaxResolutionLt(source.sink_wants(), source.last_wants());
Jonathan Yubc771b72017-12-08 17:04:29 -08001960 rtc::VideoSinkWants last_wants = source.sink_wants();
asaperssond0de2952017-04-21 01:47:31 -07001961 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1962 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1963 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1964 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1965
Jonathan Yubc771b72017-12-08 17:04:29 -08001966 // Trigger quality adapt down, expect no change (min resolution reached).
1967 video_stream_encoder_->TriggerQualityLow();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001968 timestamp_ms += kFrameIntervalMs;
1969 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
1970 WaitForEncodedFrame(timestamp_ms);
Jonathan Yubc771b72017-12-08 17:04:29 -08001971 VerifyFpsMaxResolutionEq(source.sink_wants(), last_wants);
1972 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1973 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1974 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1975 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1976
1977 // Trigger cpu adapt up, expect upscaled resolution (480x270).
mflodmancc3d4422017-08-03 08:27:51 -07001978 video_stream_encoder_->TriggerCpuNormalUsage();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001979 timestamp_ms += kFrameIntervalMs;
1980 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
1981 WaitForEncodedFrame(timestamp_ms);
asapersson09f05612017-05-15 23:40:18 -07001982 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
Jonathan Yubc771b72017-12-08 17:04:29 -08001983 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1984 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1985 EXPECT_EQ(4, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1986 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1987
1988 // Trigger cpu adapt up, expect upscaled resolution (640x360).
1989 video_stream_encoder_->TriggerCpuNormalUsage();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001990 timestamp_ms += kFrameIntervalMs;
1991 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
1992 WaitForEncodedFrame(timestamp_ms);
Jonathan Yubc771b72017-12-08 17:04:29 -08001993 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
1994 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1995 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1996 EXPECT_EQ(5, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1997 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1998
1999 // Trigger cpu adapt up, expect upscaled resolution (960x540).
2000 video_stream_encoder_->TriggerCpuNormalUsage();
Åsa Persson8c1bf952018-09-13 10:42:19 +02002001 timestamp_ms += kFrameIntervalMs;
2002 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
2003 WaitForEncodedFrame(timestamp_ms);
Jonathan Yubc771b72017-12-08 17:04:29 -08002004 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
asaperssond0de2952017-04-21 01:47:31 -07002005 last_wants = source.sink_wants();
2006 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2007 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
Jonathan Yubc771b72017-12-08 17:04:29 -08002008 EXPECT_EQ(6, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
asaperssond0de2952017-04-21 01:47:31 -07002009 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2010
2011 // Trigger cpu adapt up, no cpu downgrades, expect no change (960x540).
mflodmancc3d4422017-08-03 08:27:51 -07002012 video_stream_encoder_->TriggerCpuNormalUsage();
Åsa Persson8c1bf952018-09-13 10:42:19 +02002013 timestamp_ms += kFrameIntervalMs;
2014 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
2015 WaitForEncodedFrame(timestamp_ms);
asapersson09f05612017-05-15 23:40:18 -07002016 VerifyFpsEqResolutionEq(source.sink_wants(), last_wants);
asaperssond0de2952017-04-21 01:47:31 -07002017 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2018 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
Jonathan Yubc771b72017-12-08 17:04:29 -08002019 EXPECT_EQ(6, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
asaperssond0de2952017-04-21 01:47:31 -07002020 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2021
2022 // Trigger quality adapt up, expect no restriction (1280x720).
mflodmancc3d4422017-08-03 08:27:51 -07002023 video_stream_encoder_->TriggerQualityHigh();
Åsa Persson8c1bf952018-09-13 10:42:19 +02002024 timestamp_ms += kFrameIntervalMs;
2025 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002026 WaitForEncodedFrame(kWidth, kHeight);
asapersson09f05612017-05-15 23:40:18 -07002027 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
Åsa Persson8c1bf952018-09-13 10:42:19 +02002028 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssond0de2952017-04-21 01:47:31 -07002029 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2030 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
Jonathan Yubc771b72017-12-08 17:04:29 -08002031 EXPECT_EQ(6, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
asaperssond0de2952017-04-21 01:47:31 -07002032 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
kthelgason5e13d412016-12-01 03:59:51 -08002033
mflodmancc3d4422017-08-03 08:27:51 -07002034 video_stream_encoder_->Stop();
kthelgason5e13d412016-12-01 03:59:51 -08002035}
2036
mflodmancc3d4422017-08-03 08:27:51 -07002037TEST_F(VideoStreamEncoderTest, CpuLimitedHistogramIsReported) {
asaperssonfab67072017-04-04 05:51:49 -07002038 const int kWidth = 640;
2039 const int kHeight = 360;
perkj803d97f2016-11-01 11:45:46 -07002040
mflodmancc3d4422017-08-03 08:27:51 -07002041 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
sprang4847ae62017-06-27 07:06:52 -07002042
perkj803d97f2016-11-01 11:45:46 -07002043 for (int i = 1; i <= SendStatisticsProxy::kMinRequiredMetricsSamples; ++i) {
asaperssonfab67072017-04-04 05:51:49 -07002044 video_source_.IncomingCapturedFrame(CreateFrame(i, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002045 WaitForEncodedFrame(i);
perkj803d97f2016-11-01 11:45:46 -07002046 }
2047
mflodmancc3d4422017-08-03 08:27:51 -07002048 video_stream_encoder_->TriggerCpuOveruse();
perkj803d97f2016-11-01 11:45:46 -07002049 for (int i = 1; i <= SendStatisticsProxy::kMinRequiredMetricsSamples; ++i) {
asaperssonfab67072017-04-04 05:51:49 -07002050 video_source_.IncomingCapturedFrame(CreateFrame(
2051 SendStatisticsProxy::kMinRequiredMetricsSamples + i, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002052 WaitForEncodedFrame(SendStatisticsProxy::kMinRequiredMetricsSamples + i);
perkj803d97f2016-11-01 11:45:46 -07002053 }
2054
mflodmancc3d4422017-08-03 08:27:51 -07002055 video_stream_encoder_->Stop();
2056 video_stream_encoder_.reset();
perkj803d97f2016-11-01 11:45:46 -07002057 stats_proxy_.reset();
sprangf8ee65e2017-02-28 08:49:33 -08002058
perkj803d97f2016-11-01 11:45:46 -07002059 EXPECT_EQ(1,
2060 metrics::NumSamples("WebRTC.Video.CpuLimitedResolutionInPercent"));
2061 EXPECT_EQ(
2062 1, metrics::NumEvents("WebRTC.Video.CpuLimitedResolutionInPercent", 50));
2063}
2064
mflodmancc3d4422017-08-03 08:27:51 -07002065TEST_F(VideoStreamEncoderTest,
2066 CpuLimitedHistogramIsNotReportedForDisabledDegradation) {
2067 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonf4e44af2017-04-19 02:01:06 -07002068 const int kWidth = 640;
2069 const int kHeight = 360;
2070
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002071 video_stream_encoder_->SetSource(&video_source_,
2072 webrtc::DegradationPreference::DISABLED);
asaperssonf4e44af2017-04-19 02:01:06 -07002073
2074 for (int i = 1; i <= SendStatisticsProxy::kMinRequiredMetricsSamples; ++i) {
2075 video_source_.IncomingCapturedFrame(CreateFrame(i, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002076 WaitForEncodedFrame(i);
asaperssonf4e44af2017-04-19 02:01:06 -07002077 }
2078
mflodmancc3d4422017-08-03 08:27:51 -07002079 video_stream_encoder_->Stop();
2080 video_stream_encoder_.reset();
asaperssonf4e44af2017-04-19 02:01:06 -07002081 stats_proxy_.reset();
2082
2083 EXPECT_EQ(0,
2084 metrics::NumSamples("WebRTC.Video.CpuLimitedResolutionInPercent"));
2085}
2086
mflodmancc3d4422017-08-03 08:27:51 -07002087TEST_F(VideoStreamEncoderTest, CallsBitrateObserver) {
sprang4847ae62017-06-27 07:06:52 -07002088 MockBitrateObserver bitrate_observer;
Niels Möller0327c2d2018-05-21 14:09:31 +02002089 video_stream_encoder_->SetBitrateAllocationObserver(&bitrate_observer);
sprang57c2fff2017-01-16 06:24:02 -08002090
2091 const int kDefaultFps = 30;
Erik Språng566124a2018-04-23 12:32:22 +02002092 const VideoBitrateAllocation expected_bitrate =
sprang57c2fff2017-01-16 06:24:02 -08002093 DefaultVideoBitrateAllocator(fake_encoder_.codec_config())
kthelgason2bc68642017-02-07 07:02:22 -08002094 .GetAllocation(kLowTargetBitrateBps, kDefaultFps);
sprang57c2fff2017-01-16 06:24:02 -08002095
Niels Möller6613f8e2019-01-10 10:30:21 +01002096 // First called on bitrate updated, then again on first frame.
sprang57c2fff2017-01-16 06:24:02 -08002097 EXPECT_CALL(bitrate_observer, OnBitrateAllocationUpdated(expected_bitrate))
Niels Möller6613f8e2019-01-10 10:30:21 +01002098 .Times(2);
mflodmancc3d4422017-08-03 08:27:51 -07002099 video_stream_encoder_->OnBitrateUpdated(kLowTargetBitrateBps, 0, 0);
sprang57c2fff2017-01-16 06:24:02 -08002100
2101 const int64_t kStartTimeMs = 1;
2102 video_source_.IncomingCapturedFrame(
2103 CreateFrame(kStartTimeMs, codec_width_, codec_height_));
sprang4847ae62017-06-27 07:06:52 -07002104 WaitForEncodedFrame(kStartTimeMs);
sprang57c2fff2017-01-16 06:24:02 -08002105
2106 // Not called on second frame.
2107 EXPECT_CALL(bitrate_observer, OnBitrateAllocationUpdated(expected_bitrate))
2108 .Times(0);
2109 video_source_.IncomingCapturedFrame(
2110 CreateFrame(kStartTimeMs + 1, codec_width_, codec_height_));
sprang4847ae62017-06-27 07:06:52 -07002111 WaitForEncodedFrame(kStartTimeMs + 1);
sprang57c2fff2017-01-16 06:24:02 -08002112
2113 // Called after a process interval.
2114 const int64_t kProcessIntervalMs =
2115 vcm::VCMProcessTimer::kDefaultProcessIntervalMs;
sprang4847ae62017-06-27 07:06:52 -07002116 fake_clock_.AdvanceTimeMicros(rtc::kNumMicrosecsPerMillisec *
2117 (kProcessIntervalMs + (1000 / kDefaultFps)));
sprang57c2fff2017-01-16 06:24:02 -08002118 EXPECT_CALL(bitrate_observer, OnBitrateAllocationUpdated(expected_bitrate))
2119 .Times(1);
2120 video_source_.IncomingCapturedFrame(CreateFrame(
2121 kStartTimeMs + kProcessIntervalMs, codec_width_, codec_height_));
sprang4847ae62017-06-27 07:06:52 -07002122 WaitForEncodedFrame(kStartTimeMs + kProcessIntervalMs);
sprang57c2fff2017-01-16 06:24:02 -08002123
mflodmancc3d4422017-08-03 08:27:51 -07002124 video_stream_encoder_->Stop();
sprang57c2fff2017-01-16 06:24:02 -08002125}
2126
Niels Möller7dc26b72017-12-06 10:27:48 +01002127TEST_F(VideoStreamEncoderTest, OveruseDetectorUpdatedOnReconfigureAndAdaption) {
2128 const int kFrameWidth = 1280;
2129 const int kFrameHeight = 720;
2130 const int kFramerate = 24;
2131
2132 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
2133 test::FrameForwarder source;
2134 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002135 &source, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
Niels Möller7dc26b72017-12-06 10:27:48 +01002136
2137 // Insert a single frame, triggering initial configuration.
2138 source.IncomingCapturedFrame(CreateFrame(1, kFrameWidth, kFrameHeight));
2139 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2140
2141 EXPECT_EQ(
2142 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2143 kDefaultFramerate);
2144
2145 // Trigger reconfigure encoder (without resetting the entire instance).
2146 VideoEncoderConfig video_encoder_config;
Niels Möller259a4972018-04-05 15:36:51 +02002147 video_encoder_config.codec_type = kVideoCodecVP8;
Niels Möller7dc26b72017-12-06 10:27:48 +01002148 video_encoder_config.max_bitrate_bps = kTargetBitrateBps;
2149 video_encoder_config.number_of_streams = 1;
2150 video_encoder_config.video_stream_factory =
2151 new rtc::RefCountedObject<VideoStreamFactory>(1, kFramerate);
2152 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
Niels Möllerf1338562018-04-26 09:51:47 +02002153 kMaxPayloadLength);
Niels Möller7dc26b72017-12-06 10:27:48 +01002154 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2155
2156 // Detector should be updated with fps limit from codec config.
2157 EXPECT_EQ(
2158 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2159 kFramerate);
2160
2161 // Trigger overuse, max framerate should be reduced.
2162 VideoSendStream::Stats stats = stats_proxy_->GetStats();
2163 stats.input_frame_rate = kFramerate;
2164 stats_proxy_->SetMockStats(stats);
2165 video_stream_encoder_->TriggerCpuOveruse();
2166 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2167 int adapted_framerate =
2168 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate();
2169 EXPECT_LT(adapted_framerate, kFramerate);
2170
2171 // Trigger underuse, max framerate should go back to codec configured fps.
2172 // Set extra low fps, to make sure it's actually reset, not just incremented.
2173 stats = stats_proxy_->GetStats();
2174 stats.input_frame_rate = adapted_framerate / 2;
2175 stats_proxy_->SetMockStats(stats);
2176 video_stream_encoder_->TriggerCpuNormalUsage();
2177 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2178 EXPECT_EQ(
2179 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2180 kFramerate);
2181
2182 video_stream_encoder_->Stop();
2183}
2184
2185TEST_F(VideoStreamEncoderTest,
2186 OveruseDetectorUpdatedRespectsFramerateAfterUnderuse) {
2187 const int kFrameWidth = 1280;
2188 const int kFrameHeight = 720;
2189 const int kLowFramerate = 15;
2190 const int kHighFramerate = 25;
2191
2192 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
2193 test::FrameForwarder source;
2194 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002195 &source, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
Niels Möller7dc26b72017-12-06 10:27:48 +01002196
2197 // Trigger initial configuration.
2198 VideoEncoderConfig video_encoder_config;
Niels Möller259a4972018-04-05 15:36:51 +02002199 video_encoder_config.codec_type = kVideoCodecVP8;
Niels Möller7dc26b72017-12-06 10:27:48 +01002200 video_encoder_config.max_bitrate_bps = kTargetBitrateBps;
2201 video_encoder_config.number_of_streams = 1;
2202 video_encoder_config.video_stream_factory =
2203 new rtc::RefCountedObject<VideoStreamFactory>(1, kLowFramerate);
2204 source.IncomingCapturedFrame(CreateFrame(1, kFrameWidth, kFrameHeight));
2205 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
Niels Möllerf1338562018-04-26 09:51:47 +02002206 kMaxPayloadLength);
Niels Möller7dc26b72017-12-06 10:27:48 +01002207 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2208
2209 EXPECT_EQ(
2210 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2211 kLowFramerate);
2212
2213 // Trigger overuse, max framerate should be reduced.
2214 VideoSendStream::Stats stats = stats_proxy_->GetStats();
2215 stats.input_frame_rate = kLowFramerate;
2216 stats_proxy_->SetMockStats(stats);
2217 video_stream_encoder_->TriggerCpuOveruse();
2218 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2219 int adapted_framerate =
2220 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate();
2221 EXPECT_LT(adapted_framerate, kLowFramerate);
2222
2223 // Reconfigure the encoder with a new (higher max framerate), max fps should
2224 // still respect the adaptation.
2225 video_encoder_config.video_stream_factory =
2226 new rtc::RefCountedObject<VideoStreamFactory>(1, kHighFramerate);
2227 source.IncomingCapturedFrame(CreateFrame(1, kFrameWidth, kFrameHeight));
2228 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
Niels Möllerf1338562018-04-26 09:51:47 +02002229 kMaxPayloadLength);
Niels Möller7dc26b72017-12-06 10:27:48 +01002230 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2231
2232 EXPECT_EQ(
2233 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2234 adapted_framerate);
2235
2236 // Trigger underuse, max framerate should go back to codec configured fps.
2237 stats = stats_proxy_->GetStats();
2238 stats.input_frame_rate = adapted_framerate;
2239 stats_proxy_->SetMockStats(stats);
2240 video_stream_encoder_->TriggerCpuNormalUsage();
2241 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2242 EXPECT_EQ(
2243 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2244 kHighFramerate);
2245
2246 video_stream_encoder_->Stop();
2247}
2248
mflodmancc3d4422017-08-03 08:27:51 -07002249TEST_F(VideoStreamEncoderTest,
2250 OveruseDetectorUpdatedOnDegradationPreferenceChange) {
sprangfda496a2017-06-15 04:21:07 -07002251 const int kFrameWidth = 1280;
2252 const int kFrameHeight = 720;
2253 const int kFramerate = 24;
2254
mflodmancc3d4422017-08-03 08:27:51 -07002255 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
sprangfda496a2017-06-15 04:21:07 -07002256 test::FrameForwarder source;
mflodmancc3d4422017-08-03 08:27:51 -07002257 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002258 &source, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
sprangfda496a2017-06-15 04:21:07 -07002259
2260 // Trigger initial configuration.
2261 VideoEncoderConfig video_encoder_config;
Niels Möller259a4972018-04-05 15:36:51 +02002262 video_encoder_config.codec_type = kVideoCodecVP8;
sprangfda496a2017-06-15 04:21:07 -07002263 video_encoder_config.max_bitrate_bps = kTargetBitrateBps;
2264 video_encoder_config.number_of_streams = 1;
2265 video_encoder_config.video_stream_factory =
2266 new rtc::RefCountedObject<VideoStreamFactory>(1, kFramerate);
2267 source.IncomingCapturedFrame(CreateFrame(1, kFrameWidth, kFrameHeight));
mflodmancc3d4422017-08-03 08:27:51 -07002268 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
Niels Möllerf1338562018-04-26 09:51:47 +02002269 kMaxPayloadLength);
mflodmancc3d4422017-08-03 08:27:51 -07002270 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
sprangfda496a2017-06-15 04:21:07 -07002271
Niels Möller7dc26b72017-12-06 10:27:48 +01002272 EXPECT_EQ(
2273 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2274 kFramerate);
sprangfda496a2017-06-15 04:21:07 -07002275
2276 // Trigger overuse, max framerate should be reduced.
2277 VideoSendStream::Stats stats = stats_proxy_->GetStats();
2278 stats.input_frame_rate = kFramerate;
2279 stats_proxy_->SetMockStats(stats);
mflodmancc3d4422017-08-03 08:27:51 -07002280 video_stream_encoder_->TriggerCpuOveruse();
2281 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
Niels Möller7dc26b72017-12-06 10:27:48 +01002282 int adapted_framerate =
2283 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate();
sprangfda496a2017-06-15 04:21:07 -07002284 EXPECT_LT(adapted_framerate, kFramerate);
2285
2286 // Change degradation preference to not enable framerate scaling. Target
2287 // framerate should be changed to codec defined limit.
mflodmancc3d4422017-08-03 08:27:51 -07002288 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002289 &source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
mflodmancc3d4422017-08-03 08:27:51 -07002290 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
Niels Möller7dc26b72017-12-06 10:27:48 +01002291 EXPECT_EQ(
2292 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2293 kFramerate);
sprangfda496a2017-06-15 04:21:07 -07002294
mflodmancc3d4422017-08-03 08:27:51 -07002295 video_stream_encoder_->Stop();
sprangfda496a2017-06-15 04:21:07 -07002296}
2297
mflodmancc3d4422017-08-03 08:27:51 -07002298TEST_F(VideoStreamEncoderTest, DropsFramesAndScalesWhenBitrateIsTooLow) {
asaperssonfab67072017-04-04 05:51:49 -07002299 const int kTooLowBitrateForFrameSizeBps = 10000;
mflodmancc3d4422017-08-03 08:27:51 -07002300 video_stream_encoder_->OnBitrateUpdated(kTooLowBitrateForFrameSizeBps, 0, 0);
asaperssonfab67072017-04-04 05:51:49 -07002301 const int kWidth = 640;
2302 const int kHeight = 360;
kthelgason2bc68642017-02-07 07:02:22 -08002303
asaperssonfab67072017-04-04 05:51:49 -07002304 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
kthelgason2bc68642017-02-07 07:02:22 -08002305
2306 // Expect to drop this frame, the wait should time out.
sprang4847ae62017-06-27 07:06:52 -07002307 ExpectDroppedFrame();
kthelgason2bc68642017-02-07 07:02:22 -08002308
2309 // Expect the sink_wants to specify a scaled frame.
asapersson0944a802017-04-07 00:57:58 -07002310 EXPECT_LT(video_source_.sink_wants().max_pixel_count, kWidth * kHeight);
kthelgason2bc68642017-02-07 07:02:22 -08002311
sprangc5d62e22017-04-02 23:53:04 -07002312 int last_pixel_count = video_source_.sink_wants().max_pixel_count;
kthelgason2bc68642017-02-07 07:02:22 -08002313
asaperssonfab67072017-04-04 05:51:49 -07002314 // Next frame is scaled.
kthelgason2bc68642017-02-07 07:02:22 -08002315 video_source_.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07002316 CreateFrame(2, kWidth * 3 / 4, kHeight * 3 / 4));
kthelgason2bc68642017-02-07 07:02:22 -08002317
2318 // Expect to drop this frame, the wait should time out.
sprang4847ae62017-06-27 07:06:52 -07002319 ExpectDroppedFrame();
kthelgason2bc68642017-02-07 07:02:22 -08002320
sprangc5d62e22017-04-02 23:53:04 -07002321 EXPECT_LT(video_source_.sink_wants().max_pixel_count, last_pixel_count);
kthelgason2bc68642017-02-07 07:02:22 -08002322
mflodmancc3d4422017-08-03 08:27:51 -07002323 video_stream_encoder_->Stop();
kthelgason2bc68642017-02-07 07:02:22 -08002324}
2325
mflodmancc3d4422017-08-03 08:27:51 -07002326TEST_F(VideoStreamEncoderTest,
2327 NumberOfDroppedFramesLimitedWhenBitrateIsTooLow) {
asaperssonfab67072017-04-04 05:51:49 -07002328 const int kTooLowBitrateForFrameSizeBps = 10000;
mflodmancc3d4422017-08-03 08:27:51 -07002329 video_stream_encoder_->OnBitrateUpdated(kTooLowBitrateForFrameSizeBps, 0, 0);
asaperssonfab67072017-04-04 05:51:49 -07002330 const int kWidth = 640;
2331 const int kHeight = 360;
kthelgason2bc68642017-02-07 07:02:22 -08002332
2333 // We expect the n initial frames to get dropped.
2334 int i;
2335 for (i = 1; i <= kMaxInitialFramedrop; ++i) {
asaperssonfab67072017-04-04 05:51:49 -07002336 video_source_.IncomingCapturedFrame(CreateFrame(i, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002337 ExpectDroppedFrame();
kthelgason2bc68642017-02-07 07:02:22 -08002338 }
2339 // The n+1th frame should not be dropped, even though it's size is too large.
asaperssonfab67072017-04-04 05:51:49 -07002340 video_source_.IncomingCapturedFrame(CreateFrame(i, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002341 WaitForEncodedFrame(i);
kthelgason2bc68642017-02-07 07:02:22 -08002342
2343 // Expect the sink_wants to specify a scaled frame.
asaperssonfab67072017-04-04 05:51:49 -07002344 EXPECT_LT(video_source_.sink_wants().max_pixel_count, kWidth * kHeight);
kthelgason2bc68642017-02-07 07:02:22 -08002345
mflodmancc3d4422017-08-03 08:27:51 -07002346 video_stream_encoder_->Stop();
kthelgason2bc68642017-02-07 07:02:22 -08002347}
2348
mflodmancc3d4422017-08-03 08:27:51 -07002349TEST_F(VideoStreamEncoderTest,
2350 InitialFrameDropOffWithMaintainResolutionPreference) {
asaperssonfab67072017-04-04 05:51:49 -07002351 const int kWidth = 640;
2352 const int kHeight = 360;
mflodmancc3d4422017-08-03 08:27:51 -07002353 video_stream_encoder_->OnBitrateUpdated(kLowTargetBitrateBps, 0, 0);
kthelgason2bc68642017-02-07 07:02:22 -08002354
2355 // Set degradation preference.
mflodmancc3d4422017-08-03 08:27:51 -07002356 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002357 &video_source_, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
kthelgason2bc68642017-02-07 07:02:22 -08002358
asaperssonfab67072017-04-04 05:51:49 -07002359 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
kthelgason2bc68642017-02-07 07:02:22 -08002360 // Frame should not be dropped, even if it's too large.
sprang4847ae62017-06-27 07:06:52 -07002361 WaitForEncodedFrame(1);
kthelgason2bc68642017-02-07 07:02:22 -08002362
mflodmancc3d4422017-08-03 08:27:51 -07002363 video_stream_encoder_->Stop();
kthelgason2bc68642017-02-07 07:02:22 -08002364}
2365
mflodmancc3d4422017-08-03 08:27:51 -07002366TEST_F(VideoStreamEncoderTest, InitialFrameDropOffWhenEncoderDisabledScaling) {
asaperssonfab67072017-04-04 05:51:49 -07002367 const int kWidth = 640;
2368 const int kHeight = 360;
kthelgasonad9010c2017-02-14 00:46:51 -08002369 fake_encoder_.SetQualityScaling(false);
Niels Möller4db138e2018-04-19 09:04:13 +02002370
2371 VideoEncoderConfig video_encoder_config;
2372 test::FillEncoderConfiguration(kVideoCodecVP8, 1, &video_encoder_config);
2373 // Make format different, to force recreation of encoder.
2374 video_encoder_config.video_format.parameters["foo"] = "foo";
2375 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
Niels Möllerf1338562018-04-26 09:51:47 +02002376 kMaxPayloadLength);
mflodmancc3d4422017-08-03 08:27:51 -07002377 video_stream_encoder_->OnBitrateUpdated(kLowTargetBitrateBps, 0, 0);
asapersson09f05612017-05-15 23:40:18 -07002378
kthelgasonb83797b2017-02-14 11:57:25 -08002379 // Force quality scaler reconfiguration by resetting the source.
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002380 video_stream_encoder_->SetSource(&video_source_,
2381 webrtc::DegradationPreference::BALANCED);
kthelgasonad9010c2017-02-14 00:46:51 -08002382
asaperssonfab67072017-04-04 05:51:49 -07002383 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
kthelgasonad9010c2017-02-14 00:46:51 -08002384 // Frame should not be dropped, even if it's too large.
sprang4847ae62017-06-27 07:06:52 -07002385 WaitForEncodedFrame(1);
kthelgasonad9010c2017-02-14 00:46:51 -08002386
mflodmancc3d4422017-08-03 08:27:51 -07002387 video_stream_encoder_->Stop();
kthelgasonad9010c2017-02-14 00:46:51 -08002388 fake_encoder_.SetQualityScaling(true);
2389}
2390
Kári Tristan Helgason639602a2018-08-02 10:51:40 +02002391TEST_F(VideoStreamEncoderTest, InitialFrameDropActivatesWhenBWEstimateReady) {
2392 webrtc::test::ScopedFieldTrials field_trials(
2393 "WebRTC-InitialFramedrop/Enabled/");
2394 // Reset encoder for field trials to take effect.
2395 ConfigureEncoder(video_encoder_config_.Copy());
2396 const int kTooLowBitrateForFrameSizeBps = 10000;
2397 const int kWidth = 640;
2398 const int kHeight = 360;
2399
2400 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
2401 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
2402 // Frame should not be dropped.
2403 WaitForEncodedFrame(1);
2404
2405 video_stream_encoder_->OnBitrateUpdated(kTooLowBitrateForFrameSizeBps, 0, 0);
2406 video_source_.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
2407 // Expect to drop this frame, the wait should time out.
2408 ExpectDroppedFrame();
2409
2410 // Expect the sink_wants to specify a scaled frame.
2411 EXPECT_LT(video_source_.sink_wants().max_pixel_count, kWidth * kHeight);
2412 video_stream_encoder_->Stop();
2413}
2414
mflodmancc3d4422017-08-03 08:27:51 -07002415TEST_F(VideoStreamEncoderTest,
asaperssond0de2952017-04-21 01:47:31 -07002416 ResolutionNotAdaptedForTooSmallFrame_MaintainFramerateMode) {
2417 const int kTooSmallWidth = 10;
2418 const int kTooSmallHeight = 10;
mflodmancc3d4422017-08-03 08:27:51 -07002419 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssond0de2952017-04-21 01:47:31 -07002420
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002421 // Enable MAINTAIN_FRAMERATE preference, no initial limitation.
asaperssond0de2952017-04-21 01:47:31 -07002422 test::FrameForwarder source;
mflodmancc3d4422017-08-03 08:27:51 -07002423 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002424 &source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
asaperssond0de2952017-04-21 01:47:31 -07002425 VerifyNoLimitation(source.sink_wants());
2426 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2427
2428 // Trigger adapt down, too small frame, expect no change.
2429 source.IncomingCapturedFrame(CreateFrame(1, kTooSmallWidth, kTooSmallHeight));
sprang4847ae62017-06-27 07:06:52 -07002430 WaitForEncodedFrame(1);
mflodmancc3d4422017-08-03 08:27:51 -07002431 video_stream_encoder_->TriggerCpuOveruse();
Åsa Persson8c1bf952018-09-13 10:42:19 +02002432 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssond0de2952017-04-21 01:47:31 -07002433 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2434 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2435
mflodmancc3d4422017-08-03 08:27:51 -07002436 video_stream_encoder_->Stop();
asaperssond0de2952017-04-21 01:47:31 -07002437}
2438
mflodmancc3d4422017-08-03 08:27:51 -07002439TEST_F(VideoStreamEncoderTest,
2440 ResolutionNotAdaptedForTooSmallFrame_BalancedMode) {
asaperssonf7e294d2017-06-13 23:25:22 -07002441 const int kTooSmallWidth = 10;
2442 const int kTooSmallHeight = 10;
2443 const int kFpsLimit = 7;
mflodmancc3d4422017-08-03 08:27:51 -07002444 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -07002445
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002446 // Enable BALANCED preference, no initial limitation.
asaperssonf7e294d2017-06-13 23:25:22 -07002447 test::FrameForwarder source;
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002448 video_stream_encoder_->SetSource(&source,
2449 webrtc::DegradationPreference::BALANCED);
asaperssonf7e294d2017-06-13 23:25:22 -07002450 VerifyNoLimitation(source.sink_wants());
2451 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2452 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2453
2454 // Trigger adapt down, expect limited framerate.
2455 source.IncomingCapturedFrame(CreateFrame(1, kTooSmallWidth, kTooSmallHeight));
sprang4847ae62017-06-27 07:06:52 -07002456 WaitForEncodedFrame(1);
mflodmancc3d4422017-08-03 08:27:51 -07002457 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002458 VerifyFpsEqResolutionMax(source.sink_wants(), kFpsLimit);
2459 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2460 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2461 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2462
2463 // Trigger adapt down, too small frame, expect no change.
2464 source.IncomingCapturedFrame(CreateFrame(2, kTooSmallWidth, kTooSmallHeight));
sprang4847ae62017-06-27 07:06:52 -07002465 WaitForEncodedFrame(2);
mflodmancc3d4422017-08-03 08:27:51 -07002466 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002467 VerifyFpsEqResolutionMax(source.sink_wants(), kFpsLimit);
2468 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2469 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2470 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2471
mflodmancc3d4422017-08-03 08:27:51 -07002472 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07002473}
2474
mflodmancc3d4422017-08-03 08:27:51 -07002475TEST_F(VideoStreamEncoderTest, FailingInitEncodeDoesntCauseCrash) {
asapersson02465b82017-04-10 01:12:52 -07002476 fake_encoder_.ForceInitEncodeFailure(true);
mflodmancc3d4422017-08-03 08:27:51 -07002477 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
Niels Möllerf1338562018-04-26 09:51:47 +02002478 ResetEncoder("VP8", 2, 1, 1, false);
asapersson02465b82017-04-10 01:12:52 -07002479 const int kFrameWidth = 1280;
2480 const int kFrameHeight = 720;
2481 video_source_.IncomingCapturedFrame(
2482 CreateFrame(1, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002483 ExpectDroppedFrame();
mflodmancc3d4422017-08-03 08:27:51 -07002484 video_stream_encoder_->Stop();
asapersson02465b82017-04-10 01:12:52 -07002485}
2486
sprangb1ca0732017-02-01 08:38:12 -08002487// TODO(sprang): Extend this with fps throttling and any "balanced" extensions.
mflodmancc3d4422017-08-03 08:27:51 -07002488TEST_F(VideoStreamEncoderTest,
2489 AdaptsResolutionOnOveruse_MaintainFramerateMode) {
2490 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
sprangb1ca0732017-02-01 08:38:12 -08002491
2492 const int kFrameWidth = 1280;
2493 const int kFrameHeight = 720;
2494 // Enabled default VideoAdapter downscaling. First step is 3/4, not 3/5 as
mflodmancc3d4422017-08-03 08:27:51 -07002495 // requested by
2496 // VideoStreamEncoder::VideoSourceProxy::RequestResolutionLowerThan().
sprangb1ca0732017-02-01 08:38:12 -08002497 video_source_.set_adaptation_enabled(true);
2498
2499 video_source_.IncomingCapturedFrame(
Åsa Persson8c1bf952018-09-13 10:42:19 +02002500 CreateFrame(1 * kFrameIntervalMs, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002501 WaitForEncodedFrame(kFrameWidth, kFrameHeight);
sprangb1ca0732017-02-01 08:38:12 -08002502
2503 // Trigger CPU overuse, downscale by 3/4.
mflodmancc3d4422017-08-03 08:27:51 -07002504 video_stream_encoder_->TriggerCpuOveruse();
sprangb1ca0732017-02-01 08:38:12 -08002505 video_source_.IncomingCapturedFrame(
Åsa Persson8c1bf952018-09-13 10:42:19 +02002506 CreateFrame(2 * kFrameIntervalMs, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002507 WaitForEncodedFrame((kFrameWidth * 3) / 4, (kFrameHeight * 3) / 4);
sprangb1ca0732017-02-01 08:38:12 -08002508
asaperssonfab67072017-04-04 05:51:49 -07002509 // Trigger CPU normal use, return to original resolution.
mflodmancc3d4422017-08-03 08:27:51 -07002510 video_stream_encoder_->TriggerCpuNormalUsage();
sprangb1ca0732017-02-01 08:38:12 -08002511 video_source_.IncomingCapturedFrame(
Åsa Persson8c1bf952018-09-13 10:42:19 +02002512 CreateFrame(3 * kFrameIntervalMs, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002513 WaitForEncodedFrame(kFrameWidth, kFrameHeight);
sprangb1ca0732017-02-01 08:38:12 -08002514
mflodmancc3d4422017-08-03 08:27:51 -07002515 video_stream_encoder_->Stop();
sprangb1ca0732017-02-01 08:38:12 -08002516}
sprangfe627f32017-03-29 08:24:59 -07002517
mflodmancc3d4422017-08-03 08:27:51 -07002518TEST_F(VideoStreamEncoderTest,
2519 AdaptsFramerateOnOveruse_MaintainResolutionMode) {
sprangc5d62e22017-04-02 23:53:04 -07002520 const int kFrameWidth = 1280;
2521 const int kFrameHeight = 720;
sprangc5d62e22017-04-02 23:53:04 -07002522
mflodmancc3d4422017-08-03 08:27:51 -07002523 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
2524 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002525 &video_source_, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
sprangc5d62e22017-04-02 23:53:04 -07002526 video_source_.set_adaptation_enabled(true);
2527
sprang4847ae62017-06-27 07:06:52 -07002528 int64_t timestamp_ms = fake_clock_.TimeNanos() / rtc::kNumNanosecsPerMillisec;
sprangc5d62e22017-04-02 23:53:04 -07002529
2530 video_source_.IncomingCapturedFrame(
2531 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002532 WaitForEncodedFrame(timestamp_ms);
sprangc5d62e22017-04-02 23:53:04 -07002533
2534 // Try to trigger overuse. No fps estimate available => no effect.
mflodmancc3d4422017-08-03 08:27:51 -07002535 video_stream_encoder_->TriggerCpuOveruse();
sprangc5d62e22017-04-02 23:53:04 -07002536
2537 // Insert frames for one second to get a stable estimate.
sprang4847ae62017-06-27 07:06:52 -07002538 for (int i = 0; i < max_framerate_; ++i) {
sprangc5d62e22017-04-02 23:53:04 -07002539 timestamp_ms += kFrameIntervalMs;
sprangc5d62e22017-04-02 23:53:04 -07002540 video_source_.IncomingCapturedFrame(
2541 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002542 WaitForEncodedFrame(timestamp_ms);
sprangc5d62e22017-04-02 23:53:04 -07002543 }
2544
2545 // Trigger CPU overuse, reduce framerate by 2/3.
mflodmancc3d4422017-08-03 08:27:51 -07002546 video_stream_encoder_->TriggerCpuOveruse();
sprangc5d62e22017-04-02 23:53:04 -07002547 int num_frames_dropped = 0;
sprang4847ae62017-06-27 07:06:52 -07002548 for (int i = 0; i < max_framerate_; ++i) {
sprangc5d62e22017-04-02 23:53:04 -07002549 timestamp_ms += kFrameIntervalMs;
sprangc5d62e22017-04-02 23:53:04 -07002550 video_source_.IncomingCapturedFrame(
2551 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002552 if (!WaitForFrame(kFrameTimeoutMs)) {
sprangc5d62e22017-04-02 23:53:04 -07002553 ++num_frames_dropped;
2554 } else {
Åsa Perssonc74d8da2017-12-04 14:13:56 +01002555 sink_.CheckLastFrameSizeMatches(kFrameWidth, kFrameHeight);
sprangc5d62e22017-04-02 23:53:04 -07002556 }
2557 }
2558
sprang4847ae62017-06-27 07:06:52 -07002559 // Add some slack to account for frames dropped by the frame dropper.
2560 const int kErrorMargin = 1;
2561 EXPECT_NEAR(num_frames_dropped, max_framerate_ - (max_framerate_ * 2 / 3),
sprangc5d62e22017-04-02 23:53:04 -07002562 kErrorMargin);
2563
2564 // Trigger CPU overuse, reduce framerate by 2/3 again.
mflodmancc3d4422017-08-03 08:27:51 -07002565 video_stream_encoder_->TriggerCpuOveruse();
sprangc5d62e22017-04-02 23:53:04 -07002566 num_frames_dropped = 0;
Åsa Persson8c1bf952018-09-13 10:42:19 +02002567 for (int i = 0; i <= max_framerate_; ++i) {
sprangc5d62e22017-04-02 23:53:04 -07002568 timestamp_ms += kFrameIntervalMs;
sprangc5d62e22017-04-02 23:53:04 -07002569 video_source_.IncomingCapturedFrame(
2570 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002571 if (!WaitForFrame(kFrameTimeoutMs)) {
sprangc5d62e22017-04-02 23:53:04 -07002572 ++num_frames_dropped;
2573 } else {
Åsa Perssonc74d8da2017-12-04 14:13:56 +01002574 sink_.CheckLastFrameSizeMatches(kFrameWidth, kFrameHeight);
sprangc5d62e22017-04-02 23:53:04 -07002575 }
2576 }
sprang4847ae62017-06-27 07:06:52 -07002577 EXPECT_NEAR(num_frames_dropped, max_framerate_ - (max_framerate_ * 4 / 9),
sprangc5d62e22017-04-02 23:53:04 -07002578 kErrorMargin);
2579
2580 // Go back up one step.
mflodmancc3d4422017-08-03 08:27:51 -07002581 video_stream_encoder_->TriggerCpuNormalUsage();
sprangc5d62e22017-04-02 23:53:04 -07002582 num_frames_dropped = 0;
sprang4847ae62017-06-27 07:06:52 -07002583 for (int i = 0; i < max_framerate_; ++i) {
sprangc5d62e22017-04-02 23:53:04 -07002584 timestamp_ms += kFrameIntervalMs;
sprangc5d62e22017-04-02 23:53:04 -07002585 video_source_.IncomingCapturedFrame(
2586 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002587 if (!WaitForFrame(kFrameTimeoutMs)) {
sprangc5d62e22017-04-02 23:53:04 -07002588 ++num_frames_dropped;
2589 } else {
Åsa Perssonc74d8da2017-12-04 14:13:56 +01002590 sink_.CheckLastFrameSizeMatches(kFrameWidth, kFrameHeight);
sprangc5d62e22017-04-02 23:53:04 -07002591 }
2592 }
sprang4847ae62017-06-27 07:06:52 -07002593 EXPECT_NEAR(num_frames_dropped, max_framerate_ - (max_framerate_ * 2 / 3),
sprangc5d62e22017-04-02 23:53:04 -07002594 kErrorMargin);
2595
2596 // Go back up to original mode.
mflodmancc3d4422017-08-03 08:27:51 -07002597 video_stream_encoder_->TriggerCpuNormalUsage();
sprangc5d62e22017-04-02 23:53:04 -07002598 num_frames_dropped = 0;
sprang4847ae62017-06-27 07:06:52 -07002599 for (int i = 0; i < max_framerate_; ++i) {
sprangc5d62e22017-04-02 23:53:04 -07002600 timestamp_ms += kFrameIntervalMs;
sprangc5d62e22017-04-02 23:53:04 -07002601 video_source_.IncomingCapturedFrame(
2602 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002603 if (!WaitForFrame(kFrameTimeoutMs)) {
sprangc5d62e22017-04-02 23:53:04 -07002604 ++num_frames_dropped;
2605 } else {
Åsa Perssonc74d8da2017-12-04 14:13:56 +01002606 sink_.CheckLastFrameSizeMatches(kFrameWidth, kFrameHeight);
sprangc5d62e22017-04-02 23:53:04 -07002607 }
2608 }
2609 EXPECT_NEAR(num_frames_dropped, 0, kErrorMargin);
2610
mflodmancc3d4422017-08-03 08:27:51 -07002611 video_stream_encoder_->Stop();
sprangc5d62e22017-04-02 23:53:04 -07002612}
2613
mflodmancc3d4422017-08-03 08:27:51 -07002614TEST_F(VideoStreamEncoderTest, DoesntAdaptDownPastMinFramerate) {
sprangc5d62e22017-04-02 23:53:04 -07002615 const int kFramerateFps = 5;
2616 const int kFrameIntervalMs = rtc::kNumMillisecsPerSec / kFramerateFps;
sprangc5d62e22017-04-02 23:53:04 -07002617 const int kFrameWidth = 1280;
2618 const int kFrameHeight = 720;
2619
sprang4847ae62017-06-27 07:06:52 -07002620 // Reconfigure encoder with two temporal layers and screensharing, which will
2621 // disable frame dropping and make testing easier.
Niels Möllerf1338562018-04-26 09:51:47 +02002622 ResetEncoder("VP8", 1, 2, 1, true);
sprang4847ae62017-06-27 07:06:52 -07002623
mflodmancc3d4422017-08-03 08:27:51 -07002624 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
2625 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002626 &video_source_, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
sprangc5d62e22017-04-02 23:53:04 -07002627 video_source_.set_adaptation_enabled(true);
2628
sprang4847ae62017-06-27 07:06:52 -07002629 int64_t timestamp_ms = fake_clock_.TimeNanos() / rtc::kNumNanosecsPerMillisec;
sprangc5d62e22017-04-02 23:53:04 -07002630
2631 // Trigger overuse as much as we can.
Jonathan Yubc771b72017-12-08 17:04:29 -08002632 rtc::VideoSinkWants last_wants;
2633 do {
2634 last_wants = video_source_.sink_wants();
2635
sprangc5d62e22017-04-02 23:53:04 -07002636 // Insert frames to get a new fps estimate...
2637 for (int j = 0; j < kFramerateFps; ++j) {
2638 video_source_.IncomingCapturedFrame(
2639 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
Jonathan Yubc771b72017-12-08 17:04:29 -08002640 if (video_source_.last_sent_width()) {
2641 sink_.WaitForEncodedFrame(timestamp_ms);
2642 }
sprangc5d62e22017-04-02 23:53:04 -07002643 timestamp_ms += kFrameIntervalMs;
Yves Gerey665174f2018-06-19 15:03:05 +02002644 fake_clock_.AdvanceTimeMicros(kFrameIntervalMs *
2645 rtc::kNumMicrosecsPerMillisec);
sprangc5d62e22017-04-02 23:53:04 -07002646 }
2647 // ...and then try to adapt again.
mflodmancc3d4422017-08-03 08:27:51 -07002648 video_stream_encoder_->TriggerCpuOveruse();
Jonathan Yubc771b72017-12-08 17:04:29 -08002649 } while (video_source_.sink_wants().max_framerate_fps <
2650 last_wants.max_framerate_fps);
sprangc5d62e22017-04-02 23:53:04 -07002651
Jonathan Yubc771b72017-12-08 17:04:29 -08002652 VerifyFpsEqResolutionMax(video_source_.sink_wants(), kMinFramerateFps);
asaperssonf7e294d2017-06-13 23:25:22 -07002653
mflodmancc3d4422017-08-03 08:27:51 -07002654 video_stream_encoder_->Stop();
sprangc5d62e22017-04-02 23:53:04 -07002655}
asaperssonf7e294d2017-06-13 23:25:22 -07002656
mflodmancc3d4422017-08-03 08:27:51 -07002657TEST_F(VideoStreamEncoderTest,
2658 AdaptsResolutionAndFramerateForLowQuality_BalancedMode) {
asaperssonf7e294d2017-06-13 23:25:22 -07002659 const int kWidth = 1280;
2660 const int kHeight = 720;
2661 const int64_t kFrameIntervalMs = 150;
2662 int64_t timestamp_ms = kFrameIntervalMs;
mflodmancc3d4422017-08-03 08:27:51 -07002663 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -07002664
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002665 // Enable BALANCED preference, no initial limitation.
asaperssonf7e294d2017-06-13 23:25:22 -07002666 AdaptingFrameForwarder source;
2667 source.set_adaptation_enabled(true);
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002668 video_stream_encoder_->SetSource(&source,
2669 webrtc::DegradationPreference::BALANCED);
asaperssonf7e294d2017-06-13 23:25:22 -07002670 timestamp_ms += kFrameIntervalMs;
2671 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002672 WaitForEncodedFrame(kWidth, kHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +02002673 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07002674 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2675 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2676 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2677
2678 // Trigger adapt down, expect scaled down resolution (960x540@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002679 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002680 timestamp_ms += kFrameIntervalMs;
2681 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002682 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002683 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
2684 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2685 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2686 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2687
2688 // Trigger adapt down, expect scaled down resolution (640x360@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002689 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002690 timestamp_ms += kFrameIntervalMs;
2691 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002692 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002693 VerifyFpsMaxResolutionLt(source.sink_wants(), source.last_wants());
2694 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2695 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2696 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2697
2698 // Trigger adapt down, expect reduced fps (640x360@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07002699 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002700 timestamp_ms += kFrameIntervalMs;
2701 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002702 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002703 VerifyFpsLtResolutionEq(source.sink_wants(), source.last_wants());
2704 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2705 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2706 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2707
2708 // Trigger adapt down, expect scaled down resolution (480x270@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07002709 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002710 timestamp_ms += kFrameIntervalMs;
2711 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002712 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002713 VerifyFpsEqResolutionLt(source.sink_wants(), source.last_wants());
2714 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2715 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2716 EXPECT_EQ(4, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2717
2718 // Restrict bitrate, trigger adapt down, expect reduced fps (480x270@10fps).
mflodmancc3d4422017-08-03 08:27:51 -07002719 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002720 timestamp_ms += kFrameIntervalMs;
2721 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002722 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002723 VerifyFpsLtResolutionEq(source.sink_wants(), source.last_wants());
2724 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2725 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2726 EXPECT_EQ(5, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2727
2728 // Trigger adapt down, expect scaled down resolution (320x180@10fps).
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 VerifyFpsEqResolutionLt(source.sink_wants(), source.last_wants());
2734 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2735 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2736 EXPECT_EQ(6, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2737
2738 // Trigger adapt down, expect reduced fps (320x180@7fps).
mflodmancc3d4422017-08-03 08:27:51 -07002739 video_stream_encoder_->TriggerQualityLow();
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 VerifyFpsLtResolutionEq(source.sink_wants(), source.last_wants());
2744 rtc::VideoSinkWants last_wants = source.sink_wants();
2745 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2746 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2747 EXPECT_EQ(7, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2748
2749 // Trigger adapt down, min resolution reached, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07002750 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002751 timestamp_ms += kFrameIntervalMs;
2752 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002753 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002754 VerifyFpsEqResolutionEq(source.sink_wants(), last_wants);
2755 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2756 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2757 EXPECT_EQ(7, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2758
2759 // Trigger adapt down, expect expect increased fps (320x180@10fps).
mflodmancc3d4422017-08-03 08:27:51 -07002760 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002761 timestamp_ms += kFrameIntervalMs;
2762 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002763 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002764 VerifyFpsGtResolutionEq(source.sink_wants(), source.last_wants());
2765 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2766 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2767 EXPECT_EQ(8, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2768
2769 // Trigger adapt up, expect upscaled resolution (480x270@10fps).
mflodmancc3d4422017-08-03 08:27:51 -07002770 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002771 timestamp_ms += kFrameIntervalMs;
2772 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002773 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002774 VerifyFpsEqResolutionGt(source.sink_wants(), source.last_wants());
2775 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2776 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2777 EXPECT_EQ(9, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2778
2779 // Increase bitrate, trigger adapt up, expect increased fps (480x270@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07002780 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002781 timestamp_ms += kFrameIntervalMs;
2782 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002783 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002784 VerifyFpsGtResolutionEq(source.sink_wants(), source.last_wants());
2785 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2786 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2787 EXPECT_EQ(10, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2788
2789 // Trigger adapt up, expect upscaled resolution (640x360@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07002790 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002791 timestamp_ms += kFrameIntervalMs;
2792 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002793 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002794 VerifyFpsEqResolutionGt(source.sink_wants(), source.last_wants());
2795 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2796 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2797 EXPECT_EQ(11, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2798
2799 // Trigger adapt up, expect increased fps (640x360@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002800 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002801 timestamp_ms += kFrameIntervalMs;
2802 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002803 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002804 VerifyFpsMaxResolutionEq(source.sink_wants(), source.last_wants());
2805 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2806 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2807 EXPECT_EQ(12, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2808
2809 // Trigger adapt up, expect upscaled resolution (960x540@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002810 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002811 timestamp_ms += kFrameIntervalMs;
2812 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002813 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002814 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
2815 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2816 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2817 EXPECT_EQ(13, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2818
2819 // Trigger adapt up, expect no restriction (1280x720fps@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002820 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002821 timestamp_ms += kFrameIntervalMs;
2822 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002823 WaitForEncodedFrame(kWidth, kHeight);
asaperssonf7e294d2017-06-13 23:25:22 -07002824 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
Åsa Persson8c1bf952018-09-13 10:42:19 +02002825 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07002826 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2827 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2828 EXPECT_EQ(14, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2829
2830 // Trigger adapt up, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07002831 video_stream_encoder_->TriggerQualityHigh();
Åsa Persson8c1bf952018-09-13 10:42:19 +02002832 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07002833 EXPECT_EQ(14, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2834
mflodmancc3d4422017-08-03 08:27:51 -07002835 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07002836}
2837
mflodmancc3d4422017-08-03 08:27:51 -07002838TEST_F(VideoStreamEncoderTest, AdaptWithTwoReasonsAndDifferentOrder_Framerate) {
asaperssonf7e294d2017-06-13 23:25:22 -07002839 const int kWidth = 1280;
2840 const int kHeight = 720;
2841 const int64_t kFrameIntervalMs = 150;
2842 int64_t timestamp_ms = kFrameIntervalMs;
mflodmancc3d4422017-08-03 08:27:51 -07002843 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -07002844
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002845 // Enable BALANCED preference, no initial limitation.
asaperssonf7e294d2017-06-13 23:25:22 -07002846 AdaptingFrameForwarder source;
2847 source.set_adaptation_enabled(true);
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002848 video_stream_encoder_->SetSource(&source,
2849 webrtc::DegradationPreference::BALANCED);
asaperssonf7e294d2017-06-13 23:25:22 -07002850 timestamp_ms += kFrameIntervalMs;
2851 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002852 WaitForEncodedFrame(kWidth, kHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +02002853 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07002854 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2855 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2856 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2857 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
2858 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2859 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2860
2861 // Trigger cpu adapt down, expect scaled down resolution (960x540@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002862 video_stream_encoder_->TriggerCpuOveruse();
asaperssonf7e294d2017-06-13 23:25:22 -07002863 timestamp_ms += kFrameIntervalMs;
2864 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002865 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002866 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
2867 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2868 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2869 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2870 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
2871 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2872 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2873
2874 // Trigger cpu adapt down, expect scaled down resolution (640x360@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002875 video_stream_encoder_->TriggerCpuOveruse();
asaperssonf7e294d2017-06-13 23:25:22 -07002876 timestamp_ms += kFrameIntervalMs;
2877 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002878 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002879 VerifyFpsMaxResolutionLt(source.sink_wants(), source.last_wants());
2880 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2881 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2882 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2883 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
2884 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2885 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2886
2887 // Trigger quality adapt down, expect reduced fps (640x360@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07002888 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002889 timestamp_ms += kFrameIntervalMs;
2890 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002891 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002892 VerifyFpsLtResolutionEq(source.sink_wants(), source.last_wants());
2893 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2894 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2895 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2896 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
2897 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2898 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2899
2900 // Trigger cpu adapt up, expect increased fps (640x360@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002901 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssonf7e294d2017-06-13 23:25:22 -07002902 timestamp_ms += kFrameIntervalMs;
2903 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002904 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002905 VerifyFpsMaxResolutionEq(source.sink_wants(), source.last_wants());
2906 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2907 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2908 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2909 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
2910 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2911 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2912
2913 // Trigger quality adapt up, expect upscaled resolution (960x540@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002914 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002915 timestamp_ms += kFrameIntervalMs;
2916 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002917 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002918 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
2919 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2920 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2921 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2922 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
2923 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2924 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2925
2926 // Trigger cpu adapt up, expect no restriction (1280x720fps@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002927 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssonf7e294d2017-06-13 23:25:22 -07002928 timestamp_ms += kFrameIntervalMs;
2929 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002930 WaitForEncodedFrame(kWidth, kHeight);
asaperssonf7e294d2017-06-13 23:25:22 -07002931 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
Åsa Persson8c1bf952018-09-13 10:42:19 +02002932 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07002933 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2934 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2935 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2936 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
2937 EXPECT_EQ(4, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2938 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2939
2940 // Trigger adapt up, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07002941 video_stream_encoder_->TriggerQualityHigh();
Åsa Persson8c1bf952018-09-13 10:42:19 +02002942 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07002943 EXPECT_EQ(4, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2944 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2945
mflodmancc3d4422017-08-03 08:27:51 -07002946 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07002947}
2948
mflodmancc3d4422017-08-03 08:27:51 -07002949TEST_F(VideoStreamEncoderTest,
2950 AdaptWithTwoReasonsAndDifferentOrder_Resolution) {
asaperssonf7e294d2017-06-13 23:25:22 -07002951 const int kWidth = 640;
2952 const int kHeight = 360;
2953 const int kFpsLimit = 15;
2954 const int64_t kFrameIntervalMs = 150;
2955 int64_t timestamp_ms = kFrameIntervalMs;
mflodmancc3d4422017-08-03 08:27:51 -07002956 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -07002957
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002958 // Enable BALANCED preference, no initial limitation.
asaperssonf7e294d2017-06-13 23:25:22 -07002959 AdaptingFrameForwarder source;
2960 source.set_adaptation_enabled(true);
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002961 video_stream_encoder_->SetSource(&source,
2962 webrtc::DegradationPreference::BALANCED);
asaperssonf7e294d2017-06-13 23:25:22 -07002963 timestamp_ms += kFrameIntervalMs;
2964 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002965 WaitForEncodedFrame(kWidth, kHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +02002966 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07002967 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2968 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2969 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2970 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
2971 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2972 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2973
2974 // Trigger cpu adapt down, expect scaled down framerate (640x360@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07002975 video_stream_encoder_->TriggerCpuOveruse();
asaperssonf7e294d2017-06-13 23:25:22 -07002976 timestamp_ms += kFrameIntervalMs;
2977 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002978 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002979 VerifyFpsEqResolutionMax(source.sink_wants(), kFpsLimit);
2980 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2981 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2982 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2983 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_framerate);
2984 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2985 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2986
2987 // Trigger quality adapt down, expect scaled down resolution (480x270@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07002988 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002989 timestamp_ms += kFrameIntervalMs;
2990 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002991 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002992 VerifyFpsEqResolutionLt(source.sink_wants(), source.last_wants());
2993 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2994 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2995 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2996 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_framerate);
2997 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2998 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2999
3000 // Trigger cpu adapt up, expect upscaled resolution (640x360@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07003001 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssonf7e294d2017-06-13 23:25:22 -07003002 timestamp_ms += kFrameIntervalMs;
3003 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003004 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07003005 VerifyFpsEqResolutionGt(source.sink_wants(), source.last_wants());
3006 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
3007 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
3008 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
3009 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
3010 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
3011 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3012
3013 // Trigger quality adapt up, expect increased fps (640x360@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07003014 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07003015 timestamp_ms += kFrameIntervalMs;
3016 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003017 WaitForEncodedFrame(timestamp_ms);
Åsa Persson8c1bf952018-09-13 10:42:19 +02003018 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07003019 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
3020 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
3021 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
3022 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
3023 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
3024 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3025
3026 // Trigger adapt up, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07003027 video_stream_encoder_->TriggerQualityHigh();
Åsa Persson8c1bf952018-09-13 10:42:19 +02003028 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07003029 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
3030 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3031
mflodmancc3d4422017-08-03 08:27:51 -07003032 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07003033}
3034
mflodmancc3d4422017-08-03 08:27:51 -07003035TEST_F(VideoStreamEncoderTest, AcceptsFullHdAdaptedDownSimulcastFrames) {
ilnik6b826ef2017-06-16 06:53:48 -07003036 // Simulates simulcast behavior and makes highest stream resolutions divisible
3037 // by 4.
3038 class CroppingVideoStreamFactory
3039 : public VideoEncoderConfig::VideoStreamFactoryInterface {
3040 public:
3041 explicit CroppingVideoStreamFactory(size_t num_temporal_layers,
3042 int framerate)
3043 : num_temporal_layers_(num_temporal_layers), framerate_(framerate) {
3044 EXPECT_GT(num_temporal_layers, 0u);
3045 EXPECT_GT(framerate, 0);
3046 }
3047
3048 private:
3049 std::vector<VideoStream> CreateEncoderStreams(
3050 int width,
3051 int height,
3052 const VideoEncoderConfig& encoder_config) override {
Yves Gerey665174f2018-06-19 15:03:05 +02003053 std::vector<VideoStream> streams = test::CreateVideoStreams(
3054 width - width % 4, height - height % 4, encoder_config);
ilnik6b826ef2017-06-16 06:53:48 -07003055 for (VideoStream& stream : streams) {
Sergey Silkina796a7e2018-03-01 15:11:29 +01003056 stream.num_temporal_layers = num_temporal_layers_;
ilnik6b826ef2017-06-16 06:53:48 -07003057 stream.max_framerate = framerate_;
3058 }
3059 return streams;
3060 }
3061
3062 const size_t num_temporal_layers_;
3063 const int framerate_;
3064 };
3065
3066 const int kFrameWidth = 1920;
3067 const int kFrameHeight = 1080;
3068 // 3/4 of 1920.
3069 const int kAdaptedFrameWidth = 1440;
3070 // 3/4 of 1080 rounded down to multiple of 4.
3071 const int kAdaptedFrameHeight = 808;
3072 const int kFramerate = 24;
3073
mflodmancc3d4422017-08-03 08:27:51 -07003074 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
ilnik6b826ef2017-06-16 06:53:48 -07003075 // Trigger reconfigure encoder (without resetting the entire instance).
3076 VideoEncoderConfig video_encoder_config;
Niels Möller259a4972018-04-05 15:36:51 +02003077 video_encoder_config.codec_type = kVideoCodecVP8;
ilnik6b826ef2017-06-16 06:53:48 -07003078 video_encoder_config.max_bitrate_bps = kTargetBitrateBps;
3079 video_encoder_config.number_of_streams = 1;
3080 video_encoder_config.video_stream_factory =
3081 new rtc::RefCountedObject<CroppingVideoStreamFactory>(1, kFramerate);
mflodmancc3d4422017-08-03 08:27:51 -07003082 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
Niels Möllerf1338562018-04-26 09:51:47 +02003083 kMaxPayloadLength);
mflodmancc3d4422017-08-03 08:27:51 -07003084 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
ilnik6b826ef2017-06-16 06:53:48 -07003085
3086 video_source_.set_adaptation_enabled(true);
3087
3088 video_source_.IncomingCapturedFrame(
3089 CreateFrame(1, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07003090 WaitForEncodedFrame(kFrameWidth, kFrameHeight);
ilnik6b826ef2017-06-16 06:53:48 -07003091
3092 // Trigger CPU overuse, downscale by 3/4.
mflodmancc3d4422017-08-03 08:27:51 -07003093 video_stream_encoder_->TriggerCpuOveruse();
ilnik6b826ef2017-06-16 06:53:48 -07003094 video_source_.IncomingCapturedFrame(
3095 CreateFrame(2, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07003096 WaitForEncodedFrame(kAdaptedFrameWidth, kAdaptedFrameHeight);
ilnik6b826ef2017-06-16 06:53:48 -07003097
mflodmancc3d4422017-08-03 08:27:51 -07003098 video_stream_encoder_->Stop();
ilnik6b826ef2017-06-16 06:53:48 -07003099}
3100
mflodmancc3d4422017-08-03 08:27:51 -07003101TEST_F(VideoStreamEncoderTest, PeriodicallyUpdatesChannelParameters) {
sprang4847ae62017-06-27 07:06:52 -07003102 const int kFrameWidth = 1280;
3103 const int kFrameHeight = 720;
3104 const int kLowFps = 2;
3105 const int kHighFps = 30;
3106
mflodmancc3d4422017-08-03 08:27:51 -07003107 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
sprang4847ae62017-06-27 07:06:52 -07003108
3109 int64_t timestamp_ms = fake_clock_.TimeNanos() / rtc::kNumNanosecsPerMillisec;
3110 max_framerate_ = kLowFps;
3111
3112 // Insert 2 seconds of 2fps video.
3113 for (int i = 0; i < kLowFps * 2; ++i) {
3114 video_source_.IncomingCapturedFrame(
3115 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
3116 WaitForEncodedFrame(timestamp_ms);
3117 timestamp_ms += 1000 / kLowFps;
3118 }
3119
3120 // Make sure encoder is updated with new target.
mflodmancc3d4422017-08-03 08:27:51 -07003121 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
sprang4847ae62017-06-27 07:06:52 -07003122 video_source_.IncomingCapturedFrame(
3123 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
3124 WaitForEncodedFrame(timestamp_ms);
3125 timestamp_ms += 1000 / kLowFps;
3126
3127 EXPECT_EQ(kLowFps, fake_encoder_.GetConfiguredInputFramerate());
3128
3129 // Insert 30fps frames for just a little more than the forced update period.
3130 const int kVcmTimerIntervalFrames =
3131 (vcm::VCMProcessTimer::kDefaultProcessIntervalMs * kHighFps) / 1000;
3132 const int kFrameIntervalMs = 1000 / kHighFps;
3133 max_framerate_ = kHighFps;
3134 for (int i = 0; i < kVcmTimerIntervalFrames + 2; ++i) {
3135 video_source_.IncomingCapturedFrame(
3136 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
3137 // Wait for encoded frame, but skip ahead if it doesn't arrive as it might
3138 // be dropped if the encoder hans't been updated with the new higher target
3139 // framerate yet, causing it to overshoot the target bitrate and then
3140 // suffering the wrath of the media optimizer.
3141 TimedWaitForEncodedFrame(timestamp_ms, 2 * kFrameIntervalMs);
3142 timestamp_ms += kFrameIntervalMs;
3143 }
3144
3145 // Don expect correct measurement just yet, but it should be higher than
3146 // before.
3147 EXPECT_GT(fake_encoder_.GetConfiguredInputFramerate(), kLowFps);
3148
mflodmancc3d4422017-08-03 08:27:51 -07003149 video_stream_encoder_->Stop();
sprang4847ae62017-06-27 07:06:52 -07003150}
3151
mflodmancc3d4422017-08-03 08:27:51 -07003152TEST_F(VideoStreamEncoderTest, DoesNotUpdateBitrateAllocationWhenSuspended) {
sprang4847ae62017-06-27 07:06:52 -07003153 const int kFrameWidth = 1280;
3154 const int kFrameHeight = 720;
3155 const int kTargetBitrateBps = 1000000;
3156
3157 MockBitrateObserver bitrate_observer;
Niels Möller0327c2d2018-05-21 14:09:31 +02003158 video_stream_encoder_->SetBitrateAllocationObserver(&bitrate_observer);
Niels Möller6613f8e2019-01-10 10:30:21 +01003159
3160 EXPECT_CALL(bitrate_observer, OnBitrateAllocationUpdated(_)).Times(1);
3161 // Initial bitrate update.
mflodmancc3d4422017-08-03 08:27:51 -07003162 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
3163 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
sprang4847ae62017-06-27 07:06:52 -07003164
3165 // Insert a first video frame, causes another bitrate update.
3166 int64_t timestamp_ms = fake_clock_.TimeNanos() / rtc::kNumNanosecsPerMillisec;
3167 EXPECT_CALL(bitrate_observer, OnBitrateAllocationUpdated(_)).Times(1);
3168 video_source_.IncomingCapturedFrame(
3169 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
3170 WaitForEncodedFrame(timestamp_ms);
3171
3172 // Next, simulate video suspension due to pacer queue overrun.
mflodmancc3d4422017-08-03 08:27:51 -07003173 video_stream_encoder_->OnBitrateUpdated(0, 0, 1);
sprang4847ae62017-06-27 07:06:52 -07003174
3175 // Skip ahead until a new periodic parameter update should have occured.
3176 timestamp_ms += vcm::VCMProcessTimer::kDefaultProcessIntervalMs;
3177 fake_clock_.AdvanceTimeMicros(
3178 vcm::VCMProcessTimer::kDefaultProcessIntervalMs *
3179 rtc::kNumMicrosecsPerMillisec);
3180
3181 // Bitrate observer should not be called.
3182 EXPECT_CALL(bitrate_observer, OnBitrateAllocationUpdated(_)).Times(0);
3183 video_source_.IncomingCapturedFrame(
3184 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
3185 ExpectDroppedFrame();
3186
mflodmancc3d4422017-08-03 08:27:51 -07003187 video_stream_encoder_->Stop();
sprang4847ae62017-06-27 07:06:52 -07003188}
ilnik6b826ef2017-06-16 06:53:48 -07003189
Niels Möller4db138e2018-04-19 09:04:13 +02003190TEST_F(VideoStreamEncoderTest,
3191 DefaultCpuAdaptationThresholdsForSoftwareEncoder) {
3192 const int kFrameWidth = 1280;
3193 const int kFrameHeight = 720;
3194 const CpuOveruseOptions default_options;
3195 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
3196 video_source_.IncomingCapturedFrame(
3197 CreateFrame(1, kFrameWidth, kFrameHeight));
3198 WaitForEncodedFrame(1);
3199 EXPECT_EQ(video_stream_encoder_->overuse_detector_proxy_->GetOptions()
3200 .low_encode_usage_threshold_percent,
3201 default_options.low_encode_usage_threshold_percent);
3202 EXPECT_EQ(video_stream_encoder_->overuse_detector_proxy_->GetOptions()
3203 .high_encode_usage_threshold_percent,
3204 default_options.high_encode_usage_threshold_percent);
3205 video_stream_encoder_->Stop();
3206}
3207
3208TEST_F(VideoStreamEncoderTest,
3209 HigherCpuAdaptationThresholdsForHardwareEncoder) {
3210 const int kFrameWidth = 1280;
3211 const int kFrameHeight = 720;
3212 CpuOveruseOptions hardware_options;
3213 hardware_options.low_encode_usage_threshold_percent = 150;
3214 hardware_options.high_encode_usage_threshold_percent = 200;
Mirta Dvornicic1ec2a162018-12-10 09:47:34 +00003215 encoder_factory_.SetIsHardwareAccelerated(true);
Niels Möller4db138e2018-04-19 09:04:13 +02003216
3217 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
3218 video_source_.IncomingCapturedFrame(
3219 CreateFrame(1, kFrameWidth, kFrameHeight));
3220 WaitForEncodedFrame(1);
3221 EXPECT_EQ(video_stream_encoder_->overuse_detector_proxy_->GetOptions()
3222 .low_encode_usage_threshold_percent,
3223 hardware_options.low_encode_usage_threshold_percent);
3224 EXPECT_EQ(video_stream_encoder_->overuse_detector_proxy_->GetOptions()
3225 .high_encode_usage_threshold_percent,
3226 hardware_options.high_encode_usage_threshold_percent);
3227 video_stream_encoder_->Stop();
3228}
3229
perkj26091b12016-09-01 01:17:40 -07003230} // namespace webrtc